ElasticSearch - ส่งคืนค่าที่ไม่ซ้ำกัน


122

ฉันจะรับค่าของทั้งหมดlanguagesจากบันทึกและทำให้ไม่ซ้ำกันได้อย่างไร

ประวัติ

PUT items/1
{ "language" : 10 }

PUT items/2
{ "language" : 11 }

PUT items/3
{ "language" : 10 }

สอบถาม

GET items/_search
{ ... }

# => Expected Response
[10, 11]

ความช่วยเหลือใด ๆ จะดีมาก


1
fields: [languages]จะให้เฉพาะค่าของฟิลด์ที่กำหนด แต่การทำให้ไม่ซ้ำกันอาจทำได้ง่ายกว่าในโค้ด แม้ว่าอาจจะมีการรวบรวมที่สะดวกซึ่งสามารถทำเพื่อคุณได้
Ashalynd

1
สำหรับผู้ที่ค้นคว้าหัวข้อนี้ยังมีการอภิปรายที่เป็นประโยชน์ที่นี่: ค้นหาค่าที่แตกต่างไม่ใช่จำนวนที่แตกต่างกันในการค้นหายางยืด
blong

คำตอบ:


165

คุณสามารถใช้การรวมเงื่อนไข

{
"size": 0,
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  "size" : 500 }
    }
}}

การค้นหาจะส่งคืนสิ่งที่ต้องการ:

{
"took" : 16,
"timed_out" : false,
"_shards" : {
  "total" : 2,
  "successful" : 2,
  "failed" : 0
},
"hits" : {
"total" : 1000000,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
  "langs" : {
    "buckets" : [ {
      "key" : "10",
      "doc_count" : 244812
    }, {
      "key" : "11",
      "doc_count" : 136794

    }, {
      "key" : "12",
      "doc_count" : 32312
       } ]
    }
  }
}

sizeพารามิเตอร์ภายในระบุการรวมจำนวนสูงสุดของข้อตกลงที่จะรวมอยู่ในผลสรุปรวม หากคุณต้องการผลลัพธ์ทั้งหมดให้ตั้งค่านี้เป็นค่าที่มากกว่าจำนวนคำศัพท์เฉพาะในข้อมูลของคุณ


2
"fields" : ["language"]นำผลลัพธ์เดิมกลับมา คุณสามารถขยายคำตอบของคุณเพื่อดูว่ากรอบการรวมสามารถคืนค่าภาษาได้หรือไม่ #=> [10, 11, 10]
ChuckJHardy

1
@CharlesJHardy มันไม่ได้ผลเหมือนกัน ข้อมูลที่คุณกำลังค้นหาอยู่ภายใต้คีย์ "การรวม" ฉันแก้ไขคำตอบด้วยผลลัพธ์ตัวอย่าง คุณสามารถ / ควรตั้งค่า "size": 0 เพื่อที่จะไม่รวมเอกสารใด ๆ ให้รวมเฉพาะผลลัพธ์ที่รวบรวมไว้ที่คุณต้องการเท่านั้น
Anton

1
โปรดทราบว่าหากคุณมีค่าที่เป็นไปได้จำนวนมากlanguageคุณอาจต้องการเพิ่มsize=0และshard_size=0เพื่อให้แน่ใจว่าคุณได้รับค่าทั้งหมด ดูelasticsearch.org/guide/en/elasticsearch/reference/current/…
Dror

3
ฉันคิดว่าคำตอบนี้ไม่ได้อยู่ที่ OP คำถามเดิมต้องการค่าที่แตกต่างไม่นับ ฉันพลาดอะไรไปรึเปล่า?
bhurlow

4
@BHBH คำตอบให้ค่าที่แตกต่างกัน ซึ่งเป็นค่า "คีย์" เช่น "10" "11" และ "12" (aggregations> langs> buckets> key ... )
Anton

9

Elasticsearch 1.1+ มีCardinality Aggregationซึ่งจะให้การนับเฉพาะแก่คุณ

โปรดทราบว่าจริงๆแล้วมันเป็นค่าประมาณและความแม่นยำอาจลดลงเมื่อใช้ชุดข้อมูลที่มีคาร์ดินาลิตี้สูง แต่โดยทั่วไปแล้วการทดสอบของฉันค่อนข้างแม่นยำ

คุณยังสามารถปรับความแม่นยำด้วยprecision_thresholdพารามิเตอร์ การแลกเปลี่ยนหรือแน่นอนคือการใช้หน่วยความจำ

กราฟจากเอกสารนี้แสดงให้เห็นว่าprecision_thresholdโอกาสในการขายที่สูงขึ้นไปสู่ผลลัพธ์ที่แม่นยำกว่ามากเพียงใด


ข้อผิดพลาดสัมพัทธ์เทียบกับเกณฑ์


2
Cardinality Aggregationรับประกันหรือไม่ว่าหากมีคำศัพท์คำนั้นจะปรากฏในผลลัพธ์ (โดยมีจำนวน> = 1) หรืออาจพลาดบางคำที่ปรากฏเพียงครั้งเดียวในชุดข้อมูลขนาดใหญ่?
ทำเครื่องหมาย

2
@ เครื่องหมายขึ้นอยู่กับเกณฑ์ความแม่นยำที่คุณตั้งไว้ ยิ่งเกณฑ์สูงโอกาสที่จะพลาดก็ยิ่งน้อยลง โปรดทราบว่ามีขีด จำกัด 40,000 ในการตั้งค่าเกณฑ์ความแม่นยำ ซึ่งหมายความว่าชุดข้อมูลที่สูงกว่านั้นจะมีการประมาณและด้วยเหตุนี้จึงอาจพลาดค่าเดียว
Sundar

12
ฉันเชื่อว่าคำตอบนี้ผิด การรวมคาร์ดินาลิตี้เป็นเครื่องมือที่ยอดเยี่ยม อย่างไรก็ตามภารกิจคือการดึงคำศัพท์ด้วยตัวเองไม่ได้ประมาณจำนวนคำศัพท์ที่แตกต่างกัน
Anton

4

ฉันกำลังมองหาวิธีแก้ปัญหาแบบนี้ให้กับตัวเองเช่นกัน ผมพบว่าการอ้างอิงในการรวมข้อตกลง

ดังนั้นตามต่อไปนี้เป็นวิธีแก้ปัญหาที่เหมาะสม

{
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  
                    "size" : 500 }
    }
}}

แต่ถ้าคุณพบข้อผิดพลาดต่อไปนี้:

"error": {
        "root_cause": [
            {
                "type": "illegal_argument_exception",
                "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [fastest_method] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
            }
        ]}

ในกรณีนี้คุณต้องเพิ่ม " KEYWORD " ในคำขอดังต่อไปนี้:

   {
    "aggs" : {
        "langs" : {
            "terms" : { "field" : "language.keyword",  
                        "size" : 500 }
        }
    }}

4

หากคุณต้องการรับเอกสารแรกสำหรับlanguageค่าที่ไม่ซ้ำกันของแต่ละฟิลด์คุณสามารถทำได้:

{
 "query": {
    "match_all": {
    }
  },
  "collapse": {
    "field": "language.keyword",
    "inner_hits": {
    "name": "latest",
      "size": 1
    }
  }
}

1

หากคุณต้องการที่จะได้รับค่าที่ไม่ซ้ำกันทั้งหมดโดยไม่ต้องประมาณใด ๆ หรือการตั้งค่าจำนวนมายากล ( size: 500) จากนั้นใช้AGGREGATION คอมโพสิต (ES 6.5+)

จากเอกสารอย่างเป็นทางการ :

"หากคุณต้องการดึงคำทั้งหมดหรือการรวมคำทั้งหมดในการรวมคำที่ซ้อนกันคุณควรใช้ COMPOSITE AGGREGATIONซึ่งอนุญาตให้มีการแบ่งหน้าสำหรับคำที่เป็นไปได้ทั้งหมดแทนที่จะกำหนดขนาดที่มากกว่าจำนวนคาร์ดินาลลิตี้ของฟิลด์ในการรวมคำ การรวมคำมีขึ้นเพื่อส่งคืนคำหลักและไม่อนุญาตให้มีการแบ่งหน้า "

ตัวอย่างการนำไปใช้งานใน JavaScript:

const ITEMS_PER_PAGE = 1000;

const body =  {
    "size": 0, // Returning only aggregation results: https://www.elastic.co/guide/en/elasticsearch/reference/current/returning-only-agg-results.html
    "aggs" : {
        "langs": {
            "composite" : {
                "size": ITEMS_PER_PAGE,
                "sources" : [
                    { "language": { "terms" : { "field": "language" } } }
                ]
            }
        }
     }
};

const uniqueLanguages = [];

while (true) {
  const result = await es.search(body);

  const currentUniqueLangs = result.aggregations.langs.buckets.map(bucket => bucket.key);

  uniqueLanguages.push(...currentUniqueLangs);

  const after = result.aggregations.langs.after_key;

  if (after) {
      // continue paginating unique items
      body.aggs.langs.composite.after = after;
  } else {
      break;
  }
}

console.log(uniqueLanguages);

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.