在Elasticsearch

时间:2015-10-26 15:18:40

标签: elasticsearch

我们试图在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"
        }
      ]
    }
  ]
}

当我们查询街道“Baker Street”(以及需要的其他选项)时,我们希望得到以下列表:

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

格式无关紧要,但我们应该能够解析名字和姓氏。只是,由于我们的实际数据集要大得多,我们需要条目不同。

我们正在使用Elasticsearch 1.7。

2 个答案:

答案 0 :(得分: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"
    }
  }
}

请注意"index": "not_analyzed"字段people_all。这对于拥有完整的存储桶非常重要。如果你不使用它,我们的例子将返回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会更加花哨。

答案 1 :(得分:0)

根据评论中的建议,您的人员映射应为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

我希望这有帮助!如果这不成功,请告诉我。