From 89f07ebde98be56a847d5b108a66c0317b6a623b Mon Sep 17 00:00:00 2001 From: Sagar Sumit Date: Fri, 19 Aug 2022 19:40:42 +0530 Subject: [PATCH] Add documentation for Hudi connector --- docs/src/main/sphinx/connector.rst | 1 + docs/src/main/sphinx/connector/hudi.rst | 167 +++++++++++++++++++++++ docs/src/main/sphinx/static/img/hudi.png | Bin 0 -> 14848 bytes 3 files changed, 168 insertions(+) create mode 100644 docs/src/main/sphinx/connector/hudi.rst create mode 100644 docs/src/main/sphinx/static/img/hudi.png diff --git a/docs/src/main/sphinx/connector.rst b/docs/src/main/sphinx/connector.rst index 54cca76b3874..de328d25fc36 100644 --- a/docs/src/main/sphinx/connector.rst +++ b/docs/src/main/sphinx/connector.rst @@ -19,6 +19,7 @@ from different data sources. Elasticsearch Google Sheets Hive + Hudi Iceberg JMX Kafka diff --git a/docs/src/main/sphinx/connector/hudi.rst b/docs/src/main/sphinx/connector/hudi.rst new file mode 100644 index 000000000000..8b532c6f6e28 --- /dev/null +++ b/docs/src/main/sphinx/connector/hudi.rst @@ -0,0 +1,167 @@ +============== +Hudi connector +============== + +.. raw:: html + + + +The Hudi connector enables querying `Hudi `_ tables. + +Requirements +------------ + +To use the Hudi connector, you need: + +* Network access from the Trino coordinator and workers to the Hudi storage. +* Access to the Hive metastore service (HMS). +* Network access from the Trino coordinator to the HMS. + +Configuration +------------- + +The connector requires a Hive metastore for table metadata and supports the same +metastore configuration properties as the :doc:`Hive connector +`. At a minimum, ``hive.metastore.uri`` must be configured. +The connector recognizes Hudi tables synced to the metastore by the +`Hudi sync tool `_. + +To create a catalog that uses the Hudi connector, create a catalog properties file, +for example ``etc/catalog/example.properties``, that references the ``hudi`` +connector. Update the ``hive.metastore.uri`` with the URI of your Hive metastore +Thrift service: + +.. code-block:: properties + + connector.name=hudi + hive.metastore.uri=thrift://example.net:9083 + +Additionally, following configuration properties can be set depending on the use-case. + +.. list-table:: Hudi configuration properties + :widths: 30, 55, 15 + :header-rows: 1 + + * - Property name + - Description + - Default + * - ``hudi.metadata-enabled`` + - Fetch the list of file names and sizes from metadata rather than storage. + - ``false`` + * - ``hudi.columns-to-hide`` + - List of column names that are hidden from the query output. + It can be used to hide Hudi meta fields. By default, no fields are hidden. + - + * - ``hudi.parquet.use-column-names`` + - Access Parquet columns using names from the file. If disabled, then columns + are accessed using the index. Only applicable to Parquet file format. + - ``true`` + * - ``hudi.min-partition-batch-size`` + - Minimum number of partitions returned in a single batch. + - ``10`` + * - ``hudi.max-partition-batch-size`` + - Maximum number of partitions returned in a single batch. + - ``100`` + * - ``hudi.size-based-split-weights-enabled`` + - Unlike uniform splitting, size-based splitting ensures that each batch of splits + has enough data to process. By default, it is enabled to improve performance. + - ``true`` + * - ``hudi.standard-split-weight-size`` + - The split size corresponding to the standard weight (1.0) + when size-based split weights are enabled. + - ``128MB`` + * - ``hudi.minimum-assigned-split-weight`` + - Minimum weight that a split can be assigned + when size-based split weights are enabled. + - ``0.05`` + * - ``hudi.max-splits-per-second`` + - Rate at which splits are queued for processing. + The queue is throttled if this rate limit is breached. + - ``Integer.MAX_VALUE`` + * - ``hudi.max-outstanding-splits`` + - Maximum outstanding splits in a batch enqueued for processing. + - ``1000`` + +Supported file types +-------------------- + +The connector supports Parquet file type. + +SQL support +----------- + +The connector provides read access to data in the Hudi table that has been synced to +Hive metastore. The :ref:`globally available ` +and :ref:`read operation ` statements are supported. + +Supported query types +^^^^^^^^^^^^^^^^^^^^^ + +Hudi supports `two types of tables `_ +depending on how the data is indexed and laid out on the file system. The following +table displays a support matrix of tables types and query types for the connector. + +=========================== ============================================= +Table type Supported query type +=========================== ============================================= +Copy on write Snapshot queries + +Merge on read Read optimized queries +=========================== ============================================= + +Examples queries +^^^^^^^^^^^^^^^^ + +In the queries below, ``stock_ticks_cow`` is a Hudi copy-on-write table that we refer +in the Hudi `quickstart `_ documentation. + +Here are some sample queries: + +.. code-block:: sql + + USE a-catalog.myschema; + + SELECT symbol, max(ts) + FROM stock_ticks_cow + GROUP BY symbol + HAVING symbol = 'GOOG'; + +.. code-block:: text + + symbol | _col1 | + -----------+----------------------+ + GOOG | 2018-08-31 10:59:00 | + (1 rows) + +.. code-block:: sql + + SELECT dt, symbol + FROM stock_ticks_cow + WHERE symbol = 'GOOG'; + +.. code-block:: text + + dt | symbol | + ------------+--------+ + 2018-08-31 | GOOG | + (1 rows) + +.. code-block:: sql + + SELECT dt, count(*) + FROM stock_ticks_cow + GROUP BY dt; +.. code-block:: text + + dt | _col1 | + ------------+--------+ + 2018-08-31 | 99 | + (1 rows) + +Reading Hudi tables with the Hive connector +------------------------------------------- + +Hudi tables can also be accessed with a catalog using the Hive connector. The supported query types +with the Hive connector are same as that of Hudi connector. To query Hudi tables on Trino, place +the `hudi-trino-bundle `_ +JAR file into the Hive connector installation ``/plugin/hive``. diff --git a/docs/src/main/sphinx/static/img/hudi.png b/docs/src/main/sphinx/static/img/hudi.png new file mode 100644 index 0000000000000000000000000000000000000000..96ae05e396fce92fcefeda416c876f45c94b42bc GIT binary patch literal 14848 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�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 U7;4J?_dl9yN}7t5^5!A`3yv@(Jpcdz literal 0 HcmV?d00001