ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray - #3721

Closed
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769
Closed

ARROW-3769: [C++] Add support for reading non-dictionary encoded binary Parquet columns directly as DictionaryArray#3721
hatemhelal wants to merge 35 commits into
apache:masterfrom
mathworks:arrow-3769

Conversation

@hatemhelal

@hatemhelalhatemhelal commented Feb 20, 2019

Copy link
Copy Markdown
Contributor

This patch addresses the following JIRAS:

  • ARROW-3769: refactored record reader logic to toggle between the different builder depending on the column type (String or Binary) and the requested array type (Chunked "dense" or Dictionary). These changes are covered by unittests and benchmarks.
  • PARQUET-1537: fixed increment and covered by unittests.

Also included is an experimental class ArrowReaderProperties that can be used to select which columns are read directly as an arrow::DictionaryArray. I think some more work is needed to fully address the requests in ARROW-3772. Namely, the ability automatically infer which columns in a parquet file should be read as DictionaryArray. My current thinking is that this would be solved by introducing optional arrow type metadata to files written with the parquet::arrow::FileWriter. There are some limitations with this approach but it would seem to satisfy the requests for users working with parquet files within the supported arrow ecosystem.

Note that the behavior with this patch is that incremental reading of a parquet file will not resolve the global dictionary for all of the row groups. There are a few possible solutions for this:

  • Introduce a concept of an "unknown" dictionary. This will enable concatenating multiple row groups together so long as we define unknown dictionaries as equal (assuming indices have the same data type)
  • Add an API for merging the schemas from multiple tables together. This could be used after reading multiple row groups to enable concatenating the tables together into one.
  • Add an API for inferring the global dictionary for the entire file. This could be an expensive operation so ideally would be made optional.
  • Allow a user-specified dictionary. This could be useful in the limited case where a caller already knows the global dictionary list (computed through some other mechanism).

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated

@kevingurneykevingurneyFeb 22, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a comment here which provides an example of what the output of MakeRandomStringsWithRepeats might look like for example values of num_unique and num_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feel free to disregard this if you don't think it is helpful, but you could consider including alphabet (i.e. a list of letters from which to draw randomly) as one of the input arguments to MakeRandomStringsWithRepeats, rather than using ::arrow::random_ascii inside of the function body. This might help facilitate greater flexibility/re-usability of this function in other contexts. For example, there might be a case in the future where a client might want to generate a random string containing Unicode characters, rather than just ASCII.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I like this idea and will take this up in ARROW-4661

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
Comment threadcpp/src/parquet/encoding-test.cc Outdated
@kevingurney

Copy link
Copy Markdown
Member

@hatemhelal I did an initial review of your changes, and overall they look good!

Almost all of my feedback is minor and primarily stylistic in nature. I am new to this area of the code base, so you can take my comments with a grain of salt. Many of them may stem more from my own lack of knowledge in this area, and my attempt to learn more, than from actual issues with the code.

Let me know if you have any questions regarding any of my feedback.

Thanks!

Comment threadcpp/src/parquet/encoding-test.cc Outdated
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Thanks @kevingurney and @emkornfield for the code review! Let me know if you think of anything else.

@rdmellordmello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only have some minor comments, I think this looks really good overall!

Comment threadcpp/src/parquet/encoding-benchmark.cc Outdated
Comment threadcpp/src/parquet/encoding.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be getting confused by the diff engine on GitHub, but is this the same code as on lines 725-730? If so, is there a common function both these methods could call?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

They are the same but I don't see an easy way to share an implementation. Let me think on this one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored this slightly in the latest commit. @rdmello let me know how this looks to you.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

The latest commit adds a test case for PARQUET-1537. Just needed to have a null in the input data to reproduce the reported issue.

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

We've largely stopped using MT in unit tests because it's slower than the alternatives (cc @pitrou)

@pitrou

pitrou commented Feb 27, 2019

Copy link
Copy Markdown
Member

What does MT mean in this context?

edit: ah, Mersenne Twister. Yes, you wouldn't believe it, but it made the tests significantly slower.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Would you recommend swapping back to the default random engine or another engine entirely?

@pitrou

Copy link
Copy Markdown
Member

The default random engine, or anything else that's fast (for example a xorshift-like PRNG). Are you worried about poor quality of the default engine?

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I think default engine should be good reproducibility is the main concern for the benchmark. Probably just an overreaction to "implementation defined"...

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Switched back to std::default_random_engine. I'd like to move this utility into the testing/random.h in ARROW-4661

@wesm

wesm commented Feb 27, 2019

Copy link
Copy Markdown
Member

I can review this soon. Is this still WIP?

@hatemhelal
hatemhelal marked this pull request as ready for review February 28, 2019 08:18
@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

I can review this soon. Is this still WIP?

I think this is ready to review. This PR should resolve:

My plan is to use ARROW-3772 to build on this change and plumb this through to the parquet -> arrow reader.

@hatemhelal

Copy link
Copy Markdown
ContributorAuthor

Most recent commit adds changes that go towards resolving ARROW-3772

  • ArrowReaderProperties object that is used by parquet::arrow::FileReader to select whether or not to use_threads or read a particular column as a DictionaryArray.
  • The read_dictionary flag is plumbed down through the column reading logic to toggle between either constructing a DictionaryArray or otherwise a chunked dense array.

@wesm can you let me know if this is heading in the right direction? I'm working on some tests to accompany these changes.

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #3721 into master will increase coverage by 0.82%.
The diff coverage is 96.88%.

Impacted file tree graph

@@ Coverage Diff @@## master #3721 +/- ##
==========================================
+ Coverage 87.81% 88.64% +0.82% 
==========================================
Files 727 594 -133 Lines 89504 80194 -9310 Branches 1252 0 -1252 ==========================================
- Hits 78600 71089 -7511 + Misses 10788 9105 -1683 + Partials 116 0 -116
Impacted FilesCoverage Δ
cpp/src/arrow/testing/random.h100% <ø> (ø)⬆️
cpp/src/parquet/arrow/reader.h100% <100%> (ø)
cpp/src/parquet/encoding.cc93.84% <100%> (+6.03%)⬆️
cpp/src/parquet/encoding-test.cc100% <100%> (ø)⬆️
cpp/src/parquet/arrow/arrow-reader-writer-test.cc95.47% <100%> (+0.12%)⬆️
cpp/src/parquet/encoding.h98.46% <100%> (+0.63%)⬆️
cpp/src/parquet/arrow/record_reader.cc87.97% <90.21%> (-0.6%)⬇️
cpp/src/arrow/testing/random.cc97.56% <93.93%> (-2.44%)⬇️
cpp/src/parquet/arrow/reader.cc84.15% <97.87%> (+0.48%)⬆️
cpp/src/plasma/thirdparty/ae/ae.c70.75% <0%> (-0.95%)⬇️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d73e0a...f644fff. Read the comment docs.

@wesmwesm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, will merge this once the build passes. Thanks @hatemhelal for your patience and for addressing my comments

@wesm

wesm commented Mar 18, 2019

Copy link
Copy Markdown
Member

Ah well the build is passed so merging now

@wesmwesm closed this in fd0b90aMar 18, 2019
@xhochy

Copy link
Copy Markdown
Member

Huge thanks for tackling this @hatemhelal !

@hatemhelal
hatemhelal deleted the arrow-3769 branch July 11, 2019 07:46
kou added a commit that referenced this pull request Dec 7, 2020
As per a TODO left in ARROW-3769 / #3721 we can now use the `GTEST_SKIP` macro in `parquet/encoding-test.cpp`. `GTEST_SKIP` was added in gtest 1.10.0 so this involves bumping our minimal gtest version from 1.8.1
Closes#8782 from arw2019/ARROW-10746-GTEST_SKIP
Lead-authored-by: Andrew Wieteska <andrew.r.wieteska@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@hatemhelal@kevingurney@wesm@pitrou@codecov-io@xhochy@rdmello@emkornfield