-
Notifications
You must be signed in to change notification settings - Fork 2.5k
[HUDI-514] A schema provider to get metadata through Jdbc #1200
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
Merged
Merged
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
9fa9644
A schema provider to get metadata through Jdbc
OpenOpened 1926c44
addition maven compile dependency
OpenOpened b821f63
Optimize code and provide test cases
OpenOpened f78a11b
Merge branch 'master' into jdbc-provider
OpenOpened 368fa3c
Merge branch 'github-master' into jdbc-provider
OpenOpened fa75537
Merge remote-tracking branch 'origin/jdbc-provider' into jdbc-provider
OpenOpened bf6bbd9
update code to fit spark 2.4.4 version
OpenOpened 2a69e3a
Merge branch 'github-master' into jdbc-provider
OpenOpened 0a4cffe
fix bug
OpenOpened 95d404a
Optimize code
OpenOpened 83c671d
Merge branch 'github-master' into jdbc-provider
OpenOpened de0566a
auto close jsc object
OpenOpened ad18cae
Adding license to TestJdbcbasedSchemaProvider class
vinothchandar f53e725
Merge branch 'github-master' into jdbc-provider
OpenOpened 13e80e2
Merge remote-tracking branch 'origin/jdbc-provider' into jdbc-provider
OpenOpened d183851
fix bug and resolve conflict
OpenOpened 57061ed
try-with-resources code optimize
OpenOpened 013babf
fix code style problem
OpenOpened 450dde9
fix variable name
OpenOpened f7914c1
addition a little comments
OpenOpened a44a52a
remove extra comments
OpenOpened ca14ac9
reimplement code using java
OpenOpened File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
hudi-utilities/src/main/java/org/apache/hudi/utilities/schema/JdbcbasedSchemaProvider.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hudi.utilities.schema; | ||
|
|
||
| import org.apache.avro.Schema; | ||
| import org.apache.hudi.common.util.TypedProperties; | ||
| import org.apache.hudi.exception.HoodieException; | ||
| import org.apache.hudi.utilities.UtilHelpers; | ||
| import org.apache.spark.api.java.JavaSparkContext; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * A schema provider to get metadata through Jdbc. | ||
| */ | ||
| public class JdbcbasedSchemaProvider extends SchemaProvider { | ||
| private Schema sourceSchema; | ||
| private Map<String, String> options = new HashMap<>(); | ||
|
|
||
| /** | ||
| * Configs supported. | ||
| */ | ||
| public static class Config { | ||
| // The JDBC URL to connect to. The source-specific connection properties may be specified in the URL. | ||
| // e.g., jdbc:postgresql://localhost/test?user=fred&password=secret | ||
| private static final String SOURCE_SCHEMA_JDBC_CONNECTION_URL = "hoodie.deltastreamer.schemaprovider.source.schema.jdbc.connection.url"; | ||
| // The class name of the JDBC driver to use to connect to this URL. such as org.h2.Driver | ||
| private static final String SOURCE_SCHEMA_JDBC_DRIVER_TYPE = "hoodie.deltastreamer.schemaprovider.source.schema.jdbc.driver.type"; | ||
| private static final String SOURCE_SCHEMA_JDBC_USERNAME = "hoodie.deltastreamer.schemaprovider.source.schema.jdbc.username"; | ||
| private static final String SOURCE_SCHEMA_JDBC_PASSWORD = "hoodie.deltastreamer.schemaprovider.source.schema.jdbc.password"; | ||
| // example : test_database.test1_table or test1_table | ||
| private static final String SOURCE_SCHEMA_JDBC_DBTABLE = "hoodie.deltastreamer.schemaprovider.source.schema.jdbc.dbtable"; | ||
| // The number of seconds the driver will wait for a Statement object to execute to the given number of seconds. | ||
| // Zero means there is no limit. In the write path, this option depends on how JDBC drivers implement the API setQueryTimeout, | ||
| // e.g., the h2 JDBC driver checks the timeout of each query instead of an entire JDBC batch. It defaults to 0. | ||
| private static final String SOURCE_SCHEMA_JDBC_TIMEOUT = "hoodie.deltastreamer.schemaprovider.source.schema.jdbc.timeout"; | ||
| // If true, all the columns are nullable. | ||
| private static final String SOURCE_SCHEMA_JDBC_NULLABLE = "hoodie.deltastreamer.schemaprovider.source.schema.jdbc.nullable"; | ||
| } | ||
|
|
||
| public JdbcbasedSchemaProvider(TypedProperties props, JavaSparkContext jssc) { | ||
| super(props, jssc); | ||
| options.put("url", props.getString(Config.SOURCE_SCHEMA_JDBC_CONNECTION_URL)); | ||
| options.put("driver", props.getString(Config.SOURCE_SCHEMA_JDBC_DRIVER_TYPE)); | ||
| options.put("user", props.getString(Config.SOURCE_SCHEMA_JDBC_USERNAME)); | ||
| options.put("password", props.getString(Config.SOURCE_SCHEMA_JDBC_PASSWORD)); | ||
| options.put("dbtable", props.getString(Config.SOURCE_SCHEMA_JDBC_DBTABLE)); | ||
| // the number of seconds the driver will wait for a Statement object to execute to the given | ||
| // number of seconds. Zero means there is no limit. | ||
| options.put("timeout", props.getString(Config.SOURCE_SCHEMA_JDBC_TIMEOUT, "0")); | ||
| options.put("nullable", props.getString(Config.SOURCE_SCHEMA_JDBC_NULLABLE, "true")); | ||
| } | ||
|
|
||
| @Override | ||
| public Schema getSourceSchema() { | ||
| if (this.sourceSchema != null) { | ||
| return sourceSchema; | ||
| } | ||
|
|
||
| try { | ||
| sourceSchema = UtilHelpers.getJDBCSchema(options); | ||
| } catch (Exception e) { | ||
| throw new HoodieException("Failed to get Schema through jdbc. ", e); | ||
| } | ||
| return sourceSchema; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
hudi-utilities/src/test/java/org/apache/hudi/utilities/TestJdbcbasedSchemaProvider.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hudi.utilities; | ||
|
|
||
| import org.apache.hudi.common.util.TypedProperties; | ||
| import org.apache.hudi.exception.HoodieException; | ||
| import org.apache.hudi.utilities.schema.JdbcbasedSchemaProvider; | ||
|
|
||
| import org.apache.avro.Schema; | ||
| import org.apache.log4j.LogManager; | ||
| import org.apache.log4j.Logger; | ||
| import org.apache.spark.api.java.JavaSparkContext; | ||
| import org.junit.After; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
|
|
||
| import java.io.IOException; | ||
| import java.sql.Connection; | ||
| import java.sql.DriverManager; | ||
| import java.sql.PreparedStatement; | ||
| import java.sql.SQLException; | ||
|
|
||
| import static org.junit.Assert.assertEquals; | ||
|
|
||
| public class TestJdbcbasedSchemaProvider { | ||
|
|
||
| private static final Logger LOG = LogManager.getLogger(TestJdbcbasedSchemaProvider.class); | ||
| private static final TypedProperties PROPS = new TypedProperties(); | ||
| protected transient JavaSparkContext jsc = null; | ||
|
|
||
| @Before | ||
| public void init() { | ||
| jsc = UtilHelpers.buildSparkContext(this.getClass().getName() + "-hoodie", "local[2]"); | ||
| PROPS.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.jdbc.connection.url", "jdbc:h2:mem:test_mem"); | ||
| PROPS.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.jdbc.driver.type", "org.h2.Driver"); | ||
| PROPS.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.jdbc.username", "sa"); | ||
| PROPS.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.jdbc.password", ""); | ||
| PROPS.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.jdbc.dbtable", "triprec"); | ||
| PROPS.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.jdbc.timeout", "0"); | ||
| PROPS.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.jdbc.nullable", "false"); | ||
| } | ||
|
|
||
| @After | ||
| public void teardown() throws Exception { | ||
| if (jsc != null) { | ||
| jsc.stop(); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testJdbcbasedSchemaProvider() throws Exception { | ||
| try { | ||
| initH2Database(); | ||
| Schema sourceSchema = UtilHelpers.createSchemaProvider(JdbcbasedSchemaProvider.class.getName(), PROPS, jsc).getSourceSchema(); | ||
| assertEquals(sourceSchema.toString().toUpperCase(), new Schema.Parser().parse(UtilitiesTestBase.Helpers.readFile("delta-streamer-config/source-jdbc.avsc")).toString().toUpperCase()); | ||
| } catch (HoodieException e) { | ||
| LOG.error("Failed to get connection through jdbc. ", e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Initialize the H2 database and obtain a connection, then create a table as a test. | ||
| * Based on the characteristics of the H2 in-memory database, we do not need to display the initialized database. | ||
| * @throws SQLException | ||
| * @throws IOException | ||
| */ | ||
| private void initH2Database() throws SQLException, IOException { | ||
| Connection conn = DriverManager.getConnection("jdbc:h2:mem:test_mem", "sa", ""); | ||
| PreparedStatement ps = conn.prepareStatement(UtilitiesTestBase.Helpers.readFile("delta-streamer-config/triprec.sql")); | ||
| ps.executeUpdate(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
hudi-utilities/src/test/resources/delta-streamer-config/source-jdbc.avsc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /* | ||
|
vinothchandar marked this conversation as resolved.
|
||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| { | ||
| "type": "record", | ||
| "name": "triprec", | ||
| "namespace": "hoodie.triprec", | ||
| "fields": [ | ||
| { | ||
| "name":"ID", | ||
| "type": "int" | ||
| }, | ||
| { | ||
| "name": "TIMESTAMP", | ||
| "type": ["double", "null"] | ||
| }, | ||
| { | ||
| "name": "RIDER", | ||
| "type": ["string", "null"] | ||
| }, | ||
| { | ||
| "name": "DRIVER", | ||
| "type": ["string", "null"] | ||
| }, | ||
| { | ||
| "name": "BEGIN_LAT", | ||
| "type": ["double", "null"] | ||
| }, | ||
| { | ||
| "name": "BEGIN_LON", | ||
| "type": ["double", "null"] | ||
| }, | ||
| { | ||
| "name": "END_LAT", | ||
| "type": ["double", "null"] | ||
| }, | ||
| { | ||
| "name": "END_LON", | ||
| "type": ["double", "null"] | ||
| }, | ||
| { | ||
| "name": "FARE", | ||
| "type": ["double", "null"] | ||
| } ] | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could remove this line, If we copy from other projects, we may need add copyright to LICENSE. but if copied from stackoverflow, it would be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, i will remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to be a pain. but this piece of code would be problematic since its exactly https://stackoverflow.com/a/45992769 ? Please re-implement this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you guys have a better way? I checked the relevant information. If you want to achieve conversion elegantly, there are only two methods. First, using scala code to do the conversion, you need to implement a scala conversion class. Second, rewrite the related spark method with java. The disadvantage is that it may cause compatibility problems in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vinothchandar @leesf I reimplemented the relevant logic using the second approach.