![](/img/trans.png)
[英]How to get nested documents by field value from other documents (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"
}
對於單個分片,可以使用自定義過濾器來處理,該過濾器也可以處理分頁。 要處理上述用例,我們可以使用腳本支持,如下所示:
對於分布式搜索,這很棘手,需要插件才能掛鈎到QUERY階段。 更多細節在這里 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.