diff --git a/DataIngestion/hadoopbased.md b/DataIngestion/hadoopbased.md deleted file mode 100644 index ed87975..0000000 --- a/DataIngestion/hadoopbased.md +++ /dev/null @@ -1,478 +0,0 @@ - - -## 基于Hadoop的摄入 - -Apache Druid当前支持通过一个Hadoop摄取任务来支持基于Apache Hadoop的批量索引任务, 这些任务被提交到 [Druid Overlord](../design/Overlord.md)的一个运行实例上。详情可以查看 [基于Hadoop的摄取vs基于本地批摄取的对比](ingestion.md#批量摄取) 来了解基于Hadoop的摄取、本地简单批摄取、本地并行摄取三者的比较。 - -运行一个基于Hadoop的批量摄取任务,首先需要编写一个如下的摄取规范, 然后提交到Overlord的 [`druid/indexer/v1/task`](../operations/api.md#overlord) 接口,或者使用Druid软件包中自带的 `bin/post-index-task` 脚本。 - -### 教程 - -本章包括了基于Hadoop摄取的参考文档,对于粗略的查看,可以查看 [从Hadoop加载数据](../GettingStarted/chapter-3.md) 教程。 - -### 任务符号 - -以下为一个示例任务: -```json -{ - "type" : "index_hadoop", - "spec" : { - "dataSchema" : { - "dataSource" : "wikipedia", - "parser" : { - "type" : "hadoopyString", - "parseSpec" : { - "format" : "json", - "timestampSpec" : { - "column" : "timestamp", - "format" : "auto" - }, - "dimensionsSpec" : { - "dimensions": ["page","language","user","unpatrolled","newPage","robot","anonymous","namespace","continent","country","region","city"], - "dimensionExclusions" : [], - "spatialDimensions" : [] - } - } - }, - "metricsSpec" : [ - { - "type" : "count", - "name" : "count" - }, - { - "type" : "doubleSum", - "name" : "added", - "fieldName" : "added" - }, - { - "type" : "doubleSum", - "name" : "deleted", - "fieldName" : "deleted" - }, - { - "type" : "doubleSum", - "name" : "delta", - "fieldName" : "delta" - } - ], - "granularitySpec" : { - "type" : "uniform", - "segmentGranularity" : "DAY", - "queryGranularity" : "NONE", - "intervals" : [ "2013-08-31/2013-09-01" ] - } - }, - "ioConfig" : { - "type" : "hadoop", - "inputSpec" : { - "type" : "static", - "paths" : "/MyDirectory/example/wikipedia_data.json" - } - }, - "tuningConfig" : { - "type": "hadoop" - } - }, - "hadoopDependencyCoordinates": -} -``` - -| 属性 | 描述 | 是否必须 | -|-|-|-| -| `type` | 任务类型,应该总是 `index_hadoop` | 是 | -| `spec` | Hadoop索引任务规范。 详见 [ingestion](ingestion.md) | 是 | -| `hadoopDependencyCoordinates` | Druid使用的Hadoop依赖,这些属性会覆盖默认的Hadoop依赖。 如果该值被指定,Druid将在 `druid.extensions.hadoopDependenciesDir` 目录下查找指定的Hadoop依赖 | 否 | -| `classpathPrefix` | 为Peon进程准备的类路径。| 否 | - -还要注意,Druid会自动计算在Hadoop集群中运行的Hadoop作业容器的类路径。但是,如果Hadoop和Druid的依赖项之间发生冲突,可以通过设置 `druid.extensions.hadoopContainerDruidClasspath`属性。请参阅 [基本druid配置中的扩展配置](../configuration/human-readable-byte.md#扩展) 。 -#### `dataSchema` - -该字段是必须的。 详情可以查看摄取页中的 [`dataSchema`](ingestion.md#dataschema) 部分来看它应该包括哪些部分。 - -#### `ioConfig` - -该字段是必须的。 - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `type` | String | 应该总是 `hadoop` | 是 | -| `inputSpec` | Object | 指定从哪里拉数据。详情见以下。 | 是 | -| `segmentOutputPath` | String | 将段转储到的路径 | 仅仅在 [命令行Hadoop索引](#命令行版本) 中使用, 否则该字段必须为null | -| `metadataUpdateSpec` | Object | 关于如何更新这些段所属的druid集群的元数据的规范 | 仅仅在 [命令行Hadoop索引](#命令行版本) 中使用, 否则该字段必须为null | - -##### `inputSpec` - -有多种类型的inputSec: - -**`static`** - -一种`inputSpec`的类型,该类型提供数据文件的静态路径。 - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `inputFormat` | String | 指定要使用的Hadoop输入格式的类,比如 `org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat` | 否 | -| `paths` | String数组 | 标识原始数据位置的输入路径的字符串 | 是 | - -例如,以下例子使用了静态输入路径: - -```json -"paths" : "hdfs://path/to/data/is/here/data.gz,hdfs://path/to/data/is/here/moredata.gz,hdfs://path/to/data/is/here/evenmoredata.gz" -``` - -也可以从云存储直接读取数据,例如AWS S3或者谷歌云存储。 前提是需要首先的所有Druid *MiddleManager进程或者Indexer进程*的类路径下安装必要的依赖库。对于S3,需要通过以下命令来安装 [Hadoop AWS 模块](https://hadoop.apache.org/docs/current/hadoop-aws/tools/hadoop-aws/index.html) - -```json -java -classpath "${DRUID_HOME}lib/*" org.apache.druid.cli.Main tools pull-deps -h "org.apache.hadoop:hadoop-aws:${HADOOP_VERSION}"; -cp ${DRUID_HOME}/hadoop-dependencies/hadoop-aws/${HADOOP_VERSION}/hadoop-aws-${HADOOP_VERSION}.jar ${DRUID_HOME}/extensions/druid-hdfs-storage/ -``` - -一旦在所有的MiddleManager和Indexer进程中安装了Hadoop AWS模块,即可将S3路径放到 `inputSpec` 中,同时需要有任务属性。 对于更多配置,可以查看 [Hadoop AWS 模块](https://hadoop.apache.org/docs/current/hadoop-aws/tools/hadoop-aws/index.html) - -```json -"paths" : "s3a://billy-bucket/the/data/is/here/data.gz,s3a://billy-bucket/the/data/is/here/moredata.gz,s3a://billy-bucket/the/data/is/here/evenmoredata.gz" -``` - -```json -"jobProperties" : { - "fs.s3a.impl" : "org.apache.hadoop.fs.s3a.S3AFileSystem", - "fs.AbstractFileSystem.s3a.impl" : "org.apache.hadoop.fs.s3a.S3A", - "fs.s3a.access.key" : "YOUR_ACCESS_KEY", - "fs.s3a.secret.key" : "YOUR_SECRET_KEY" -} -``` - -对于谷歌云存储,需要将 [GCS connector jar](https://github.com/GoogleCloudDataproc/hadoop-connectors/blob/master/gcs/INSTALL.md) 安装到*所有MiddleManager或者Indexer进程*的 `${DRUID_HOME}/hadoop-dependencies`。 一旦在所有的MiddleManager和Indexer进程中安装了GCS连接器jar包,即可将谷歌云存储路径放到 `inputSpec` 中,同时需要有任务属性。对于更多配置,可以查看 [instructions to configure Hadoop](https://github.com/GoogleCloudPlatform/bigdata-interop/blob/master/gcs/INSTALL.md#configure-hadoop), [GCS core default](https://github.com/GoogleCloudPlatform/bigdata-interop/blob/master/gcs/conf/gcs-core-default.xml) 和 [GCS core template](https://github.com/GoogleCloudPlatform/bdutil/blob/master/conf/hadoop2/gcs-core-template.xml). - -```json -"paths" : "gs://billy-bucket/the/data/is/here/data.gz,gs://billy-bucket/the/data/is/here/moredata.gz,gs://billy-bucket/the/data/is/here/evenmoredata.gz" -``` -```json -"jobProperties" : { - "fs.gs.impl" : "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem", - "fs.AbstractFileSystem.gs.impl" : "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS" -} -``` - -**`granularity`** - -一种`inputSpec`类型,该类型期望数据已经按照日期时间组织到对应的目录中,路径格式为: `y=XXXX/m=XX/d=XX/H=XX/M=XX/S=XX` (其中日期用小写表示,时间用大写表示)。 - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `dataGranularity` | String | 指定期望的数据粒度,例如,hour意味着期望的目录格式为: `y=XXXX/m=XX/d=XX/H=XX` | 是 | -| `inputFormat` | String | 指定要使用的Hadoop输入格式的类,比如 `org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat` | 否 | -| `inputPath` | String | 要将日期时间路径附加到的基路径。| 是 | -| `filePattern` | String | 要包含的文件应匹配的模式 | 是 | -| `pathFormat` | String | 每个目录的Joda datetime目录。 默认值为: `"'y'=yyyy/'m'=MM/'d'=dd/'H'=HH"` ,详情可以看 [Joda文档](http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html) | 否 | - -例如, 如果示例配置具有 2012-06-01/2012-06-02 时间间隔,则数据期望的路径是: - -```json -s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=00 -s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=01 -... -s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=23 -``` - -**`dataSource`** - -一种`inputSpec`的类型, 该类型读取已经存储在Druid中的数据。 该类型被用来"re-indexing"(重新索引)数据和下边描述 `multi` 类型 `inputSpec` 的 "delta-ingestion"(增量摄取)。 - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `type` | String | 应该总是 `dataSource` | 是 | -| `ingestionSpec` | JSON对象 | 要加载的Druid段的规范。详情见下边内容。 | 是 | -| `maxSplitSize` | Number | 允许根据段的大小将多个段合并为单个Hadoop InputSplit。使用-1,druid根据用户指定的映射任务数计算最大拆分大小(`mapred.map.tasks` 或者 `mapreduce.job.maps`). 默认情况下,对一个段进行一次拆分。`maxSplitSize` 以字节为单位指定。 | 否 | -| `useNewAggs` | Boolean | 如果"false",则hadoop索引任务的"metricsSpec"中的聚合器列表必须与接收原始数据时在原始索引任务中使用的聚合器列表相同。默认值为"false"。当"inputSpec"类型为"dataSource"而不是"multi"时,可以将此字段设置为"true",以便在重新编制索引时启用任意聚合器。请参阅下面的"multi"类型增量摄取支持。| 否 | - -下表中为`ingestionSpec`中的一些选项: - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `dataSource` | String | Druid数据源名称,从该数据源读取数据 | 是 | -| `intervals` | List | ISO-8601时间间隔的字符串List | 是 | -| `segments` | List | 从中读取数据的段的列表,默认情况下自动获取。您可以通过向Coordinator的接口 `/druid/Coordinator/v1/metadata/datasources/segments?full` 进行POST查询来获取要放在这里的段列表。例如["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000","2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"]. 您可能希望手动提供此列表,以确保读取的段与任务提交时的段完全相同,如果用户提供的列表与任务实际运行时的数据库状态不匹配,则任务将失败 | 否 | -| `filter` | JSON | 查看 [Filter](../querying/filters.md) | 否 | -| `dimensions` | String数组 | 要加载的维度列的名称。默认情况下,列表将根据 `parseSpec` 构造。如果 `parseSpec` 没有维度的显式列表,则将读取存储数据中的所有维度列。 | 否 | -| `metrics` | String数组 | 要加载的Metric列的名称。默认情况下,列表将根据所有已配置聚合器的"name"构造。 | 否 | -| `ignoreWhenNoSegments` | boolean | 如果找不到段,是否忽略此 `ingestionSpec`。默认行为是在找不到段时引发错误。| 否 | - -示例: - -```json -"ioConfig" : { - "type" : "hadoop", - "inputSpec" : { - "type" : "dataSource", - "ingestionSpec" : { - "dataSource": "wikipedia", - "intervals": ["2014-10-20T00:00:00Z/P2W"] - } - }, - ... -} -``` - -**`multi`** - -这是一个组合类型的 `inputSpec`, 来组合其他 `inputSpec`。此inputSpec用于增量接收。您还可以使用一个 `multi` 类型的inputSpec组合来自多个数据源的数据。但是,每个特定的数据源只能指定一次。注意,"useNewAggs"必须设置为默认值false以支持增量摄取。 - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `children` | JSON对象数组 | 一个JSON对象List,里边包含了其他类型的inputSpec | 是 | - -示例: - -```json -"ioConfig" : { - "type" : "hadoop", - "inputSpec" : { - "type" : "multi", - "children": [ - { - "type" : "dataSource", - "ingestionSpec" : { - "dataSource": "wikipedia", - "intervals": ["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", "2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"], - "segments": [ - { - "dataSource": "test1", - "interval": "2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", - "version": "v2", - "loadSpec": { - "type": "local", - "path": "/tmp/index1.zip" - }, - "dimensions": "host", - "metrics": "visited_sum,unique_hosts", - "shardSpec": { - "type": "none" - }, - "binaryVersion": 9, - "size": 2, - "identifier": "test1_2000-01-01T00:00:00.000Z_3000-01-01T00:00:00.000Z_v2" - } - ] - } - }, - { - "type" : "static", - "paths": "/path/to/more/wikipedia/data/" - } - ] - }, - ... -} -``` - -**强烈建议显式**地在 `dataSource` 中的 `inputSpec` 中提供段列表,以便增量摄取任务是幂等的。您可以通过对Coordinator进行以下调用来获取该段列表,POST `/druid/coordinator/v1/metadata/datasources/{dataSourceName}/segments?full`, 请求体:[interval1,interval2,…], 例如["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000","2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"] - -#### `tuningConfig` - -`tuningConfig` 是一个可选项,如果未指定的话,则使用默认的参数。 - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `workingPath` | String | 用于存储中间结果(Hadoop作业之间的结果)的工作路径 | 该配置仅仅使用在 [命令行Hadoop索引](#命令行版本) ,默认值为: `/tmp/druid-indexing`, 否则该值必须设置为null | -| `version` | String | 创建的段的版本。 对于Hadoop索引任务一般是忽略的,除非 `useExplicitVersion` 被设置为 `true` | 否(默认为索引任务开始的时间) | -| `partitionsSpec` | Object | 指定如何将时间块内的分区为段。缺少此属性意味着不会发生分区。 详情可见 [`partitionsSpec`](#partitionsspec) | 否(默认为 `hashed`) | -| `maxRowsInMemory` | Integer | 在持久化之前在堆内存中聚合的行数。注意:由于rollup操作,该值是聚合后的行数,可能不等于输入的行数。 该值常用来管理需要的JVM堆内存大小。通常情况下,用户并不需要设置该值,而是依赖数据自身。 如果数据是非常小的,用户希望在内存存储上百万行数据的话,则需要设置该值。 | 否(默认为:1000000)| -| `maxBytesInMemory` | Long | 在持久化之前在堆内存中聚合的字节数。通常这是在内部计算的,用户不需要设置它。此值表示在持久化之前要在堆内存中聚合的字节数。这是基于对内存使用量的粗略估计,而不是实际使用量。用于索引的最大堆内存使用量为 `maxBytesInMemory *(2 + maxPendingResistent)` | 否(默认为:最大JVM内存的1/6)| -| `leaveIntermediate` | Boolean | 作业完成时,不管通过还是失败,都在工作路径中留下中间文件(用于调试)。 | 否(默认为false)| -| `cleanupOnFailure` | Boolean | 当任务失败时清理中间文件(除非 `leaveIntermediate` 设置为true) | 否(默认为true)| -| `overwriteFiles` | Boolean | 在索引过程中覆盖找到的现存文件 | 否(默认为false)| -| `ignoreInvalidRows` | Boolean | **已废弃**。忽略发现有问题的行。如果为false,解析过程中遇到的任何异常都将引发并停止摄取;如果为true,将跳过不可解析的行和字段。如果定义了 `maxParseExceptions`,则忽略此属性。 | 否(默认为false)| -| `combineText` | Boolean | 使用CombineTextInputFormat将多个文件合并为一个文件拆分。这可以在处理大量小文件时加快Hadoop作业的速度。 | 否(默认为false)| -| `useCombiner` | Boolean | 如果可能的话,使用Hadoop Combiner在mapper阶段合并行 | 否(默认为false)| -| `jobProperties` | Object | 增加到Hadoop作业配置的属性map,详情见下边。 | 否(默认为null)| -| `indexSpec` | Object | 调整数据如何被索引。 详细信息可以见位于摄取页的 [`indexSpec`](ingestion.md#tuningConfig) | 否 | -| `indexSpecForIntermediatePersists` | Object | 定义要在索引时用于中间持久化临时段的段存储格式选项。这可用于禁用中间段上的dimension/metric压缩,以减少最终合并所需的内存。但是,在中间段上禁用压缩可能会增加页缓存的使用,因为可能在它们被合并到发布的最终段之前使用它们,有关可能的值,请参阅 [`indexSpec`](ingestion.md#tuningConfig)。 | 否(默认与indexSpec一样)| -| `numBackgroundPersistThreads` | Integer | 用于增量持久化的新后台线程数。使用此功能会显著增加内存压力和CPU使用率,但会使任务更快完成。如果从默认值0(对持久性使用当前线程)更改,建议将其设置为1。 | 否(默认为0)| -| `forceExtendableShardSpecs` | Boolean | 强制使用可扩展的shardSpec。基于哈希的分区总是使用可扩展的shardSpec。对于单维分区,此选项应设置为true以使用可扩展shardSpec。对于分区,请检查 [分区规范](#partitionsspec) | 否(默认为false)| -| `useExplicitVersion` | Boolean | 强制HadoopIndexTask使用version | 否(默认为false)| -| `logParseExceptions` | Boolean | 如果为true,则在发生解析异常时记录错误消息,其中包含有关发生错误的行的信息。| 否(默认为false)| -| `maxParseExceptions` | Integer | 任务停止接收并失败之前可能发生的最大分析异常数。如果设置了`reportParseExceptions`,则该配置被覆盖。 | 否(默认为unlimited)| -| `useYarnRMJobStatusFallback` | Boolean | 如果索引任务创建的Hadoop作业无法从JobHistory服务器检索其完成状态,并且此参数为true,则索引任务将尝试从 `http:///ws/v1/cluster/apps/` 获取应用程序状态,其中 `` 是Hadoop配置中 `yarn.resourcemanager.webapp.address` 的地址。此标志用于索引任务的作业成功但JobHistory服务器不可用的情况下的回退,从而导致索引任务失败,因为它无法确定作业状态。 | 否(默认为true)| - -##### `jobProperties` - -```json - "tuningConfig" : { - "type": "hadoop", - "jobProperties": { - "": "", - "": "" - } - } -``` -Hadoop的 [MapReduce文档](https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml) 列出来了所有可能的配置参数。 - -在一些Hadoop分布式环境中,可能需要设置 `mapreduce.job.classpath` 或者 `mapreduce.job.user.classpath.first` 来避免类加载相关的问题。 更多详细信息可以参见 [使用不同Hadoop版本的文档](../operations/other-hadoop.md) - -#### `partitionsSpec` - -段总是基于时间戳进行分区(根据 `granularitySpec`),并且可以根据分区类型以其他方式进一步分区。Druid支持两种类型的分区策略:`hashed`(基于每行中所有维度的hash)和 `single_dim`(基于单个维度的范围)。 - -在大多数情况下,建议使用哈希分区,因为相对于单一维度分区,哈希分区将提高索引性能并创建更统一大小的数据段。 - -##### 基于哈希的分区 - -```json - "partitionsSpec": { - "type": "hashed", - "targetRowsPerSegment": 5000000 - } -``` - -哈希分区的工作原理是首先选择多个段,然后根据每一行中所有维度的哈希对这些段中的行进行分区。段的数量是根据输入集的基数和目标分区大小自动确定的。 - -配置项为: - -| 字段 | 描述 | 是否必须 | -|-|-|-| -| `type` | 使用的partitionsSpec的类型 | "hashed" | -| `targetRowsPerSegment` | 要包含在分区中的目标行数,应为500MB~1GB段的数。如果未设置 `numShards` ,则默认为5000000。 | 为该配置或者 `numShards` | -| `targetPartitionSize` | 已弃用。重命名为`targetRowsPerSegment`。要包含在分区中的目标行数,应为500MB~1GB段的数。 | 为该配置或者 `numShards` | -| `maxRowsPerSegment` | 已弃用。重命名为`targetRowsPerSegment`。要包含在分区中的目标行数,应为500MB~1GB段的数。 | 为该配置或者 `numShards` | 为该配置或者 `numShards` | -| `numShards` | 直接指定分区数,而不是目标分区大小。摄取将运行得更快,因为它可以跳过自动选择多个分区所需的步骤。| 为该配置或者 `maxRowsPerSegment` | -| `partitionDimensions` | 要划分的维度。留空可选择所有维度。仅与`numShard` 一起使用,在设置 `targetRowsPerSegment` 时将被忽略。| 否 | - - -##### 单一维度范围分区 - -```json - "partitionsSpec": { - "type": "single_dim", - "targetRowsPerSegment": 5000000 - } -``` - -单一维度范围分区的工作原理是首先选择要分区的维度,然后将该维度分隔成连续的范围,每个段将包含该维度值在该范围内的所有行。例如,可以在维度"host"上对段进行分区,范围为"a.example.com"到"f.example.com"和"f.example.com"到"z.example.com"。 默认情况下,将自动确定要使用的维度,但可以使用特定维度替代它。 - -配置项为: - -| 字段 | 描述 | 是否必须 | -|-|-|-| -| `type` | 使用的partitionsSpec的类型 | "single_dim" | -| `targetRowsPerSegment` | 要包含在分区中的目标行数,应为500MB~1GB段的数。 | 是 | -| `targetPartitionSize` | 已弃用。重命名为`targetRowsPerSegment`。要包含在分区中的目标行数,应为500MB~1GB段的数。 | 否 | -| `maxRowsPerSegment` | 要包含在分区中的最大行数。默认值为比`targetRowsPerSegment` 大50%。 | 否 | -| `maxPartitionSize` | 已弃用。请改用 `maxRowsPerSegment`。要包含在分区中的最大行数, 默认为比 `targetPartitionSize` 大50%。 | 否 | -| `partitionDimension` | 要分区的维度。留空可自动选择维度。 | 否 | -| `assumeGrouped` | 假设输入数据已经按时间和维度分组。摄取将运行得更快,但如果违反此假设,则可能会选择次优分区。 | 否 | - -### 远程Hadoop集群 - -如果已经有了一个远程的Hadoop集群,确保在Druid的 `_common` 配置目录中包含 `*.xml` 文件。 - -如果Hadoop与Druid的版本存在依赖等问题,请查看 [这些文档](../operations/other-hadoop.md) - -### Elastic MapReduce - -如果集群运行在AWS上,可以使用Elastic MapReduce(EMR)来从S3中索引数据。需要以下几步: - -* 创建一个 [持续运行的集群](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-longrunning-transient.html) -* 创建集群时,请输入以下配置。如果使用向导,则应在"编辑软件设置"下处于高级模式: - -```json -classification=yarn-site,properties=[mapreduce.reduce.memory.mb=6144,mapreduce.reduce.java.opts=-server -Xms2g -Xmx2g -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,mapreduce.map.java.opts=758,mapreduce.map.java.opts=-server -Xms512m -Xmx512m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,mapreduce.task.timeout=1800000] -``` -* 按照 [Hadoop连接配置](../tutorials/img/chapter-4.md#Hadoop连接配置) 指导,使用EMR master中 `/etc/hadoop/conf` 的XML文件。 - -### Kerberized Hadoop集群 - -默认情况下,druid可以使用本地kerberos密钥缓存中现有的TGT kerberos票证。虽然TGT票证的生命周期有限,但您需要定期调用 `kinit` 命令以确保TGT票证的有效性。为了避免这个额外的外部cron作业脚本周期性地调用 `kinit`,您可以提供主体名称和keytab位置,druid将在启动和作业启动时透明地执行身份验证。 - -| 属性 | 可能的值 | -|-|-| -| `druid.hadoop.security.kerberos.principal` | `druid@EXAMPLE.COM` | -| `druid.hadoop.security.kerberos.keytab` | `/etc/security/keytabs/druid.headlessUser.keytab` | - -#### 从具有EMR的S3加载 - -* 在Hadoop索引任务中 `tuningConfig` 部分的 `jobProperties` 字段中添加一下内容: - -```json -"jobProperties" : { - "fs.s3.awsAccessKeyId" : "YOUR_ACCESS_KEY", - "fs.s3.awsSecretAccessKey" : "YOUR_SECRET_KEY", - "fs.s3.impl" : "org.apache.hadoop.fs.s3native.NativeS3FileSystem", - "fs.s3n.awsAccessKeyId" : "YOUR_ACCESS_KEY", - "fs.s3n.awsSecretAccessKey" : "YOUR_SECRET_KEY", - "fs.s3n.impl" : "org.apache.hadoop.fs.s3native.NativeS3FileSystem", - "io.compression.codecs" : "org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.SnappyCodec" -} -``` -注意,此方法使用Hadoop的内置S3文件系统,而不是Amazon的EMRFS,并且与Amazon的特定功能(如S3加密和一致视图)不兼容。如果您需要使用这些特性,那么您将需要通过 [其他Hadoop发行版](#使用其他的Hadoop) 一节中描述的机制之一,使Amazon EMR Hadoop JARs对Druid可用。 - -### 使用其他的Hadoop - -Druid在许多Hadoop发行版中都是开箱即用的。 - -如果Druid与您当前使用的Hadoop版本发生依赖冲突时,您可以尝试在 [Druid用户组](https://groups.google.com/forum/#!forum/druid-user) 中搜索解决方案, 或者阅读 [Druid不同版本Hadoop文档](../operations/other-hadoop.md) - -### 命令行版本 - -运行: - -```json -java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath lib/*: org.apache.druid.cli.Main index hadoop -``` -#### 可选项 - -* "--coordinate" - 提供要使用的Apache Hadoop版本。此属性将覆盖默认的Hadoop。一旦指定,Apache Druid将从 `druid.extensions.hadoopDependenciesDir` 位置寻找Hadoop依赖。 -* "--no-default-hadoop" - 不要下拉默认的hadoop版本 - -#### 规范文件 - -spec文件需要包含一个JSON对象,其中的内容与Hadoop索引任务中的"spec"字段相同。有关规范格式的详细信息,请参见 [Hadoop批处理摄取](hadoopbased.md)。 - -另外, `metadataUpdateSpec` 和 `segmentOutputPath` 字段需要被添加到ioConfig中: -```json - "ioConfig" : { - ... - "metadataUpdateSpec" : { - "type":"mysql", - "connectURI" : "jdbc:mysql://localhost:3306/druid", - "password" : "druid", - "segmentTable" : "druid_segments", - "user" : "druid" - }, - "segmentOutputPath" : "/MyDirectory/data/index/output" - }, -``` -同时, `workingPath` 字段需要被添加到tuningConfig: -```json - "tuningConfig" : { - ... - "workingPath": "/tmp", - ... - } -``` -**Metadata Update Job Spec** - -这是一个属性规范,告诉作业如何更新元数据,以便Druid集群能够看到输出段并加载它们。 - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `type` | String | "metadata"是唯一可用的值 | 是 | -| `connectURI` | String | 连接元数据存储的可用的JDBC | 是 | -| `user` | String | DB的用户名 | 是 | -| `password` | String | DB的密码 | 是 | -| `segmentTable` | String | DB中使用的表 | 是 | - -这些属性应该模仿您为 [Coordinator](../design/Coordinator.md) 配置的内容。 - -**segmentOutputPath配置** - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `segmentOutputPath` | String | 将段转储到的路径 | 是 | - -**workingPath配置** - -| 字段 | 类型 | 描述 | 是否必须 | -|-|-|-|-| -| `workingPath` | String | 用于中间结果(Hadoop作业之间的结果)的工作路径。 | 否(默认为 `/tmp/druid-indexing` )| - -请注意,命令行Hadoop indexer不具备索引服务的锁定功能,因此如果选择使用它,则必须注意不要覆盖由实时处理创建的段(如果设置了实时管道)。 \ No newline at end of file diff --git a/DataIngestion/ingestion.md b/DataIngestion/ingestion.md deleted file mode 100644 index b345f38..0000000 --- a/DataIngestion/ingestion.md +++ /dev/null @@ -1,530 +0,0 @@ - - -## 数据摄入 -### 综述 - -Druid中的所有数据都被组织成*段*,这些段是数据文件,通常每个段最多有几百万行。在Druid中加载数据称为*摄取或索引*,它包括从源系统读取数据并基于该数据创建段。 - -在大多数摄取方法中,加载数据的工作由Druid [MiddleManager](../design/MiddleManager.md) 进程(或 [Indexer](../design/Indexer.md) 进程)完成。一个例外是基于Hadoop的摄取,这项工作是使用Hadoop MapReduce作业在YARN上完成的(尽管MiddleManager或Indexer进程仍然参与启动和监视Hadoop作业)。一旦段被生成并存储在 [深层存储](../design/Deepstorage.md) 中,它们将被Historical进程加载。有关如何在引擎下工作的更多细节,请参阅Druid设计文档的[存储设计](../design/Design.md) 部分。 - -### 如何使用本文档 - -您**当前正在阅读的这个页面**提供了通用Druid摄取概念的信息,以及 [所有摄取方法](#摄入方式) **通用的配置**信息。 - -**每个摄取方法的单独页面**提供了有关每个摄取方法**独有的概念和配置**的附加信息。 - -我们建议您先阅读(或至少略读)这个通用页面,然后参考您选择的一种或多种摄取方法的页面。 - -### 摄入方式 - -下表列出了Druid最常用的数据摄取方法,帮助您根据自己的情况选择最佳方法。每个摄取方法都支持自己的一组源系统。有关每个方法如何工作的详细信息以及特定于该方法的配置属性,请查看其文档页。 - -#### 流式摄取 -最推荐、也是最流行的流式摄取方法是直接从Kafka读取数据的 [Kafka索引服务](kafka.md) 。如果你喜欢Kinesis,[Kinesis索引服务](kinesis.md) 也能很好地工作。 - -下表比较了主要可用选项: - -| **Method** | [**Kafka**](kafka.md) | [**Kinesis**](kinesis.md) | [**Tranquility**](tranquility.md) | -| - | - | - | - | -| **Supervisor类型** | `kafka` | `kinesis` | `N/A` | -| 如何工作 | Druid直接从 Apache Kafka读取数据 | Druid直接从Amazon Kinesis中读取数据 | Tranquility, 一个独立于Druid的库,用来将数据推送到Druid | -| 可以摄入迟到的数据 | Yes | Yes | No(迟到的数据将会被基于 `windowPeriod` 的配置丢弃掉) | -| 保证不重不丢(Exactly-once)| Yes | Yes | No - -#### 批量摄取 - -从文件进行批加载时,应使用一次性 [任务](taskrefer.md),并且有三个选项:`index_parallel`(本地并行批任务)、`index_hadoop`(基于hadoop)或`index`(本地简单批任务)。 - -一般来说,如果本地批处理能满足您的需要时我们建议使用它,因为设置更简单(它不依赖于外部Hadoop集群)。但是,仍有一些情况下,基于Hadoop的批摄取可能是更好的选择,例如,当您已经有一个正在运行的Hadoop集群,并且希望使用现有集群的集群资源进行批摄取时。 - -此表比较了三个可用选项: - -| **方式** | [**本地批任务(并行)**](native.md#并行任务) | [**基于Hadoop**](hadoopbased.md) | [**本地批任务(简单)**](native.md#简单任务) | -| - | - | - | - | -| **任务类型** | `index_parallel` | `index_hadoop` | `index` | -| **并行?** | 如果 `inputFormat` 是可分割的且 `tuningConfig` 中的 `maxNumConcurrentSubTasks` > 1, 则 **Yes** | Yes | No,每个任务都是单线程的 | -| **支持追加或者覆盖** | 都支持 | 只支持覆盖 | 都支持 | -| **外部依赖** | 无 | Hadoop集群,用来提交Map-Reduce任务 | 无 | -| **输入位置** | 任何 [输入数据源](native.md#输入数据源) | 任何Hadoop文件系统或者Druid数据源 | 任何 [输入数据源](native.md#输入数据源) | -| **文件格式** | 任何 [输入格式](dataformats.md) | 任何Hadoop输入格式 | 任何 [输入格式](dataformats.md) | -| [**Rollup modes**](#Rollup) | 如果 `tuningConfig` 中的 `forceGuaranteedRollup` = true, 则为 **Perfect(最佳rollup)** | 总是Perfect(最佳rollup) | 如果 `tuningConfig` 中的 `forceGuaranteedRollup` = true, 则为 **Perfect(最佳rollup)** | -| **分区选项** | 可选的有`Dynamic`, `hash-based` 和 `range-based` 三种分区方式,详情参见 [分区规范](native.md#partitionsSpec) | 通过 [partitionsSpec](hadoopbased.md#partitionsSpec)中指定 `hash-based` 和 `range-based`分区 | 可选的有`Dynamic`和`hash-based`二种分区方式,详情参见 [分区规范](native.md#partitionsSpec) | - -### Druid数据模型 -#### 数据源 -Druid数据存储在数据源中,与传统RDBMS中的表类似。Druid提供了一个独特的数据建模系统,它与关系模型和时间序列模型都具有相似性。 -#### 主时间戳列 -Druid Schema必须始终包含一个主时间戳。主时间戳用于对 [数据进行分区和排序](#分区)。Druid查询能够快速识别和检索与主时间戳列的时间范围相对应的数据。Druid还可以将主时间戳列用于基于时间的[数据管理操作](datamanage.md),例如删除时间块、覆盖时间块和基于时间的保留规则。 - -主时间戳基于 [`timestampSpec`](#timestampSpec) 进行解析。此外,[`granularitySpec`](#granularitySpec) 控制基于主时间戳的其他重要操作。无论从哪个输入字段读取主时间戳,它都将作为名为 `__time` 的列存储在Druid数据源中。 - -如果有多个时间戳列,则可以将其他列存储为 [辅助时间戳](schemadesign.md#辅助时间戳)。 - -#### 维度 -维度是按原样存储的列,可以用于任何目的, 可以在查询时以特殊方式对维度进行分组、筛选或应用聚合器。如果在禁用了 [rollup](#Rollup) 的情况下运行,那么该维度集将被简单地视为要摄取的一组列,并且其行为与不支持rollup功能的典型数据库的预期完全相同。 - -通过 [`dimensionSpec`](#dimensionSpec) 配置维度。 - -#### 指标 -Metrics是以聚合形式存储的列。启用 [rollup](#Rollup) 时,它们最有用。指定一个Metric允许您为Druid选择一个聚合函数,以便在摄取期间应用于每一行。这有两个好处: - -1. 如果启用了 [rollup](#Rollup),即使保留摘要信息,也可以将多行折叠为一行。在 [Rollup教程](../tutorials/chapter-5.md) 中,这用于将netflow数据折叠为每(`minute`,`srcIP`,`dstIP`)元组一行,同时保留有关总数据包和字节计数的聚合信息。 -2. 一些聚合器,特别是近似聚合器,即使在非汇总数据上,如果在接收时部分计算,也可以在查询时更快地计算它们。 - -Metrics是通过 [`metricsSpec`](#metricsSpec) 配置的。 - -### Rollup -#### 什么是rollup -Druid可以在接收过程中将数据进行汇总,以最小化需要存储的原始数据量。Rollup是一种汇总或预聚合的形式。实际上,Rollup可以极大地减少需要存储的数据的大小,从而潜在地减少行数的数量级。这种存储量的减少是有代价的:当我们汇总数据时,我们就失去了查询单个事件的能力。 - -禁用rollup时,Druid将按原样加载每一行,而不进行任何形式的预聚合。此模式类似于您对不支持汇总功能的典型数据库的期望。 - -如果启用了rollup,那么任何具有相同[维度](#维度)和[时间戳](#主时间戳列)的行(在基于 `queryGranularity` 的截断之后)都可以在Druid中折叠或汇总为一行。 - -rollup默认是启用状态。 - -#### 启用或者禁用rollup - -Rollup由 `granularitySpec` 中的 `rollup` 配置项控制。 默认情况下,值为 `true`(启用状态)。如果你想让Druid按原样存储每条记录,而不需要任何汇总,将该值设置为 `false`。 - -#### rollup示例 -有关如何配置Rollup以及该特性将如何修改数据的示例,请参阅[Rollup教程](../tutorials/chapter-5.md)。 - -#### 最大化rollup比率 -通过比较Druid中的行数和接收的事件数,可以测量数据源的汇总率。这个数字越高,从汇总中获得的好处就越多。一种方法是使用[Druid SQL](../querying/druidsql.md)查询,比如: -```json -SELECT SUM("cnt") / COUNT(*) * 1.0 FROM datasource -``` - -在这个查询中,`cnt` 应该引用在摄取时指定的"count"类型Metrics。有关启用汇总时计数工作方式的详细信息,请参阅"架构设计"页上的 [计数接收事件数](../DataIngestion/schemadesign.md#计数接收事件数)。 - -最大化Rollup的提示: -* 一般来说,拥有的维度越少,维度的基数越低,您将获得更好的汇总比率 -* 使用 [Sketches](schemadesign.md#Sketches高基维处理) 避免存储高基数维度,因为会损害汇总比率 -* 在摄入时调整 `queryGranularity`(例如,使用 `PT5M` 而不是 `PT1M` )会增加Druid中两行具有匹配时间戳的可能性,并可以提高汇总率 -* 将相同的数据加载到多个Druid数据源中是有益的。有些用户选择创建禁用汇总(或启用汇总,但汇总比率最小)的"完整"数据源和具有较少维度和较高汇总比率的"缩写"数据源。当查询只涉及"缩写"集里边的维度时,使用该数据源将导致更快的查询时间,这种方案只需稍微增加存储空间即可完成,因为简化的数据源往往要小得多。 -* 如果您使用的 [尽力而为的汇总(best-effort rollup)](#) 摄取配置不能保证[完全汇总(perfect rollup)](#),则可以通过切换到保证的完全汇总选项,或在初始摄取后在[后台重新编制(reindex)](./datamanage.md#压缩与重新索引)数据索引,潜在地提高汇总比率。 - -#### 最佳rollup VS 尽可能rollup -一些Druid摄取方法保证了*完美的汇总(perfect rollup)*,这意味着输入数据在摄取时被完美地聚合。另一些则提供了*尽力而为的汇总(best-effort rollup)*,这意味着输入数据可能无法完全聚合,因此可能有多个段保存具有相同时间戳和维度值的行。 - -一般来说,提供*尽力而为的汇总(best-effort rollup)*的摄取方法之所以这样做,是因为它们要么是在没有清洗步骤(这是*完美的汇总(perfect rollup)*所必需的)的情况下并行摄取,要么是因为它们在接收到某个时间段的所有数据(我们称之为*增量发布(incremental publishing)*)之前完成并发布段。在这两种情况下,理论上可以汇总的记录可能会以不同的段结束。所有类型的流接收都在此模式下运行。 - -保证*完美的汇总(perfect rollup)*的摄取方法通过额外的预处理步骤来确定实际数据摄取阶段之前的间隔和分区。此预处理步骤扫描整个输入数据集,这通常会增加摄取所需的时间,但提供完美汇总所需的信息。 - -下表显示了每个方法如何处理汇总: -| **方法** | **如何工作** | -| - | - | -| [本地批](native.md) | 基于配置,`index_parallel` 和 `index` 可以是完美的,也可以是最佳的。 | -| [Hadoop批](hadoopbased.md) | 总是 perfect | -| [Kafka索引服务](kafka.md) | 总是 best-effort | -| [Kinesis索引服务](kinesis.md) | 总是 best-effort | - -### 分区 -#### 为什么分区 - -数据源中段的最佳分区和排序会对占用空间和性能产生重大影响 -。 -Druid数据源总是按时间划分为*时间块*,每个时间块包含一个或多个段。此分区适用于所有摄取方法,并基于摄取规范的 `dataSchema` 中的 `segmentGranularity`参数。 - -特定时间块内的段也可以进一步分区,使用的选项根据您选择的摄取类型而不同。一般来说,使用特定维度执行此辅助分区将改善局部性,这意味着具有该维度相同值的行存储在一起,并且可以快速访问。 - -通常,通过将数据分区到一些常用来做过滤操作的维度(如果存在的话)上,可以获得最佳性能和最小的总体占用空间。而且,这种分区通常会改善压缩性能而且还往往会提高查询性能(用户报告存储容量减少了三倍)。 - -> [!WARNING] -> 分区和排序是最好的朋友!如果您确实有一个天然的分区维度,那么您还应该考虑将它放在 `dimensionsSpec` 的 `dimension` 列表中的第一个维度,它告诉Druid按照该列对每个段中的行进行排序。除了单独分区所获得的改进之外,这通常还会进一步改进压缩。 -> 但是,请注意,目前,Druid总是首先按时间戳对一个段内的行进行排序,甚至在 `dimensionsSpec` 中列出的第一个维度之前,这将使得维度排序达不到最大效率。如果需要,可以通过在 `granularitySpec` 中将 `queryGranularity` 设置为等于 `segmentGranularity` 的值来解决此限制,这将把段内的所有时间戳设置为相同的值,并将"真实"时间戳保存为[辅助时间戳](./schemadesign.md#辅助时间戳)。这个限制可能在Druid的未来版本中被移除。 - -#### 如何设置分区 -并不是所有的摄入方式都支持显式的分区配置,也不是所有的方法都具有同样的灵活性。在当前的Druid版本中,如果您是通过一个不太灵活的方法(如Kafka)进行初始摄取,那么您可以使用 [重新索引的技术(reindex)](./datamanage.md#压缩与重新索引),在最初摄取数据后对其重新分区。这是一种强大的技术:即使您不断地从流中添加新数据, 也可以使用它来确保任何早于某个阈值的数据都得到最佳分区。 - -下表显示了每个摄取方法如何处理分区: - -| **方法** | **如何工作** | -| - | - | -| [本地批](native.md) | 通过 `tuningConfig` 中的 [`partitionsSpec`](./native.md#partitionsSpec) | -| [Hadoop批](hadoopbased.md) | 通过 `tuningConfig` 中的 [`partitionsSpec`](./native.md#partitionsSpec) | -| [Kafka索引服务](kafka.md) | Druid中的分区是由Kafka主题的分区方式决定的。您可以在初次摄入后 [重新索引的技术(reindex)](./datamanage.md#压缩与重新索引)以重新分区 | -| [Kinesis索引服务](kinesis.md) | Druid中的分区是由Kinesis流的分区方式决定的。您可以在初次摄入后 [重新索引的技术(reindex)](./datamanage.md#压缩与重新索引)以重新分区 | - -> [!WARNING] -> -> 注意,当然,划分数据的一种方法是将其加载到分开的数据源中。这是一种完全可行的方法,当数据源的数量不会导致每个数据源的开销过大时,它可以很好地工作。如果使用这种方法,那么可以忽略这一部分,因为这部分描述了如何在单个数据源中设置分区。 -> -> 有关将数据拆分为单独数据源的详细信息以及潜在的操作注意事项,请参阅 [多租户注意事项](../querying/multitenancy.md)。 - -### 摄入规范 - -无论使用哪一种摄入方式,数据要么是通过一次性[tasks](taskrefer.md)或者通过持续性的"supervisor"(运行并监控一段时间内的一系列任务)来被加载到Druid中。 在任一种情况下,task或者supervisor的定义都在*摄入规范*中定义。 - -摄入规范包括以下三个主要的部分: -* [`dataSchema`](#dataschema), 包含了 [`数据源名称`](#datasource), [`主时间戳列`](#timestampspec), [`维度`](#dimensionspec), [`指标`](#metricsspec) 和 [`转换与过滤`](#transformspec) -* [`ioConfig`](#ioconfig), 该部分告诉Druid如何去连接数据源系统以及如何去解析数据。 更多详细信息,可以看[摄入方法](#摄入方式)的文档。 -* [`tuningConfig`](#tuningconfig), 该部分控制着每一种[摄入方法](#摄入方式)的不同的特定调整参数 - -一个 `index_parallel` 类型任务的示例摄入规范如下: -```json -{ - "type": "index_parallel", - "spec": { - "dataSchema": { - "dataSource": "wikipedia", - "timestampSpec": { - "column": "timestamp", - "format": "auto" - }, - "dimensionsSpec": { - "dimensions": [ - { "type": "string", "page" }, - { "type": "string", "language" }, - { "type": "long", "name": "userId" } - ] - }, - "metricsSpec": [ - { "type": "count", "name": "count" }, - { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, - { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } - ], - "granularitySpec": { - "segmentGranularity": "day", - "queryGranularity": "none", - "intervals": [ - "2013-08-31/2013-09-01" - ] - } - }, - "ioConfig": { - "type": "index_parallel", - "inputSource": { - "type": "local", - "baseDir": "examples/indexing/", - "filter": "wikipedia_data.json" - }, - "inputFormat": { - "type": "json", - "flattenSpec": { - "useFieldDiscovery": true, - "fields": [ - { "type": "path", "name": "userId", "expr": "$.user.id" } - ] - } - } - }, - "tuningConfig": { - "type": "index_parallel" - } - } -} -``` - -该部分中支持的特定选项依赖于选择的[摄入方法](#摄入方式)。 更多的示例,可以参考每一种[摄入方法](#摄入方式)的文档。 - -您还可以不用编写一个摄入规范,可视化的加载数据,该功能位于 [Druid控制台](../operations/manageui.md) 的 "Load Data" 视图中。 Druid可视化数据加载器目前支持 [Kafka](kafka.md), [Kinesis](kinesis.md) 和 [本地批](native.md) 模式。 - -#### `dataSchema` -> [!WARNING] -> -> `dataSchema` 规范在0.17.0版本中做了更改,新的规范支持除*Hadoop摄取方式*外的所有方式。 可以在 [过时的 `dataSchema` 规范]()查看老的规范 - -`dataSchema` 包含了以下部分: -* [`数据源名称`](#datasource), [`主时间戳列`](#timestampspec), [`维度`](#dimensionspec), [`指标`](#metricsspec) 和 [`转换与过滤`](#transformspec) - -一个 `dataSchema` 如下: -```json -"dataSchema": { - "dataSource": "wikipedia", - "timestampSpec": { - "column": "timestamp", - "format": "auto" - }, - "dimensionsSpec": { - "dimensions": [ - { "type": "string", "page" }, - { "type": "string", "language" }, - { "type": "long", "name": "userId" } - ] - }, - "metricsSpec": [ - { "type": "count", "name": "count" }, - { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, - { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } - ], - "granularitySpec": { - "segmentGranularity": "day", - "queryGranularity": "none", - "intervals": [ - "2013-08-31/2013-09-01" - ] - } -} -``` - -##### `dataSource` -`dataSource` 位于 `dataSchema` -> `dataSource` 中,简单的标识了数据将被写入的数据源的名称,示例如下: -```json -"dataSource": "my-first-datasource" -``` -##### `timestampSpec` -`timestampSpec` 位于 `dataSchema` -> `timestampSpec` 中,用来配置 [主时间戳](#timestampspec), 示例如下: -```json -"timestampSpec": { - "column": "timestamp", - "format": "auto" -} -``` -> [!WARNING] -> 概念上,输入数据被读取后,Druid会以一个特定的顺序来对数据应用摄入规范: 首先 `flattenSpec`(如果有),然后 `timestampSpec`, 然后 `transformSpec` ,最后是 `dimensionsSpec` 和 `metricsSpec`。在编写摄入规范时需要牢记这一点 - -`timestampSpec` 可以包含以下的部分: - - - - - - - - - - - - - - - - - - - - - - - - -
字段描述默认值
column要从中读取主时间戳的输入行字段。

