映射和类型

编辑

正如前几节所解释的,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 中复杂的日期解析。在这些情况下,可以简单地禁用日期转换,并通过 es.mapping.date.rich 属性longString 形式传递原始信息。

顺便提一下,elasticsearch-hadoop 尝试检测运行时是否有专用的日期解析库(特别是 Joda,Elasticsearch 也使用它),如果有,则会使用它们。如果没有,它将默认使用 JDK 类进行解析,而 JDK 类的功能不如 Joda。展望未来,特别是随着 JDK 8 的出现,elasticsearch-hadoop 将尝试迁移到 javax.time 库,以确保无论运行时可用的类路径如何,都具有相同的行为。

排序和映射

编辑

需要注意的是,JSON 对象(用 {} 分隔,通常与映射关联)是无序的,换句话说,它们保持顺序。JSON 数组(通常与列表或序列关联)是有序的,也就是说,它们保留初始插入顺序。这会影响从 Elasticsearch 读取对象的方式,因为可能会发现插入结构与提取结构不同。不过,很容易规避这个问题 - 由于 JSON 对象(映射)包含字段,请使用字段名称(或键)而不是它们在文档中的位置来可靠地获取它们的值(在 Java 术语中,将 JSON 对象视为 HashMap 而不是 LinkedHashMap)。

地理类型

编辑

对于地理定位,Elasticsearch 提供了两种专用类型,即geo_pointgeo_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.includees.read.field.as.array.exclude 来指定额外信息。

自动映射

编辑

默认情况下,当数据被添加到以前未创建的索引下时,Elasticsearch 提供自动索引和映射。换句话说,可以将数据添加到 Elasticsearch 中,而无需事先定义索引和映射。这非常方便,因为 Elasticsearch 会自动适应输入的数据 - 此外,如果某些条目有额外的字段,Elasticsearch 的无模式特性允许它们被索引,而没有任何问题。

重要的是要记住,自动映射使用有效负载值来识别字段类型,使用添加每个字段的第一个文档。elasticsearch-hadoop 通过 JSON 与 Elasticsearch 通信,JSON 不提供任何类型信息,而只提供字段名称及其值。可以将其视为类型擦除或信息丢失;例如,JSON 不区分整数数值类型 - byteshortintlong 都被放在相同的 long 存储桶中。这可能会产生意想不到的副作用,因为类型信息是猜测的,例如

数字仅映射为 long/double
编辑

每当 Elasticsearch 遇到数字时,它都会为它分配最大的类型,因为它不知道字段的确切数字类型。分配一个小的类型(如 byteintfloat)如果未来的文档更大,可能会导致问题,因此 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 格式的日期 (dateOptionalTime)

integer 数字 (4) 被映射到最大的可用类型 (long)

fractional 数字 (12.3) 被映射到最大的可用类型 (double)

不正确的映射
编辑

当字符串字段包含数字(例如 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_indexindex.mapper.dynamic 设置禁用自动索引创建以及动态映射(对于文档中存在的额外字段)。作为安全措施,elasticsearch-hadoop 提供了一个专用的配置选项 es.index.auto.create,它允许 elasticsearch-hadoop 创建索引或不创建索引,而无需修改 Elasticsearch 集群选项。

显式映射

编辑

当需要覆盖默认值、数据检测不正确(如上所述)或者在大多数情况下需要自定义索引分析时,应考虑显式或手动映射。有关如何定义索引及其类型的说明,请参阅 Elasticsearch 创建索引映射文档 - 请注意,这些需要在数据上传到 Elasticsearch 之前存在(否则 Elasticsearch 将使用自动映射,如果已启用)。

在大多数情况下,模板非常方便,因为它们会自动应用于与模式匹配的新创建的索引;换句话说,无需为每个索引定义映射,只需定义一次模板,然后将其应用于与其模式匹配的所有索引。

限制

编辑

Elasticsearch 允许字段名称包含点 (.)。但 ES-Hadoop 不支持它们,并且在读取或写入带有点的字段时会失败。请参阅 Elasticsearch 点扩展处理器,了解用于辅助替换字段名称中的点的工具。