Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRILL-8450: Add Data Type Inference to XML Format Plugin #2819

Merged
merged 6 commits into from
Aug 22, 2023

Conversation

cgivre
Copy link
Contributor

@cgivre cgivre commented Aug 8, 2023

DRILL-8450: Add Data Type Inference to XML Format Plugin

Description

This PR adds data type inference to the XML format plugin. In similar fashion to other plugins, it adds a new configuration parameter: allTextMode, which when set to true, reads all data as strings. The default is true.
Note that the inference is limited to doubles, date, timestamps, boolean and strings.

Documentation

Updated README

Testing

Added unit test.

@cgivre cgivre self-assigned this Aug 8, 2023
@cgivre cgivre added enhancement PRs that add a new functionality to Drill doc-impacting PRs that affect the documentation labels Aug 8, 2023
Copy link
Contributor

@mbeckerle mbeckerle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 One comment to fix.

This was simpler than I expected. You already had the typify() method which does the real work.

I learned how to add a new config property to this thing. Very useful.

All fields are read as strings. Nested fields are read as maps. Future functionality could include support for lists.
The XML reader has an `allTextMode` which, when set to `true` reads all data fields as strings.
When set to `false`, Drill will attempt to infer data types.
Nested fields are read as maps. Future functionality could include support for lists.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really part of this change set, but I don't know what you are suggesting by "future functionality could include support for lists." I'd like to understand that plan/idea just as part of grokking all of this XML mapping.

Entry<Class, String> result = Typifier.typify(data);
String dataType = result.getKey().getSimpleName();

// If the string is empty, return UNKNOWN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next line of code contradicts this comment by returning VARCHAR.
(Unless VARCHAR == UNKNOWN, which is news to me.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mbeckerle Drill doesn't really have an UNKNOWN data type. The way the typifier works is that if it can't determine the datatype, it falls back to string which can basically accept anything.

Regarding the lists... The issue is that to create a list, you have to set the data mode to REPEATED. The problem with XML is that there's no real way to know if a field is repeated or not. Consider this:

<book>
  <author>a</author>
</book>
<book>
    <author>a1</author>
    <author>a2</author>
</book>

Since Drill uses the streaming reader, when it first encounters the author field, it would add an entry for a VARCHAR field. However, when it gets to the next author record, it should be list, but there's no way to really know that w/o a schema.

With JSON we don't have this problem because it uses [ to denote lists.

Does that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes perfect sense.

For XML you need XSD to know what's potentially repeating.

Sometimes that is easy because of minOccurs/maxOccurs.

But there's also these "implied arrays".

<element name="a" type="xs:int"/><!-- this is a[1] -->
<element name="b" type="xs:int"/>
<element name="a" type="xs:int"/><!-- this is a[2] -->

That's allowed in both XSD and DFDL schemas (though I want to change Daffodil to issue a warning if you do this, because it is such a bad idea when representing structured data.)

The element 'a' looks like an array, in that you can index it.

I think for drill there are just 2 columns: 'a', 'b', but as there is more than one declaration for 'a', it is an implied array.

Even just detecting this (and disallowing it for now) requires a more sophisticated metadata builder which is what I'm working on now.

@cgivre cgivre marked this pull request as draft August 10, 2023 15:11
@cgivre
Copy link
Contributor Author

cgivre commented Aug 10, 2023

Converting to draft. There's a unit test failing in the HTTP plugin.

@cgivre cgivre marked this pull request as ready for review August 14, 2023 02:09
@cgivre
Copy link
Contributor Author

cgivre commented Aug 14, 2023

@mbeckerle Unit tests fixed. I also added the data type inference for APIs that generate XML.
@jnturton, The CI is still failing with that Kerberos issue.

@cgivre
Copy link
Contributor Author

cgivre commented Aug 18, 2023

@mbeckerle Could you please take another look. I had to fix a few things for a unit test. Thx!

Copy link
Contributor

@mbeckerle mbeckerle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 last UT fix change looks fine, just a question.

@@ -111,7 +111,7 @@ public String toString() {
public static class HttpXmlOptionsBuilder {

private int dataLevel;
private boolean allTextMode;
private Boolean allTextMode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there were 3 modes: allTextMode, allNumbersAreDouble mode, and infer-types mode.

So why is this a boolean vs am enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mbeckerle
In the JSON reader there are two parameters: allTextMode and readAllNumbersAsDouble. Both are boolean. For the XML reader, I chose not to implement the readAllNumbersAsDouble parameter because in practice, it requires very clean data. From using Drill with clients, I can tell you from a lot of personal experience that this was one of the biggest data challenges. For instance, you'd get data where there was an DOUBLE field and then there would be a row with zero denoted as 0. This would then cause schema change exceptions.

We have actually made significant improvements in Drill's implicit casting rules which do prevent a lot of schema change exceptions and as a result, IMHO, it makes distinguishing between INTs and DOUBLES a lot less important. So.. out of laziness I decided it wasn't worth it. I can be convinced otherwise.

@cgivre
Copy link
Contributor Author

cgivre commented Aug 21, 2023

@mbeckerle @jnturton Are we ok to merge this? I'll add support for arrays in a separate PR.

@jnturton
Copy link
Contributor

LGTM

@cgivre cgivre merged commit ee1cfeb into apache:master Aug 22, 2023
8 checks passed
@cgivre cgivre deleted the xml_data_types branch August 22, 2023 00:48
cgivre added a commit to cgivre/drill that referenced this pull request Nov 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc-impacting PRs that affect the documentation enhancement PRs that add a new functionality to Drill
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants