簡體   English   中英

ElasticSearch僅返回具有不同值的文檔

[英]ElasticSearch returning only documents with distinct value

假設我有這個給定的數據

{
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "GEORGE",
            "favorite_cars" : [ "honda","Hyundae" ]
          }

每當我在搜索最喜歡的汽車是豐田的人時查詢這些數據,它就會返回這些數據

{

            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }

結果是兩個名稱為ABC的記錄。 如何僅選擇不同的文檔? 我想得到的結果只是這個

{
                "name" : "ABC",
                "favorite_cars" : [ "ferrari","toyota" ]
              }

這是我的查詢

{
    "fuzzy_like_this_field" : {
        "favorite_cars" : {
            "like_text" : "toyota",
            "max_query_terms" : 12
        }
    }
}

我正在使用ElasticSearch 1.0.0。 使用java api客戶端

您可以使用聚合消除重復項。 對於術語聚合 ,結果將按一個字段(例如name進行分組,同時提供字段每個值的發生次數,並按此計數(降序)對結果進行排序。

{
  "query": {
    "fuzzy_like_this_field": {
      "favorite_cars": {
        "like_text": "toyota",
        "max_query_terms": 12
      }
    }
  },
  "aggs": {
    "grouped_by_name": {
      "terms": {
        "field": "name",
        "size": 0
      }
    }
  }
}

除了hits ,結果還將包含具有key唯一值的buckets以及doc_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
      } ]
    }
  }
}

請注意,由於重復消除和結果排序,使用聚合將是昂貴的。

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);
    }

} 

因此,您將在地圖中擁有唯一的searchHit對象的地圖。

您還可以創建對象映射並使用它來代替SearchHit。

我希望這能解決你的問題。 如果代碼中有任何錯誤,請原諒我。 這只是一個偽代碼,可以讓您了解如何解決問題。

謝謝

@JRL幾乎是正確的。 您需要在查詢中使用聚合。 這將為您提供按出現順序排列的對象中前10000名“favorite_cars”的列表。

{
    "query":{ "match_all":{ } },
    "size":0,
    "Distinct" : {
        "Cars" : {
            "terms" : { "field" : "favorite_cars", "order": { "_count": "desc"}, "size":10000 }
         }
    }
}

同樣值得注意的是,你不希望你的“favorite_car”字段被分析以獲得“邁凱輪F1”而不是“邁凱輪”,“F1”。

"favorite_car": {
    "type": "string",
    "index": "not_analyzed"
}

對於單個分片,可以使用自定義過濾器來處理,該過濾器也可以處理分頁。 要處理上述用例,我們可以使用腳本支持,如下所示:

  • 定義自定義腳本過濾器。 對於此討論,假設它被稱為AcceptDistinctDocumentScriptFilter
  • 此自定義篩選器將主鍵列表作為輸入。
  • 這些主鍵是其值將用於確定記錄唯一性的字段。
  • 現在,我們使用普通搜索請求而不是使用聚合,並將自定義腳本過濾器傳遞給請求。
  • 如果搜索已經定義了過濾器\\查詢條件,則使用邏輯AND運算符附加自定義過濾器。
  • 以下是使用偽語法的示例,如果請求是:select * from myindex where file_hash ='hash_value',則將自定義過濾器附加為:
    select * from myindex where file_hash ='hash_value'和AcceptDistinctDocumentScriptFilter(params = ['file_name','file_folder'])

對於分布式搜索,這很棘手,需要插件才能掛鈎到QUERY階段。 更多細節在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM