映射和类型
编辑映射和类型
编辑如前几节所述,elasticsearch-hadoop 与 Hadoop 生态系统紧密集成,并对类型信息进行仔细的内省,以便 Elasticsearch 和 Hadoop 之间的数据流尽可能透明。本节将更详细地介绍类型转换是如何进行的,以及数据如何在两个系统之间映射。
将数据转换为 Elasticsearch
编辑根据设计,elasticsearch-hadoop 本身不提供任何数据转换或映射层,因为根本不需要它们:Hadoop 旨在执行 ETL,并且某些库(如 Pig 和 Hive)本身提供了类型信息。此外,Elasticsearch 本身就提供了丰富的映射支持,包括自动检测、动态/无模式映射、模板和完全手动控制。需要将字符串拆分为标记、执行数据验证或消除不需要的数据?在从 Elasticsearch 读取/写入数据之前,有很多方法可以在 Hadoop 中执行此操作。需要控制数据在 Elasticsearch 中的存储方式?使用 Elasticsearch API 定义映射、更新设置或添加通用元数据。
时间/日期映射
编辑在处理日期时,Elasticsearch 始终使用ISO 8601 格式表示日期/时间。这是 Elasticsearch 的默认日期格式 - 如果需要自定义格式,请添加到默认选项中,而不是直接替换它。有关更多信息,请参阅 Elasticsearch 参考文档中的日期格式部分。请注意,在读取数据时,如果日期不是 ISO8601 格式,则默认情况下 elasticsearch-hadoop 可能无法理解它,因为它不会复制 Elasticsearch 中复杂的日期解析。在这些情况下,可以简单地禁用日期转换,并将原始信息作为long
或String
传递,通过es.mapping.date.rich
属性。
顺便说一句,elasticsearch-hadoop 会尝试检测在运行时是否可以使用专用的日期解析库(特别是 Joda,Elasticsearch 也使用它),如果可以使用,则会使用它们。如果不能,它将默认使用 JDK 类进行解析,这些类功能不那么丰富。展望未来,尤其是在 JDK 8 的出现之后,elasticsearch-hadoop 将尝试迁移到javax.time
库,以便无论运行时可用的类路径如何,都能获得相同的行为。
排序和映射
编辑需要注意的是,JSON 对象(由{}
分隔,通常与映射相关联)是无序的,换句话说,它们不保持顺序。JSON 数组(通常与列表或序列相关联)是有序的,也就是说,它们确实保留了初始插入顺序。这会影响从 Elasticsearch 读取对象的方式,因为可能会发现插入结构与提取结构不同。但是,解决此问题很容易 - 由于 JSON 对象(映射)包含字段,因此请使用字段名称(或键)而不是文档中的位置来可靠地获取其值(在 Java 术语中,可以将 JSON 对象视为HashMap
而不是LinkedHashMap
)。
地理类型
编辑对于地理位置,Elasticsearch 提供了两种专用类型,即geo_point
和geo_shape
,它们在 elasticsearch-hadoop 集成的任何库中都没有直接等效项。此外,Elasticsearch 接受每种类型的多种格式(因为表示数据的方式有多种),事实上,geo_point
有 4 种不同的表示形式,geo_shape
有 9 种。为了解决这个问题,连接器会根据其各自类型使用的实际格式,将地理类型分解为基本类型。
对于强类型库(如 SparkSQL DataFrame
),需要事先知道格式,因此,elasticsearch-hadoop 将采样数据,请求 elasticsearch-hadoop 获取一个代表映射的随机文档,解析它并根据找到的值识别使用的格式并创建必要的模式。这在启动时自动发生,无需任何用户干预。与往常一样,用户数据必须全部使用相同的格式(SparkSQL 的要求),否则读取不同的格式将触发异常。
请注意,通常用户在读取或写入数据时,处理这些类型不会出现任何问题。
处理数组/多值字段
编辑Elasticsearch 对具有单个或多个值的字段的处理方式相同;实际上,映射没有提供关于此的信息。作为客户端,这意味着在实际读取字段之前,无法判断字段是单值还是多值。在大多数情况下,这不是问题,elasticsearch-hadoop 会自动创建必要的列表/数组。但是,在具有严格模式的环境(例如 Spark SQL)中,不允许更改字段的实际值与其声明类型不一致。更糟糕的是,即使在读取数据之前,也需要提供此信息。由于映射不够明确,因此 elasticsearch-hadoop 允许用户通过字段信息 指定额外信息,特别是es.read.field.as.array.include
和es.read.field.as.array.exclude
。
自动映射
编辑默认情况下,当在之前未创建的索引下添加数据时,Elasticsearch 提供自动索引和映射。换句话说,可以在没有预先定义索引和映射的情况下将数据添加到 Elasticsearch 中。这非常方便,因为 Elasticsearch 会自动适应提供给它的数据 - 此外,如果某些条目具有额外的字段,Elasticsearch 的无模式特性允许它们被索引而不会出现任何问题。
需要记住,自动映射使用有效负载值来识别字段类型,使用添加每个字段的第一个文档。elasticsearch-hadoop 通过 JSON 与 Elasticsearch 通信,JSON 不提供任何类型信息,而只提供字段名称及其值。可以将其视为类型擦除或信息丢失;例如,JSON 不会区分整数数值类型 - byte
、short
、int
、long
都放在同一个long
桶中。这可能会产生意想不到的副作用,因为类型信息是猜测的,例如
数字仅映射为long
/double
编辑每当 Elasticsearch 遇到一个数字时,它都会为其分配最大的类型,因为它不知道该字段的确切数字类型。分配较小的类型(例如byte
、int
或float
)可能会导致问题,如果将来的文档更大,Elasticsearch 会使用安全的默认值。例如,文档
{ "tweet" { "user" : "kimchy", "message" : "This is a tweet!", "postDate" : "2009-11-15T14:12:12", "priority" : 4, "rank" : 12.3 } }
触发以下映射
{ "test" : { "mappings" : { "index" : { "properties" : { "message" : { "type" : "string" }, "postDate" : { "type" : "date", "format" : "dateOptionalTime" }, "priority" : { "type" : "long" }, "rank" : { "type" : "double" }, "user" : { "type" : "string" } } } } } }
postDate 字段被识别为 ISO 8601 格式的日期( |
|
integer 数字( |
|
fractional 数字( |
错误映射
编辑当字符串字段包含数字(例如1234
)时,就会发生这种情况 - Elasticsearch 没有信息表明该数字实际上是一个字符串,因此它将该字段映射为数字,导致遇到字符串时出现解析异常。例如,此文档
{ "array":[123, "string"] }
在自动映射时会导致异常
{"error":"MapperParsingException[failed to parse [array]]; nested: NumberFormatException[For input string: \"string\"]; ","status":400}
因为array
字段最初被检测为数字(因为123
),这会导致"string"
触发解析异常,因为显然它不是数字。同样的问题也可能出现在可能被解释为日期的字符串中。
因此,如果需要覆盖默认值和/或如果遇到上面列出的问题,可能是由于数据集多样化造成的,请考虑使用显式映射。
禁用自动映射
编辑Elasticsearch 允许通过节点配置文件上的action.auto_create_index
和index.mapper.dynamic
设置来禁用自动索引创建以及动态映射(对于文档中存在的额外字段)。作为安全措施,elasticsearch-hadoop 提供了一个专用的配置选项 es.index.auto.create
,它允许 elasticsearch-hadoop 创建或不创建索引,而无需修改 Elasticsearch 集群选项。
显式映射
编辑当需要覆盖默认值、如果数据检测不正确(如上所述)或在大多数情况下自定义索引分析时,应考虑使用显式或手动映射。请参阅 Elasticsearch创建索引 和映射 文档,了解如何定义索引及其类型 - 请注意,这些需要在之前将数据上传到 Elasticsearch(否则,如果启用了自动映射,Elasticsearch 将使用自动映射)。
在大多数情况下,模板非常方便,因为它们会自动应用于创建的与模式匹配的新索引;换句话说,与其为每个索引定义映射,不如只定义一次模板,然后将其应用于所有与模式匹配的索引。
限制
编辑Elasticsearch 允许字段名称包含点 (.)。但是 ES-Hadoop 不支持它们,并且在读取或写入包含点的字段时会失败。请参阅 Elasticsearch 点扩展处理器,以获取用于帮助替换字段名称中点的工具。