【问题标题】:Find distinct inner objects in Elasticsearch在 Elasticsearch 中查找不同的内部对象
【发布时间】:2015-10-26 15:18:40
【问题描述】:

我们试图在 Elasticsearch 中找到不同的内部对象。这将是我们案例的最小示例。 我们遇到了类似以下映射的问题(更改类型或索引或添加新字段不会有问题,但结构应该保持原样):

{
  "building": {
    "properties": {
      "street": {
        "type": "string",
        "store": "yes",
        "index": "not_analyzed"
      },
      "house number": {
        "type": "string",
        "store": "yes",
        "index": "not_analyzed"
      },
      "city": {
        "type": "string",
        "store": "yes",
        "index": "not_analyzed"
      },
      "people": {
        "type": "object",
        "store": "yes",
        "index": "not_analyzed",
        "properties": {
          "firstName": {
            "type": "string",
            "store": "yes",
            "index": "not_analyzed"
          },
          "lastName": {
            "type": "string",
            "store": "yes",
            "index": "not_analyzed"
          }
        }
      }
    }
  }
}

假设我们有这个示例数据:

{
  "buildings": [
    {
      "street": "Baker Street",
      "house number": "221 B",
      "city": "London",
      "people": [
        {
          "firstName": "John",
          "lastName": "Doe"
        },
        {
          "firstName": "Jane",
          "lastName": "Doe"
        }
      ]
    },
    {
      "street": "Baker Street",
      "house number": "5",
      "city": "London",
      "people": [
        {
          "firstName": "John",
          "lastName": "Doe"
        }
      ]
    },
    {
      "street": "Garden Street",
      "house number": "1",
      "city": "London",
      "people": [
        {
          "firstName": "Jane",
          "lastName": "Smith"
        }
      ]
    }
  ]
}

当我们查询街道“贝克街”(以及所需的任何其他选项)时,我们期望得到以下列表:

[
    {
      "firstName": "John",
      "lastName": "Doe"
    },
    {
      "firstName": "Jane",
      "lastName": "Doe"
    }
]

格式没有太大关系,但我们应该能够解析名字和姓氏。只是,由于我们的实际数据集要大得多,我们需要区分条目。

我们使用的是 Elasticsearch 1.7。

【问题讨论】:

标签: elasticsearch


【解决方案1】:

我们终于解决了我们的问题。

我们的解决方案是(如我们所料)预先计算的people_all 字段。但是,我们没有使用copy_totransform,而是像在导入数据时编写其他字段一样编写它。该字段如下所示:

"people": {
  "type": "nested",
  ..
  "properties": {
    "firstName": {
      "type": "string",
      "store": "yes",
      "index": "not_analyzed"
    },
    "lastName": {
      "type": "string",
      "store": "yes",
      "index": "not_analyzed"
    },
    "people_all": {
      "type": "string",
      "index": "not_analyzed"
    }
  }
}

请注意people_all 字段中的"index": "not_analyzed"。拥有完整的存储桶很重要。如果您不使用它,我们的示例将返回 3 个桶“john”、“jane”和“doe”。

写完这个新字段后,我们可以运行如下聚合:

{
  "size": 0,
  "query": {
    "term": {
      "street": "Baker Street"
    }
  },
  "aggs": {
    "people_distinct": {
      "nested": {
        "path": "people"
      },
      "aggs": {
        "people_all_distinct": {
          "terms": {
            "field": "people.people_all",
            "size": 0
          }
        }
      }
    }
  }
}

我们返回以下响应:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 0.0,
    "hits": []
  },
  "aggregations": {
    "people_distinct": {
      "doc_count": 3,
      "people_name_distinct": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "John Doe",
            "doc_count": 2
          },
          {
            "key": "Jane Doe",
            "doc_count": 1
          }
        ]
      }
    }
  }
}

我们现在可以在响应中创建不同的人对象。

如果有更好的方法来实现我们的目标,请告诉我们。 解析桶并不是一个最佳的解决方案,在每个桶中都有firstNamelastName字段会更好。

【讨论】:

    【解决方案2】:

    正如评论中所建议的那样,您的人员映射应该是 nested 而不是 object 类型,因为它可能会产生意想不到的结果。之后您还需要重新索引您的数据。

    至于问题,您需要根据您的查询汇总结果。

    {
      "query": {
        "term": {
          "street": "Baker Street"
        }
      },
      "aggs": {
        "distinct_people": {
          "terms": {
            "field": "people",
            "size": 1000
          }
        }
      }
    }
    

    请注意,我在聚合中将size 设置为 1000,您可能需要使用更大的数字来获取所有不同的人,ES 默认只返回 10 个结果。

    如果您只对聚合存储桶感兴趣,可以将查询 size 设置为 0 或使用参数 search_type=count。 您可以在此处阅读有关聚合的更多信息。 https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html

    我希望这会有所帮助!如果这不起作用,请告诉我。

    【讨论】:

    • 感谢您的快速回答!不幸的是,这不起作用(我们尝试使用“对象”和“嵌套”)。我们已经尝试将人员字段复制到“people_all”字段并使用这个新字段,但这也没有达到预期的结果。 { "aggs" : { "people_distinct" : { "nested" : { "path" : "people" }, "aggs" : { "people_name_distinct" : { "terms" : { "field" : "people.people_all" } } } } } } 在这种情况下会导致 3 个桶:jane、john、doe
    • 在搜索了更多信息后,我们偶然发现了 not_analyzed 字段,它应该可以解决我们的问题。如果people_allnot_analyzed,则存储桶应该是“Jane Doe”和“John Doe”。但这似乎不起作用。是因为它是一个嵌套字段吗?我会告诉你,只要我找到更多信息。 假设:这不起作用,因为people_full 是一个字符串数组。
    猜你喜欢
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    相关资源
    最近更新 更多