Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[ORC-341] Support time zone as a parameter for Java reader and writer #249

Closed
wants to merge 3 commits into from

Conversation

jcamachor
Copy link
Contributor

No description provided.

@wgtmac
Copy link
Member

wgtmac commented Apr 16, 2018

Why do we need this change?

@jcamachor
Copy link
Contributor Author

@wgtmac , see discussion in https://issues.apache.org/jira/browse/HIVE-12192 for more context.

@wgtmac
Copy link
Member

wgtmac commented Apr 17, 2018

AFAIK, I don't think ORC has any issue in HIVE-12192. What ORC guarantees is that we should always get same wall clock time representation w/o timezone. Current Java implementation leverages java.sql.Timestamp which uses local timezone and that's why writer and reader always use timestamp values in local timezone. Unless we add a new TimestampColumnVector which enforces UTC timezone to adopt your change here.

@omalley
Copy link
Contributor

omalley commented Apr 17, 2018

@jcamachor I'd suggest a much simpler API:

  • Instead of passing in the reader timezone, make a boolean option to useUtcForTimestamp.
  • Extend TimestampColumnVector to have a boolean isUTC field.
  • The TimestampTreeWriter can use the isUTC in the ColumnVector to determine if it is in UTC.
  • The reader can set isUTC appropriately based on the option.

Thoughts?

@omalley
Copy link
Contributor

omalley commented Apr 17, 2018

Also note that the C++ reader already uses UTC for its TimestampColumnVector. :)

@jcamachor
Copy link
Contributor Author

@omalley , it seems like a good idea, let me explore it and refresh the PR. I will adapt HIVE-19226 to these new changes too.

@wgtmac , I understand you are suggesting that this can be fixed only from Hive side? Problem is that existing ORC files should still be read properly, hence you would need to recognize old vs new ORC files. In addition, you will apply displacement twice when reading/writing, in Hive and in ORC. It seems to me the cleaner solution is just being able to point to ORC that timestamp data is in UTC from Java reader/writer. FWIW, change to stringify in TimestampColumnVector is needed indeed.

@wgtmac
Copy link
Member

wgtmac commented Apr 17, 2018

@jcamachor Yes I was just meaning ORC doesn't have problems in dealing with timestamps itself. Definitely using UTC everywhere makes things way easier.

@jcamachor
Copy link
Contributor Author

@omalley , I have been trying to add the Boolean useUTCTimestamp as suggested. Making it work with the reader/writer does not seem to be a problem, since I can pass the information through the context. However, we also create column vectors in the TypeDescription class, where we do not seem to have any context information, just the type string representation. It seems that unless we pass the information through that representation, we cannot know the value for the boolean when we create the column over there, and I do not think we want to go in that direction. Any ideas?

If we do not go in that direction, I thought that I can change current patch to use a boolean instead of the TimeZone itself (but without storing it).

Please, let me know what you think.

@wgtmac
Copy link
Member

wgtmac commented Apr 18, 2018

For reader, can we set useUTCTImestamp in the function TimestampTreeReader::nextVector? For writer, it is caller's responsibility to set useUTCTImestamp before calling TimestampTreeWriter::writeBatch. Does this help? @jcamachor

@jcamachor
Copy link
Contributor Author

@wgtmac , thanks for the feedback. Please bear with me for a bit, as it is first time I am touching ORC code base.
OK, I think TypeDescription is not a problem then since we set the value at reader / writer, independently of the default that we use at creation time. For reader, everything seems easy. However, for the writer, it is a bit trickier since the stripe footer stores the information about the time zone, hence it should be set beforehand using, e.g., the context or options objects. Does that seem reasonable?

@jcamachor
Copy link
Contributor Author

Pushed a new commit with the changes.

We would still need a storage-api release for the TimestampColumnVector changes.

@wgtmac
Copy link
Member

wgtmac commented Apr 19, 2018

@jcamachor You are right. WriterOptions/WriterContext are ideal places to set this kind of values.

@@ -975,6 +992,8 @@ public void nextVector(ColumnVector previousVector,
TimestampColumnVector result = (TimestampColumnVector) previousVector;
super.nextVector(previousVector, isNull, batchSize);

// TODO: If context.isUseUTCTimestamp(), set TimestampColumnVector.useUTC to true
Copy link
Member

Choose a reason for hiding this comment

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

I think it is better to set storage-api to 3.0.0 and fix this TODO in this patch as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is a vote going on for a storage-api release, then next week I can rebase the patch to consume it and hopefully we can check it in. Thanks @wgtmac !

@jcamachor
Copy link
Contributor Author

I have just updated the patch now that we have moved to the new storage-api version. I will run some tests with Hive locally asap and will get back confirming that everything is working as expected.

@jcamachor jcamachor force-pushed the ORC-341 branch 2 times, most recently from 0f617ee to e52e79e Compare May 2, 2018 21:20
@jcamachor
Copy link
Contributor Author

I have been testing the patch from Hive and everything seems to be working as expected.

I have rebased the patch and merge both commits. Also, I had to extend my changes to the newly created WriterImplV2.

@omalley , @wgtmac , could you take a final look and merge if it is OK? Thanks

Copy link
Member

@wgtmac wgtmac left a comment

Choose a reason for hiding this comment

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

@jcamachor Please see my comments.

// for unit tests to set different time zones
this.baseEpochSecsLocalTz = Timestamp.valueOf(BASE_TIMESTAMP_STRING).getTime() / MILLIS_PER_SECOND;
if (writer.isUseUTCTimestamp()) {
this.localTimezone = TimeZone.getTimeZone("UTC");
Copy link
Member

Choose a reason for hiding this comment

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

We'd better change its name to this.writeTimezone to avoid confusion in the future.
Same for localDateFormat and baseEpochSecsLocalTz below.

@@ -990,6 +1007,10 @@ public void nextVector(ColumnVector previousVector,
TimestampColumnVector result = (TimestampColumnVector) previousVector;
super.nextVector(previousVector, isNull, batchSize);

if (context.isUseUTCTimestamp()) {
result.setIsUTC(true);
Copy link
Member

Choose a reason for hiding this comment

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

result.setIsUTC(context.isUseUTCTimestamp());

Just in case result is in UTC but context.isUseUTCTimestamp() is false.

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

public class TimestampTreeWriter extends TreeWriterBase {
Copy link
Member

Choose a reason for hiding this comment

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

We should also change writeBatch function below.

The input vector.isUTC may be true while writer.isUseUTCTimestamp() is false; vice versa. In this case, we need to convert them to correct writer timezone.

Copy link
Contributor

@omalley omalley left a comment

Choose a reason for hiding this comment

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

This is looking good, although a couple of points need to get fixed.

  • the TimestampColumnStatistics on the read side need to be fixed. I think the write side will just work.
  • As Gang pointed out the writer needs to use the value in the ColumnVector to interpret the values.
  • Effectively the writer option is really about setting the writerTimezone to UTC.
  • This does mean that ORC readers older than Hive 1.2 will misinterpret timestamps from these files unless their local timezone is UTC.

return this;
}

public boolean isUseUTCTimestamp() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be getUseUTCTimestamp.

@@ -320,6 +321,16 @@ public ReaderOptions fileMetadata(final FileMetadata metadata) {
public FileMetadata getFileMetadata() {
return fileMetadata;
}

public ReaderOptions useUTCTimestamp(boolean value) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This should also cause the TimestampStatistics to use UTC.

@@ -761,6 +782,10 @@ public boolean getWriteVariableLengthBlocks() {
public HadoopShims getHadoopShims() {
return shims;
}

public boolean isUseUTCTimestamp() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Rename this to getUseUTCTimestamp.

@@ -373,7 +379,11 @@ private void flushStripe() throws IOException {
OrcProto.StripeFooter.Builder builder =
OrcProto.StripeFooter.newBuilder();
if (writeTimeZone) {
builder.setWriterTimezone(TimeZone.getDefault().getID());
if (useUTCTimeZone) {
builder.setWriterTimezone(TimeZone.getTimeZone("UTC").getID());
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd be tempted to just use setWriterTimezone("UTC"), because we'll already fail if UTC is called something else.

} else {
this.localTimezone = TimeZone.getDefault();
}
this.localDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Copy link
Contributor

Choose a reason for hiding this comment

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

It sucks that there isn't a simpler way in Java to do this.

@jcamachor
Copy link
Contributor Author

@wgtmac , @omalley , thanks for the feedback. I think I have addressed all your points with last two commits, could you take another look? Thanks

@asfgit asfgit closed this in aa790d4 May 7, 2018
morazow added a commit to exasol/cloud-storage-extension that referenced this pull request Jan 28, 2021
The Parquet and Avro format store long value (the number of milliseconds
since epoch) as timestamp value. Thus no timezone information is encoded
when writing.

However, when we import the files using Exasol UDFs, we construct a Java
`java.sql.Timestamp` object from the milliseconds since epoch, and emit
them into table. At this moment, the Java Timestamp uses the JVM
timezone. It is usually `Europe/Berlin` for instance for the Exasol
docker container. You can the Exasol system timezone using `DBTIMEZONE`
(`SELECT DBTIMEZONE`).

This introduces a difference integration tests, timestamps written in
UTC is returned in Europe/Berlin timezone. Therefore, we shift the
expected values to database timezone.

This issue does not occur in the Orc format because it also encodes the
timezone information in the file so that Orc readers uses that timezone
(apache/orc#249).
morazow added a commit to exasol/cloud-storage-extension that referenced this pull request Feb 1, 2021
## Added data importer integration tests

## Fixed timestamp integration tests

The Parquet and Avro format store long value (the number of milliseconds
since epoch) as timestamp value. Thus no timezone information is encoded
when writing.

However, when we import the files using Exasol UDFs, we construct a Java
`java.sql.Timestamp` object from the milliseconds since epoch, and emit
them into table. At this moment, the Java Timestamp uses the JVM
timezone. It is usually `Europe/Berlin` for instance for the Exasol
docker container. You can the Exasol system timezone using `DBTIMEZONE`
(`SELECT DBTIMEZONE`).

This introduces a difference integration tests, timestamps written in
UTC is returned in Europe/Berlin timezone. Therefore, we shift the
expected values to database timezone.

This issue does not occur in the Orc format because it also encodes the
timezone information in the file so that Orc readers uses that timezone
(apache/orc#249).

## Added nested suites with single docker container stack
Sign up for free to 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.

3 participants