不管这个输入字段的名称是什么,主时间戳总是作为一个名为"__time"的列存储在您的Druid数据源中
timestamp
format - 时间戳格式,可选项有: -
    -
  • iso: 使用"T"分割的ISO8601,像"2000-01-01T01:02:03.456"
  • -
  • posix: 自纪元以来的秒数
  • -
  • millis: 自纪元以来的毫秒数
  • -
  • micro: 自纪元以来的微秒数
  • -
  • nano: 自纪元以来的纳秒数
  • -
  • auto: 自动检测ISO或者毫秒格式
  • -
  • 任何 Joda DateTimeFormat字符串
  • -
-
auto
missingValue用于具有空或缺少时间戳列的输入记录的时间戳。应该是ISO8601格式,如"2000-01-01T01:02:03.456"。由于Druid需要一个主时间戳,因此此设置对于接收根本没有任何时间戳的数据集非常有用。none
- -##### `dimensionSpec` -`dimensionsSpec` 位于 `dataSchema` -> `dimensionsSpec`, 用来配置维度。示例如下: -```json -"dimensionsSpec" : { - "dimensions": [ - "page", - "language", - { "type": "long", "name": "userId" } - ], - "dimensionExclusions" : [], - "spatialDimensions" : [] -} -``` - -> [!WARNING] -> 概念上,输入数据被读取后,Druid会以一个特定的顺序来对数据应用摄入规范: 首先 `flattenSpec`(如果有),然后 `timestampSpec`, 然后 `transformSpec` ,最后是 `dimensionsSpec` 和 `metricsSpec`。在编写摄入规范时需要牢记这一点 - -`dimensionsSpec` 可以包括以下部分: - -| 字段 | 描述 | 默认值 | -|-|-|-| -| dimensions | 维度名称或者对象的列表,在 `dimensions` 和 `dimensionExclusions` 中不能包含相同的列。

