ElasticSearch仅返回具有不同值的文档

use*_*206 17 java aggregate nosql elasticsearch spring-data-elasticsearch

假设我有这个给定的数据

{
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "GEORGE",
            "favorite_cars" : [ "honda","Hyundae" ]
          }
Run Code Online (Sandbox Code Playgroud)

每当我在搜索最喜欢的汽车是丰田的人时查询这些数据,它就会返回这些数据

{

            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }
Run Code Online (Sandbox Code Playgroud)

结果是两个名称为ABC的记录.如何仅选择不同的文档?我想得到的结果只是这个

{
                "name" : "ABC",
                "favorite_cars" : [ "ferrari","toyota" ]
              }
Run Code Online (Sandbox Code Playgroud)

这是我的查询

{
    "fuzzy_like_this_field" : {
        "favorite_cars" : {
            "like_text" : "toyota",
            "max_query_terms" : 12
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用ElasticSearch 1.0.0.使用java api客户端

JRL*_*JRL 21

您可以使用聚合消除重复项.对于术语聚合,结果将按一个字段分组,例如name,还提供字段的每个值的发生次数,并将按此计数(降序)对结果进行排序.

{
  "query": {
    "fuzzy_like_this_field": {
      "favorite_cars": {
        "like_text": "toyota",
        "max_query_terms": 12
      }
    }
  },
  "aggs": {
    "grouped_by_name": {
      "terms": {
        "field": "name",
        "size": 0
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

除此之外hits,结果还将包含带有计数buckets的唯一值:keydoc_count

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.19178301,
    "hits" : [ {
      "_index" : "pru",
      "_type" : "pru",
      "_id" : "vGkoVV5cR8SN3lvbWzLaFQ",
      "_score" : 0.19178301,
      "_source":{"name":"ABC","favorite_cars":["ferrari","toyota"]}
    }, {
      "_index" : "pru",
      "_type" : "pru",
      "_id" : "IdEbAcI6TM6oCVxCI_3fug",
      "_score" : 0.19178301,
      "_source":{"name":"ABC","favorite_cars":["ferrari","toyota"]}
    } ]
  },
  "aggregations" : {
    "grouped_by_name" : {
      "buckets" : [ {
        "key" : "abc",
        "doc_count" : 2
      } ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,由于重复消除和结果排序,使用聚合将是昂贵的.

  • PS:在ES 1.6中弃用了fuzzy_like_this_field https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-flt-field-query.html (2认同)

dar*_*dow 9

ElasticSearch不提供任何查询,您可以通过该查询根据字段值获取不同的文档.

理想情况下,您应该使用相同的类型ID索引相同的文档,因为ElasticSearch使用这两个内容为文档提供_uid唯一ID.唯一ID很重要,不仅因为它检测重复文档的方式,而且在任何修改的情况下更新同一文档而不是插入新文档.有关索引文档的更多信息,请阅读此内容.

但肯定有一个解决你的问题的方法.由于您使用的是java api客户端,因此您可以根据自己的字段值删除重复的文档.事实上,它使您可以更灵活地对从ES获得的响应执行自定义操作.

SearchResponse response = client.prepareSearch().execute().actionGet();
SearchHits hits = response.getHits();

Iterator<SearchHit> iterator = hits.iterator();
Map<String, SearchHit> distinctObjects = new HashMap<String,SearchHit>();
while (iterator.hasNext()) {
    SearchHit searchHit = (SearchHit) iterator.next();
    Map<String, Object> source = searchHit.getSource();
    if(source.get("name") != null){
        distinctObjects.put(source.get("name").toString(),source);
    }

} 
Run Code Online (Sandbox Code Playgroud)

因此,您将在地图中拥有唯一的searchHit对象的地图.

您还可以创建对象映射并使用它来代替SearchHit.

我希望这能解决你的问题.如果代码中有任何错误,请原谅我.这只是一个伪代码,可以让您了解如何解决问题.

谢谢

  • 这种方法使得处理分页变得困难。由于可以在每个页面上删除某些元素,因此可以关闭每个页面上的结果数量。 (2认同)