【问题标题】:Elasticsearch - what to do if fields have the same name but multiple mappingElasticsearch - 如果字段名称相同但有多个映射怎么办
【发布时间】:2015-12-29 14:32:18
【问题描述】:

我使用 Elasticsearch 来存储从我的系统外部的多个来源发送的数据,即我不控制传入的数据 - 我只是接收 json 文档并存储它。我没有中间有过滤器的logstash,只有ES和Kibana。每个数据源都发送自己的数据类型,它们都存储在相同的索引(每个租户)中,但类型不同。但是,由于我无法控制发送给我的数据,因此可以接收具有相同名称和不同结构的字段的不同类型的文档。
例如,假设我有type1 和 type2 带有字段 FLD,在这两种情况下都是一个对象,但这个对象的结构不一样。具体来说,FLD.name 是 type1 中的字符串字段,但 type2 中的对象。在这种情况下,当type1数据到达时存储成功,但当type2数据到达时,它被拒绝:

未能在索引 [[myindex]] 上放置映射,类型 [type2]
java.lang.IllegalArgumentException:[FLD] 的映射器与其他类型中的现有映射冲突[无法将非对象映射 [FLD.name] 与对象映射 [FLD.name] 合并]

ES 文档明确声明,不同映射类型的同一索引中的同名字段在内部映射到同一个字段,并且必须具有相同的映射(see here)。

我的问题是在这种情况下我该怎么办?我更愿意将所有类型保留在同一个索引中。是否可以为字段名称或类似的东西添加每个类型的唯一后缀?还有其他解决方案吗?我是 Elasticsearch 的新手,所以也许我遗漏了一些简单的东西......在此先感谢。

【问题讨论】:

  • 我真的怀疑是否有任何出路,除了使用不同的名称..因为这个功能是弹性在 2.0 中实现的,与他们的结束相比有很大的变化
  • 如果我想使用不同的名称 - 我在技术上是如何做到的?是否有任何“过滤器”可以根据特定模式修改名称?由于字段是动态的,我无法在数据到达之前提前完成。我应该在他们的文档中寻找什么功能?我想到的另一个选择是重新设计数据的存储方式:使用当前类型作为索引(每个索引中的所有数据都将以相同的方式映射)并使租户 ID 成为以某种方式添加到文档中的字段之一。虽然它使索引更大,多租户支持更具挑战性。
  • 不,没有过滤器可以根据任何模式修改字段的名称...我建议您重新考虑如何存储数据。将类型存储为索引也不推荐..
  • 这个运气好吗?请分享你的所作所为。
  • 最终通过在不同索引中保存不同类型来解决原始问题。不是好主意,但我们想不出更好的办法。请注意,我们有多个但数量有限的来源,因此索引的数量会合理增长。此外,我们添加了 pre-index-enricher 服务,该服务会在文档的实际索引之前干扰数据输入流。我们在那里添加了一些合成字段。但是,如果您的字段列表是已知列表(但不是类型),您可以使用它来重命名。这不是我们的情况(字段列表可能会改变),所以我们没有将它用于此目的。

标签: java elasticsearch


【解决方案1】:

没有办法在索引任意 JSON 之前对其进行预处理 - 甚至 Dynamic templates 都不够灵活。

您可以将嵌套对象展平为键值对,并使用 Nested datatypeMulti-fieldsignore_malformed 来索引任意 JSON(即使存在类型冲突),如 here 所述。不幸的是,如果您尝试将字符串与kv_pairs.value.long 匹配,Elasticsearch 仍然会在查询时抛出异常,因此您必须根据值的格式选择适当的字段。

【讨论】:

    【解决方案2】:

    我认为这不是最佳做法,但您可以将字段内容存储为String,并在检索信息后手动进行反序列化。

    所以,想象一个像这样的类:

    class Person {
        private final Object name;
    }
    

    这可以接收StringList 或任何其他Object 的列表,例如

    因此,与其将 Person 序列化为 String 并保存,不如将其序列化为 String 将内容保存在另一个类中,例如:

    String personContent new ObjectMapper().writeValueAsString(person);
    RequestDto dto = new RequestDto(personContent);
    String dtoContent new ObjectMapper().writeValueAsString(dto);
    

    并保存dtoContent

    IndexRequest request = new IndexRequest("persons")
    request.source(dtoContent, XContentType.JSON);
    IndexResponse response = client.index(request, RequestOptions.DEFAULT);
    

    RequestDto 将是一个带有 String 字段的简单类:

    class RequestDto {
        private String content;
    }
    

    我不是 ElasticSearch 方面的专家,但通过他的验证,您可能会失去 ElasticSearch 的许多功能。

    【讨论】:

      猜你喜欢
      • 2019-12-17
      • 2016-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-01
      相关资源
      最近更新 更多