如果该配置为一个空数组,Druid将会把所有未出现在 `dimensionExclusions` 中的非时间、非指标列当做字符串类型的维度列,参见[Inclusions and exclusions](#Inclusions-and-exclusions)。 | `[]` | -| dimensionExclusions | 在摄取中需要排除的列名称,在该配置中只支持名称,不支持对象。在 `dimensions` 和 `dimensionExclusions` 中不能包含相同的列。 | `[]` | -| spatialDimensions | 一个[空间维度](../querying/spatialfilter.md)的数组 | `[]` | - -###### `Dimension objects` -在 `dimensions` 列的每一个维度可以是一个名称,也可以是一个对象。 提供一个名称等价于提供了一个给定名称的 `string` 类型的维度对象。例如: `page` 等价于 `{"name": "page", "type": "string"}`。 - -维度对象可以有以下的部分: - -| 字段 | 描述 | 默认值 | -|-|-|-| -| type | `string`, `long`, `float` 或者 `double` | `string` | -| name | 维度名称,将用作从输入记录中读取的字段名,以及存储在生成的段中的列名。

注意: 如果想在摄取的时候重新命名列,可以使用 [`transformSpec`](#transformspec) | none(必填)| -| createBitmapIndex | 对于字符串类型的维度,是否应为生成的段中的列创建位图索引。创建位图索引需要更多存储空间,但会加快某些类型的筛选(特别是相等和前缀筛选)。仅支持字符串类型的维度。| `true` | - -###### `Inclusions and exclusions` -Druid以两种可能的方式来解释 `dimensionsSpec` : *normal* 和 *schemaless* - -当 `dimensions` 或者 `spatialDimensions` 为非空时, 将会采用正常的解释方式。 在该情况下, 前边说的两个列表结合起来的集合当做摄入的维度集合。 - -当 `dimensions` 和 `spatialDimensions` 同时为空或者null时候,将会采用无模式的解释方式。 在该情况下,维度集合由以下方式决定: -1. 首先,从 [`inputFormat`](./dataformats.md) (或者 [`flattenSpec`](./dataformats.md#FlattenSpec), 如果正在使用 )中所有输入字段集合开始 -2. 排除掉任何在 `dimensionExclusions` 中的列 -3. 排除掉在 [`timestampSpec`](#timestampspec) 中的时间列 -4. 排除掉 [`metricsSpec`](#metricsspec) 中用于聚合器输入的列 -5. 排除掉 [`metricsSpec`](#metricsspec) 中任何与聚合器同名的列 -6. 所有的其他字段都被按照[默认配置](#dimensionspec)摄入为 `string` 类型的维度 - -> [!WARNING] -> 注意:在无模式的维度解释方式中,由 [`transformSpec`](#transformspec) 生成的列当前并未考虑。 - -##### `metricsSpec` - -`metricsSpec` 位于 `dataSchema` -> `metricsSpec` 中,是一个在摄入阶段要应用的 [聚合器](../querying/Aggregations.md) 列表。 在启用了 [rollup](#rollup) 时是很有用的,因为它将配置如何在摄入阶段进行聚合。 - -一个 `metricsSpec` 实例如下: -```json -"metricsSpec": [ - { "type": "count", "name": "count" }, - { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, - { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } -] -``` -> [!WARNING] -> 通常,当 [rollup](#rollup) 被禁用时,应该有一个空的 `metricsSpec`(因为没有rollup,Druid不会在摄取时进行任何的聚合,所以没有理由包含摄取时聚合器)。但是,在某些情况下,定义Metrics仍然是有意义的:例如,如果要创建一个复杂的列作为 [近似聚合](../querying/Aggregations.md#近似聚合) 的预计算部分,则只能通过在 `metricsSpec` 中定义度量来实现 - -##### `granularitySpec` - -`granularitySpec` 位于 `dataSchema` -> `granularitySpec`, 用来配置以下操作: -1. 通过 `segmentGranularity` 来将数据源分区到 [时间块](../design/Design.md#数据源和段) -2. 如果需要的话,通过 `queryGranularity` 来截断时间戳 -3. 通过 `interval` 来指定批摄取中应创建段的时间块 -4. 通过 `rollup` 来指定是否在摄取时进行汇总 - -除了 `rollup`, 这些操作都是基于 [主时间戳列](#主时间戳列) - -一个 `granularitySpec` 实例如下: -```json -"granularitySpec": { - "segmentGranularity": "day", - "queryGranularity": "none", - "intervals": [ - "2013-08-31/2013-09-01" - ], - "rollup": true -} -``` - -`granularitySpec` 可以有以下的部分: - -| 字段 | 描述 | 默认值 | -|-|-|-| -| type | `uniform` 或者 `arbitrary` ,大多数时候使用 `uniform` | `uniform` | -| segmentGranularity | 数据源的 [时间分块](../design/Design.md#数据源和段) 粒度。每个时间块可以创建多个段, 例如,当设置为 `day` 时,同一天的事件属于同一时间块,该时间块可以根据其他配置和输入大小进一步划分为多个段。这里可以提供任何粒度。请注意,同一时间块中的所有段应具有相同的段粒度。

如果 `type` 字段设置为 `arbitrary` 则忽略 | `day` | -| queryGranularity | 每个段内时间戳存储的分辨率, 必须等于或比 `segmentGranularity` 更细。这将是您可以查询的最细粒度,并且仍然可以查询到合理的结果。但是请注意,您仍然可以在比此粒度更粗的场景进行查询,例如 "`minute`"的值意味着记录将以分钟的粒度存储,并且可以在分钟的任意倍数(包括分钟、5分钟、小时等)进行查询。

这里可以提供任何 [粒度](../querying/AggregationGranularity.md) 。使用 `none` 按原样存储时间戳,而不进行任何截断。请注意,即使将 `queryGranularity` 设置为 `none`,也将应用 `rollup`。 | `none` | -| rollup | 是否在摄取时使用 [rollup](#rollup)。 注意:即使 `queryGranularity` 设置为 `none`,rollup也仍然是有效的,当数据具有相同的时间戳时数据将被汇总 | `true` | -| interval | 描述应该创建段的时间块的间隔列表。如果 `type` 设置为`uniform`,则此列表将根据 `segmentGranularity` 进行拆分和舍入。如果 `type` 设置为 `arbitrary` ,则将按原样使用此列表。

如果该值不提供或者为空值,则批处理摄取任务通常会根据在输入数据中找到的时间戳来确定要输出的时间块。

如果指定,批处理摄取任务可以跳过确定分区阶段,这可能会导致更快的摄取。批量摄取任务也可以预先请求它们的所有锁,而不是逐个请求。批处理摄取任务将丢弃任何时间戳超出指定间隔的记录。

在任何形式的流摄取中忽略该配置。 | `null` | - -##### `transformSpec` -`transformSpec` 位于 `dataSchema` -> `transformSpec`,用来摄取时转换和过滤输入数据。 一个 `transformSpec` 实例如下: -```json -"transformSpec": { - "transforms": [ - { "type": "expression", "name": "countryUpper", "expression": "upper(country)" } - ], - "filter": { - "type": "selector", - "dimension": "country", - "value": "San Serriffe" - } -} -``` - -> [!WARNING] -> 概念上,输入数据被读取后,Druid会以一个特定的顺序来对数据应用摄入规范: 首先 `flattenSpec`(如果有),然后 `timestampSpec`, 然后 `transformSpec` ,最后是 `dimensionsSpec` 和 `metricsSpec`。在编写摄入规范时需要牢记这一点 - -##### 过时的 `dataSchema` 规范 -> [!WARNING] -> -> `dataSchema` 规范在0.17.0版本中做了更改,新的规范支持除*Hadoop摄取方式*外的所有方式。 可以在 [`dataSchema`](#dataschema)查看老的规范 - -除了上面 `dataSchema` 一节中列出的组件之外,过时的 `dataSchema` 规范还有以下两个组件。 -* [input row parser](), [flatten of nested data]() - -**parser**(已废弃) -在过时的 `dataSchema` 中,`parser` 位于 `dataSchema` -> `parser`中,负责配置与解析输入记录相关的各种项。由于 `parser` 已经废弃,不推荐使用,强烈建议改用 `inputFormat`。 对于 `inputFormat` 和支持的 `parser` 类型,可以参见 [数据格式](dataformats.md)。 - -`parseSpec`主要部分的详细,参见他们的子部分: -* [`timestampSpec`](#timestampspec), 配置 [主时间戳列](#主时间戳列) -* [`dimensionsSpec`](#dimensionspec), 配置 [维度](#维度) -* [`flattenSpec`](./dataformats.md#FlattenSpec) - -一个 `parser` 实例如下: - -```json -"parser": { - "type": "string", - "parseSpec": { - "format": "json", - "flattenSpec": { - "useFieldDiscovery": true, - "fields": [ - { "type": "path", "name": "userId", "expr": "$.user.id" } - ] - }, - "timestampSpec": { - "column": "timestamp", - "format": "auto" - }, - "dimensionsSpec": { - "dimensions": [ - { "type": "string", "page" }, - { "type": "string", "language" }, - { "type": "long", "name": "userId" } - ] - } - } -} -``` -**flattenSpec** -在过时的 `dataSchema` 中,`flattenSpec` 位于`dataSchema` -> `parser` -> `parseSpec` -> `flattenSpec`中,负责在潜在的嵌套输入数据(如JSON、Avro等)和Druid的数据模型之间架起桥梁。有关详细信息,请参见 [flattenSpec](./dataformats.md#FlattenSpec) 。 - -#### `ioConfig` - -`ioConfig` 影响从源系统(如Apache Kafka、Amazon S3、挂载的文件系统或任何其他受支持的源系统)读取数据的方式。`inputFormat` 属性适用于除Hadoop摄取之外的[所有摄取方法](#摄入方式)。Hadoop摄取仍然使用过时的 `dataSchema` 中的 [parser]。`ioConfig` 的其余部分特定于每个单独的摄取方法。读取JSON数据的 `ioConfig` 示例如下: -```json -"ioConfig": { - "type": "", - "inputFormat": { - "type": "json" - }, - ... -} -``` -详情可以参见每个 [摄取方式](#摄入方式) 提供的文档。 - -#### `tuningConfig` - -优化属性在 `tuningConfig` 中指定,`tuningConfig` 位于摄取规范的顶层。有些属性适用于所有摄取方法,但大多数属性特定于每个单独的摄取方法。`tuningConfig` 将所有共享的公共属性设置为默认值的示例如下: -```json -"tuningConfig": { - "type": "", - "maxRowsInMemory": 1000000, - "maxBytesInMemory": , - "indexSpec": { - "bitmap": { "type": "concise" }, - "dimensionCompression": "lz4", - "metricCompression": "lz4", - "longEncoding": "longs" - }, - -} -``` - -| 字段 | 描述 | 默认值 | -|-|-|-| -| type | 每一种摄入方式都有自己的类型,必须指定为与摄入方式匹配的类型。通常的选项有 `index`, `hadoop`, `kafka` 和 `kinesis` | | -| maxRowsInMemory | 数据持久化到硬盘前在内存中存储的最大数据条数。 注意,这个数字是汇总后的,所以可能并不等于输入的记录数。 当摄入的数据达到 `maxRowsInMemory` 或者 `maxBytesInMemory` 时数据将被持久化到硬盘。 | `1000000` | -| maxBytesInMemory | 在持久化之前要存储在JVM堆中的数据最大字节数。这是基于对内存使用的粗略估计。当达到 `maxRowsInMemory` 或`maxBytesInMemory` 时(以先发生的为准),摄取的记录将被持久化到磁盘。

将 `maxBytesInMemory` 设置为-1将禁用此检查,这意味着Druid将完全依赖 `maxRowsInMemory` 来控制内存使用。将其设置为零意味着将使用默认值(JVM堆大小的六分之一)。

请注意,内存使用量的估计值被设计为高估值,并且在使用复杂的摄取时聚合器(包括sketches)时可能特别高。如果这导致索引工作负载过于频繁地持久化到磁盘,则可以将 `maxBytesInMemory` 设置为-1并转而依赖 `maxRowsInMemory`。 | JVM堆内存最大值的1/6 | -| indexSpec | 优化数据如何被索引,详情可以看下面的表格 | 看下面的表格 | -| 其他属性 | 每一种摄入方式都有其自己的优化属性。 详情可以查看每一种方法的文档。 [Kafka索引服务](kafka.md), [Kinesis索引服务](kinesis.md), [本地批](native.md) 和 [Hadoop批](hadoopbased.md) | | - -**`indexSpec`** - -上边表格中的 `indexSpec` 部分可以包含以下属性: - -| 字段 | 描述 | 默认值 | -|-|-|-| -| bitmap | 位图索引的压缩格式。 需要一个 `type` 设置为 `concise` 或者 `roaring` 的JSON对象。对于 `roaring`类型,布尔属性`compressRunOnSerialization`(默认为true)控制在确定运行长度编码更节省空间时是否使用该编码。 | `{"type":"concise"}` | -| dimensionCompression | 维度列的压缩格式。 可选项有 `lz4`, `lzf` 或者 `uncompressed` | `lz4` | -| metricCompression | Metrics列的压缩格式。可选项有 `lz4`, `lzf`, `uncompressed` 或者 `none`(`none` 比 `uncompressed` 更有效,但是在老版本的Druid不支持) | `lz4` | -| longEncoding | long类型列的编码格式。无论它们是维度还是Metrics,都适用,选项是 `auto` 或 `long`。`auto` 根据列基数使用偏移量或查找表对值进行编码,并以可变大小存储它们。`longs` 按原样存储值,每个值8字节。 | `longs` | - -除了这些属性之外,每个摄取方法都有自己的特定调整属性。有关详细信息,请参阅每个 [摄取方法](#摄入方式) 的文档。 \ No newline at end of file diff --git a/SUMMARY.md b/SUMMARY.md index f3a63a8..ece2424 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -49,19 +49,19 @@ * [Zookeeper](design/Zookeeper.md) * [数据摄取]() - * [摄取概述](DataIngestion/ingestion.md) - * [数据格式](DataIngestion/dataformats.md) - * [schema设计](DataIngestion/schemadesign.md) - * [数据管理](DataIngestion/datamanage.md) - * [流式摄取](DataIngestion/kafka.md) - * [Apache Kafka](DataIngestion/kafka.md) - * [Apache Kinesis](DataIngestion/kinesis.md) - * [Tranquility](DataIngestion/tranquility.md) - * [批量摄取](DataIngestion/native.md) - * [本地批](DataIngestion/native.md) - * [Hadoop批](DataIngestion/hadoopbased.md) - * [任务参考](DataIngestion/taskrefer.md) - * [问题FAQ](DataIngestion/faq.md) + * [摄取概述](ingestion/ingestion.md) + * [数据格式](ingestion/dataformats.md) + * [schema设计](ingestion/schemadesign.md) + * [数据管理](ingestion/datamanage.md) + * [流式摄取](ingestion/kafka.md) + * [Apache Kafka](ingestion/kafka.md) + * [Apache Kinesis](ingestion/kinesis.md) + * [Tranquility](ingestion/tranquility.md) + * [批量摄取](ingestion/native.md) + * [本地批](ingestion/native.md) + * [Hadoop批](ingestion/hadoop.md) + * [任务参考](ingestion/taskrefer.md) + * [问题FAQ](ingestion/faq.md) * [数据查询]() * [Druid SQL](querying/druidsql.md) diff --git a/dependencies/deep-storage.md b/dependencies/deep-storage.md index 77ae9b2..ba966da 100644 --- a/dependencies/deep-storage.md +++ b/dependencies/deep-storage.md @@ -1,27 +1,4 @@ ---- -id: deep-storage -title: "Deep storage" ---- - - - +# 深度存储 Deep storage is where segments are stored. It is a storage mechanism that Apache Druid does not provide. This deep storage infrastructure defines the level of durability of your data, as long as Druid processes can see this storage infrastructure and get at the segments stored on it, you will not lose data no matter how many Druid nodes you lose. If segments disappear from this storage layer, then you will lose whatever data those segments represented. diff --git a/dependencies/metadata-storage.md b/dependencies/metadata-storage.md index 6c3263b..34cca24 100644 --- a/dependencies/metadata-storage.md +++ b/dependencies/metadata-storage.md @@ -1,27 +1,4 @@ ---- -id: metadata-storage -title: "Metadata storage" ---- - - - +# 元数据存储 The Metadata Storage is an external dependency of Apache Druid. Druid uses it to store various metadata about the system, but not to store the actual data. There are diff --git a/dependencies/zookeeper.md b/dependencies/zookeeper.md index ec6814e..5ceac35 100644 --- a/dependencies/zookeeper.md +++ b/dependencies/zookeeper.md @@ -1,27 +1,4 @@ ---- -id: zookeeper -title: "ZooKeeper" ---- - - - +# ZooKeeper Apache Druid uses [Apache ZooKeeper](http://zookeeper.apache.org/) (ZK) for management of current cluster state. diff --git a/design/Coordinator.md b/design/Coordinator.md index 1bc50d5..5607dd8 100644 --- a/design/Coordinator.md +++ b/design/Coordinator.md @@ -45,12 +45,12 @@ org.apache.druid.cli.Main server coordinator 每次运行时,Druid Coordinator都通过合并小段或拆分大片段来压缩段。当您的段没有进行段大小(可能会导致查询性能下降)优化时,该操作非常有用。有关详细信息,请参见[段大小优化](../operations/segmentSizeOpt.md)。 -Coordinator首先根据[段搜索策略](#段搜索策略)查找要压缩的段。找到某些段后,它会发出[压缩任务](../DataIngestion/taskrefer.md#compact)来压缩这些段。运行压缩任务的最大数目为 `min(sum of worker capacity * slotRatio, maxSlots)`。请注意,即使 `min(sum of worker capacity * slotRatio, maxSlots)` = 0,如果为数据源启用了压缩,则始终会提交至少一个压缩任务。请参阅[压缩配置API](../operations/api.md#Coordinator)和[压缩配置](../configuration/human-readable-byte.md#Coordinator)以启用压缩。 +Coordinator首先根据[段搜索策略](#段搜索策略)查找要压缩的段。找到某些段后,它会发出[压缩任务](../ingestion/taskrefer.md#compact)来压缩这些段。运行压缩任务的最大数目为 `min(sum of worker capacity * slotRatio, maxSlots)`。请注意,即使 `min(sum of worker capacity * slotRatio, maxSlots)` = 0,如果为数据源启用了压缩,则始终会提交至少一个压缩任务。请参阅[压缩配置API](../operations/api.md#Coordinator)和[压缩配置](../configuration/human-readable-byte.md#Coordinator)以启用压缩。 压缩任务可能由于以下原因而失败: * 如果压缩任务的输入段在开始前被删除或覆盖,则该压缩任务将立即失败。 -* 如果优先级较高的任务获取与压缩任务的时间间隔重叠的[时间块锁](../DataIngestion/taskrefer.md#锁),则压缩任务失败。 +* 如果优先级较高的任务获取与压缩任务的时间间隔重叠的[时间块锁](../ingestion/taskrefer.md#锁),则压缩任务失败。 一旦压缩任务失败,Coordinator只需再次检查失败任务间隔中的段,并在下次运行中发出另一个压缩任务。 diff --git a/design/Design.md b/design/Design.md index 6c2e897..7031c5d 100644 --- a/design/Design.md +++ b/design/Design.md @@ -79,7 +79,7 @@ Druid数据被存储在"datasources"中,类似于传统RDBMS中的表。每一 有关段文件格式的信息,请参见[段文件](segments.md) -有关数据在Druid的建模,请参见[schema设计](../DataIngestion/schemadesign.md) +有关数据在Druid的建模,请参见[schema设计](../ingestion/schemadesign.md) #### 索引和切换(Indexing and handoff) diff --git a/design/segments.md b/design/segments.md index 059e341..5beb5fc 100644 --- a/design/segments.md +++ b/design/segments.md @@ -12,7 +12,7 @@ ## 段 -ApacheDruid将索引存储在按时间分区的*段文件*中。在基本设置中,通常为每个时间间隔创建一个段文件,其中时间间隔可在 `granularitySpec` 的`segmentGranularity` 参数中配置。为了使Druid在繁重的查询负载下运行良好,段文件大小必须在建议的300MB-700MB范围内。如果段文件大于此范围,请考虑更改时间间隔的粒度,或者对数据进行分区,并在 `partitionsSpec` 中调整 `targetPartitionSize`(此参数的建议起点是500万行)。有关更多信息,请参阅下面的**分片部分**和[批处理摄取](../DataIngestion/native.md)文档的**分区规范**部分。 +ApacheDruid将索引存储在按时间分区的*段文件*中。在基本设置中,通常为每个时间间隔创建一个段文件,其中时间间隔可在 `granularitySpec` 的`segmentGranularity` 参数中配置。为了使Druid在繁重的查询负载下运行良好,段文件大小必须在建议的300MB-700MB范围内。如果段文件大于此范围,请考虑更改时间间隔的粒度,或者对数据进行分区,并在 `partitionsSpec` 中调整 `targetPartitionSize`(此参数的建议起点是500万行)。有关更多信息,请参阅下面的**分片部分**和[批处理摄取](../ingestion/native.md)文档的**分区规范**部分。 ### 段文件的核心数据结构 diff --git a/DataIngestion/dataformats.md b/ingestion/dataformats.md similarity index 96% rename from DataIngestion/dataformats.md rename to ingestion/dataformats.md index 8142c7c..4b1158b 100644 --- a/DataIngestion/dataformats.md +++ b/ingestion/dataformats.md @@ -48,7 +48,7 @@ Druid支持自定义数据格式,可以使用 `Regex` 解析器或 `JavaScript > [!WARNING] > 输入格式是在0.17.0中引入的指定输入数据的数据格式的新方法。不幸的是,输入格式还不支持Druid支持的所有数据格式或摄取方法。特别是如果您想使用Hadoop接收,您仍然需要使用 [解析器](#parser)。如果您的数据是以本节未列出的某种格式格式化的,请考虑改用解析器。 -所有形式的Druid摄取都需要某种形式的schema对象。要摄取的数据的格式是使用[`ioConfig`](../DataIngestion/ingestion.md#ioConfig) 中的 `inputFormat` 条目指定的。 +所有形式的Druid摄取都需要某种形式的schema对象。要摄取的数据的格式是使用[`ioConfig`](/ingestion.md#ioConfig) 中的 `inputFormat` 条目指定的。 #### JSON @@ -210,7 +210,7 @@ Parquet `inputFormat` 有以下组件: | 字段 | 描述 | 默认值 | |-|-|-| -| useFieldDiscovery | 如果为true,则将所有根级字段解释为可用字段,供 [`timestampSpec`](../DataIngestion/ingestion.md#timestampSpec)、[`transformSpec`](../DataIngestion/ingestion.md#transformSpec)、[`dimensionsSpec`](../DataIngestion/ingestion.md#dimensionsSpec) 和 [`metricsSpec`](../DataIngestion/ingestion.md#metricsSpec) 使用。

如果为false,则只有显式指定的字段(请参阅 `fields`)才可供使用。 | true | +| useFieldDiscovery | 如果为true,则将所有根级字段解释为可用字段,供 [`timestampSpec`](/ingestion.md#timestampSpec)、[`transformSpec`](/ingestion.md#transformSpec)、[`dimensionsSpec`](/ingestion.md#dimensionsSpec) 和 [`metricsSpec`](/ingestion.md#metricsSpec) 使用。

如果为false,则只有显式指定的字段(请参阅 `fields`)才可供使用。 | true | | fields | 指定感兴趣的字段及其访问方式, 详细请见下边 | `[]` | **字段展平规范** @@ -281,7 +281,7 @@ Parquet `inputFormat` 有以下组件: > [!WARNING] > 需要添加 [druid-avro-extensions](../development/avro-extensions.md) 来使用 Avro Hadoop解析器 -该解析器用于 [Hadoop批摄取](hadoopbased.md)。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.druid.data.input.avro.AvroValueInputFormat`。您可能想在 `tuningConfig` 中的 `jobProperties` 选项设置Avro reader的schema, 例如:`"avro.schema.input.value.path": "/path/to/your/schema.avsc"` 或者 `"avro.schema.input.value": "your_schema_JSON_object"`。如果未设置Avro读取器的schema,则将使用Avro对象容器文件中的schema,详情可以参见 [avro规范](http://avro.apache.org/docs/1.7.7/spec.html#Schema+Resolution) +该解析器用于 [Hadoop批摄取](hadoop.md)。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.druid.data.input.avro.AvroValueInputFormat`。您可能想在 `tuningConfig` 中的 `jobProperties` 选项设置Avro reader的schema, 例如:`"avro.schema.input.value.path": "/path/to/your/schema.avsc"` 或者 `"avro.schema.input.value": "your_schema_JSON_object"`。如果未设置Avro读取器的schema,则将使用Avro对象容器文件中的schema,详情可以参见 [avro规范](http://avro.apache.org/docs/1.7.7/spec.html#Schema+Resolution) | 字段 | 类型 | 描述 | 是否必填 | |-|-|-|-| @@ -332,7 +332,7 @@ Avro parseSpec可以包含使用"root"或"path"字段类型的 [flattenSpec](#fl > [!WARNING] > 如果您正在考虑从早于0.15.0的版本升级到0.15.0或更高版本,请仔细阅读 [从contrib扩展的迁移](../development/orc-extensions.md#从contrib扩展迁移)。 -该解析器用于 [Hadoop批摄取](hadoopbased.md)。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.orc.mapreduce.OrcInputFormat`。 +该解析器用于 [Hadoop批摄取](hadoop.md)。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.orc.mapreduce.OrcInputFormat`。 | 字段 | 类型 | 描述 | 是否必填 | |-|-|-|-| @@ -554,7 +554,7 @@ Avro parseSpec可以包含使用"root"或"path"字段类型的 [flattenSpec](#fl > [!WARNING] > 需要添加 [druid-parquet-extensions](../development/parquet-extensions.md) 来使用Parquet Hadoop解析器 -该解析器用于 [Hadoop批摄取](hadoopbased.md)。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.druid.data.input.parquet.DruidParquetInputFormat`。 +该解析器用于 [Hadoop批摄取](hadoop.md)。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.druid.data.input.parquet.DruidParquetInputFormat`。 Parquet Hadoop 解析器支持自动字段发现,如果提供了一个带有 `parquet` `parquetSpec`的 `flattenSpec` 也支持展平。 Parquet嵌套 list 和 map [逻辑类型](https://github.com/apache/parquet-format/blob/master/LogicalTypes.md) 应与所有受支持类型的JSON path表达式一起正确操作。 @@ -680,7 +680,7 @@ Parquet Hadoop 解析器支持自动字段发现,如果提供了一个带有 ` > [!WARNING] > 使用Parquet Avro Hadoop Parser需要同时加入 [druid-parquet-extensions](../development/parquet-extensions.md) 和 [druid-avro-extensions](../development/avro-extensions.md) -该解析器用于 [Hadoop批摄取](hadoopbased.md), 该解析器首先将Parquet数据转换为Avro记录,然后再解析它们后摄入到Druid。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.druid.data.input.parquet.DruidParquetAvroInputFormat`。 +该解析器用于 [Hadoop批摄取](hadoop.md), 该解析器首先将Parquet数据转换为Avro记录,然后再解析它们后摄入到Druid。在 `ioConfig` 中,`inputSpec` 中的 `inputFormat` 必须设置为 `org.apache.druid.data.input.parquet.DruidParquetAvroInputFormat`。 Parquet Avro Hadoop 解析器支持自动字段发现,如果提供了一个带有 `avro` `parquetSpec`的 `flattenSpec` 也支持展平。 Parquet嵌套 list 和 map [逻辑类型](https://github.com/apache/parquet-format/blob/master/LogicalTypes.md) 应与所有受支持类型的JSON path表达式一起正确操作。该解析器将Hadoop作业属性 `parquet.avro.add-list-element-records` 设置为false(通常默认为true),以便将原始列表元素"展开"为多值维度。 diff --git a/DataIngestion/datamanage.md b/ingestion/datamanage.md similarity index 98% rename from DataIngestion/datamanage.md rename to ingestion/datamanage.md index c39f924..4075abb 100644 --- a/DataIngestion/datamanage.md +++ b/ingestion/datamanage.md @@ -140,7 +140,7 @@ Druid不支持按主键更新单个记录。 #### 使用基于Hadoop的摄取 -本节假设读者理解如何使用Hadoop进行批量摄取。有关详细信息,请参见 [Hadoop批处理摄取](hadoopbased.md)。Hadoop批量摄取可用于重新索引数据和增量摄取数据。 +本节假设读者理解如何使用Hadoop进行批量摄取。有关详细信息,请参见 [Hadoop批处理摄取](hadoop.md)。Hadoop批量摄取可用于重新索引数据和增量摄取数据。 Druid使用 `ioConfig` 中的 `inputSpec` 来知道要接收的数据位于何处以及如何读取它。对于简单的Hadoop批接收,`static` 或 `granularity` 粒度规范类型允许您读取存储在深层存储中的数据。 diff --git a/DataIngestion/faq.md b/ingestion/faq.md similarity index 100% rename from DataIngestion/faq.md rename to ingestion/faq.md diff --git a/ingestion/hadoop.md b/ingestion/hadoop.md new file mode 100644 index 0000000..26c1216 --- /dev/null +++ b/ingestion/hadoop.md @@ -0,0 +1,1025 @@ +# Hadoop 导入数据 + +Apache Hadoop-based batch ingestion in Apache Druid is supported via a Hadoop-ingestion task. These tasks can be posted to a running +instance of a Druid [Overlord](../design/overlord.md). Please refer to our [Hadoop-based vs. native batch comparison table](index.md#batch) for +comparisons between Hadoop-based, native batch (simple), and native batch (parallel) ingestion. + +To run a Hadoop-based ingestion task, write an ingestion spec as specified below. Then POST it to the +[`/druid/indexer/v1/task`](../operations/api-reference.md#tasks) endpoint on the Overlord, or use the +`bin/post-index-task` script included with Druid. + +## Tutorial + +This page contains reference documentation for Hadoop-based ingestion. +For a walk-through instead, check out the [Loading from Apache Hadoop](../tutorials/tutorial-batch-hadoop.md) tutorial. + +## Task syntax + +A sample task is shown below: + +```json +{ + "type" : "index_hadoop", + "spec" : { + "dataSchema" : { + "dataSource" : "wikipedia", + "parser" : { + "type" : "hadoopyString", + "parseSpec" : { + "format" : "json", + "timestampSpec" : { + "column" : "timestamp", + "format" : "auto" + }, + "dimensionsSpec" : { + "dimensions": ["page","language","user","unpatrolled","newPage","robot","anonymous","namespace","continent","country","region","city"], + "dimensionExclusions" : [], + "spatialDimensions" : [] + } + } + }, + "metricsSpec" : [ + { + "type" : "count", + "name" : "count" + }, + { + "type" : "doubleSum", + "name" : "added", + "fieldName" : "added" + }, + { + "type" : "doubleSum", + "name" : "deleted", + "fieldName" : "deleted" + }, + { + "type" : "doubleSum", + "name" : "delta", + "fieldName" : "delta" + } + ], + "granularitySpec" : { + "type" : "uniform", + "segmentGranularity" : "DAY", + "queryGranularity" : "NONE", + "intervals" : [ "2013-08-31/2013-09-01" ] + } + }, + "ioConfig" : { + "type" : "hadoop", + "inputSpec" : { + "type" : "static", + "paths" : "/MyDirectory/example/wikipedia_data.json" + } + }, + "tuningConfig" : { + "type": "hadoop" + } + }, + "hadoopDependencyCoordinates": +} +``` + +|property|description|required?| +|--------|-----------|---------| +|type|The task type, this should always be "index_hadoop".|yes| +|spec|A Hadoop Index Spec. See [Ingestion](../ingestion/index.md)|yes| +|hadoopDependencyCoordinates|A JSON array of Hadoop dependency coordinates that Druid will use, this property will override the default Hadoop coordinates. Once specified, Druid will look for those Hadoop dependencies from the location specified by `druid.extensions.hadoopDependenciesDir`|no| +|classpathPrefix|Classpath that will be prepended for the Peon process.|no| + +Also note that Druid automatically computes the classpath for Hadoop job containers that run in the Hadoop cluster. But in case of conflicts between Hadoop and Druid's dependencies, you can manually specify the classpath by setting `druid.extensions.hadoopContainerDruidClasspath` property. See the extensions config in [base druid configuration](../configuration/index.md#extensions). + +## `dataSchema` + +This field is required. See the [`dataSchema`](index.md#legacy-dataschema-spec) section of the main ingestion page for details on +what it should contain. + +## `ioConfig` + +This field is required. + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|type|String|This should always be 'hadoop'.|yes| +|inputSpec|Object|A specification of where to pull the data in from. See below.|yes| +|segmentOutputPath|String|The path to dump segments into.|Only used by the [Command-line Hadoop indexer](#cli). This field must be null otherwise.| +|metadataUpdateSpec|Object|A specification of how to update the metadata for the druid cluster these segments belong to.|Only used by the [Command-line Hadoop indexer](#cli). This field must be null otherwise.| + +### `inputSpec` + +There are multiple types of inputSpecs: + +#### `static` + +A type of inputSpec where a static path to the data files is provided. + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|inputFormat|String|Specifies the Hadoop InputFormat class to use. e.g. `org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat` |no| +|paths|Array of String|A String of input paths indicating where the raw data is located.|yes| + +For example, using the static input paths: + +``` +"paths" : "hdfs://path/to/data/is/here/data.gz,hdfs://path/to/data/is/here/moredata.gz,hdfs://path/to/data/is/here/evenmoredata.gz" +``` + +You can also read from cloud storage such as AWS S3 or Google Cloud Storage. +To do so, you need to install the necessary library under Druid's classpath in _all MiddleManager or Indexer processes_. +For S3, you can run the below command to install the [Hadoop AWS module](https://hadoop.apache.org/docs/current/hadoop-aws/tools/hadoop-aws/). + +```bash +java -classpath "${DRUID_HOME}lib/*" org.apache.druid.cli.Main tools pull-deps -h "org.apache.hadoop:hadoop-aws:${HADOOP_VERSION}"; +cp ${DRUID_HOME}/hadoop-dependencies/hadoop-aws/${HADOOP_VERSION}/hadoop-aws-${HADOOP_VERSION}.jar ${DRUID_HOME}/extensions/druid-hdfs-storage/ +``` + +Once you install the Hadoop AWS module in all MiddleManager and Indexer processes, you can put +your S3 paths in the inputSpec with the below job properties. +For more configurations, see the [Hadoop AWS module](https://hadoop.apache.org/docs/current/hadoop-aws/tools/hadoop-aws/). + +``` +"paths" : "s3a://billy-bucket/the/data/is/here/data.gz,s3a://billy-bucket/the/data/is/here/moredata.gz,s3a://billy-bucket/the/data/is/here/evenmoredata.gz" +``` + +```json +"jobProperties" : { + "fs.s3a.impl" : "org.apache.hadoop.fs.s3a.S3AFileSystem", + "fs.AbstractFileSystem.s3a.impl" : "org.apache.hadoop.fs.s3a.S3A", + "fs.s3a.access.key" : "YOUR_ACCESS_KEY", + "fs.s3a.secret.key" : "YOUR_SECRET_KEY" +} +``` + +For Google Cloud Storage, you need to install [GCS connector jar](https://github.com/GoogleCloudPlatform/bigdata-interop/blob/master/gcs/INSTALL.md) +under `${DRUID_HOME}/hadoop-dependencies` in _all MiddleManager or Indexer processes_. +Once you install the GCS Connector jar in all MiddleManager and Indexer processes, you can put +your Google Cloud Storage paths in the inputSpec with the below job properties. +For more configurations, see the [instructions to configure Hadoop](https://github.com/GoogleCloudPlatform/bigdata-interop/blob/master/gcs/INSTALL.md#configure-hadoop), +[GCS core default](https://github.com/GoogleCloudDataproc/hadoop-connectors/blob/v2.0.0/gcs/conf/gcs-core-default.xml) +and [GCS core template](https://github.com/GoogleCloudPlatform/bdutil/blob/master/conf/hadoop2/gcs-core-template.xml). + +``` +"paths" : "gs://billy-bucket/the/data/is/here/data.gz,gs://billy-bucket/the/data/is/here/moredata.gz,gs://billy-bucket/the/data/is/here/evenmoredata.gz" +``` + +```json +"jobProperties" : { + "fs.gs.impl" : "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem", + "fs.AbstractFileSystem.gs.impl" : "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS" +} +``` + +#### `granularity` + +A type of inputSpec that expects data to be organized in directories according to datetime using the path format: `y=XXXX/m=XX/d=XX/H=XX/M=XX/S=XX` (where date is represented by lowercase and time is represented by uppercase). + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|dataGranularity|String|Specifies the granularity to expect the data at, e.g. hour means to expect directories `y=XXXX/m=XX/d=XX/H=XX`.|yes| +|inputFormat|String|Specifies the Hadoop InputFormat class to use. e.g. `org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat` |no| +|inputPath|String|Base path to append the datetime path to.|yes| +|filePattern|String|Pattern that files should match to be included.|yes| +|pathFormat|String|Joda datetime format for each directory. Default value is `"'y'=yyyy/'m'=MM/'d'=dd/'H'=HH"`, or see [Joda documentation](http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html)|no| + +For example, if the sample config were run with the interval 2012-06-01/2012-06-02, it would expect data at the paths: + +``` +s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=00 +s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=01 +... +s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=23 +``` + +#### `dataSource` + +This is a type of `inputSpec` that reads data already stored inside Druid. This is used to allow "re-indexing" data and for "delta-ingestion" described later in `multi` type inputSpec. + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|type|String.|This should always be 'dataSource'.|yes| +|ingestionSpec|JSON object.|Specification of Druid segments to be loaded. See below.|yes| +|maxSplitSize|Number|Enables combining multiple segments into single Hadoop InputSplit according to size of segments. With -1, druid calculates max split size based on user specified number of map task(mapred.map.tasks or mapreduce.job.maps). By default, one split is made for one segment. maxSplitSize is specified in bytes.|no| +|useNewAggs|Boolean|If "false", then list of aggregators in "metricsSpec" of hadoop indexing task must be same as that used in original indexing task while ingesting raw data. Default value is "false". This field can be set to "true" when "inputSpec" type is "dataSource" and not "multi" to enable arbitrary aggregators while reindexing. See below for "multi" type support for delta-ingestion.|no| + +Here is what goes inside `ingestionSpec`: + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|dataSource|String|Druid dataSource name from which you are loading the data.|yes| +|intervals|List|A list of strings representing ISO-8601 Intervals.|yes| +|segments|List|List of segments from which to read data from, by default it is obtained automatically. You can obtain list of segments to put here by making a POST query to Coordinator at url /druid/coordinator/v1/metadata/datasources/segments?full with list of intervals specified in the request payload, e.g. ["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", "2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"]. You may want to provide this list manually in order to ensure that segments read are exactly same as they were at the time of task submission, task would fail if the list provided by the user does not match with state of database when the task actually runs.|no| +|filter|JSON|See [Filters](../querying/filters.md)|no| +|dimensions|Array of String|Name of dimension columns to load. By default, the list will be constructed from parseSpec. If parseSpec does not have an explicit list of dimensions then all the dimension columns present in stored data will be read.|no| +|metrics|Array of String|Name of metric columns to load. By default, the list will be constructed from the "name" of all the configured aggregators.|no| +|ignoreWhenNoSegments|boolean|Whether to ignore this ingestionSpec if no segments were found. Default behavior is to throw error when no segments were found.|no| + +For example + +```json +"ioConfig" : { + "type" : "hadoop", + "inputSpec" : { + "type" : "dataSource", + "ingestionSpec" : { + "dataSource": "wikipedia", + "intervals": ["2014-10-20T00:00:00Z/P2W"] + } + }, + ... +} +``` + +#### `multi` + +This is a composing inputSpec to combine other inputSpecs. This inputSpec is used for delta ingestion. You can also use a `multi` inputSpec to combine data from multiple dataSources. However, each particular dataSource can only be specified one time. +Note that, "useNewAggs" must be set to default value false to support delta-ingestion. + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|children|Array of JSON objects|List of JSON objects containing other inputSpecs.|yes| + +For example: + +```json +"ioConfig" : { + "type" : "hadoop", + "inputSpec" : { + "type" : "multi", + "children": [ + { + "type" : "dataSource", + "ingestionSpec" : { + "dataSource": "wikipedia", + "intervals": ["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", "2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"], + "segments": [ + { + "dataSource": "test1", + "interval": "2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", + "version": "v2", + "loadSpec": { + "type": "local", + "path": "/tmp/index1.zip" + }, + "dimensions": "host", + "metrics": "visited_sum,unique_hosts", + "shardSpec": { + "type": "none" + }, + "binaryVersion": 9, + "size": 2, + "identifier": "test1_2000-01-01T00:00:00.000Z_3000-01-01T00:00:00.000Z_v2" + } + ] + } + }, + { + "type" : "static", + "paths": "/path/to/more/wikipedia/data/" + } + ] + }, + ... +} +``` + +It is STRONGLY RECOMMENDED to provide list of segments in `dataSource` inputSpec explicitly so that your delta ingestion task is idempotent. You can obtain that list of segments by making following call to the Coordinator. +POST `/druid/coordinator/v1/metadata/datasources/{dataSourceName}/segments?full` +Request Body: [interval1, interval2,...] for example ["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", "2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"] + +## `tuningConfig` + +The tuningConfig is optional and default parameters will be used if no tuningConfig is specified. + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|workingPath|String|The working path to use for intermediate results (results between Hadoop jobs).|Only used by the [Command-line Hadoop indexer](#cli). The default is '/tmp/druid-indexing'. This field must be null otherwise.| +|version|String|The version of created segments. Ignored for HadoopIndexTask unless useExplicitVersion is set to true|no (default == datetime that indexing starts at)| +|partitionsSpec|Object|A specification of how to partition each time bucket into segments. Absence of this property means no partitioning will occur. See [`partitionsSpec`](#partitionsspec) below.|no (default == 'hashed')| +|maxRowsInMemory|Integer|The number of rows to aggregate before persisting. Note that this is the number of post-aggregation rows which may not be equal to the number of input events due to roll-up. This is used to manage the required JVM heap size. Normally user does not need to set this, but depending on the nature of data, if rows are short in terms of bytes, user may not want to store a million rows in memory and this value should be set.|no (default == 1000000)| +|maxBytesInMemory|Long|The number of bytes to aggregate in heap memory before persisting. Normally this is computed internally and user does not need to set it. This is based on a rough estimate of memory usage and not actual usage. The maximum heap memory usage for indexing is maxBytesInMemory * (2 + maxPendingPersists). Note that `maxBytesInMemory` also includes heap usage of artifacts created from intermediary persists. This means that after every persist, the amount of `maxBytesInMemory` until next persist will decreases, and task will fail when the sum of bytes of all intermediary persisted artifacts exceeds `maxBytesInMemory`.|no (default == One-sixth of max JVM memory)| +|leaveIntermediate|Boolean|Leave behind intermediate files (for debugging) in the workingPath when a job completes, whether it passes or fails.|no (default == false)| +|cleanupOnFailure|Boolean|Clean up intermediate files when a job fails (unless leaveIntermediate is on).|no (default == true)| +|overwriteFiles|Boolean|Override existing files found during indexing.|no (default == false)| +|ignoreInvalidRows|Boolean|DEPRECATED. Ignore rows found to have problems. If false, any exception encountered during parsing will be thrown and will halt ingestion; if true, unparseable rows and fields will be skipped. If `maxParseExceptions` is defined, this property is ignored.|no (default == false)| +|combineText|Boolean|Use CombineTextInputFormat to combine multiple files into a file split. This can speed up Hadoop jobs when processing a large number of small files.|no (default == false)| +|useCombiner|Boolean|Use Hadoop combiner to merge rows at mapper if possible.|no (default == false)| +|jobProperties|Object|A map of properties to add to the Hadoop job configuration, see below for details.|no (default == null)| +|indexSpec|Object|Tune how data is indexed. See [`indexSpec`](index.md#indexspec) on the main ingestion page for more information.|no| +|indexSpecForIntermediatePersists|Object|defines segment storage format options to be used at indexing time for intermediate persisted temporary segments. this can be used to disable dimension/metric compression on intermediate segments to reduce memory required for final merging. however, disabling compression on intermediate segments might increase page cache use while they are used before getting merged into final segment published, see [`indexSpec`](index.md#indexspec) for possible values.|no (default = same as indexSpec)| +|numBackgroundPersistThreads|Integer|The number of new background threads to use for incremental persists. Using this feature causes a notable increase in memory pressure and CPU usage but will make the job finish more quickly. If changing from the default of 0 (use current thread for persists), we recommend setting it to 1.|no (default == 0)| +|forceExtendableShardSpecs|Boolean|Forces use of extendable shardSpecs. Hash-based partitioning always uses an extendable shardSpec. For single-dimension partitioning, this option should be set to true to use an extendable shardSpec. For partitioning, please check [Partitioning specification](#partitionsspec). This option can be useful when you need to append more data to existing dataSource.|no (default = false)| +|useExplicitVersion|Boolean|Forces HadoopIndexTask to use version.|no (default = false)| +|logParseExceptions|Boolean|If true, log an error message when a parsing exception occurs, containing information about the row where the error occurred.|no(default = false)| +|maxParseExceptions|Integer|The maximum number of parse exceptions that can occur before the task halts ingestion and fails. Overrides `ignoreInvalidRows` if `maxParseExceptions` is defined.|no(default = unlimited)| +|useYarnRMJobStatusFallback|Boolean|If the Hadoop jobs created by the indexing task are unable to retrieve their completion status from the JobHistory server, and this parameter is true, the indexing task will try to fetch the application status from `http:///ws/v1/cluster/apps/`, where `` is the value of `yarn.resourcemanager.webapp.address` in your Hadoop configuration. This flag is intended as a fallback for cases where an indexing task's jobs succeed, but the JobHistory server is unavailable, causing the indexing task to fail because it cannot determine the job statuses.|no (default = true)| +|awaitSegmentAvailabilityTimeoutMillis|Long|Milliseconds to wait for the newly indexed segments to become available for query after ingestion completes. If `<= 0`, no wait will occur. If `> 0`, the task will wait for the Coordinator to indicate that the new segments are available for querying. If the timeout expires, the task will exit as successful, but the segments were not confirmed to have become available for query.|no (default = 0)| + +### `jobProperties` + +```json + "tuningConfig" : { + "type": "hadoop", + "jobProperties": { + "": "", + "": "" + } + } +``` + +Hadoop's [MapReduce documentation](https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml) lists the possible configuration parameters. + +With some Hadoop distributions, it may be necessary to set `mapreduce.job.classpath` or `mapreduce.job.user.classpath.first` +to avoid class loading issues. See the [working with different Hadoop versions documentation](../operations/other-hadoop.md) +for more details. + +## `partitionsSpec` + +Segments are always partitioned based on timestamp (according to the granularitySpec) and may be further partitioned in +some other way depending on partition type. Druid supports two types of partitioning strategies: `hashed` (based on the +hash of all dimensions in each row), and `single_dim` (based on ranges of a single dimension). + +Hashed partitioning is recommended in most cases, as it will improve indexing performance and create more uniformly +sized data segments relative to single-dimension partitioning. + +### Hash-based partitioning + +```json + "partitionsSpec": { + "type": "hashed", + "targetRowsPerSegment": 5000000 + } +``` + +Hashed partitioning works by first selecting a number of segments, and then partitioning rows across those segments +according to the hash of all dimensions in each row. The number of segments is determined automatically based on the +cardinality of the input set and a target partition size. + +The configuration options are: + +|Field|Description|Required| +|--------|-----------|---------| +|type|Type of partitionSpec to be used.|"hashed"| +|targetRowsPerSegment|Target number of rows to include in a partition, should be a number that targets segments of 500MB\~1GB. Defaults to 5000000 if `numShards` is not set.|either this or `numShards`| +|targetPartitionSize|Deprecated. Renamed to `targetRowsPerSegment`. Target number of rows to include in a partition, should be a number that targets segments of 500MB\~1GB.|either this or `numShards`| +|maxRowsPerSegment|Deprecated. Renamed to `targetRowsPerSegment`. Target number of rows to include in a partition, should be a number that targets segments of 500MB\~1GB.|either this or `numShards`| +|numShards|Specify the number of partitions directly, instead of a target partition size. Ingestion will run faster, since it can skip the step necessary to select a number of partitions automatically.|either this or `maxRowsPerSegment`| +|partitionDimensions|The dimensions to partition on. Leave blank to select all dimensions. Only used with `numShards`, will be ignored when `targetRowsPerSegment` is set.|no| +|partitionFunction|A function to compute hash of partition dimensions. See [Hash partition function](#hash-partition-function)|`murmur3_32_abs`|no| + +##### Hash partition function + +In hash partitioning, the partition function is used to compute hash of partition dimensions. The partition dimension +values are first serialized into a byte array as a whole, and then the partition function is applied to compute hash of +the byte array. +Druid currently supports only one partition function. + +|name|description| +|----|-----------| +|`murmur3_32_abs`|Applies an absolute value function to the result of [`murmur3_32`](https://guava.dev/releases/16.0/api/docs/com/google/common/hash/Hashing.html#murmur3_32()).| + +### Single-dimension range partitioning + +```json + "partitionsSpec": { + "type": "single_dim", + "targetRowsPerSegment": 5000000 + } +``` + +Single-dimension range partitioning works by first selecting a dimension to partition on, and then separating that dimension +into contiguous ranges. Each segment will contain all rows with values of that dimension in that range. For example, +your segments may be partitioned on the dimension "host" using the ranges "a.example.com" to "f.example.com" and +"f.example.com" to "z.example.com". By default, the dimension to use is determined automatically, although you can +override it with a specific dimension. + +The configuration options are: + +|Field|Description|Required| +|--------|-----------|---------| +|type|Type of partitionSpec to be used.|"single_dim"| +|targetRowsPerSegment|Target number of rows to include in a partition, should be a number that targets segments of 500MB\~1GB.|yes| +|targetPartitionSize|Deprecated. Renamed to `targetRowsPerSegment`. Target number of rows to include in a partition, should be a number that targets segments of 500MB\~1GB.|no| +|maxRowsPerSegment|Maximum number of rows to include in a partition. Defaults to 50% larger than the `targetRowsPerSegment`.|no| +|maxPartitionSize|Deprecated. Use `maxRowsPerSegment` instead. Maximum number of rows to include in a partition. Defaults to 50% larger than the `targetPartitionSize`.|no| +|partitionDimension|The dimension to partition on. Leave blank to select a dimension automatically.|no| +|assumeGrouped|Assume that input data has already been grouped on time and dimensions. Ingestion will run faster, but may choose sub-optimal partitions if this assumption is violated.|no| + +## Remote Hadoop clusters + +If you have a remote Hadoop cluster, make sure to include the folder holding your configuration `*.xml` files in your Druid `_common` configuration folder. + +If you are having dependency problems with your version of Hadoop and the version compiled with Druid, please see [these docs](../operations/other-hadoop.md). + +## Elastic MapReduce + +If your cluster is running on Amazon Web Services, you can use Elastic MapReduce (EMR) to index data +from S3. To do this: + +- Create a persistent, [long-running cluster](http://docs.aws.amazon.com/ElasticMapReduce/latest/ManagementGuide/emr-plan-longrunning-transient). +- When creating your cluster, enter the following configuration. If you're using the wizard, this + should be in advanced mode under "Edit software settings": + +``` +classification=yarn-site,properties=[mapreduce.reduce.memory.mb=6144,mapreduce.reduce.java.opts=-server -Xms2g -Xmx2g -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,mapreduce.map.java.opts=758,mapreduce.map.java.opts=-server -Xms512m -Xmx512m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,mapreduce.task.timeout=1800000] +``` + +- Follow the instructions under + [Configure for connecting to Hadoop](../tutorials/cluster.md#hadoop) using the XML files from `/etc/hadoop/conf` + on your EMR master. + +## Kerberized Hadoop clusters + +By default druid can use the existing TGT kerberos ticket available in local kerberos key cache. +Although TGT ticket has a limited life cycle, +therefore you need to call `kinit` command periodically to ensure validity of TGT ticket. +To avoid this extra external cron job script calling `kinit` periodically, +you can provide the principal name and keytab location and druid will do the authentication transparently at startup and job launching time. + +|Property|Possible Values|Description|Default| +|--------|---------------|-----------|-------| +|`druid.hadoop.security.kerberos.principal`|`druid@EXAMPLE.COM`| Principal user name |empty| +|`druid.hadoop.security.kerberos.keytab`|`/etc/security/keytabs/druid.headlessUser.keytab`|Path to keytab file|empty| + +### Loading from S3 with EMR + +- In the `jobProperties` field in the `tuningConfig` section of your Hadoop indexing task, add: + +``` +"jobProperties" : { + "fs.s3.awsAccessKeyId" : "YOUR_ACCESS_KEY", + "fs.s3.awsSecretAccessKey" : "YOUR_SECRET_KEY", + "fs.s3.impl" : "org.apache.hadoop.fs.s3native.NativeS3FileSystem", + "fs.s3n.awsAccessKeyId" : "YOUR_ACCESS_KEY", + "fs.s3n.awsSecretAccessKey" : "YOUR_SECRET_KEY", + "fs.s3n.impl" : "org.apache.hadoop.fs.s3native.NativeS3FileSystem", + "io.compression.codecs" : "org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.SnappyCodec" +} +``` + +Note that this method uses Hadoop's built-in S3 filesystem rather than Amazon's EMRFS, and is not compatible +with Amazon-specific features such as S3 encryption and consistent views. If you need to use these +features, you will need to make the Amazon EMR Hadoop JARs available to Druid through one of the +mechanisms described in the [Using other Hadoop distributions](#using-other-hadoop-distributions) section. + +## Using other Hadoop distributions + +Druid works out of the box with many Hadoop distributions. + +If you are having dependency conflicts between Druid and your version of Hadoop, you can try +searching for a solution in the [Druid user groups](https://groups.google.com/forum/#!forum/druid-user), or reading the +Druid [Different Hadoop Versions](../operations/other-hadoop.md) documentation. + + + +## Command line (non-task) version + +To run: + +``` +java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath lib/*: org.apache.druid.cli.Main index hadoop +``` + +### Options + +- "--coordinate" - provide a version of Apache Hadoop to use. This property will override the default Hadoop coordinates. Once specified, Apache Druid will look for those Hadoop dependencies from the location specified by `druid.extensions.hadoopDependenciesDir`. +- "--no-default-hadoop" - don't pull down the default hadoop version + +### Spec file + +The spec file needs to contain a JSON object where the contents are the same as the "spec" field in the Hadoop index task. See [Hadoop Batch Ingestion](../ingestion/hadoop.md) for details on the spec format. + +In addition, a `metadataUpdateSpec` and `segmentOutputPath` field needs to be added to the ioConfig: + +``` + "ioConfig" : { + ... + "metadataUpdateSpec" : { + "type":"mysql", + "connectURI" : "jdbc:mysql://localhost:3306/druid", + "password" : "diurd", + "segmentTable" : "druid_segments", + "user" : "druid" + }, + "segmentOutputPath" : "/MyDirectory/data/index/output" + }, +``` + +and a `workingPath` field needs to be added to the tuningConfig: + +``` + "tuningConfig" : { + ... + "workingPath": "/tmp", + ... + } +``` + +#### Metadata Update Job Spec + +This is a specification of the properties that tell the job how to update metadata such that the Druid cluster will see the output segments and load them. + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|type|String|"metadata" is the only value available.|yes| +|connectURI|String|A valid JDBC url to metadata storage.|yes| +|user|String|Username for db.|yes| +|password|String|password for db.|yes| +|segmentTable|String|Table to use in DB.|yes| + +These properties should parrot what you have configured for your [Coordinator](../design/coordinator.md). + +#### segmentOutputPath Config + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|segmentOutputPath|String|the path to dump segments into.|yes| + +#### workingPath Config + +|Field|Type|Description|Required| +|-----|----|-----------|--------| +|workingPath|String|the working path to use for intermediate results (results between Hadoop jobs).|no (default == '/tmp/druid-indexing')| + +Please note that the command line Hadoop indexer doesn't have the locking capabilities of the indexing service, so if you choose to use it, +you have to take caution to not override segments created by real-time processing (if you that a real-time pipeline set up). + + + + +## 基于Hadoop的摄入 + +Apache Druid当前支持通过一个Hadoop摄取任务来支持基于Apache Hadoop的批量索引任务, 这些任务被提交到 [Druid Overlord](../design/Overlord.md)的一个运行实例上。详情可以查看 [基于Hadoop的摄取vs基于本地批摄取的对比](ingestion.md#批量摄取) 来了解基于Hadoop的摄取、本地简单批摄取、本地并行摄取三者的比较。 + +运行一个基于Hadoop的批量摄取任务,首先需要编写一个如下的摄取规范, 然后提交到Overlord的 [`druid/indexer/v1/task`](../operations/api.md#overlord) 接口,或者使用Druid软件包中自带的 `bin/post-index-task` 脚本。 + +### 教程 + +本章包括了基于Hadoop摄取的参考文档,对于粗略的查看,可以查看 [从Hadoop加载数据](../GettingStarted/chapter-3.md) 教程。 + +### 任务符号 + +以下为一个示例任务: +```json +{ + "type" : "index_hadoop", + "spec" : { + "dataSchema" : { + "dataSource" : "wikipedia", + "parser" : { + "type" : "hadoopyString", + "parseSpec" : { + "format" : "json", + "timestampSpec" : { + "column" : "timestamp", + "format" : "auto" + }, + "dimensionsSpec" : { + "dimensions": ["page","language","user","unpatrolled","newPage","robot","anonymous","namespace","continent","country","region","city"], + "dimensionExclusions" : [], + "spatialDimensions" : [] + } + } + }, + "metricsSpec" : [ + { + "type" : "count", + "name" : "count" + }, + { + "type" : "doubleSum", + "name" : "added", + "fieldName" : "added" + }, + { + "type" : "doubleSum", + "name" : "deleted", + "fieldName" : "deleted" + }, + { + "type" : "doubleSum", + "name" : "delta", + "fieldName" : "delta" + } + ], + "granularitySpec" : { + "type" : "uniform", + "segmentGranularity" : "DAY", + "queryGranularity" : "NONE", + "intervals" : [ "2013-08-31/2013-09-01" ] + } + }, + "ioConfig" : { + "type" : "hadoop", + "inputSpec" : { + "type" : "static", + "paths" : "/MyDirectory/example/wikipedia_data.json" + } + }, + "tuningConfig" : { + "type": "hadoop" + } + }, + "hadoopDependencyCoordinates": +} +``` + +| 属性 | 描述 | 是否必须 | +|-|-|-| +| `type` | 任务类型,应该总是 `index_hadoop` | 是 | +| `spec` | Hadoop索引任务规范。 详见 [ingestion](ingestion.md) | 是 | +| `hadoopDependencyCoordinates` | Druid使用的Hadoop依赖,这些属性会覆盖默认的Hadoop依赖。 如果该值被指定,Druid将在 `druid.extensions.hadoopDependenciesDir` 目录下查找指定的Hadoop依赖 | 否 | +| `classpathPrefix` | 为Peon进程准备的类路径。| 否 | + +还要注意,Druid会自动计算在Hadoop集群中运行的Hadoop作业容器的类路径。但是,如果Hadoop和Druid的依赖项之间发生冲突,可以通过设置 `druid.extensions.hadoopContainerDruidClasspath`属性。请参阅 [基本druid配置中的扩展配置](../configuration/human-readable-byte.md#扩展) 。 +#### `dataSchema` + +该字段是必须的。 详情可以查看摄取页中的 [`dataSchema`](ingestion.md#dataschema) 部分来看它应该包括哪些部分。 + +#### `ioConfig` + +该字段是必须的。 + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `type` | String | 应该总是 `hadoop` | 是 | +| `inputSpec` | Object | 指定从哪里拉数据。详情见以下。 | 是 | +| `segmentOutputPath` | String | 将段转储到的路径 | 仅仅在 [命令行Hadoop索引](#命令行版本) 中使用, 否则该字段必须为null | +| `metadataUpdateSpec` | Object | 关于如何更新这些段所属的druid集群的元数据的规范 | 仅仅在 [命令行Hadoop索引](#命令行版本) 中使用, 否则该字段必须为null | + +##### `inputSpec` + +有多种类型的inputSec: + +**`static`** + +一种`inputSpec`的类型,该类型提供数据文件的静态路径。 + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `inputFormat` | String | 指定要使用的Hadoop输入格式的类,比如 `org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat` | 否 | +| `paths` | String数组 | 标识原始数据位置的输入路径的字符串 | 是 | + +例如,以下例子使用了静态输入路径: + +```json +"paths" : "hdfs://path/to/data/is/here/data.gz,hdfs://path/to/data/is/here/moredata.gz,hdfs://path/to/data/is/here/evenmoredata.gz" +``` + +也可以从云存储直接读取数据,例如AWS S3或者谷歌云存储。 前提是需要首先的所有Druid *MiddleManager进程或者Indexer进程*的类路径下安装必要的依赖库。对于S3,需要通过以下命令来安装 [Hadoop AWS 模块](https://hadoop.apache.org/docs/current/hadoop-aws/tools/hadoop-aws/index.html) + +```json +java -classpath "${DRUID_HOME}lib/*" org.apache.druid.cli.Main tools pull-deps -h "org.apache.hadoop:hadoop-aws:${HADOOP_VERSION}"; +cp ${DRUID_HOME}/hadoop-dependencies/hadoop-aws/${HADOOP_VERSION}/hadoop-aws-${HADOOP_VERSION}.jar ${DRUID_HOME}/extensions/druid-hdfs-storage/ +``` + +一旦在所有的MiddleManager和Indexer进程中安装了Hadoop AWS模块,即可将S3路径放到 `inputSpec` 中,同时需要有任务属性。 对于更多配置,可以查看 [Hadoop AWS 模块](https://hadoop.apache.org/docs/current/hadoop-aws/tools/hadoop-aws/index.html) + +```json +"paths" : "s3a://billy-bucket/the/data/is/here/data.gz,s3a://billy-bucket/the/data/is/here/moredata.gz,s3a://billy-bucket/the/data/is/here/evenmoredata.gz" +``` + +```json +"jobProperties" : { + "fs.s3a.impl" : "org.apache.hadoop.fs.s3a.S3AFileSystem", + "fs.AbstractFileSystem.s3a.impl" : "org.apache.hadoop.fs.s3a.S3A", + "fs.s3a.access.key" : "YOUR_ACCESS_KEY", + "fs.s3a.secret.key" : "YOUR_SECRET_KEY" +} +``` + +对于谷歌云存储,需要将 [GCS connector jar](https://github.com/GoogleCloudDataproc/hadoop-connectors/blob/master/gcs/INSTALL.md) 安装到*所有MiddleManager或者Indexer进程*的 `${DRUID_HOME}/hadoop-dependencies`。 一旦在所有的MiddleManager和Indexer进程中安装了GCS连接器jar包,即可将谷歌云存储路径放到 `inputSpec` 中,同时需要有任务属性。对于更多配置,可以查看 [instructions to configure Hadoop](https://github.com/GoogleCloudPlatform/bigdata-interop/blob/master/gcs/INSTALL.md#configure-hadoop), [GCS core default](https://github.com/GoogleCloudPlatform/bigdata-interop/blob/master/gcs/conf/gcs-core-default.xml) 和 [GCS core template](https://github.com/GoogleCloudPlatform/bdutil/blob/master/conf/hadoop2/gcs-core-template.xml). + +```json +"paths" : "gs://billy-bucket/the/data/is/here/data.gz,gs://billy-bucket/the/data/is/here/moredata.gz,gs://billy-bucket/the/data/is/here/evenmoredata.gz" +``` +```json +"jobProperties" : { + "fs.gs.impl" : "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem", + "fs.AbstractFileSystem.gs.impl" : "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS" +} +``` + +**`granularity`** + +一种`inputSpec`类型,该类型期望数据已经按照日期时间组织到对应的目录中,路径格式为: `y=XXXX/m=XX/d=XX/H=XX/M=XX/S=XX` (其中日期用小写表示,时间用大写表示)。 + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `dataGranularity` | String | 指定期望的数据粒度,例如,hour意味着期望的目录格式为: `y=XXXX/m=XX/d=XX/H=XX` | 是 | +| `inputFormat` | String | 指定要使用的Hadoop输入格式的类,比如 `org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat` | 否 | +| `inputPath` | String | 要将日期时间路径附加到的基路径。| 是 | +| `filePattern` | String | 要包含的文件应匹配的模式 | 是 | +| `pathFormat` | String | 每个目录的Joda datetime目录。 默认值为: `"'y'=yyyy/'m'=MM/'d'=dd/'H'=HH"` ,详情可以看 [Joda文档](http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html) | 否 | + +例如, 如果示例配置具有 2012-06-01/2012-06-02 时间间隔,则数据期望的路径是: + +```json +s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=00 +s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=01 +... +s3n://billy-bucket/the/data/is/here/y=2012/m=06/d=01/H=23 +``` + +**`dataSource`** + +一种`inputSpec`的类型, 该类型读取已经存储在Druid中的数据。 该类型被用来"re-indexing"(重新索引)数据和下边描述 `multi` 类型 `inputSpec` 的 "delta-ingestion"(增量摄取)。 + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `type` | String | 应该总是 `dataSource` | 是 | +| `ingestionSpec` | JSON对象 | 要加载的Druid段的规范。详情见下边内容。 | 是 | +| `maxSplitSize` | Number | 允许根据段的大小将多个段合并为单个Hadoop InputSplit。使用-1,druid根据用户指定的映射任务数计算最大拆分大小(`mapred.map.tasks` 或者 `mapreduce.job.maps`). 默认情况下,对一个段进行一次拆分。`maxSplitSize` 以字节为单位指定。 | 否 | +| `useNewAggs` | Boolean | 如果"false",则hadoop索引任务的"metricsSpec"中的聚合器列表必须与接收原始数据时在原始索引任务中使用的聚合器列表相同。默认值为"false"。当"inputSpec"类型为"dataSource"而不是"multi"时,可以将此字段设置为"true",以便在重新编制索引时启用任意聚合器。请参阅下面的"multi"类型增量摄取支持。| 否 | + +下表中为`ingestionSpec`中的一些选项: + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `dataSource` | String | Druid数据源名称,从该数据源读取数据 | 是 | +| `intervals` | List | ISO-8601时间间隔的字符串List | 是 | +| `segments` | List | 从中读取数据的段的列表,默认情况下自动获取。您可以通过向Coordinator的接口 `/druid/Coordinator/v1/metadata/datasources/segments?full` 进行POST查询来获取要放在这里的段列表。例如["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000","2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"]. 您可能希望手动提供此列表,以确保读取的段与任务提交时的段完全相同,如果用户提供的列表与任务实际运行时的数据库状态不匹配,则任务将失败 | 否 | +| `filter` | JSON | 查看 [Filter](../querying/filters.md) | 否 | +| `dimensions` | String数组 | 要加载的维度列的名称。默认情况下,列表将根据 `parseSpec` 构造。如果 `parseSpec` 没有维度的显式列表,则将读取存储数据中的所有维度列。 | 否 | +| `metrics` | String数组 | 要加载的Metric列的名称。默认情况下,列表将根据所有已配置聚合器的"name"构造。 | 否 | +| `ignoreWhenNoSegments` | boolean | 如果找不到段,是否忽略此 `ingestionSpec`。默认行为是在找不到段时引发错误。| 否 | + +示例: + +```json +"ioConfig" : { + "type" : "hadoop", + "inputSpec" : { + "type" : "dataSource", + "ingestionSpec" : { + "dataSource": "wikipedia", + "intervals": ["2014-10-20T00:00:00Z/P2W"] + } + }, + ... +} +``` + +**`multi`** + +这是一个组合类型的 `inputSpec`, 来组合其他 `inputSpec`。此inputSpec用于增量接收。您还可以使用一个 `multi` 类型的inputSpec组合来自多个数据源的数据。但是,每个特定的数据源只能指定一次。注意,"useNewAggs"必须设置为默认值false以支持增量摄取。 + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `children` | JSON对象数组 | 一个JSON对象List,里边包含了其他类型的inputSpec | 是 | + +示例: + +```json +"ioConfig" : { + "type" : "hadoop", + "inputSpec" : { + "type" : "multi", + "children": [ + { + "type" : "dataSource", + "ingestionSpec" : { + "dataSource": "wikipedia", + "intervals": ["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", "2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"], + "segments": [ + { + "dataSource": "test1", + "interval": "2012-01-01T00:00:00.000/2012-01-03T00:00:00.000", + "version": "v2", + "loadSpec": { + "type": "local", + "path": "/tmp/index1.zip" + }, + "dimensions": "host", + "metrics": "visited_sum,unique_hosts", + "shardSpec": { + "type": "none" + }, + "binaryVersion": 9, + "size": 2, + "identifier": "test1_2000-01-01T00:00:00.000Z_3000-01-01T00:00:00.000Z_v2" + } + ] + } + }, + { + "type" : "static", + "paths": "/path/to/more/wikipedia/data/" + } + ] + }, + ... +} +``` + +**强烈建议显式**地在 `dataSource` 中的 `inputSpec` 中提供段列表,以便增量摄取任务是幂等的。您可以通过对Coordinator进行以下调用来获取该段列表,POST `/druid/coordinator/v1/metadata/datasources/{dataSourceName}/segments?full`, 请求体:[interval1,interval2,…], 例如["2012-01-01T00:00:00.000/2012-01-03T00:00:00.000","2012-01-05T00:00:00.000/2012-01-07T00:00:00.000"] + +#### `tuningConfig` + +`tuningConfig` 是一个可选项,如果未指定的话,则使用默认的参数。 + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `workingPath` | String | 用于存储中间结果(Hadoop作业之间的结果)的工作路径 | 该配置仅仅使用在 [命令行Hadoop索引](#命令行版本) ,默认值为: `/tmp/druid-indexing`, 否则该值必须设置为null | +| `version` | String | 创建的段的版本。 对于Hadoop索引任务一般是忽略的,除非 `useExplicitVersion` 被设置为 `true` | 否(默认为索引任务开始的时间) | +| `partitionsSpec` | Object | 指定如何将时间块内的分区为段。缺少此属性意味着不会发生分区。 详情可见 [`partitionsSpec`](#partitionsspec) | 否(默认为 `hashed`) | +| `maxRowsInMemory` | Integer | 在持久化之前在堆内存中聚合的行数。注意:由于rollup操作,该值是聚合后的行数,可能不等于输入的行数。 该值常用来管理需要的JVM堆内存大小。通常情况下,用户并不需要设置该值,而是依赖数据自身。 如果数据是非常小的,用户希望在内存存储上百万行数据的话,则需要设置该值。 | 否(默认为:1000000)| +| `maxBytesInMemory` | Long | 在持久化之前在堆内存中聚合的字节数。通常这是在内部计算的,用户不需要设置它。此值表示在持久化之前要在堆内存中聚合的字节数。这是基于对内存使用量的粗略估计,而不是实际使用量。用于索引的最大堆内存使用量为 `maxBytesInMemory *(2 + maxPendingResistent)` | 否(默认为:最大JVM内存的1/6)| +| `leaveIntermediate` | Boolean | 作业完成时,不管通过还是失败,都在工作路径中留下中间文件(用于调试)。 | 否(默认为false)| +| `cleanupOnFailure` | Boolean | 当任务失败时清理中间文件(除非 `leaveIntermediate` 设置为true) | 否(默认为true)| +| `overwriteFiles` | Boolean | 在索引过程中覆盖找到的现存文件 | 否(默认为false)| +| `ignoreInvalidRows` | Boolean | **已废弃**。忽略发现有问题的行。如果为false,解析过程中遇到的任何异常都将引发并停止摄取;如果为true,将跳过不可解析的行和字段。如果定义了 `maxParseExceptions`,则忽略此属性。 | 否(默认为false)| +| `combineText` | Boolean | 使用CombineTextInputFormat将多个文件合并为一个文件拆分。这可以在处理大量小文件时加快Hadoop作业的速度。 | 否(默认为false)| +| `useCombiner` | Boolean | 如果可能的话,使用Hadoop Combiner在mapper阶段合并行 | 否(默认为false)| +| `jobProperties` | Object | 增加到Hadoop作业配置的属性map,详情见下边。 | 否(默认为null)| +| `indexSpec` | Object | 调整数据如何被索引。 详细信息可以见位于摄取页的 [`indexSpec`](ingestion.md#tuningConfig) | 否 | +| `indexSpecForIntermediatePersists` | Object | 定义要在索引时用于中间持久化临时段的段存储格式选项。这可用于禁用中间段上的dimension/metric压缩,以减少最终合并所需的内存。但是,在中间段上禁用压缩可能会增加页缓存的使用,因为可能在它们被合并到发布的最终段之前使用它们,有关可能的值,请参阅 [`indexSpec`](ingestion.md#tuningConfig)。 | 否(默认与indexSpec一样)| +| `numBackgroundPersistThreads` | Integer | 用于增量持久化的新后台线程数。使用此功能会显著增加内存压力和CPU使用率,但会使任务更快完成。如果从默认值0(对持久性使用当前线程)更改,建议将其设置为1。 | 否(默认为0)| +| `forceExtendableShardSpecs` | Boolean | 强制使用可扩展的shardSpec。基于哈希的分区总是使用可扩展的shardSpec。对于单维分区,此选项应设置为true以使用可扩展shardSpec。对于分区,请检查 [分区规范](#partitionsspec) | 否(默认为false)| +| `useExplicitVersion` | Boolean | 强制HadoopIndexTask使用version | 否(默认为false)| +| `logParseExceptions` | Boolean | 如果为true,则在发生解析异常时记录错误消息,其中包含有关发生错误的行的信息。| 否(默认为false)| +| `maxParseExceptions` | Integer | 任务停止接收并失败之前可能发生的最大分析异常数。如果设置了`reportParseExceptions`,则该配置被覆盖。 | 否(默认为unlimited)| +| `useYarnRMJobStatusFallback` | Boolean | 如果索引任务创建的Hadoop作业无法从JobHistory服务器检索其完成状态,并且此参数为true,则索引任务将尝试从 `http:///ws/v1/cluster/apps/` 获取应用程序状态,其中 `` 是Hadoop配置中 `yarn.resourcemanager.webapp.address` 的地址。此标志用于索引任务的作业成功但JobHistory服务器不可用的情况下的回退,从而导致索引任务失败,因为它无法确定作业状态。 | 否(默认为true)| + +##### `jobProperties` + +```json + "tuningConfig" : { + "type": "hadoop", + "jobProperties": { + "": "", + "": "" + } + } +``` +Hadoop的 [MapReduce文档](https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml) 列出来了所有可能的配置参数。 + +在一些Hadoop分布式环境中,可能需要设置 `mapreduce.job.classpath` 或者 `mapreduce.job.user.classpath.first` 来避免类加载相关的问题。 更多详细信息可以参见 [使用不同Hadoop版本的文档](../operations/other-hadoop.md) + +#### `partitionsSpec` + +段总是基于时间戳进行分区(根据 `granularitySpec`),并且可以根据分区类型以其他方式进一步分区。Druid支持两种类型的分区策略:`hashed`(基于每行中所有维度的hash)和 `single_dim`(基于单个维度的范围)。 + +在大多数情况下,建议使用哈希分区,因为相对于单一维度分区,哈希分区将提高索引性能并创建更统一大小的数据段。 + +##### 基于哈希的分区 + +```json + "partitionsSpec": { + "type": "hashed", + "targetRowsPerSegment": 5000000 + } +``` + +哈希分区的工作原理是首先选择多个段,然后根据每一行中所有维度的哈希对这些段中的行进行分区。段的数量是根据输入集的基数和目标分区大小自动确定的。 + +配置项为: + +| 字段 | 描述 | 是否必须 | +|-|-|-| +| `type` | 使用的partitionsSpec的类型 | "hashed" | +| `targetRowsPerSegment` | 要包含在分区中的目标行数,应为500MB~1GB段的数。如果未设置 `numShards` ,则默认为5000000。 | 为该配置或者 `numShards` | +| `targetPartitionSize` | 已弃用。重命名为`targetRowsPerSegment`。要包含在分区中的目标行数,应为500MB~1GB段的数。 | 为该配置或者 `numShards` | +| `maxRowsPerSegment` | 已弃用。重命名为`targetRowsPerSegment`。要包含在分区中的目标行数,应为500MB~1GB段的数。 | 为该配置或者 `numShards` | 为该配置或者 `numShards` | +| `numShards` | 直接指定分区数,而不是目标分区大小。摄取将运行得更快,因为它可以跳过自动选择多个分区所需的步骤。| 为该配置或者 `maxRowsPerSegment` | +| `partitionDimensions` | 要划分的维度。留空可选择所有维度。仅与`numShard` 一起使用,在设置 `targetRowsPerSegment` 时将被忽略。| 否 | + + +##### 单一维度范围分区 + +```json + "partitionsSpec": { + "type": "single_dim", + "targetRowsPerSegment": 5000000 + } +``` + +单一维度范围分区的工作原理是首先选择要分区的维度,然后将该维度分隔成连续的范围,每个段将包含该维度值在该范围内的所有行。例如,可以在维度"host"上对段进行分区,范围为"a.example.com"到"f.example.com"和"f.example.com"到"z.example.com"。 默认情况下,将自动确定要使用的维度,但可以使用特定维度替代它。 + +配置项为: + +| 字段 | 描述 | 是否必须 | +|-|-|-| +| `type` | 使用的partitionsSpec的类型 | "single_dim" | +| `targetRowsPerSegment` | 要包含在分区中的目标行数,应为500MB~1GB段的数。 | 是 | +| `targetPartitionSize` | 已弃用。重命名为`targetRowsPerSegment`。要包含在分区中的目标行数,应为500MB~1GB段的数。 | 否 | +| `maxRowsPerSegment` | 要包含在分区中的最大行数。默认值为比`targetRowsPerSegment` 大50%。 | 否 | +| `maxPartitionSize` | 已弃用。请改用 `maxRowsPerSegment`。要包含在分区中的最大行数, 默认为比 `targetPartitionSize` 大50%。 | 否 | +| `partitionDimension` | 要分区的维度。留空可自动选择维度。 | 否 | +| `assumeGrouped` | 假设输入数据已经按时间和维度分组。摄取将运行得更快,但如果违反此假设,则可能会选择次优分区。 | 否 | + +### 远程Hadoop集群 + +如果已经有了一个远程的Hadoop集群,确保在Druid的 `_common` 配置目录中包含 `*.xml` 文件。 + +如果Hadoop与Druid的版本存在依赖等问题,请查看 [这些文档](../operations/other-hadoop.md) + +### Elastic MapReduce + +如果集群运行在AWS上,可以使用Elastic MapReduce(EMR)来从S3中索引数据。需要以下几步: + +* 创建一个 [持续运行的集群](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-longrunning-transient.html) +* 创建集群时,请输入以下配置。如果使用向导,则应在"编辑软件设置"下处于高级模式: + +```json +classification=yarn-site,properties=[mapreduce.reduce.memory.mb=6144,mapreduce.reduce.java.opts=-server -Xms2g -Xmx2g -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,mapreduce.map.java.opts=758,mapreduce.map.java.opts=-server -Xms512m -Xmx512m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,mapreduce.task.timeout=1800000] +``` +* 按照 [Hadoop连接配置](../tutorials/img/chapter-4.md#Hadoop连接配置) 指导,使用EMR master中 `/etc/hadoop/conf` 的XML文件。 + +### Kerberized Hadoop集群 + +默认情况下,druid可以使用本地kerberos密钥缓存中现有的TGT kerberos票证。虽然TGT票证的生命周期有限,但您需要定期调用 `kinit` 命令以确保TGT票证的有效性。为了避免这个额外的外部cron作业脚本周期性地调用 `kinit`,您可以提供主体名称和keytab位置,druid将在启动和作业启动时透明地执行身份验证。 + +| 属性 | 可能的值 | +|-|-| +| `druid.hadoop.security.kerberos.principal` | `druid@EXAMPLE.COM` | +| `druid.hadoop.security.kerberos.keytab` | `/etc/security/keytabs/druid.headlessUser.keytab` | + +#### 从具有EMR的S3加载 + +* 在Hadoop索引任务中 `tuningConfig` 部分的 `jobProperties` 字段中添加一下内容: + +```json +"jobProperties" : { + "fs.s3.awsAccessKeyId" : "YOUR_ACCESS_KEY", + "fs.s3.awsSecretAccessKey" : "YOUR_SECRET_KEY", + "fs.s3.impl" : "org.apache.hadoop.fs.s3native.NativeS3FileSystem", + "fs.s3n.awsAccessKeyId" : "YOUR_ACCESS_KEY", + "fs.s3n.awsSecretAccessKey" : "YOUR_SECRET_KEY", + "fs.s3n.impl" : "org.apache.hadoop.fs.s3native.NativeS3FileSystem", + "io.compression.codecs" : "org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.SnappyCodec" +} +``` +注意,此方法使用Hadoop的内置S3文件系统,而不是Amazon的EMRFS,并且与Amazon的特定功能(如S3加密和一致视图)不兼容。如果您需要使用这些特性,那么您将需要通过 [其他Hadoop发行版](#使用其他的Hadoop) 一节中描述的机制之一,使Amazon EMR Hadoop JARs对Druid可用。 + +### 使用其他的Hadoop + +Druid在许多Hadoop发行版中都是开箱即用的。 + +如果Druid与您当前使用的Hadoop版本发生依赖冲突时,您可以尝试在 [Druid用户组](https://groups.google.com/forum/#!forum/druid-user) 中搜索解决方案, 或者阅读 [Druid不同版本Hadoop文档](../operations/other-hadoop.md) + +### 命令行版本 + +运行: + +```json +java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath lib/*: org.apache.druid.cli.Main index hadoop +``` +#### 可选项 + +* "--coordinate" - 提供要使用的Apache Hadoop版本。此属性将覆盖默认的Hadoop。一旦指定,Apache Druid将从 `druid.extensions.hadoopDependenciesDir` 位置寻找Hadoop依赖。 +* "--no-default-hadoop" - 不要下拉默认的hadoop版本 + +#### 规范文件 + +spec文件需要包含一个JSON对象,其中的内容与Hadoop索引任务中的"spec"字段相同。有关规范格式的详细信息,请参见 [Hadoop批处理摄取](hadoop.md)。 + +另外, `metadataUpdateSpec` 和 `segmentOutputPath` 字段需要被添加到ioConfig中: +```json + "ioConfig" : { + ... + "metadataUpdateSpec" : { + "type":"mysql", + "connectURI" : "jdbc:mysql://localhost:3306/druid", + "password" : "druid", + "segmentTable" : "druid_segments", + "user" : "druid" + }, + "segmentOutputPath" : "/MyDirectory/data/index/output" + }, +``` +同时, `workingPath` 字段需要被添加到tuningConfig: +```json + "tuningConfig" : { + ... + "workingPath": "/tmp", + ... + } +``` +**Metadata Update Job Spec** + +这是一个属性规范,告诉作业如何更新元数据,以便Druid集群能够看到输出段并加载它们。 + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `type` | String | "metadata"是唯一可用的值 | 是 | +| `connectURI` | String | 连接元数据存储的可用的JDBC | 是 | +| `user` | String | DB的用户名 | 是 | +| `password` | String | DB的密码 | 是 | +| `segmentTable` | String | DB中使用的表 | 是 | + +这些属性应该模仿您为 [Coordinator](../design/Coordinator.md) 配置的内容。 + +**segmentOutputPath配置** + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `segmentOutputPath` | String | 将段转储到的路径 | 是 | + +**workingPath配置** + +| 字段 | 类型 | 描述 | 是否必须 | +|-|-|-|-| +| `workingPath` | String | 用于中间结果(Hadoop作业之间的结果)的工作路径。 | 否(默认为 `/tmp/druid-indexing` )| + +请注意,命令行Hadoop indexer不具备索引服务的锁定功能,因此如果选择使用它,则必须注意不要覆盖由实时处理创建的段(如果设置了实时管道)。 \ No newline at end of file diff --git a/ingestion/index.md b/ingestion/index.md new file mode 100644 index 0000000..02be4e7 --- /dev/null +++ b/ingestion/index.md @@ -0,0 +1,1251 @@ +# 数据导入 + +All data in Druid is organized into _segments_, which are data files each of which may have up to a few million rows. +Loading data in Druid is called _ingestion_ or _indexing_, and consists of reading data from a source system and creating +segments based on that data. + +In most ingestion methods, the Druid [MiddleManager](../design/middlemanager.md) processes +(or the [Indexer](../design/indexer.md) processes) load your source data. One exception is +Hadoop-based ingestion, where this work is instead done using a Hadoop MapReduce job on YARN (although MiddleManager or Indexer +processes are still involved in starting and monitoring the Hadoop jobs). + +Once segments have been generated and stored in [deep storage](../dependencies/deep-storage.md), they are loaded by Historical processes. +For more details on how this works, see the [Storage design](../design/architecture.md#storage-design) section +of Druid's design documentation. + +## How to use this documentation + +This **page you are currently reading** provides information about universal Druid ingestion concepts, and about +configurations that are common to all [ingestion methods](#ingestion-methods). + +The **individual pages for each ingestion method** provide additional information about concepts and configurations +that are unique to each ingestion method. + +We recommend reading (or at least skimming) this universal page first, and then referring to the page for the +ingestion method or methods that you have chosen. + +## Ingestion methods + +The table below lists Druid's most common data ingestion methods, along with comparisons to help you choose +the best one for your situation. Each ingestion method supports its own set of source systems to pull from. For details +about how each method works, as well as configuration properties specific to that method, check out its documentation +page. + +### Streaming + +The most recommended, and most popular, method of streaming ingestion is the +[Kafka indexing service](../development/extensions-core/kafka-ingestion.md) that reads directly from Kafka. Alternatively, the Kinesis +indexing service works with Amazon Kinesis Data Streams. + +This table compares the options: + +| **Method** | [Kafka](../development/extensions-core/kafka-ingestion.md) | [Kinesis](../development/extensions-core/kinesis-ingestion.md) | +|---|-----|--------------| +| **Supervisor type** | `kafka` | `kinesis`| +| **How it works** | Druid reads directly from Apache Kafka. | Druid reads directly from Amazon Kinesis.| +| **Can ingest late data?** | Yes | Yes | +| **Exactly-once guarantees?** | Yes | Yes | + +### Batch + +When doing batch loads from files, you should use one-time [tasks](tasks.md), and you have three options: `index_parallel` (native batch; parallel), `index_hadoop` (Hadoop-based), +or `index` (native batch; single-task). + +In general, we recommend native batch whenever it meets your needs, since the setup is simpler (it does not depend on +an external Hadoop cluster). However, there are still scenarios where Hadoop-based batch ingestion might be a better choice, +for example when you already have a running Hadoop cluster and want to +use the cluster resource of the existing cluster for batch ingestion. + +This table compares the three available options: + +| **Method** | [Native batch (parallel)](native-batch.md#parallel-task) | [Hadoop-based](hadoop.md) | [Native batch (simple)](native-batch.md#simple-task) | +|---|-----|--------------|------------| +| **Task type** | `index_parallel` | `index_hadoop` | `index` | +| **Parallel?** | Yes, if `inputFormat` is splittable and `maxNumConcurrentSubTasks` > 1 in `tuningConfig`. See [data format documentation](./data-formats.md) for details. | Yes, always. | No. Each task is single-threaded. | +| **Can append or overwrite?** | Yes, both. | Overwrite only. | Yes, both. | +| **External dependencies** | None. | Hadoop cluster (Druid submits Map/Reduce jobs). | None. | +| **Input locations** | Any [`inputSource`](./native-batch.md#input-sources). | Any Hadoop FileSystem or Druid datasource. | Any [`inputSource`](./native-batch.md#input-sources). | +| **File formats** | Any [`inputFormat`](./data-formats.md#input-format). | Any Hadoop InputFormat. | Any [`inputFormat`](./data-formats.md#input-format). | +| **[Rollup modes](#rollup)** | Perfect if `forceGuaranteedRollup` = true in the [`tuningConfig`](native-batch.md#tuningconfig). | Always perfect. | Perfect if `forceGuaranteedRollup` = true in the [`tuningConfig`](native-batch.md#tuningconfig). | +| **Partitioning options** | Dynamic, hash-based, and range-based partitioning methods are available. See [Partitions Spec](./native-batch.md#partitionsspec) for details. | Hash-based or range-based partitioning via [`partitionsSpec`](hadoop.md#partitionsspec). | Dynamic and hash-based partitioning methods are available. See [Partitions Spec](./native-batch.md#partitionsspec-1) for details. | + + + +## Druid's data model + +### Datasources + +Druid data is stored in datasources, which are similar to tables in a traditional RDBMS. Druid +offers a unique data modeling system that bears similarity to both relational and timeseries models. + +### Primary timestamp + +Druid schemas must always include a primary timestamp. The primary timestamp is used for +[partitioning and sorting](#partitioning) your data. Druid queries are able to rapidly identify and retrieve data +corresponding to time ranges of the primary timestamp column. Druid is also able to use the primary timestamp column +for time-based [data management operations](data-management.md) such as dropping time chunks, overwriting time chunks, +and time-based retention rules. + +The primary timestamp is parsed based on the [`timestampSpec`](#timestampspec). In addition, the +[`granularitySpec`](#granularityspec) controls other important operations that are based on the primary timestamp. +Regardless of which input field the primary timestamp is read from, it will always be stored as a column named `__time` +in your Druid datasource. + +If you have more than one timestamp column, you can store the others as +[secondary timestamps](schema-design.md#secondary-timestamps). + +### Dimensions + +Dimensions are columns that are stored as-is and can be used for any purpose. You can group, filter, or apply +aggregators to dimensions at query time in an ad-hoc manner. If you run with [rollup](#rollup) disabled, then the set of +dimensions is simply treated like a set of columns to ingest, and behaves exactly as you would expect from a typical +database that does not support a rollup feature. + +Dimensions are configured through the [`dimensionsSpec`](#dimensionsspec). + +### Metrics + +Metrics are columns that are stored in an aggregated form. They are most useful when [rollup](#rollup) is enabled. +Specifying a metric allows you to choose an aggregation function for Druid to apply to each row during ingestion. This +has two benefits: + +1. If [rollup](#rollup) is enabled, multiple rows can be collapsed into one row even while retaining summary + information. In the [rollup tutorial](../tutorials/tutorial-rollup.md), this is used to collapse netflow data to a + single row per `(minute, srcIP, dstIP)` tuple, while retaining aggregate information about total packet and byte counts. +2. Some aggregators, especially approximate ones, can be computed faster at query time even on non-rolled-up data if + they are partially computed at ingestion time. + +Metrics are configured through the [`metricsSpec`](#metricsspec). + +## Rollup + +### What is rollup? + +Druid can roll up data as it is ingested to minimize the amount of raw data that needs to be stored. Rollup is +a form of summarization or pre-aggregation. In practice, rolling up data can dramatically reduce the size of data that +needs to be stored, reducing row counts by potentially orders of magnitude. This storage reduction does come at a cost: +as we roll up data, we lose the ability to query individual events. + +When rollup is disabled, Druid loads each row as-is without doing any form of pre-aggregation. This mode is similar +to what you would expect from a typical database that does not support a rollup feature. + +When rollup is enabled, then any rows that have identical [dimensions](#dimensions) and [timestamp](#primary-timestamp) +to each other (after [`queryGranularity`-based truncation](#granularityspec)) can be collapsed, or _rolled up_, into a +single row in Druid. + +By default, rollup is enabled. + +### Enabling or disabling rollup + +Rollup is controlled by the `rollup` setting in the [`granularitySpec`](#granularityspec). By default, it is `true` +(enabled). Set this to `false` if you want Druid to store each record as-is, without any rollup summarization. + +### Example of rollup + +For an example of how to configure rollup, and of how the feature will modify your data, check out the +[rollup tutorial](../tutorials/tutorial-rollup.md). + +### Maximizing rollup ratio + +You can measure the rollup ratio of a datasource by comparing the number of rows in Druid (`COUNT`) with the number of ingested +events. One way to do this is with a +[Druid SQL](../querying/sql.md) query such as the following, where "count" refers to a `count`-type metric generated at ingestion time: + +```sql +SELECT SUM("count") / (COUNT(*) * 1.0) +FROM datasource +``` + +The higher this number is, the more benefit you are gaining from rollup. + +> See [Counting the number of ingested events](schema-design.md#counting) on the "Schema design" page for more details about +how counting works when rollup is enabled. + +Tips for maximizing rollup: + +- Generally, the fewer dimensions you have, and the lower the cardinality of your dimensions, the better rollup ratios + you will achieve. +- Use [sketches](schema-design.md#sketches) to avoid storing high cardinality dimensions, which harm rollup ratios. +- Adjusting `queryGranularity` at ingestion time (for example, using `PT5M` instead of `PT1M`) increases the + likelihood of two rows in Druid having matching timestamps, and can improve your rollup ratios. +- It can be beneficial to load the same data into more than one Druid datasource. Some users choose to create a "full" + datasource that has rollup disabled (or enabled, but with a minimal rollup ratio) and an "abbreviated" datasource that + has fewer dimensions and a higher rollup ratio. When queries only involve dimensions in the "abbreviated" set, using + that datasource leads to much faster query times. This can often be done with just a small increase in storage + footprint, since abbreviated datasources tend to be substantially smaller. +- If you are using a [best-effort rollup](#perfect-rollup-vs-best-effort-rollup) ingestion configuration that does not guarantee perfect + rollup, you can potentially improve your rollup ratio by switching to a guaranteed perfect rollup option, or by + [reindexing](data-management.md#reingesting-data) or [compacting](compaction.md) your data in the background after initial ingestion. + +### Perfect rollup vs Best-effort rollup + +Some Druid ingestion methods guarantee _perfect rollup_, meaning that input data are perfectly aggregated at ingestion +time. Others offer _best-effort rollup_, meaning that input data might not be perfectly aggregated and thus there could +be multiple segments holding rows with the same timestamp and dimension values. + +In general, ingestion methods that offer best-effort rollup do this because they are either parallelizing ingestion +without a shuffling step (which would be required for perfect rollup), or because they are finalizing and publishing +segments before all data for a time chunk has been received, which we call _incremental publishing_. In both of these +cases, records that could theoretically be rolled up may end up in different segments. All types of streaming ingestion +run in this mode. + +Ingestion methods that guarantee perfect rollup do it with an additional preprocessing step to determine intervals +and partitioning before the actual data ingestion stage. This preprocessing step scans the entire input dataset, which +generally increases the time required for ingestion, but provides information necessary for perfect rollup. + +The following table shows how each method handles rollup: + +|Method|How it works| +|------|------------| +|[Native batch](native-batch.md)|`index_parallel` and `index` type may be either perfect or best-effort, based on configuration.| +|[Hadoop](hadoop.md)|Always perfect.| +|[Kafka indexing service](../development/extensions-core/kafka-ingestion.md)|Always best-effort.| +|[Kinesis indexing service](../development/extensions-core/kinesis-ingestion.md)|Always best-effort.| + +## Partitioning + +### Why partition? + +Optimal partitioning and sorting of segments within your datasources can have substantial impact on footprint and +performance. + +Druid datasources are always partitioned by time into _time chunks_, and each time chunk contains one or more segments. +This partitioning happens for all ingestion methods, and is based on the `segmentGranularity` parameter of your +ingestion spec's `dataSchema`. + +The segments within a particular time chunk may also be partitioned further, using options that vary based on the +ingestion type you have chosen. In general, doing this secondary partitioning using a particular dimension will +improve locality, meaning that rows with the same value for that dimension are stored together and can be accessed +quickly. + +You will usually get the best performance and smallest overall footprint by partitioning your data on some "natural" +dimension that you often filter by, if one exists. This will often improve compression - users have reported threefold +storage size decreases - and it also tends to improve query performance as well. + +> Partitioning and sorting are best friends! If you do have a "natural" partitioning dimension, you should also consider +> placing it first in the `dimensions` list of your `dimensionsSpec`, which tells Druid to sort rows within each segment +> by that column. This will often improve compression even more, beyond the improvement gained by partitioning alone. +> +> However, note that currently, Druid always sorts rows within a segment by timestamp first, even before the first +> dimension listed in your `dimensionsSpec`. This can prevent dimension sorting from being maximally effective. If +> necessary, you can work around this limitation by setting `queryGranularity` equal to `segmentGranularity` in your +> [`granularitySpec`](#granularityspec), which will set all timestamps within the segment to the same value, and by saving +> your "real" timestamp as a [secondary timestamp](schema-design.md#secondary-timestamps). This limitation may be removed +> in a future version of Druid. + +### How to set up partitioning + +Not all ingestion methods support an explicit partitioning configuration, and not all have equivalent levels of +flexibility. As of current Druid versions, If you are doing initial ingestion through a less-flexible method (like +Kafka) then you can use [reindexing](data-management.md#reingesting-data) or [compaction](compaction.md) to repartition your data after it +is initially ingested. This is a powerful technique: you can use it to ensure that any data older than a certain +threshold is optimally partitioned, even as you continuously add new data from a stream. + +The following table shows how each ingestion method handles partitioning: + +|Method|How it works| +|------|------------| +|[Native batch](native-batch.md)|Configured using [`partitionsSpec`](native-batch.md#partitionsspec) inside the `tuningConfig`.| +|[Hadoop](hadoop.md)|Configured using [`partitionsSpec`](hadoop.md#partitionsspec) inside the `tuningConfig`.| +|[Kafka indexing service](../development/extensions-core/kafka-ingestion.md)|Partitioning in Druid is guided by how your Kafka topic is partitioned. You can also [reindex](data-management.md#reingesting-data) or [compact](compaction.md) to repartition after initial ingestion.| +|[Kinesis indexing service](../development/extensions-core/kinesis-ingestion.md)|Partitioning in Druid is guided by how your Kinesis stream is sharded. You can also [reindex](data-management.md#reingesting-data) or [compact](compaction.md) to repartition after initial ingestion.| + +> Note that, of course, one way to partition data is to load it into separate datasources. This is a perfectly viable +> approach and works very well when the number of datasources does not lead to excessive per-datasource overheads. If +> you go with this approach, then you can ignore this section, since it is describing how to set up partitioning +> _within a single datasource_. +> +> For more details on splitting data up into separate datasources, and potential operational considerations, refer +> to the [Multitenancy considerations](../querying/multitenancy.md) page. + + + +## Ingestion specs + +No matter what ingestion method you use, data is loaded into Druid using either one-time [tasks](tasks.md) or +ongoing "supervisors" (which run and supervise a set of tasks over time). In any case, part of the task or supervisor +definition is an _ingestion spec_. + +Ingestion specs consists of three main components: + +- [`dataSchema`](#dataschema), which configures the [datasource name](#datasource), + [primary timestamp](#timestampspec), [dimensions](#dimensionsspec), [metrics](#metricsspec), and [transforms and filters](#transformspec) (if needed). +- [`ioConfig`](#ioconfig), which tells Druid how to connect to the source system and how to parse data. For more information, see the + documentation for each [ingestion method](#ingestion-methods). +- [`tuningConfig`](#tuningconfig), which controls various tuning parameters specific to each + [ingestion method](#ingestion-methods). + +Example ingestion spec for task type `index_parallel` (native batch): + +``` +{ + "type": "index_parallel", + "spec": { + "dataSchema": { + "dataSource": "wikipedia", + "timestampSpec": { + "column": "timestamp", + "format": "auto" + }, + "dimensionsSpec": { + "dimensions": [ + "page", + "language", + { "type": "long", "name": "userId" } + ] + }, + "metricsSpec": [ + { "type": "count", "name": "count" }, + { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, + { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } + ], + "granularitySpec": { + "segmentGranularity": "day", + "queryGranularity": "none", + "intervals": [ + "2013-08-31/2013-09-01" + ] + } + }, + "ioConfig": { + "type": "index_parallel", + "inputSource": { + "type": "local", + "baseDir": "examples/indexing/", + "filter": "wikipedia_data.json" + }, + "inputFormat": { + "type": "json", + "flattenSpec": { + "useFieldDiscovery": true, + "fields": [ + { "type": "path", "name": "userId", "expr": "$.user.id" } + ] + } + } + }, + "tuningConfig": { + "type": "index_parallel" + } + } +} +``` + +The specific options supported by these sections will depend on the [ingestion method](#ingestion-methods) you have chosen. +For more examples, refer to the documentation for each ingestion method. + +You can also load data visually, without the need to write an ingestion spec, using the "Load data" functionality +available in Druid's [web console](../operations/druid-console.md). Druid's visual data loader supports +[Kafka](../development/extensions-core/kafka-ingestion.md), +[Kinesis](../development/extensions-core/kinesis-ingestion.md), and +[native batch](native-batch.md) mode. + +## `dataSchema` + +> The `dataSchema` spec has been changed in 0.17.0. The new spec is supported by all ingestion methods +except for _Hadoop_ ingestion. See the [Legacy `dataSchema` spec](#legacy-dataschema-spec) for the old spec. + +The `dataSchema` is a holder for the following components: + +- [datasource name](#datasource), [primary timestamp](#timestampspec), + [dimensions](#dimensionsspec), [metrics](#metricsspec), and + [transforms and filters](#transformspec) (if needed). + +An example `dataSchema` is: + +``` +"dataSchema": { + "dataSource": "wikipedia", + "timestampSpec": { + "column": "timestamp", + "format": "auto" + }, + "dimensionsSpec": { + "dimensions": [ + "page", + "language", + { "type": "long", "name": "userId" } + ] + }, + "metricsSpec": [ + { "type": "count", "name": "count" }, + { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, + { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } + ], + "granularitySpec": { + "segmentGranularity": "day", + "queryGranularity": "none", + "intervals": [ + "2013-08-31/2013-09-01" + ] + } +} +``` + +### `dataSource` + +The `dataSource` is located in `dataSchema` → `dataSource` and is simply the name of the +[datasource](../design/architecture.md#datasources-and-segments) that data will be written to. An example +`dataSource` is: + +``` +"dataSource": "my-first-datasource" +``` + +### `timestampSpec` + +The `timestampSpec` is located in `dataSchema` → `timestampSpec` and is responsible for +configuring the [primary timestamp](#primary-timestamp). An example `timestampSpec` is: + +``` +"timestampSpec": { + "column": "timestamp", + "format": "auto" +} +``` + +> Conceptually, after input data records are read, Druid applies ingestion spec components in a particular order: +> first [`flattenSpec`](data-formats.md#flattenspec) (if any), then [`timestampSpec`](#timestampspec), then [`transformSpec`](#transformspec), +> and finally [`dimensionsSpec`](#dimensionsspec) and [`metricsSpec`](#metricsspec). Keep this in mind when writing +> your ingestion spec. + +A `timestampSpec` can have the following components: + +|Field|Description|Default| +|-----|-----------|-------| +|column|Input row field to read the primary timestamp from.

Regardless of the name of this input field, the primary timestamp will always be stored as a column named `__time` in your Druid datasource.|timestamp| +|format|Timestamp format. Options are:
  • `iso`: ISO8601 with 'T' separator, like "2000-01-01T01:02:03.456"
  • `posix`: seconds since epoch
  • `millis`: milliseconds since epoch
  • `micro`: microseconds since epoch
  • `nano`: nanoseconds since epoch
  • `auto`: automatically detects ISO (either 'T' or space separator) or millis format
  • any [Joda DateTimeFormat string](http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html)
|auto| +|missingValue|Timestamp to use for input records that have a null or missing timestamp `column`. Should be in ISO8601 format, like `"2000-01-01T01:02:03.456"`, even if you have specified something else for `format`. Since Druid requires a primary timestamp, this setting can be useful for ingesting datasets that do not have any per-record timestamps at all. |none| + +### `dimensionsSpec` + +The `dimensionsSpec` is located in `dataSchema` → `dimensionsSpec` and is responsible for +configuring [dimensions](#dimensions). An example `dimensionsSpec` is: + +``` +"dimensionsSpec" : { + "dimensions": [ + "page", + "language", + { "type": "long", "name": "userId" } + ], + "dimensionExclusions" : [], + "spatialDimensions" : [] +} +``` + +> Conceptually, after input data records are read, Druid applies ingestion spec components in a particular order: +> first [`flattenSpec`](data-formats.md#flattenspec) (if any), then [`timestampSpec`](#timestampspec), then [`transformSpec`](#transformspec), +> and finally [`dimensionsSpec`](#dimensionsspec) and [`metricsSpec`](#metricsspec). Keep this in mind when writing +> your ingestion spec. + +A `dimensionsSpec` can have the following components: + +| Field | Description | Default | +|-------|-------------|---------| +| dimensions | A list of [dimension names or objects](#dimension-objects). Cannot have the same column in both `dimensions` and `dimensionExclusions`.

If this and `spatialDimensions` are both null or empty arrays, Druid will treat all non-timestamp, non-metric columns that do not appear in `dimensionExclusions` as String-typed dimension columns. See [inclusions and exclusions](#inclusions-and-exclusions) below for details. | `[]` | +| dimensionExclusions | The names of dimensions to exclude from ingestion. Only names are supported here, not objects.

This list is only used if the `dimensions` and `spatialDimensions` lists are both null or empty arrays; otherwise it is ignored. See [inclusions and exclusions](#inclusions-and-exclusions) below for details. | `[]` | +| spatialDimensions | An array of [spatial dimensions](../development/geo.md). | `[]` | + +#### Dimension objects + +Each dimension in the `dimensions` list can either be a name or an object. Providing a name is equivalent to providing +a `string` type dimension object with the given name, e.g. `"page"` is equivalent to `{"name": "page", "type": "string"}`. + +Dimension objects can have the following components: + +| Field | Description | Default | +|-------|-------------|---------| +| type | Either `string`, `long`, `float`, or `double`. | `string` | +| name | The name of the dimension. This will be used as the field name to read from input records, as well as the column name stored in generated segments.

Note that you can use a [`transformSpec`](#transformspec) if you want to rename columns during ingestion time. | none (required) | +| createBitmapIndex | For `string` typed dimensions, whether or not bitmap indexes should be created for the column in generated segments. Creating a bitmap index requires more storage, but speeds up certain kinds of filtering (especially equality and prefix filtering). Only supported for `string` typed dimensions. | `true` | +| multiValueHandling | Specify the type of handling for [multi-value fields](../querying/multi-value-dimensions.md). Possible values are `sorted_array`, `sorted_set`, and `array`. `sorted_array` and `sorted_set` order the array upon ingestion. `sorted_set` removes duplicates. `array` ingests data as-is | `sorted_array` | + +#### Inclusions and exclusions + +Druid will interpret a `dimensionsSpec` in two possible ways: _normal_ or _schemaless_. + +Normal interpretation occurs when either `dimensions` or `spatialDimensions` is non-empty. In this case, the combination of the two lists will be taken as the set of dimensions to be ingested, and the list of `dimensionExclusions` will be ignored. + +Schemaless interpretation occurs when both `dimensions` and `spatialDimensions` are empty or null. In this case, the set of dimensions is determined in the following way: + +1. First, start from the set of all root-level fields from the input record, as determined by the [`inputFormat`](./data-formats.md). "Root-level" includes all fields at the top level of a data structure, but does not included fields nested within maps or lists. To extract these, you must use a [`flattenSpec`](./data-formats.md#flattenspec). All fields of non-nested data formats, such as CSV and delimited text, are considered root-level. +2. If a [`flattenSpec`](./data-formats.md#flattenspec) is being used, the set of root-level fields includes any fields generated by the flattenSpec. The useFieldDiscovery parameter determines whether the original root-level fields will be retained or discarded. +3. Any field listed in `dimensionExclusions` is excluded. +4. The field listed as `column` in the [`timestampSpec`](#timestampspec) is excluded. +5. Any field used as an input to an aggregator from the [metricsSpec](#metricsspec) is excluded. +6. Any field with the same name as an aggregator from the [metricsSpec](#metricsspec) is excluded. +7. All other fields are ingested as `string` typed dimensions with the [default settings](#dimension-objects). + +> Note: Fields generated by a [`transformSpec`](#transformspec) are not currently considered candidates for +> schemaless dimension interpretation. + +### `metricsSpec` + +The `metricsSpec` is located in `dataSchema` → `metricsSpec` and is a list of [aggregators](../querying/aggregations.md) +to apply at ingestion time. This is most useful when [rollup](#rollup) is enabled, since it's how you configure +ingestion-time aggregation. + +An example `metricsSpec` is: + +``` +"metricsSpec": [ + { "type": "count", "name": "count" }, + { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, + { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } +] +``` + +> Generally, when [rollup](#rollup) is disabled, you should have an empty `metricsSpec` (because without rollup, +> Druid does not do any ingestion-time aggregation, so there is little reason to include an ingestion-time aggregator). However, +> in some cases, it can still make sense to define metrics: for example, if you want to create a complex column as a way of +> pre-computing part of an [approximate aggregation](../querying/aggregations.md#approximate-aggregations), this can only +> be done by defining a metric in a `metricsSpec`. + +### `granularitySpec` + +The `granularitySpec` is located in `dataSchema` → `granularitySpec` and is responsible for configuring +the following operations: + +1. Partitioning a datasource into [time chunks](../design/architecture.md#datasources-and-segments) (via `segmentGranularity`). +2. Truncating the timestamp, if desired (via `queryGranularity`). +3. Specifying which time chunks of segments should be created, for batch ingestion (via `intervals`). +4. Specifying whether ingestion-time [rollup](#rollup) should be used or not (via `rollup`). + +Other than `rollup`, these operations are all based on the [primary timestamp](#primary-timestamp). + +An example `granularitySpec` is: + +``` +"granularitySpec": { + "segmentGranularity": "day", + "queryGranularity": "none", + "intervals": [ + "2013-08-31/2013-09-01" + ], + "rollup": true +} +``` + +A `granularitySpec` can have the following components: + +| Field | Description | Default | +|-------|-------------|---------| +| type | Either `uniform` or `arbitrary`. In most cases you want to use `uniform`.| `uniform` | +| segmentGranularity | [Time chunking](../design/architecture.md#datasources-and-segments) granularity for this datasource. Multiple segments can be created per time chunk. For example, when set to `day`, the events of the same day fall into the same time chunk which can be optionally further partitioned into multiple segments based on other configurations and input size. Any [granularity](../querying/granularities.md) can be provided here. Note that all segments in the same time chunk should have the same segment granularity.

Ignored if `type` is set to `arbitrary`.| `day` | +| queryGranularity | The resolution of timestamp storage within each segment. This must be equal to, or finer, than `segmentGranularity`. This will be the finest granularity that you can query at and still receive sensible results, but note that you can still query at anything coarser than this granularity. E.g., a value of `minute` will mean that records will be stored at minutely granularity, and can be sensibly queried at any multiple of minutes (including minutely, 5-minutely, hourly, etc).

Any [granularity](../querying/granularities.md) can be provided here. Use `none` to store timestamps as-is, without any truncation. Note that `rollup` will be applied if it is set even when the `queryGranularity` is set to `none`. | `none` | +| rollup | Whether to use ingestion-time [rollup](#rollup) or not. Note that rollup is still effective even when `queryGranularity` is set to `none`. Your data will be rolled up if they have the exactly same timestamp. | `true` | +| intervals | A list of intervals describing what time chunks of segments should be created. If `type` is set to `uniform`, this list will be broken up and rounded-off based on the `segmentGranularity`. If `type` is set to `arbitrary`, this list will be used as-is.

If `null` or not provided, batch ingestion tasks will generally determine which time chunks to output based on what timestamps are found in the input data.

If specified, batch ingestion tasks may be able to skip a determining-partitions phase, which can result in faster ingestion. Batch ingestion tasks may also be able to request all their locks up-front instead of one by one. Batch ingestion tasks will throw away any records with timestamps outside of the specified intervals.

Ignored for any form of streaming ingestion. | `null` | + +### `transformSpec` + +The `transformSpec` is located in `dataSchema` → `transformSpec` and is responsible for transforming and filtering +records during ingestion time. It is optional. An example `transformSpec` is: + +``` +"transformSpec": { + "transforms": [ + { "type": "expression", "name": "countryUpper", "expression": "upper(country)" } + ], + "filter": { + "type": "selector", + "dimension": "country", + "value": "San Serriffe" + } +} +``` + +> Conceptually, after input data records are read, Druid applies ingestion spec components in a particular order: +> first [`flattenSpec`](data-formats.md#flattenspec) (if any), then [`timestampSpec`](#timestampspec), then [`transformSpec`](#transformspec), +> and finally [`dimensionsSpec`](#dimensionsspec) and [`metricsSpec`](#metricsspec). Keep this in mind when writing +> your ingestion spec. + +#### Transforms + +The `transforms` list allows you to specify a set of expressions to evaluate on top of input data. Each transform has a +"name" which can be referred to by your `dimensionsSpec`, `metricsSpec`, etc. + +If a transform has the same name as a field in an input row, then it will shadow the original field. Transforms that +shadow fields may still refer to the fields they shadow. This can be used to transform a field "in-place". + +Transforms do have some limitations. They can only refer to fields present in the actual input rows; in particular, +they cannot refer to other transforms. And they cannot remove fields, only add them. However, they can shadow a field +with another field containing all nulls, which will act similarly to removing the field. + +Transforms can refer to the [timestamp](#timestampspec) of an input row by referring to `__time` as part of the expression. +They can also _replace_ the timestamp if you set their "name" to `__time`. In both cases, `__time` should be treated as +a millisecond timestamp (number of milliseconds since Jan 1, 1970 at midnight UTC). Transforms are applied _after_ the +`timestampSpec`. + +Druid currently includes one kind of built-in transform, the expression transform. It has the following syntax: + +``` +{ + "type": "expression", + "name": "", + "expression": "" +} +``` + +The `expression` is a [Druid query expression](../misc/math-expr.md). + +> Conceptually, after input data records are read, Druid applies ingestion spec components in a particular order: +> first [`flattenSpec`](data-formats.md#flattenspec) (if any), then [`timestampSpec`](#timestampspec), then [`transformSpec`](#transformspec), +> and finally [`dimensionsSpec`](#dimensionsspec) and [`metricsSpec`](#metricsspec). Keep this in mind when writing +> your ingestion spec. + +#### Filter + +The `filter` conditionally filters input rows during ingestion. Only rows that pass the filter will be +ingested. Any of Druid's standard [query filters](../querying/filters.md) can be used. Note that within a +`transformSpec`, the `transforms` are applied before the `filter`, so the filter can refer to a transform. + +### Legacy `dataSchema` spec + +> The `dataSchema` spec has been changed in 0.17.0. The new spec is supported by all ingestion methods +except for _Hadoop_ ingestion. See [`dataSchema`](#dataschema) for the new spec. + +The legacy `dataSchema` spec has below two more components in addition to the ones listed in the [`dataSchema`](#dataschema) section above. + +- [input row parser](#parser-deprecated), [flattening of nested data](#flattenspec) (if needed) + +#### `parser` (Deprecated) + +In legacy `dataSchema`, the `parser` is located in the `dataSchema` → `parser` and is responsible for configuring a wide variety of +items related to parsing input records. The `parser` is deprecated and it is highly recommended to use `inputFormat` instead. +For details about `inputFormat` and supported `parser` types, see the ["Data formats" page](data-formats.md). + +For details about major components of the `parseSpec`, refer to their subsections: + +- [`timestampSpec`](#timestampspec), responsible for configuring the [primary timestamp](#primary-timestamp). +- [`dimensionsSpec`](#dimensionsspec), responsible for configuring [dimensions](#dimensions). +- [`flattenSpec`](#flattenspec), responsible for flattening nested data formats. + +An example `parser` is: + +``` +"parser": { + "type": "string", + "parseSpec": { + "format": "json", + "flattenSpec": { + "useFieldDiscovery": true, + "fields": [ + { "type": "path", "name": "userId", "expr": "$.user.id" } + ] + }, + "timestampSpec": { + "column": "timestamp", + "format": "auto" + }, + "dimensionsSpec": { + "dimensions": [ + "page", + "language", + { "type": "long", "name": "userId" } + ] + } + } +} +``` + +#### `flattenSpec` + +In the legacy `dataSchema`, the `flattenSpec` is located in `dataSchema` → `parser` → `parseSpec` → `flattenSpec` and is responsible for +bridging the gap between potentially nested input data (such as JSON, Avro, etc) and Druid's flat data model. +See [Flatten spec](./data-formats.md#flattenspec) for more details. + +## `ioConfig` + +The `ioConfig` influences how data is read from a source system, such as Apache Kafka, Amazon S3, a mounted +filesystem, or any other supported source system. The `inputFormat` property applies to all +[ingestion method](#ingestion-methods) except for Hadoop ingestion. The Hadoop ingestion still +uses the [`parser`](#parser-deprecated) in the legacy `dataSchema`. +The rest of `ioConfig` is specific to each individual ingestion method. +An example `ioConfig` to read JSON data is: + +```json +"ioConfig": { + "type": "", + "inputFormat": { + "type": "json" + }, + ... +} +``` +For more details, see the documentation provided by each [ingestion method](#ingestion-methods). + +## `tuningConfig` + +Tuning properties are specified in a `tuningConfig`, which goes at the top level of an ingestion spec. Some +properties apply to all [ingestion methods](#ingestion-methods), but most are specific to each individual +ingestion method. An example `tuningConfig` that sets all of the shared, common properties to their defaults +is: + +```plaintext +"tuningConfig": { + "type": "", + "maxRowsInMemory": 1000000, + "maxBytesInMemory": , + "indexSpec": { + "bitmap": { "type": "roaring" }, + "dimensionCompression": "lz4", + "metricCompression": "lz4", + "longEncoding": "longs" + }, + +} +``` + +|Field|Description|Default| +|-----|-----------|-------| +|type|Each ingestion method has its own tuning type code. You must specify the type code that matches your ingestion method. Common options are `index`, `hadoop`, `kafka`, and `kinesis`.|| +|maxRowsInMemory|The maximum number of records to store in memory before persisting to disk. Note that this is the number of rows post-rollup, and so it may not be equal to the number of input records. Ingested records will be persisted to disk when either `maxRowsInMemory` or `maxBytesInMemory` are reached (whichever happens first).|`1000000`| +|maxBytesInMemory|The maximum aggregate size of records, in bytes, to store in the JVM heap before persisting. This is based on a rough estimate of memory usage. Ingested records will be persisted to disk when either `maxRowsInMemory` or `maxBytesInMemory` are reached (whichever happens first). `maxBytesInMemory` also includes heap usage of artifacts created from intermediary persists. This means that after every persist, the amount of `maxBytesInMemory` until next persist will decreases, and task will fail when the sum of bytes of all intermediary persisted artifacts exceeds `maxBytesInMemory`.

Setting maxBytesInMemory to -1 disables this check, meaning Druid will rely entirely on maxRowsInMemory to control memory usage. Setting it to zero means the default value will be used (one-sixth of JVM heap size).

Note that the estimate of memory usage is designed to be an overestimate, and can be especially high when using complex ingest-time aggregators, including sketches. If this causes your indexing workloads to persist to disk too often, you can set maxBytesInMemory to -1 and rely on maxRowsInMemory instead.|One-sixth of max JVM heap size| +|skipBytesInMemoryOverheadCheck|The calculation of maxBytesInMemory takes into account overhead objects created during ingestion and each intermediate persist. Setting this to true can exclude the bytes of these overhead objects from maxBytesInMemory check.|false| +|indexSpec|Tune how data is indexed. See below for more information.|See table below| +|Other properties|Each ingestion method has its own list of additional tuning properties. See the documentation for each method for a full list: [Kafka indexing service](../development/extensions-core/kafka-ingestion.md#tuningconfig), [Kinesis indexing service](../development/extensions-core/kinesis-ingestion.md#tuningconfig), [Native batch](native-batch.md#tuningconfig), and [Hadoop-based](hadoop.md#tuningconfig).|| + +#### `indexSpec` + +The `indexSpec` object can include the following properties: + +|Field|Description|Default| +|-----|-----------|-------| +|bitmap|Compression format for bitmap indexes. Should be a JSON object with `type` set to `roaring` or `concise`. For type `roaring`, the boolean property `compressRunOnSerialization` (defaults to true) controls whether or not run-length encoding will be used when it is determined to be more space-efficient.|`{"type": "concise"}`| +|dimensionCompression|Compression format for dimension columns. Options are `lz4`, `lzf`, or `uncompressed`.|`lz4`| +|metricCompression|Compression format for primitive type metric columns. Options are `lz4`, `lzf`, `uncompressed`, or `none` (which is more efficient than `uncompressed`, but not supported by older versions of Druid).|`lz4`| +|longEncoding|Encoding format for long-typed columns. Applies regardless of whether they are dimensions or metrics. Options are `auto` or `longs`. `auto` encodes the values using offset or lookup table depending on column cardinality, and store them with variable size. `longs` stores the value as-is with 8 bytes each.|`longs`| + +Beyond these properties, each ingestion method has its own specific tuning properties. See the documentation for each +[ingestion method](#ingestion-methods) for details. + + +## 数据摄入 +### 综述 + +Druid中的所有数据都被组织成*段*,这些段是数据文件,通常每个段最多有几百万行。在Druid中加载数据称为*摄取或索引*,它包括从源系统读取数据并基于该数据创建段。 + +在大多数摄取方法中,加载数据的工作由Druid [MiddleManager](../design/MiddleManager.md) 进程(或 [Indexer](../design/Indexer.md) 进程)完成。一个例外是基于Hadoop的摄取,这项工作是使用Hadoop MapReduce作业在YARN上完成的(尽管MiddleManager或Indexer进程仍然参与启动和监视Hadoop作业)。一旦段被生成并存储在 [深层存储](../design/Deepstorage.md) 中,它们将被Historical进程加载。有关如何在引擎下工作的更多细节,请参阅Druid设计文档的[存储设计](../design/Design.md) 部分。 + +### 如何使用本文档 + +您**当前正在阅读的这个页面**提供了通用Druid摄取概念的信息,以及 [所有摄取方法](#摄入方式) **通用的配置**信息。 + +**每个摄取方法的单独页面**提供了有关每个摄取方法**独有的概念和配置**的附加信息。 + +我们建议您先阅读(或至少略读)这个通用页面,然后参考您选择的一种或多种摄取方法的页面。 + +### 摄入方式 + +下表列出了Druid最常用的数据摄取方法,帮助您根据自己的情况选择最佳方法。每个摄取方法都支持自己的一组源系统。有关每个方法如何工作的详细信息以及特定于该方法的配置属性,请查看其文档页。 + +#### 流式摄取 +最推荐、也是最流行的流式摄取方法是直接从Kafka读取数据的 [Kafka索引服务](kafka.md) 。如果你喜欢Kinesis,[Kinesis索引服务](kinesis.md) 也能很好地工作。 + +下表比较了主要可用选项: + +| **Method** | [**Kafka**](kafka.md) | [**Kinesis**](kinesis.md) | [**Tranquility**](tranquility.md) | +| - | - | - | - | +| **Supervisor类型** | `kafka` | `kinesis` | `N/A` | +| 如何工作 | Druid直接从 Apache Kafka读取数据 | Druid直接从Amazon Kinesis中读取数据 | Tranquility, 一个独立于Druid的库,用来将数据推送到Druid | +| 可以摄入迟到的数据 | Yes | Yes | No(迟到的数据将会被基于 `windowPeriod` 的配置丢弃掉) | +| 保证不重不丢(Exactly-once)| Yes | Yes | No + +#### 批量摄取 + +从文件进行批加载时,应使用一次性 [任务](taskrefer.md),并且有三个选项:`index_parallel`(本地并行批任务)、`index_hadoop`(基于hadoop)或`index`(本地简单批任务)。 + +一般来说,如果本地批处理能满足您的需要时我们建议使用它,因为设置更简单(它不依赖于外部Hadoop集群)。但是,仍有一些情况下,基于Hadoop的批摄取可能是更好的选择,例如,当您已经有一个正在运行的Hadoop集群,并且希望使用现有集群的集群资源进行批摄取时。 + +此表比较了三个可用选项: + +| **方式** | [**本地批任务(并行)**](native.md#并行任务) | [**基于Hadoop**](hadoop.md) | [**本地批任务(简单)**](native.md#简单任务) | +| - | - | - | - | +| **任务类型** | `index_parallel` | `index_hadoop` | `index` | +| **并行?** | 如果 `inputFormat` 是可分割的且 `tuningConfig` 中的 `maxNumConcurrentSubTasks` > 1, 则 **Yes** | Yes | No,每个任务都是单线程的 | +| **支持追加或者覆盖** | 都支持 | 只支持覆盖 | 都支持 | +| **外部依赖** | 无 | Hadoop集群,用来提交Map-Reduce任务 | 无 | +| **输入位置** | 任何 [输入数据源](native.md#输入数据源) | 任何Hadoop文件系统或者Druid数据源 | 任何 [输入数据源](native.md#输入数据源) | +| **文件格式** | 任何 [输入格式](dataformats.md) | 任何Hadoop输入格式 | 任何 [输入格式](dataformats.md) | +| [**Rollup modes**](#Rollup) | 如果 `tuningConfig` 中的 `forceGuaranteedRollup` = true, 则为 **Perfect(最佳rollup)** | 总是Perfect(最佳rollup) | 如果 `tuningConfig` 中的 `forceGuaranteedRollup` = true, 则为 **Perfect(最佳rollup)** | +| **分区选项** | 可选的有`Dynamic`, `hash-based` 和 `range-based` 三种分区方式,详情参见 [分区规范](native.md#partitionsSpec) | 通过 [partitionsSpec](hadoop.md#partitionsSpec)中指定 `hash-based` 和 `range-based`分区 | 可选的有`Dynamic`和`hash-based`二种分区方式,详情参见 [分区规范](native.md#partitionsSpec) | + +### Druid数据模型 +#### 数据源 +Druid数据存储在数据源中,与传统RDBMS中的表类似。Druid提供了一个独特的数据建模系统,它与关系模型和时间序列模型都具有相似性。 +#### 主时间戳列 +Druid Schema必须始终包含一个主时间戳。主时间戳用于对 [数据进行分区和排序](#分区)。Druid查询能够快速识别和检索与主时间戳列的时间范围相对应的数据。Druid还可以将主时间戳列用于基于时间的[数据管理操作](datamanage.md),例如删除时间块、覆盖时间块和基于时间的保留规则。 + +主时间戳基于 [`timestampSpec`](#timestampSpec) 进行解析。此外,[`granularitySpec`](#granularitySpec) 控制基于主时间戳的其他重要操作。无论从哪个输入字段读取主时间戳,它都将作为名为 `__time` 的列存储在Druid数据源中。 + +如果有多个时间戳列,则可以将其他列存储为 [辅助时间戳](schemadesign.md#辅助时间戳)。 + +#### 维度 +维度是按原样存储的列,可以用于任何目的, 可以在查询时以特殊方式对维度进行分组、筛选或应用聚合器。如果在禁用了 [rollup](#Rollup) 的情况下运行,那么该维度集将被简单地视为要摄取的一组列,并且其行为与不支持rollup功能的典型数据库的预期完全相同。 + +通过 [`dimensionSpec`](#dimensionSpec) 配置维度。 + +#### 指标 +Metrics是以聚合形式存储的列。启用 [rollup](#Rollup) 时,它们最有用。指定一个Metric允许您为Druid选择一个聚合函数,以便在摄取期间应用于每一行。这有两个好处: + +1. 如果启用了 [rollup](#Rollup),即使保留摘要信息,也可以将多行折叠为一行。在 [Rollup教程](../tutorials/chapter-5.md) 中,这用于将netflow数据折叠为每(`minute`,`srcIP`,`dstIP`)元组一行,同时保留有关总数据包和字节计数的聚合信息。 +2. 一些聚合器,特别是近似聚合器,即使在非汇总数据上,如果在接收时部分计算,也可以在查询时更快地计算它们。 + +Metrics是通过 [`metricsSpec`](#metricsSpec) 配置的。 + +### Rollup +#### 什么是rollup +Druid可以在接收过程中将数据进行汇总,以最小化需要存储的原始数据量。Rollup是一种汇总或预聚合的形式。实际上,Rollup可以极大地减少需要存储的数据的大小,从而潜在地减少行数的数量级。这种存储量的减少是有代价的:当我们汇总数据时,我们就失去了查询单个事件的能力。 + +禁用rollup时,Druid将按原样加载每一行,而不进行任何形式的预聚合。此模式类似于您对不支持汇总功能的典型数据库的期望。 + +如果启用了rollup,那么任何具有相同[维度](#维度)和[时间戳](#主时间戳列)的行(在基于 `queryGranularity` 的截断之后)都可以在Druid中折叠或汇总为一行。 + +rollup默认是启用状态。 + +#### 启用或者禁用rollup + +Rollup由 `granularitySpec` 中的 `rollup` 配置项控制。 默认情况下,值为 `true`(启用状态)。如果你想让Druid按原样存储每条记录,而不需要任何汇总,将该值设置为 `false`。 + +#### rollup示例 +有关如何配置Rollup以及该特性将如何修改数据的示例,请参阅[Rollup教程](../tutorials/chapter-5.md)。 + +#### 最大化rollup比率 +通过比较Druid中的行数和接收的事件数,可以测量数据源的汇总率。这个数字越高,从汇总中获得的好处就越多。一种方法是使用[Druid SQL](../querying/druidsql.md)查询,比如: +```json +SELECT SUM("cnt") / COUNT(*) * 1.0 FROM datasource +``` + +在这个查询中,`cnt` 应该引用在摄取时指定的"count"类型Metrics。有关启用汇总时计数工作方式的详细信息,请参阅"架构设计"页上的 [计数接收事件数](/schemadesign.md#计数接收事件数)。 + +最大化Rollup的提示: +* 一般来说,拥有的维度越少,维度的基数越低,您将获得更好的汇总比率 +* 使用 [Sketches](schemadesign.md#Sketches高基维处理) 避免存储高基数维度,因为会损害汇总比率 +* 在摄入时调整 `queryGranularity`(例如,使用 `PT5M` 而不是 `PT1M` )会增加Druid中两行具有匹配时间戳的可能性,并可以提高汇总率 +* 将相同的数据加载到多个Druid数据源中是有益的。有些用户选择创建禁用汇总(或启用汇总,但汇总比率最小)的"完整"数据源和具有较少维度和较高汇总比率的"缩写"数据源。当查询只涉及"缩写"集里边的维度时,使用该数据源将导致更快的查询时间,这种方案只需稍微增加存储空间即可完成,因为简化的数据源往往要小得多。 +* 如果您使用的 [尽力而为的汇总(best-effort rollup)](#) 摄取配置不能保证[完全汇总(perfect rollup)](#),则可以通过切换到保证的完全汇总选项,或在初始摄取后在[后台重新编制(reindex)](./datamanage.md#压缩与重新索引)数据索引,潜在地提高汇总比率。 + +#### 最佳rollup VS 尽可能rollup +一些Druid摄取方法保证了*完美的汇总(perfect rollup)*,这意味着输入数据在摄取时被完美地聚合。另一些则提供了*尽力而为的汇总(best-effort rollup)*,这意味着输入数据可能无法完全聚合,因此可能有多个段保存具有相同时间戳和维度值的行。 + +一般来说,提供*尽力而为的汇总(best-effort rollup)*的摄取方法之所以这样做,是因为它们要么是在没有清洗步骤(这是*完美的汇总(perfect rollup)*所必需的)的情况下并行摄取,要么是因为它们在接收到某个时间段的所有数据(我们称之为*增量发布(incremental publishing)*)之前完成并发布段。在这两种情况下,理论上可以汇总的记录可能会以不同的段结束。所有类型的流接收都在此模式下运行。 + +保证*完美的汇总(perfect rollup)*的摄取方法通过额外的预处理步骤来确定实际数据摄取阶段之前的间隔和分区。此预处理步骤扫描整个输入数据集,这通常会增加摄取所需的时间,但提供完美汇总所需的信息。 + +下表显示了每个方法如何处理汇总: +| **方法** | **如何工作** | +| - | - | +| [本地批](native.md) | 基于配置,`index_parallel` 和 `index` 可以是完美的,也可以是最佳的。 | +| [Hadoop批](hadoop.md) | 总是 perfect | +| [Kafka索引服务](kafka.md) | 总是 best-effort | +| [Kinesis索引服务](kinesis.md) | 总是 best-effort | + +### 分区 +#### 为什么分区 + +数据源中段的最佳分区和排序会对占用空间和性能产生重大影响 +。 +Druid数据源总是按时间划分为*时间块*,每个时间块包含一个或多个段。此分区适用于所有摄取方法,并基于摄取规范的 `dataSchema` 中的 `segmentGranularity`参数。 + +特定时间块内的段也可以进一步分区,使用的选项根据您选择的摄取类型而不同。一般来说,使用特定维度执行此辅助分区将改善局部性,这意味着具有该维度相同值的行存储在一起,并且可以快速访问。 + +通常,通过将数据分区到一些常用来做过滤操作的维度(如果存在的话)上,可以获得最佳性能和最小的总体占用空间。而且,这种分区通常会改善压缩性能而且还往往会提高查询性能(用户报告存储容量减少了三倍)。 + +> [!WARNING] +> 分区和排序是最好的朋友!如果您确实有一个天然的分区维度,那么您还应该考虑将它放在 `dimensionsSpec` 的 `dimension` 列表中的第一个维度,它告诉Druid按照该列对每个段中的行进行排序。除了单独分区所获得的改进之外,这通常还会进一步改进压缩。 +> 但是,请注意,目前,Druid总是首先按时间戳对一个段内的行进行排序,甚至在 `dimensionsSpec` 中列出的第一个维度之前,这将使得维度排序达不到最大效率。如果需要,可以通过在 `granularitySpec` 中将 `queryGranularity` 设置为等于 `segmentGranularity` 的值来解决此限制,这将把段内的所有时间戳设置为相同的值,并将"真实"时间戳保存为[辅助时间戳](./schemadesign.md#辅助时间戳)。这个限制可能在Druid的未来版本中被移除。 + +#### 如何设置分区 +并不是所有的摄入方式都支持显式的分区配置,也不是所有的方法都具有同样的灵活性。在当前的Druid版本中,如果您是通过一个不太灵活的方法(如Kafka)进行初始摄取,那么您可以使用 [重新索引的技术(reindex)](./datamanage.md#压缩与重新索引),在最初摄取数据后对其重新分区。这是一种强大的技术:即使您不断地从流中添加新数据, 也可以使用它来确保任何早于某个阈值的数据都得到最佳分区。 + +下表显示了每个摄取方法如何处理分区: + +| **方法** | **如何工作** | +| - | - | +| [本地批](native.md) | 通过 `tuningConfig` 中的 [`partitionsSpec`](./native.md#partitionsSpec) | +| [Hadoop批](hadoop.md) | 通过 `tuningConfig` 中的 [`partitionsSpec`](./native.md#partitionsSpec) | +| [Kafka索引服务](kafka.md) | Druid中的分区是由Kafka主题的分区方式决定的。您可以在初次摄入后 [重新索引的技术(reindex)](./datamanage.md#压缩与重新索引)以重新分区 | +| [Kinesis索引服务](kinesis.md) | Druid中的分区是由Kinesis流的分区方式决定的。您可以在初次摄入后 [重新索引的技术(reindex)](./datamanage.md#压缩与重新索引)以重新分区 | + +> [!WARNING] +> +> 注意,当然,划分数据的一种方法是将其加载到分开的数据源中。这是一种完全可行的方法,当数据源的数量不会导致每个数据源的开销过大时,它可以很好地工作。如果使用这种方法,那么可以忽略这一部分,因为这部分描述了如何在单个数据源中设置分区。 +> +> 有关将数据拆分为单独数据源的详细信息以及潜在的操作注意事项,请参阅 [多租户注意事项](../querying/multitenancy.md)。 + +### 摄入规范 + +无论使用哪一种摄入方式,数据要么是通过一次性[tasks](taskrefer.md)或者通过持续性的"supervisor"(运行并监控一段时间内的一系列任务)来被加载到Druid中。 在任一种情况下,task或者supervisor的定义都在*摄入规范*中定义。 + +摄入规范包括以下三个主要的部分: +* [`dataSchema`](#dataschema), 包含了 [`数据源名称`](#datasource), [`主时间戳列`](#timestampspec), [`维度`](#dimensionspec), [`指标`](#metricsspec) 和 [`转换与过滤`](#transformspec) +* [`ioConfig`](#ioconfig), 该部分告诉Druid如何去连接数据源系统以及如何去解析数据。 更多详细信息,可以看[摄入方法](#摄入方式)的文档。 +* [`tuningConfig`](#tuningconfig), 该部分控制着每一种[摄入方法](#摄入方式)的不同的特定调整参数 + +一个 `index_parallel` 类型任务的示例摄入规范如下: +```json +{ + "type": "index_parallel", + "spec": { + "dataSchema": { + "dataSource": "wikipedia", + "timestampSpec": { + "column": "timestamp", + "format": "auto" + }, + "dimensionsSpec": { + "dimensions": [ + { "type": "string", "page" }, + { "type": "string", "language" }, + { "type": "long", "name": "userId" } + ] + }, + "metricsSpec": [ + { "type": "count", "name": "count" }, + { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, + { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } + ], + "granularitySpec": { + "segmentGranularity": "day", + "queryGranularity": "none", + "intervals": [ + "2013-08-31/2013-09-01" + ] + } + }, + "ioConfig": { + "type": "index_parallel", + "inputSource": { + "type": "local", + "baseDir": "examples/indexing/", + "filter": "wikipedia_data.json" + }, + "inputFormat": { + "type": "json", + "flattenSpec": { + "useFieldDiscovery": true, + "fields": [ + { "type": "path", "name": "userId", "expr": "$.user.id" } + ] + } + } + }, + "tuningConfig": { + "type": "index_parallel" + } + } +} +``` + +该部分中支持的特定选项依赖于选择的[摄入方法](#摄入方式)。 更多的示例,可以参考每一种[摄入方法](#摄入方式)的文档。 + +您还可以不用编写一个摄入规范,可视化的加载数据,该功能位于 [Druid控制台](../operations/manageui.md) 的 "Load Data" 视图中。 Druid可视化数据加载器目前支持 [Kafka](kafka.md), [Kinesis](kinesis.md) 和 [本地批](native.md) 模式。 + +#### `dataSchema` +> [!WARNING] +> +> `dataSchema` 规范在0.17.0版本中做了更改,新的规范支持除*Hadoop摄取方式*外的所有方式。 可以在 [过时的 `dataSchema` 规范]()查看老的规范 + +`dataSchema` 包含了以下部分: +* [`数据源名称`](#datasource), [`主时间戳列`](#timestampspec), [`维度`](#dimensionspec), [`指标`](#metricsspec) 和 [`转换与过滤`](#transformspec) + +一个 `dataSchema` 如下: +```json +"dataSchema": { + "dataSource": "wikipedia", + "timestampSpec": { + "column": "timestamp", + "format": "auto" + }, + "dimensionsSpec": { + "dimensions": [ + { "type": "string", "page" }, + { "type": "string", "language" }, + { "type": "long", "name": "userId" } + ] + }, + "metricsSpec": [ + { "type": "count", "name": "count" }, + { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, + { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } + ], + "granularitySpec": { + "segmentGranularity": "day", + "queryGranularity": "none", + "intervals": [ + "2013-08-31/2013-09-01" + ] + } +} +``` + +##### `dataSource` +`dataSource` 位于 `dataSchema` -> `dataSource` 中,简单的标识了数据将被写入的数据源的名称,示例如下: +```json +"dataSource": "my-first-datasource" +``` +##### `timestampSpec` +`timestampSpec` 位于 `dataSchema` -> `timestampSpec` 中,用来配置 [主时间戳](#timestampspec), 示例如下: +```json +"timestampSpec": { + "column": "timestamp", + "format": "auto" +} +``` +> [!WARNING] +> 概念上,输入数据被读取后,Druid会以一个特定的顺序来对数据应用摄入规范: 首先 `flattenSpec`(如果有),然后 `timestampSpec`, 然后 `transformSpec` ,最后是 `dimensionsSpec` 和 `metricsSpec`。在编写摄入规范时需要牢记这一点 + +`timestampSpec` 可以包含以下的部分: + + + + + + + + + + + + + + + + + + + + + + + + +
字段描述默认值
column要从中读取主时间戳的输入行字段。

不管这个输入字段的名称是什么,主时间戳总是作为一个名为"__time"的列存储在您的Druid数据源中
timestamp
format + 时间戳格式,可选项有: +
    +
  • iso: 使用"T"分割的ISO8601,像"2000-01-01T01:02:03.456"
  • +
  • posix: 自纪元以来的秒数
  • +
  • millis: 自纪元以来的毫秒数
  • +
  • micro: 自纪元以来的微秒数
  • +
  • nano: 自纪元以来的纳秒数
  • +
  • auto: 自动检测ISO或者毫秒格式
  • +
  • 任何 Joda DateTimeFormat字符串
  • +
+
auto
missingValue用于具有空或缺少时间戳列的输入记录的时间戳。应该是ISO8601格式,如"2000-01-01T01:02:03.456"。由于Druid需要一个主时间戳,因此此设置对于接收根本没有任何时间戳的数据集非常有用。none
+ +##### `dimensionSpec` +`dimensionsSpec` 位于 `dataSchema` -> `dimensionsSpec`, 用来配置维度。示例如下: +```json +"dimensionsSpec" : { + "dimensions": [ + "page", + "language", + { "type": "long", "name": "userId" } + ], + "dimensionExclusions" : [], + "spatialDimensions" : [] +} +``` + +> [!WARNING] +> 概念上,输入数据被读取后,Druid会以一个特定的顺序来对数据应用摄入规范: 首先 `flattenSpec`(如果有),然后 `timestampSpec`, 然后 `transformSpec` ,最后是 `dimensionsSpec` 和 `metricsSpec`。在编写摄入规范时需要牢记这一点 + +`dimensionsSpec` 可以包括以下部分: + +| 字段 | 描述 | 默认值 | +|-|-|-| +| dimensions | 维度名称或者对象的列表,在 `dimensions` 和 `dimensionExclusions` 中不能包含相同的列。

如果该配置为一个空数组,Druid将会把所有未出现在 `dimensionExclusions` 中的非时间、非指标列当做字符串类型的维度列,参见[Inclusions and exclusions](#Inclusions-and-exclusions)。 | `[]` | +| dimensionExclusions | 在摄取中需要排除的列名称,在该配置中只支持名称,不支持对象。在 `dimensions` 和 `dimensionExclusions` 中不能包含相同的列。 | `[]` | +| spatialDimensions | 一个[空间维度](../querying/spatialfilter.md)的数组 | `[]` | + +###### `Dimension objects` +在 `dimensions` 列的每一个维度可以是一个名称,也可以是一个对象。 提供一个名称等价于提供了一个给定名称的 `string` 类型的维度对象。例如: `page` 等价于 `{"name": "page", "type": "string"}`。 + +维度对象可以有以下的部分: + +| 字段 | 描述 | 默认值 | +|-|-|-| +| type | `string`, `long`, `float` 或者 `double` | `string` | +| name | 维度名称,将用作从输入记录中读取的字段名,以及存储在生成的段中的列名。

注意: 如果想在摄取的时候重新命名列,可以使用 [`transformSpec`](#transformspec) | none(必填)| +| createBitmapIndex | 对于字符串类型的维度,是否应为生成的段中的列创建位图索引。创建位图索引需要更多存储空间,但会加快某些类型的筛选(特别是相等和前缀筛选)。仅支持字符串类型的维度。| `true` | + +###### `Inclusions and exclusions` +Druid以两种可能的方式来解释 `dimensionsSpec` : *normal* 和 *schemaless* + +当 `dimensions` 或者 `spatialDimensions` 为非空时, 将会采用正常的解释方式。 在该情况下, 前边说的两个列表结合起来的集合当做摄入的维度集合。 + +当 `dimensions` 和 `spatialDimensions` 同时为空或者null时候,将会采用无模式的解释方式。 在该情况下,维度集合由以下方式决定: +1. 首先,从 [`inputFormat`](./dataformats.md) (或者 [`flattenSpec`](./dataformats.md#FlattenSpec), 如果正在使用 )中所有输入字段集合开始 +2. 排除掉任何在 `dimensionExclusions` 中的列 +3. 排除掉在 [`timestampSpec`](#timestampspec) 中的时间列 +4. 排除掉 [`metricsSpec`](#metricsspec) 中用于聚合器输入的列 +5. 排除掉 [`metricsSpec`](#metricsspec) 中任何与聚合器同名的列 +6. 所有的其他字段都被按照[默认配置](#dimensionspec)摄入为 `string` 类型的维度 + +> [!WARNING] +> 注意:在无模式的维度解释方式中,由 [`transformSpec`](#transformspec) 生成的列当前并未考虑。 + +##### `metricsSpec` + +`metricsSpec` 位于 `dataSchema` -> `metricsSpec` 中,是一个在摄入阶段要应用的 [聚合器](../querying/Aggregations.md) 列表。 在启用了 [rollup](#rollup) 时是很有用的,因为它将配置如何在摄入阶段进行聚合。 + +一个 `metricsSpec` 实例如下: +```json +"metricsSpec": [ + { "type": "count", "name": "count" }, + { "type": "doubleSum", "name": "bytes_added_sum", "fieldName": "bytes_added" }, + { "type": "doubleSum", "name": "bytes_deleted_sum", "fieldName": "bytes_deleted" } +] +``` +> [!WARNING] +> 通常,当 [rollup](#rollup) 被禁用时,应该有一个空的 `metricsSpec`(因为没有rollup,Druid不会在摄取时进行任何的聚合,所以没有理由包含摄取时聚合器)。但是,在某些情况下,定义Metrics仍然是有意义的:例如,如果要创建一个复杂的列作为 [近似聚合](../querying/Aggregations.md#近似聚合) 的预计算部分,则只能通过在 `metricsSpec` 中定义度量来实现 + +##### `granularitySpec` + +`granularitySpec` 位于 `dataSchema` -> `granularitySpec`, 用来配置以下操作: +1. 通过 `segmentGranularity` 来将数据源分区到 [时间块](../design/Design.md#数据源和段) +2. 如果需要的话,通过 `queryGranularity` 来截断时间戳 +3. 通过 `interval` 来指定批摄取中应创建段的时间块 +4. 通过 `rollup` 来指定是否在摄取时进行汇总 + +除了 `rollup`, 这些操作都是基于 [主时间戳列](#主时间戳列) + +一个 `granularitySpec` 实例如下: +```json +"granularitySpec": { + "segmentGranularity": "day", + "queryGranularity": "none", + "intervals": [ + "2013-08-31/2013-09-01" + ], + "rollup": true +} +``` + +`granularitySpec` 可以有以下的部分: + +| 字段 | 描述 | 默认值 | +|-|-|-| +| type | `uniform` 或者 `arbitrary` ,大多数时候使用 `uniform` | `uniform` | +| segmentGranularity | 数据源的 [时间分块](../design/Design.md#数据源和段) 粒度。每个时间块可以创建多个段, 例如,当设置为 `day` 时,同一天的事件属于同一时间块,该时间块可以根据其他配置和输入大小进一步划分为多个段。这里可以提供任何粒度。请注意,同一时间块中的所有段应具有相同的段粒度。

如果 `type` 字段设置为 `arbitrary` 则忽略 | `day` | +| queryGranularity | 每个段内时间戳存储的分辨率, 必须等于或比 `segmentGranularity` 更细。这将是您可以查询的最细粒度,并且仍然可以查询到合理的结果。但是请注意,您仍然可以在比此粒度更粗的场景进行查询,例如 "`minute`"的值意味着记录将以分钟的粒度存储,并且可以在分钟的任意倍数(包括分钟、5分钟、小时等)进行查询。

这里可以提供任何 [粒度](../querying/AggregationGranularity.md) 。使用 `none` 按原样存储时间戳,而不进行任何截断。请注意,即使将 `queryGranularity` 设置为 `none`,也将应用 `rollup`。 | `none` | +| rollup | 是否在摄取时使用 [rollup](#rollup)。 注意:即使 `queryGranularity` 设置为 `none`,rollup也仍然是有效的,当数据具有相同的时间戳时数据将被汇总 | `true` | +| interval | 描述应该创建段的时间块的间隔列表。如果 `type` 设置为`uniform`,则此列表将根据 `segmentGranularity` 进行拆分和舍入。如果 `type` 设置为 `arbitrary` ,则将按原样使用此列表。

如果该值不提供或者为空值,则批处理摄取任务通常会根据在输入数据中找到的时间戳来确定要输出的时间块。

如果指定,批处理摄取任务可以跳过确定分区阶段,这可能会导致更快的摄取。批量摄取任务也可以预先请求它们的所有锁,而不是逐个请求。批处理摄取任务将丢弃任何时间戳超出指定间隔的记录。

在任何形式的流摄取中忽略该配置。 | `null` | + +##### `transformSpec` +`transformSpec` 位于 `dataSchema` -> `transformSpec`,用来摄取时转换和过滤输入数据。 一个 `transformSpec` 实例如下: +```json +"transformSpec": { + "transforms": [ + { "type": "expression", "name": "countryUpper", "expression": "upper(country)" } + ], + "filter": { + "type": "selector", + "dimension": "country", + "value": "San Serriffe" + } +} +``` + +> [!WARNING] +> 概念上,输入数据被读取后,Druid会以一个特定的顺序来对数据应用摄入规范: 首先 `flattenSpec`(如果有),然后 `timestampSpec`, 然后 `transformSpec` ,最后是 `dimensionsSpec` 和 `metricsSpec`。在编写摄入规范时需要牢记这一点 + +##### 过时的 `dataSchema` 规范 +> [!WARNING] +> +> `dataSchema` 规范在0.17.0版本中做了更改,新的规范支持除*Hadoop摄取方式*外的所有方式。 可以在 [`dataSchema`](#dataschema)查看老的规范 + +除了上面 `dataSchema` 一节中列出的组件之外,过时的 `dataSchema` 规范还有以下两个组件。 +* [input row parser](), [flatten of nested data]() + +**parser**(已废弃) +在过时的 `dataSchema` 中,`parser` 位于 `dataSchema` -> `parser`中,负责配置与解析输入记录相关的各种项。由于 `parser` 已经废弃,不推荐使用,强烈建议改用 `inputFormat`。 对于 `inputFormat` 和支持的 `parser` 类型,可以参见 [数据格式](dataformats.md)。 + +`parseSpec`主要部分的详细,参见他们的子部分: +* [`timestampSpec`](#timestampspec), 配置 [主时间戳列](#主时间戳列) +* [`dimensionsSpec`](#dimensionspec), 配置 [维度](#维度) +* [`flattenSpec`](./dataformats.md#FlattenSpec) + +一个 `parser` 实例如下: + +```json +"parser": { + "type": "string", + "parseSpec": { + "format": "json", + "flattenSpec": { + "useFieldDiscovery": true, + "fields": [ + { "type": "path", "name": "userId", "expr": "$.user.id" } + ] + }, + "timestampSpec": { + "column": "timestamp", + "format": "auto" + }, + "dimensionsSpec": { + "dimensions": [ + { "type": "string", "page" }, + { "type": "string", "language" }, + { "type": "long", "name": "userId" } + ] + } + } +} +``` +**flattenSpec** +在过时的 `dataSchema` 中,`flattenSpec` 位于`dataSchema` -> `parser` -> `parseSpec` -> `flattenSpec`中,负责在潜在的嵌套输入数据(如JSON、Avro等)和Druid的数据模型之间架起桥梁。有关详细信息,请参见 [flattenSpec](./dataformats.md#FlattenSpec) 。 + +#### `ioConfig` + +`ioConfig` 影响从源系统(如Apache Kafka、Amazon S3、挂载的文件系统或任何其他受支持的源系统)读取数据的方式。`inputFormat` 属性适用于除Hadoop摄取之外的[所有摄取方法](#摄入方式)。Hadoop摄取仍然使用过时的 `dataSchema` 中的 [parser]。`ioConfig` 的其余部分特定于每个单独的摄取方法。读取JSON数据的 `ioConfig` 示例如下: +```json +"ioConfig": { + "type": "", + "inputFormat": { + "type": "json" + }, + ... +} +``` +详情可以参见每个 [摄取方式](#摄入方式) 提供的文档。 + +#### `tuningConfig` + +优化属性在 `tuningConfig` 中指定,`tuningConfig` 位于摄取规范的顶层。有些属性适用于所有摄取方法,但大多数属性特定于每个单独的摄取方法。`tuningConfig` 将所有共享的公共属性设置为默认值的示例如下: +```json +"tuningConfig": { + "type": "", + "maxRowsInMemory": 1000000, + "maxBytesInMemory": , + "indexSpec": { + "bitmap": { "type": "concise" }, + "dimensionCompression": "lz4", + "metricCompression": "lz4", + "longEncoding": "longs" + }, + +} +``` + +| 字段 | 描述 | 默认值 | +|-|-|-| +| type | 每一种摄入方式都有自己的类型,必须指定为与摄入方式匹配的类型。通常的选项有 `index`, `hadoop`, `kafka` 和 `kinesis` | | +| maxRowsInMemory | 数据持久化到硬盘前在内存中存储的最大数据条数。 注意,这个数字是汇总后的,所以可能并不等于输入的记录数。 当摄入的数据达到 `maxRowsInMemory` 或者 `maxBytesInMemory` 时数据将被持久化到硬盘。 | `1000000` | +| maxBytesInMemory | 在持久化之前要存储在JVM堆中的数据最大字节数。这是基于对内存使用的粗略估计。当达到 `maxRowsInMemory` 或`maxBytesInMemory` 时(以先发生的为准),摄取的记录将被持久化到磁盘。

将 `maxBytesInMemory` 设置为-1将禁用此检查,这意味着Druid将完全依赖 `maxRowsInMemory` 来控制内存使用。将其设置为零意味着将使用默认值(JVM堆大小的六分之一)。

请注意,内存使用量的估计值被设计为高估值,并且在使用复杂的摄取时聚合器(包括sketches)时可能特别高。如果这导致索引工作负载过于频繁地持久化到磁盘,则可以将 `maxBytesInMemory` 设置为-1并转而依赖 `maxRowsInMemory`。 | JVM堆内存最大值的1/6 | +| indexSpec | 优化数据如何被索引,详情可以看下面的表格 | 看下面的表格 | +| 其他属性 | 每一种摄入方式都有其自己的优化属性。 详情可以查看每一种方法的文档。 [Kafka索引服务](kafka.md), [Kinesis索引服务](kinesis.md), [本地批](native.md) 和 [Hadoop批](hadoop.md) | | + +**`indexSpec`** + +上边表格中的 `indexSpec` 部分可以包含以下属性: + +| 字段 | 描述 | 默认值 | +|-|-|-| +| bitmap | 位图索引的压缩格式。 需要一个 `type` 设置为 `concise` 或者 `roaring` 的JSON对象。对于 `roaring`类型,布尔属性`compressRunOnSerialization`(默认为true)控制在确定运行长度编码更节省空间时是否使用该编码。 | `{"type":"concise"}` | +| dimensionCompression | 维度列的压缩格式。 可选项有 `lz4`, `lzf` 或者 `uncompressed` | `lz4` | +| metricCompression | Metrics列的压缩格式。可选项有 `lz4`, `lzf`, `uncompressed` 或者 `none`(`none` 比 `uncompressed` 更有效,但是在老版本的Druid不支持) | `lz4` | +| longEncoding | long类型列的编码格式。无论它们是维度还是Metrics,都适用,选项是 `auto` 或 `long`。`auto` 根据列基数使用偏移量或查找表对值进行编码,并以可变大小存储它们。`longs` 按原样存储值,每个值8字节。 | `longs` | + +除了这些属性之外,每个摄取方法都有自己的特定调整属性。有关详细信息,请参阅每个 [摄取方法](#摄入方式) 的文档。 \ No newline at end of file diff --git a/DataIngestion/kafka.md b/ingestion/kafka.md similarity index 100% rename from DataIngestion/kafka.md rename to ingestion/kafka.md diff --git a/DataIngestion/native.md b/ingestion/native.md similarity index 100% rename from DataIngestion/native.md rename to ingestion/native.md diff --git a/DataIngestion/schemadesign.md b/ingestion/schemadesign.md similarity index 100% rename from DataIngestion/schemadesign.md rename to ingestion/schemadesign.md diff --git a/DataIngestion/taskrefer.md b/ingestion/taskrefer.md similarity index 99% rename from DataIngestion/taskrefer.md rename to ingestion/taskrefer.md index 51ba4fb..31833f2 100644 --- a/DataIngestion/taskrefer.md +++ b/ingestion/taskrefer.md @@ -293,7 +293,7 @@ http://:/druid/worker/v1/chat//unparse #### `index_hadoop` -参见 [基于Hadoop的摄取](hadoopbased.md) +参见 [基于Hadoop的摄取](hadoop.md) #### `index_kafka` diff --git a/querying/datasource.md b/querying/datasource.md index 0e6091d..4c02e7a 100644 --- a/querying/datasource.md +++ b/querying/datasource.md @@ -1,7 +1,7 @@ ## 数据源 -在Apache Druid中,数据源是被查询的对象。 最常见的数据源类型是一个表数据源,本文档在很多场景中"dataSource"就是指代表数据源,尤其是在 [数据摄取](../DataIngestion/ingestion.md) 部分中,在数据摄取中,总是创建一个表数据源或者往表数据源中写入数据。但是在查询时,有许多种类型的数据源可用。 +在Apache Druid中,数据源是被查询的对象。 最常见的数据源类型是一个表数据源,本文档在很多场景中"dataSource"就是指代表数据源,尤其是在 [数据摄取](../ingestion/ingestion.md) 部分中,在数据摄取中,总是创建一个表数据源或者往表数据源中写入数据。但是在查询时,有许多种类型的数据源可用。 出现在API请求和响应中的"datasource"一般拼写为 `dataSource` ,注意是大写的S。 @@ -36,7 +36,7 @@ SELECT column1, column2 FROM "druid"."dataSourceName" } ``` -表数据源是最常见的类型,该类数据源可以在 [数据摄取](../DataIngestion/ingestion.md) 后获得。它们被分成若干段,分布在集群中,并且并行地进行查询。 +表数据源是最常见的类型,该类数据源可以在 [数据摄取](../ingestion/ingestion.md) 后获得。它们被分成若干段,分布在集群中,并且并行地进行查询。 在 [Druid SQL](druidsql.md) 中,表数据源位于 `druid` schema中。 这是默认schema,表数据源可以被指定为 `druid.dataSourceName` 或者简单的 `dataSourceName` diff --git a/querying/druidsql.md b/querying/druidsql.md index a5e8e5a..b3a6734 100644 --- a/querying/druidsql.md +++ b/querying/druidsql.md @@ -831,13 +831,13 @@ GROUP BY servers.server; **TASKS表** -"TASKS"表提供有关活跃的和最近完成的索引任务的信息。有关更多信息,请查看 [摄取任务的文档](../DataIngestion/taskrefer.md)。 +"TASKS"表提供有关活跃的和最近完成的索引任务的信息。有关更多信息,请查看 [摄取任务的文档](../ingestion/taskrefer.md)。 | 字段 | 类型 | 注意 | |-|-|-| | `task_id` | STRING | 唯一的任务标识符 | | `group_id` | STRING | 本任务的任务组ID,值依赖于任务的 `type`, 例如,对于原生索引任务, 它与 `task_id` 相同,对于子任务,该值为父任务的ID | -| `type` | STRING | 任务类型,例如该值为"index"表示为索引任务。 可以查看 [任务概述](../DataIngestion/taskrefer.md) | +| `type` | STRING | 任务类型,例如该值为"index"表示为索引任务。 可以查看 [任务概述](../ingestion/taskrefer.md) | | `datasource` | STRING | 被索引的数据源名称 | | `created_time` | STRING | ISO8601格式的时间戳,与创建摄取任务的时间相对应。请注意,此值是为已完成和正在等待的任务填充的。对于正在运行和挂起的任务,此值设置为1970-01-01T00:00:00Z | | `queue_insertion_time` | STRING | ISO8601格式的时间戳,与此任务添加到Overlord上的队列时对应 | @@ -863,7 +863,7 @@ SUPERVISORS表提供supervisor的详细信息 | 字段 | 类型 | 注意 | |-|-|-| | `supervisor_id` | STRING | supervisor任务的标识符 | -| `state` | STRING | supervisor的基本状态,可用状态有: `UNHEALTHY_SUPERVISOR`, `UNHEALTHY_TASKS`, `PENDING`, `RUNNING`, `SUSPENDED`, `STOPPING`。详情可以查看 [Kafka摄取文档](../DataIngestion/kafka.md) | +| `state` | STRING | supervisor的基本状态,可用状态有: `UNHEALTHY_SUPERVISOR`, `UNHEALTHY_TASKS`, `PENDING`, `RUNNING`, `SUSPENDED`, `STOPPING`。详情可以查看 [Kafka摄取文档](../ingestion/kafka.md) | | `detailed_state` | STRING | supervisor特定的状态。(详情查看特定的supervisor状态的文档)| | `healthy` | LONG | 布尔值表示为long类型,其中1=true,0=false。1表示supervisor健康 | | `type` | STRING | supervisor的类型,例如 `kafka`, `kinesis` 或者 `materialized_view` | diff --git a/querying/granularity.md b/querying/granularity.md index da5cafc..7b2fcfb 100644 --- a/querying/granularity.md +++ b/querying/granularity.md @@ -162,7 +162,7 @@ } ] ``` -**注意**:当查询时的 `granularity` 小于 [数据摄取](../DataIngestion/ingestion.md) 时候设置的 `queryGranularity`是不合理的,因为在存储的数据中没有更细粒度的数据了。 所以,当查询时设置的粒度小于摄取时设置的粒度时,Druid将基于`granularity`与`queryGranularity`相同的基础上进行生产结果。 +**注意**:当查询时的 `granularity` 小于 [数据摄取](../ingestion/ingestion.md) 时候设置的 `queryGranularity`是不合理的,因为在存储的数据中没有更细粒度的数据了。 所以,当查询时设置的粒度小于摄取时设置的粒度时,Druid将基于`granularity`与`queryGranularity`相同的基础上进行生产结果。 如果查询粒度更改为 `all`,将会在一个bucket中查到所以数据: diff --git a/querying/multitenancy.md b/querying/multitenancy.md index a62cbb3..7847629 100644 --- a/querying/multitenancy.md +++ b/querying/multitenancy.md @@ -36,7 +36,7 @@ Druid中的数据源等价于关系型数据库中的表。 对于多租户场 如果您的多租户集群使用共享数据源,那么您的大多数查询可能会在"tenant_id"维度上过滤。当数据被租户很好地分区时,这类查询的性能最好。有几种方法可以做到这一点。 -使用批处理索引,您可以使用 [单维分区](../DataIngestion/hadoopbased.md#单一维度范围分区) 按租户ID对数据进行分区。Druid总是先按时间进行分区,但每个时间段内的辅助分区将位于租户ID上。 +使用批处理索引,您可以使用 [单维分区](../ingestion/hadoop.md#单一维度范围分区) 按租户ID对数据进行分区。Druid总是先按时间进行分区,但每个时间段内的辅助分区将位于租户ID上。 通过实时索引,你可以通过调整发送给Druid的数据流来实现这一点。例如,如果您使用的是Kafka,那么您可以让Kafka生产者按照租户ID的哈希对您的Topic进行分区。 diff --git a/querying/queryexecution.md b/querying/queryexecution.md index 7c4f2d5..533efc8 100644 --- a/querying/queryexecution.md +++ b/querying/queryexecution.md @@ -24,7 +24,7 @@ Druid的查询执行方法因查询的 [数据源类型](#数据源类型) 而 直接在 [表数据源](datasource.md#table) 上操作的查询使用由Broker进程引导的**分散-聚集**方法执行。过程如下: 1. Broker根据 `"interval"` 参数确定哪些 [段](../design/segments.md) 与查询相关。段总是按时间划分的,因此任何间隔与查询间隔重叠的段都可能是相关的。 -2. 如果输入数据使用 [`single_dim` partitionsSpec](../DataIngestion/native.md#partitionsSpec) 按范围分区,并且过滤器与用于分区的维度匹配,则Broker还可以根据 `"filter"` 进一步修剪段列表。 +2. 如果输入数据使用 [`single_dim` partitionsSpec](../ingestion/native.md#partitionsSpec) 按范围分区,并且过滤器与用于分区的维度匹配,则Broker还可以根据 `"filter"` 进一步修剪段列表。 3. Broker在删除了查询的段列表之后,将查询转发到当前为这些段提供服务的数据服务器(如Historical或者运行在MiddleManagers的任务)。 4. 对于除 [Scan](scan.md) 之外的所有查询类型,数据服务器并行处理每个段,并为每个段生成部分结果。所做的具体处理取决于查询类型。如果启用了 [查询缓存](querycached.md),则可以缓存这些部分结果。对于Scan查询,段由单个线程按顺序处理,结果不被缓存。 5. Broker从每个数据服务器接收部分结果,将它们合并到最终结果集中,并将它们返回给调用方。对于Timeseries和Scan查询,以及没有排序的GroupBy查询,Broker可以以流式方式执行此操作。否则,Broker将在返回任何内容之前完全计算结果集。 diff --git a/tutorials/chapter-8.md b/tutorials/chapter-8.md index e7ff317..e8d4a0e 100644 --- a/tutorials/chapter-8.md +++ b/tutorials/chapter-8.md @@ -147,6 +147,6 @@ Coordinator将旧的输入段标记为未使用需要一段时间,因此您可 ![](img-8/tutorial-compaction-08.png) ### 进一步阅读 -[任务文档](../DataIngestion/taskrefer.md) +[任务文档](../ingestion/taskrefer.md) [段优化](../operations/segmentSizeOpt.md) \ No newline at end of file diff --git a/tutorials/cluster.md b/tutorials/cluster.md index c2c4857..9282504 100644 --- a/tutorials/cluster.md +++ b/tutorials/cluster.md @@ -249,385 +249,208 @@ druid.indexer.logs.directory=/druid/indexing-logs 请参考 [HDFS extension](../development/extensions-core/hdfs.md) 页面中的内容来获得更多的信息。 -## Configure for connecting to Hadoop (optional) -If you will be loading data from a Hadoop cluster, then at this point you should configure Druid to be aware -of your cluster: - -- Update `druid.indexer.task.hadoopWorkingPath` in `conf/druid/cluster/middleManager/runtime.properties` to -a path on HDFS that you'd like to use for temporary files required during the indexing process. -`druid.indexer.task.hadoopWorkingPath=/tmp/druid-indexing` is a common choice. - -- Place your Hadoop configuration XMLs (core-site.xml, hdfs-site.xml, yarn-site.xml, -mapred-site.xml) on the classpath of your Druid processes. You can do this by copying them into -`conf/druid/cluster/_common/core-site.xml`, `conf/druid/cluster/_common/hdfs-site.xml`, and so on. - -Note that you don't need to use HDFS deep storage in order to load data from Hadoop. For example, if -your cluster is running on Amazon Web Services, we recommend using S3 for deep storage even if you -are loading data using Hadoop or Elastic MapReduce. - -For more info, please see the [Hadoop-based ingestion](../ingestion/hadoop.md) page. - -## Configure Zookeeper connection - -In a production cluster, we recommend using a dedicated ZK cluster in a quorum, deployed separately from the Druid servers. - -In `conf/druid/cluster/_common/common.runtime.properties`, set -`druid.zk.service.host` to a [connection string](https://zookeeper.apache.org/doc/current/zookeeperProgrammers.html) -containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server in your ZK quorum. -(e.g. "127.0.0.1:4545" or "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002") - -You can also choose to run ZK on the Master servers instead of having a dedicated ZK cluster. If doing so, we recommend deploying 3 Master servers so that you have a ZK quorum. - -## Configuration Tuning - -### Migrating from a Single-Server Deployment - -#### Master - -If you are using an example configuration from [single-server deployment examples](../operations/single-server.md), these examples combine the Coordinator and Overlord processes into one combined process. - -The example configs under `conf/druid/cluster/master/coordinator-overlord` also combine the Coordinator and Overlord processes. - -You can copy your existing `coordinator-overlord` configs from the single-server deployment to `conf/druid/cluster/master/coordinator-overlord`. - -#### Data - -Suppose we are migrating from a single-server deployment that had 32 CPU and 256GB RAM. In the old deployment, the following configurations for Historicals and MiddleManagers were applied: - -Historical (Single-server) - -``` -druid.processing.buffer.sizeBytes=500000000 -druid.processing.numMergeBuffers=8 -druid.processing.numThreads=31 -``` - -MiddleManager (Single-server) - -``` -druid.worker.capacity=8 -druid.indexer.fork.property.druid.processing.numMergeBuffers=2 -druid.indexer.fork.property.druid.processing.buffer.sizeBytes=100000000 -druid.indexer.fork.property.druid.processing.numThreads=1 -``` - -In the clustered deployment, we can choose a split factor (2 in this example), and deploy 2 Data servers with 16CPU and 128GB RAM each. The areas to scale are the following: - -Historical - -- `druid.processing.numThreads`: Set to `(num_cores - 1)` based on the new hardware -- `druid.processing.numMergeBuffers`: Divide the old value from the single-server deployment by the split factor -- `druid.processing.buffer.sizeBytes`: Keep this unchanged - -MiddleManager: - -- `druid.worker.capacity`: Divide the old value from the single-server deployment by the split factor -- `druid.indexer.fork.property.druid.processing.numMergeBuffers`: Keep this unchanged -- `druid.indexer.fork.property.druid.processing.buffer.sizeBytes`: Keep this unchanged -- `druid.indexer.fork.property.druid.processing.numThreads`: Keep this unchanged - -The resulting configs after the split: - -New Historical (on 2 Data servers) - -``` - druid.processing.buffer.sizeBytes=500000000 - druid.processing.numMergeBuffers=8 - druid.processing.numThreads=31 -``` - -New MiddleManager (on 2 Data servers) - -``` -druid.worker.capacity=4 -druid.indexer.fork.property.druid.processing.numMergeBuffers=2 -druid.indexer.fork.property.druid.processing.buffer.sizeBytes=100000000 -druid.indexer.fork.property.druid.processing.numThreads=1 -``` - -#### Query - -You can copy your existing Broker and Router configs to the directories under `conf/druid/cluster/query`, no modifications are needed, as long as the new hardware is sized accordingly. - -### Fresh deployment - -If you are using the example cluster described above: -- 1 Master server (m5.2xlarge) -- 2 Data servers (i3.4xlarge) -- 1 Query server (m5.2xlarge) - -The configurations under `conf/druid/cluster` have already been sized for this hardware and you do not need to make further modifications for general use cases. - -If you have chosen different hardware, the [basic cluster tuning guide](../operations/basic-cluster-tuning.md) can help you size your configurations. - -## Open ports (if using a firewall) - -If you're using a firewall or some other system that only allows traffic on specific ports, allow -inbound connections on the following: - -### Master Server -- 1527 (Derby metadata store; not needed if you are using a separate metadata store like MySQL or PostgreSQL) -- 2181 (ZooKeeper; not needed if you are using a separate ZooKeeper cluster) -- 8081 (Coordinator) -- 8090 (Overlord) - -### Data Server -- 8083 (Historical) -- 8091, 8100–8199 (Druid Middle Manager; you may need higher than port 8199 if you have a very high `druid.worker.capacity`) - -### Query Server -- 8082 (Broker) -- 8088 (Router, if used) - -> In production, we recommend deploying ZooKeeper and your metadata store on their own dedicated hardware, -> rather than on the Master server. - -## Start Master Server - -Copy the Druid distribution and your edited configurations to your Master server. - -If you have been editing the configurations on your local machine, you can use *rsync* to copy them: - -```bash -rsync -az apache-druid-apache-druid-0.21.1/ MASTER_SERVER:apache-druid-apache-druid-0.21.1/ -``` - -### No Zookeeper on Master - -From the distribution root, run the following command to start the Master server: - -``` -bin/start-cluster-master-no-zk-server -``` - -### With Zookeeper on Master - -If you plan to run ZK on Master servers, first update `conf/zoo.cfg` to reflect how you plan to run ZK. Then, you -can start the Master server processes together with ZK using: - -``` -bin/start-cluster-master-with-zk-server -``` - -> In production, we also recommend running a ZooKeeper cluster on its own dedicated hardware. - -## Start Data Server - -Copy the Druid distribution and your edited configurations to your Data servers. - -From the distribution root, run the following command to start the Data server: - -``` -bin/start-cluster-data-server -``` - -You can add more Data servers as needed. - -> For clusters with complex resource allocation needs, you can break apart Historicals and MiddleManagers and scale the components individually. -> This also allows you take advantage of Druid's built-in MiddleManager autoscaling facility. - -## Start Query Server - -Copy the Druid distribution and your edited configurations to your Query servers. - -From the distribution root, run the following command to start the Query server: - -``` -bin/start-cluster-query-server -``` - -You can add more Query servers as needed based on query load. If you increase the number of Query servers, be sure to adjust the connection pools on your Historicals and Tasks as described in the [basic cluster tuning guide](../operations/basic-cluster-tuning.md). - -## Loading data - -Congratulations, you now have a Druid cluster! The next step is to learn about recommended ways to load data into -Druid based on your use case. Read more about [loading data](../ingestion/index.md). - - - - - -### Hadoop连接配置 +## Hadoop连接配置 如果要从Hadoop集群加载数据,那么此时应对Druid做如下配置: * 在`conf/druid/cluster/_common/common.runtime.properties`文件中更新`druid.indexer.task.hadoopWorkingPath`配置项,将其更新为您期望的一个用于临时文件存储的HDFS路径。 通常会配置为`druid.indexer.task.hadoopWorkingPath=/tmp/druid-indexing` * 需要将Hadoop的配置文件(core-site.xml, hdfs-site.xml, yarn-site.xml, mapred-site.xml)放置在Druid进程的classpath中,可以将他们拷贝到`conf/druid/cluster/_common`目录中 -请注意,您无需为了可以从Hadoop加载数据而使用HDFS深度存储。例如,如果您的集群在Amazon Web Services上运行,即使您使用Hadoop或Elastic MapReduce加载数据,我们也建议使用S3进行深度存储。 +请注意,您无需为了可以从Hadoop加载数据而使用HDFS深度存储。 更多信息可以看[基于Hadoop的数据摄取](../../DataIngestion/hadoopbased.md)部分的文档。 -### Zookeeper连接配置 -在生产集群中,我们建议使用专用的ZK集群,该集群与Druid服务器分开部署。 +## Hadoop 的连接配置(可选) +如果你希望懂 Hadoop 集群中加载数据,那么你需要对你的 Druid 集群进行下面的一些配置: -在 `conf/druid/cluster/_common/common.runtime.properties` 中,将 `druid.zk.service.host` 设置为包含用逗号分隔的host:port对列表的连接字符串,每个对与ZK中的ZooKeeper服务器相对应。(例如" 127.0.0.1:4545"或"127.0.0.1:3000,127.0.0.1:3001、127.0.0.1:3002") +- 更新 `conf/druid/cluster/middleManager/runtime.properties` 文件中的 `druid.indexer.task.hadoopWorkingPath` 配置选项。 +将 HDFS 配置路径文件更新到一个你期望使用的临时文件存储路径。`druid.indexer.task.hadoopWorkingPath=/tmp/druid-indexing` 为通常的配置。 -您也可以选择在Master服务上运行ZK,而不使用专用的ZK集群。如果这样做,我们建议部署3个Master服务,以便您具有ZK仲裁。 +- 将你的 Hadoop XMLs配置文件(core-site.xml, hdfs-site.xml, yarn-site.xml, mapred-site.xml)放到你的 Druid 进程中。 +你可以将 `conf/druid/cluster/_common/core-site.xml`, `conf/druid/cluster/_common/hdfs-site.xml` 拷贝到 `conf/druid/cluster/_common` 目录中。 -### 配置调整 -#### 从单服务器环境迁移部署 -##### Master服务 +请注意,你不需要为了从 Hadoop 中载入数据而使用 HDFS 深度存储。 -如果您使用的是[单服务器部署示例](chapter-3.md)中的示例配置,则这些示例中将Coordinator和Overlord进程合并为一个合并的进程。 +例如,如果您的集群在 Amazon Web Services 上运行,即使已经使用 Hadoop 或 Elastic MapReduce 加载数据,我们也建议使用 S3 进行深度存储。 -`conf/druid/cluster/master/coordinator-overlord` 下的示例配置同样合并了Coordinator和Overlord进程。 +有关更多的信息,请参考 [Hadoop-based ingestion](../ingestion/hadoop.md) 页面中的内容。 -您可以将现有的 `coordinator-overlord` 配置从单服务器部署复制到`conf/druid/cluster/master/coordinator-overlord` +## 配置 Zookeeper 连接 +在实际的生产环境中,我们建议你使用专用的 ZK 集群来进行部署。ZK 的集群与 Druid 的集群部署是分离的。 -##### Data服务 +在 `conf/druid/cluster/_common/common.runtime.properties` 配置文件中,设置 +`druid.zk.service.host` 为 [connection string](https://zookeeper.apache.org/doc/current/zookeeperProgrammers.html)。 +在连接配置中使用的是逗号分隔符(host:port 对),每一个对应的是一个 ZK 的服务器,(例如, "127.0.0.1:4545" or "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002")。 -假设我们正在从一个32CPU和256GB内存的单服务器部署环境进行迁移,在老的环境中,Historical和MiddleManager使用了如下的配置: +你也可以选择在 Master 服务器上运行 ZK,而不使用专用的 ZK 集群。 +如果这样做的话,我们建议部署 3 个 Master 服务服务器,以便具有 ZK 仲裁(因为 Zookeeper 的部署至少需要 3 个服务器,并且服务器的总数量为奇数)。 -Historical(单服务器) +## 配置调整 -```json +### 从一个单独部署服务器上进行合并 + +#### Master 服务 + +如果你已经有一个已经存在并且独立运行的独立服务器部署的话,例如在页面 [single-server deployment examples](../operations/single-server.md) 中部署的服务器, +下面的这个示例将会帮助你将 Coordinator 和 Overlord 合并到一个进程上面 + +`conf/druid/cluster/master/coordinator-overlord` 下面的示例,显示例如如何同时合并 Coordinator 和 Overlord 进程。 + +你可以从已经部署的独立服务器上拷贝已经存在 `coordinator-overlord` 配置文件,并部署到 `conf/druid/cluster/master/coordinator-overlord`。 + +#### Data 服务 +假设我们将要从一个 32 CPU 和 256GB 内存的独立服务器上进行合并。 +在老的部署中,下面的配置是针对 Historicals 和 MiddleManagers 进程的: + +Historical(独立服务器部署) + +``` druid.processing.buffer.sizeBytes=500000000 druid.processing.numMergeBuffers=8 druid.processing.numThreads=31 ``` -MiddleManager(单服务器) +MiddleManager(独立服务器部署) -```json +``` druid.worker.capacity=8 druid.indexer.fork.property.druid.processing.numMergeBuffers=2 druid.indexer.fork.property.druid.processing.buffer.sizeBytes=100000000 druid.indexer.fork.property.druid.processing.numThreads=1 ``` -在集群部署中,我们选择一个分裂因子(假设为2),则部署2个16CPU和128GB内存的Data服务,各项的调整如下: +在集群部署环境中,我们可以选择使用 2 个服务器来运行上面的 2 个服务,这 2 个服务器的配置为 16CPU 和 128GB RAM 。 +我们将会按照下面的配置方式进行配置: Historical -* `druid.processing.numThreads`设置为新硬件的(`CPU核数 - 1`) -* `druid.processing.numMergeBuffers` 使用分裂因子去除单服务部署环境的值 -* `druid.processing.buffer.sizeBytes` 该值保持不变 +- `druid.processing.numThreads`: 基于配置的新硬件环境,设置为 `(num_cores - 1)` +- `druid.processing.numMergeBuffers`: 针对独立服务器使用的数量使用分裂因子相除 +- `druid.processing.buffer.sizeBytes`: 保持不变 MiddleManager: -* `druid.worker.capacity`: 使用分裂因子去除单服务部署环境的值 -* `druid.indexer.fork.property.druid.processing.numMergeBuffers`: 该值保持不变 -* `druid.indexer.fork.property.druid.processing.buffer.sizeBytes`: 该值保持不变 -* `druid.indexer.fork.property.druid.processing.numThreads`: 该值保持不变 +- `druid.worker.capacity`: 针对独立服务器使用的数量使用分裂因子相除 +- `druid.indexer.fork.property.druid.processing.numMergeBuffers`: 保持不变 +- `druid.indexer.fork.property.druid.processing.buffer.sizeBytes`: 保持不变 +- `druid.indexer.fork.property.druid.processing.numThreads`: 保持不变 -调整后的结果配置如下: +在完成上面配置后的结果如下: -新的Historical(2 Data服务器) +集群 Historical (使用 2 个数据服务器) -```json +``` druid.processing.buffer.sizeBytes=500000000 druid.processing.numMergeBuffers=8 druid.processing.numThreads=31 - ``` +``` -新的MiddleManager(2 Data服务器) +集群 MiddleManager (使用 2 个数据服务器) -```json +``` druid.worker.capacity=4 druid.indexer.fork.property.druid.processing.numMergeBuffers=2 druid.indexer.fork.property.druid.processing.buffer.sizeBytes=100000000 druid.indexer.fork.property.druid.processing.numThreads=1 ``` -##### Query服务 +#### Query 服务 +你可以将已经在独立服务器部署中存在的配置文件拷贝到 `conf/druid/cluster/query` 目录中完成部署。 +如果新的服务器的硬件配置和独立服务器的配置是相对的话,新的部署不需要做修改。 -您可以将现有的Broker和Router配置复制到`conf/druid/cluster/query`下的目录中,无需进行任何修改. +### 刷新部署 deployment -#### 首次部署 +如果你使用下面的服务器配置环境为示例的话: +- 1 Master server (m5.2xlarge) +- 2 Data servers (i3.4xlarge) +- 1 Query server (m5.2xlarge) -如果您正在使用如下描述的示例集群规格: +在 `conf/druid/cluster` 文件夹中的配置文件已经针对上面的硬件环境进行了优化,针对基本情况的使用来说,你不需要针对上面的配置进行修改。 -* 1 Master 服务器(m5.2xlarge) -* 2 Data 服务器(i3.4xlarge) -* 1 Query 服务器(m5.2xlarge) +如果你选择使用不同的硬件的话,页面 [basic cluster tuning guide](../operations/basic-cluster-tuning.md) 中的内容能够帮助你对你的硬件配置做一些选择。 -`conf/druid/cluster`下的配置已经为此硬件确定了,一般情况下您无需做进一步的修改。 +## 打开端口(如果你使用了防火墙的话) -如果您选择了其他硬件,则[基本的集群调整指南](../../operations/basicClusterTuning.md)可以帮助您调整配置大小。 +如果你的服务使用了防火墙,或者一些网络配置中限制了端口的访问的话。那么你需要在你的服务器上开放下面的端口,并运行数据进行访问: -### 开启端口(如果使用了防火墙) +### Master 服务器 +- 1527 (Derby 原数据存储;如果你使用的是其他的数据库,例如 MySQL 或 PostgreSQL 的话就不需要) +- 2181 (ZooKeeper;如果你使用的是分布式 ZooKeeper 集群部署的话就不需要) +- 8081 (Coordinator 服务) +- 8090 (Overlord 服务) -如果您正在使用防火墙或其他仅允许特定端口上流量准入的系统,请在以下端口上允许入站连接: +### Data 服务器 +- 8083 (Historical 服务) +- 8091, 8100–8199 (Druid Middle Manager 服务,如果你使用了比较高的 `druid.worker.capacity` 配置的话,那么你需要的端口可能会高于 8199) -#### Master服务 +### Query 服务器 +- 8082 (Broker 服务) +- 8088 (Router 服务,如果使用的话) -* 1527(Derby元数据存储,如果您正在使用一个像MySQL或者PostgreSQL的分离的元数据存储则不需要) -* 2181(Zookeeper,如果使用了独立的ZK集群则不需要) -* 8081(Coordinator) -* 8090(Overlord) +> 在生产环境中,我们推荐你部署 ZooKeeper 和你的元数据存储到他们自己的硬件上(独立部署)。不要和 Master server 混合部署在一起。 -#### Data服务 +## 启动 Master 服务器 +拷贝 Druid 的分发包和你修改过的配置到 Master 服务器上。 -* 8083(Historical) -* 8091,8100-8199(Druid MiddleManager,如果`druid.worker.capacity`参数设置较大的话,则需要更多高于8199的端口) +如果你已经在你的本地计算机上修改了配置,你可以使用 *rsync* 来进行拷贝。 -#### Query服务 - -* 8082(Broker) -* 8088(Router,如果使用了) - -> [!WARNING] -> 在生产中,我们建议将ZooKeeper和元数据存储部署在其专用硬件上,而不是在Master服务器上。 - -### 启动Master服务 - -将Druid发行版和您编辑的配置文件复制到Master服务器上。 - -如果您一直在本地计算机上编辑配置,则可以使用rsync复制它们: - -```json -rsync -az apache-druid-0.17.0/ MASTER_SERVER:apache-druid-0.17.0/ +```bash +rsync -az apache-druid-apache-druid-0.21.1/ MASTER_SERVER:apache-druid-apache-druid-0.21.1/ ``` -#### 不带Zookeeper启动 +### Master 没有 Zookeeper 的启动 -在发行版根目录中,运行以下命令以启动Master服务: -```json +从分发包的 root 节点中,运行下面的命令来启动 Master 服务器: + +``` bin/start-cluster-master-no-zk-server ``` -#### 带Zookeeper启动 +### Master 有 Zookeeper 的启动 +如果你计划在 Master 服务器上还同时运行 ZK 的话,首先需要更新 `conf/zoo.cfg` 中的配置来确定你如何运行 ZK。 +然后你可以选择在启动 ZK 的同时启动 Master 服务器。 -如果计划在Master服务器上运行ZK,请首先更新`conf/zoo.cfg`以标识您计划如何运行ZK,然后,您可以使用以下命令与ZK一起启动Master服务进程: -```json +使用下面的命令行来进行启动: + +``` bin/start-cluster-master-with-zk-server ``` -> [!WARNING] -> 在生产中,我们建议将ZooKeeper运行在其专用硬件上。 +> 在生产环境中,我们推荐你部署 ZooKeeper 在独立的集群上面。 -### 启动Data服务 +## 启动 Data 服务器 +拷贝 Druid 的分发包和你修改过的配置到 Data 服务器上。 -将Druid发行版和您编辑的配置文件复制到您的Data服务器。 +从分发包的 root 节点中,运行下面的命令来启动 Data 服务器: -在发行版根目录中,运行以下命令以启动Data服务: -```json +``` bin/start-cluster-data-server ``` -您可以在需要的时候增加更多的Data服务器。 +如果需要的话,你还可以为你的数据服务器添加更多的节点。 -> [!WARNING] -> 对于具有复杂资源分配需求的集群,您可以将Historical和MiddleManager分开部署,并分别扩容组件。这也使您能够利用Druid的内置MiddleManager自动伸缩功能。 +> 针对集群环境中更加复杂的应用环境和需求,你可以将 Historicals 和 MiddleManagers 服务分开部署,然后分别进行扩容。 +> 上面的这种分开部署方式,能够给代理 Druid 已经构建并且实现的 MiddleManager 自动扩容功能。 -### 启动Query服务 -将Druid发行版和您编辑的配置文件复制到您的Query服务器。 +## 启动 Query 服务器 +拷贝 Druid 的分发包和你修改过的配置到 Query 服务器上。 -在发行版根目录中,运行以下命令以启动Query服务: +从分发包的 root 节点中,运行下面的命令来启动 Query 服务器: -```json +``` bin/start-cluster-query-server ``` +针对你查询的负载情况,你可以为你的查询服务器增加更多的节点。 -您可以根据查询负载添加更多查询服务器。 如果增加了查询服务器的数量,请确保按照[基本集群调优指南](../../operations/basicClusterTuning.md)中的说明调整Historical和Task上的连接池。 +如果为你的查询服务器增加了更多的节点的话,请确定同时为你的 Historicals 服务增加更多的连接池。 -### 加载数据 +请参考页面 [basic cluster tuning guide](../operations/basic-cluster-tuning.md) 中描述的内容。 -恭喜,您现在有了Druid集群!下一步是根据使用场景来了解将数据加载到Druid的推荐方法。 - -了解有关[加载数据](../DataIngestion/index.md)的更多信息。 +## 载入数据 +恭喜你,我们现在有了配置成功并且运行的 Druid 集群了! +下一步就是根据根据你的使用情况来用推荐的方法将数据载入到 Druid 集群中了。 +请参考页面 [loading data](../ingestion/index.md) 中的内容。 diff --git a/tutorials/tutorial-batch-hadoop.md b/tutorials/tutorial-batch-hadoop.md index f30b695..fc23154 100644 --- a/tutorials/tutorial-batch-hadoop.md +++ b/tutorials/tutorial-batch-hadoop.md @@ -471,4 +471,4 @@ druid.indexer.logs.directory=var/druid/indexing-logs ### 进一步阅读 -更多关于从Hadoop加载数据的信息,可以查看[Druid Hadoop批量摄取文档](../DataIngestion/hadoopbased.md) \ No newline at end of file +更多关于从Hadoop加载数据的信息,可以查看[Druid Hadoop批量摄取文档](../ingestion/hadoop.md) \ No newline at end of file diff --git a/tutorials/tutorial-batch.md b/tutorials/tutorial-batch.md index b96b772..bda1e2a 100644 --- a/tutorials/tutorial-batch.md +++ b/tutorials/tutorial-batch.md @@ -222,4 +222,4 @@ curl -X 'POST' -H 'Content-Type:application/json' -d @quickstart/tutorial/wikipe ### 更多信息 -更多关于加载批数据的信息可以查看[原生批摄取文档](../DataIngestion/native.md) \ No newline at end of file +更多关于加载批数据的信息可以查看[原生批摄取文档](../ingestion/native.md) \ No newline at end of file diff --git a/tutorials/tutorial-kafka.md b/tutorials/tutorial-kafka.md index 856074e..6622510 100644 --- a/tutorials/tutorial-kafka.md +++ b/tutorials/tutorial-kafka.md @@ -483,7 +483,7 @@ curl -XPOST -H'Content-Type: application/json' -d @quickstart/tutorial/wikipedia ``` 如果supervisor被成功创建后,将会返回一个supervisor的ID,在本例中看到的是 `{"id":"wikipedia"}` -更详细的信息可以查看[Druid Kafka索引服务文档](../DataIngestion/kafka.md) +更详细的信息可以查看[Druid Kafka索引服务文档](../ingestion/kafka.md) 您可以在[Druid控制台]( http://localhost:8888/unified-console.html#tasks)中查看现有的supervisors和tasks @@ -494,4 +494,4 @@ curl -XPOST -H'Content-Type: application/json' -d @quickstart/tutorial/wikipedia ### 清理数据 如果您希望阅读其他任何入门教程,则需要关闭集群并通过删除druid软件包下的`var`目录的内容来重置集群状态,因为其他教程将写入相同的"wikipedia"数据源。 ### 进一步阅读 -更多关于从Kafka流加载数据的信息,可以查看[Druid Kafka索引服务文档](../DataIngestion/kafka.md) \ No newline at end of file +更多关于从Kafka流加载数据的信息,可以查看[Druid Kafka索引服务文档](../ingestion/kafka.md) \ No newline at end of file