Tìm kiếm đàn hồi - Trả lại giá trị duy nhất


122

Làm cách nào để lấy các giá trị của tất cả languagescác bản ghi và làm cho chúng trở thành duy nhất.

Hồ sơ

PUT items/1
{ "language" : 10 }

PUT items/2
{ "language" : 11 }

PUT items/3
{ "language" : 10 }

Truy vấn

GET items/_search
{ ... }

# => Expected Response
[10, 11]

Bất kỳ sự trợ giúp nào đều sẽ là tuyệt vời.


1
fields: [languages]sẽ chỉ cung cấp các giá trị của trường đã cho, nhưng làm cho chúng là duy nhất có lẽ dễ thực hiện hơn trong mã. Mặc dù có thể có một tập hợp hữu ích có thể làm điều đó cho bạn.
Ashalynd

1
Đối với những người nghiên cứu chủ đề này, cũng có cuộc thảo luận hữu ích ở đây: Tìm giá trị khác biệt, đếm không phân biệt trong elasticsearch
Blong

Câu trả lời:


165

Bạn có thể sử dụng tổng hợp các điều khoản .

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

Một tìm kiếm sẽ trả về một cái gì đó như:

{
"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
       } ]
    }
  }
}

Các sizetham số trong phạm vi quy định cụ thể tập hợp số lượng tối đa điều kiện để đưa vào kết quả tập hợp. Nếu bạn cần tất cả các kết quả, hãy đặt giá trị này thành giá trị lớn hơn số lượng từ khóa duy nhất trong dữ liệu của bạn.


2
"fields" : ["language"]mang lại kết quả tương tự. Bạn có thể mở rộng câu trả lời của mình để xem liệu khung tổng hợp có thể chỉ trả về các giá trị ngôn ngữ không? #=> [10, 11, 10]
ChuckJHardy

1
@CharlesJHardy, nó không có cùng kết quả. Dữ liệu bạn đang tìm kiếm nằm trong khóa "tổng hợp". Tôi đã chỉnh sửa câu trả lời của mình với một kết quả ví dụ. Bạn cũng có thể / nên đặt "size": 0, để không bao gồm bất kỳ tài liệu nào, chỉ đưa vào các kết quả tổng hợp mà bạn muốn.
Anton

1
Lưu ý rằng nếu bạn có nhiều giá trị khả thi, languagebạn có thể muốn thêm size=0shard_size=0để đảm bảo rằng bạn nhận được tất cả các giá trị. Xem elasticsearch.org/guide/en/elasticsearch/reference/current/...
Dror

3
Tôi nghĩ câu trả lời này không đề cập đến OP. Câu hỏi ban đầu muốn các giá trị khác biệt không được tính. Tui bỏ lỡ điều gì vậy?
bhurlow

4
@BHBH, Câu trả lời cung cấp các giá trị khác biệt. Chúng là các giá trị "khóa", tức là "10", "11" và "12". (tổng hợp> langs> bucket> key ...)
Anton

9

Elasticsearch 1.1+ có Tổng hợp số lượng sẽ cung cấp cho bạn một số lượng duy nhất

Lưu ý rằng nó thực sự là một con số gần đúng và độ chính xác có thể giảm đi với các bộ dữ liệu có bản số cao, nhưng nhìn chung nó khá chính xác trong thử nghiệm của tôi.

Bạn cũng có thể điều chỉnh độ chính xác với precision_thresholdtham số. Sự đánh đổi, hay tất nhiên, là sử dụng bộ nhớ.

Biểu đồ này từ tài liệu cho thấy giá trị cao hơn precision_thresholddẫn đến kết quả chính xác hơn nhiều như thế nào .


Lỗi tương đối so với ngưỡng


2
Liệu Cardinality Aggregation đảm bảo rằng nếu một thuật ngữ tồn tại, sau đó nó sẽ xuất hiện trong kết quả (với một số lượng> = 1)? Hoặc nó có thể bỏ sót một số thuật ngữ chỉ xuất hiện một lần trong một tập dữ liệu lớn?
đánh dấu

2
@ đánh dấu nó tùy thuộc vào ngưỡng chính xác mà bạn đặt. Ngưỡng càng cao, cơ hội bỏ lỡ càng ít. Lưu ý rằng có giới hạn 40.000 trong cài đặt ngưỡng chính xác. Những phương tiện, một tập dữ liệu cao hơn, sẽ có một ước tính và do đó giá trị duy nhất có thể được bỏ qua
Sundar

12
Tôi tin rằng câu trả lời này là sai. Việc tổng hợp bản số là một công cụ tuyệt vời. Tuy nhiên, nhiệm vụ là truy xuất chính các thuật ngữ chứ không phải ước tính xem có bao nhiêu thuật ngữ khác nhau.
Anton

4

nếu bạn muốn nhận tài liệu đầu tiên cho mỗi languagegiá trị duy nhất của trường, bạn có thể làm như sau:

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

3

Tôi cũng đang tìm kiếm loại giải pháp cho chính mình. Tôi tìm thấy tài liệu tham khảo trong tổng hợp các điều khoản .

Vì vậy, theo đó sau đây là giải pháp thích hợp.

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

Nhưng nếu bạn gặp phải lỗi sau:

"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."
            }
        ]}

Trong trường hợp đó, bạn phải thêm " KEYWORD " trong yêu cầu, như sau:

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

1

Nếu bạn muốn nhận tất cả các giá trị duy nhất mà không có bất kỳ giá trị nào gần đúng hoặc đặt một số ma thuật ( size: 500), thì hãy sử dụng COMPOSITE AGGREGATION (ES 6.5+) .

Từ tài liệu chính thức :

"Nếu bạn muốn truy xuất tất cả các cụm từ hoặc tất cả các kết hợp các cụm từ trong một tổng hợp các cụm từ lồng nhau, bạn nên sử dụng COMPOSITE AGGREGATION cho phép phân trang trên tất cả các cụm từ có thể thay vì đặt kích thước lớn hơn số lượng của trường trong tổng hợp cụm từ. tổng hợp cụm từ có nghĩa là để trả lại các cụm từ hàng đầu và không cho phép phân trang. "

Ví dụ triển khai trong 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);

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.