ElasticSearch - Benzersiz Değerleri Döndür


122

languagesKayıtlardan tüm değerlerini nasıl alır ve onları benzersiz kılardım.

kayıtlar

PUT items/1
{ "language" : 10 }

PUT items/2
{ "language" : 11 }

PUT items/3
{ "language" : 10 }

Sorgu

GET items/_search
{ ... }

# => Expected Response
[10, 11]

Herhangi bir yardım harika olur.


1
fields: [languages]yalnızca verilen alanın değerlerini verir, ancak onları benzersiz kılmak muhtemelen kodda yapmak daha kolaydır. Yine de bunu sizin için yapabilecek kullanışlı bir toplama olabilir.
— Ashalynd

1
Bu konuyu araştıranlar için, burada da yararlı bir tartışma var:
— Elasticsearch'te

Yanıtlar:


165

Toplama terimlerini kullanabilirsiniz .

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

Bir arama şöyle bir sonuç verecektir:

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

sizeAgregasyon belirlediği içindeki parametre terimi en fazla agregasyon sonucu dahil etmek. Tüm sonuçlara ihtiyacınız varsa, bunu verilerinizdeki benzersiz terimlerin sayısından daha büyük bir değere ayarlayın.


2
"fields" : ["language"]aynı sonucu geri getiriyor. Toplama çerçevesinin yalnızca dil değerlerini döndüreceğini görmek için yanıtınızı genişletebilir misiniz? #=> [10, 11, 10]
— ChuckJHardy

1
@CharlesJHardy, aynı sonuca sahip değil. Aradığınız veriler "toplamalar" anahtarının altındadır. Cevabımı örnek bir sonuçla düzenledim. Ayrıca herhangi bir belgeyi dahil etmemek için sadece istediğiniz toplu sonuçları dahil etmek için "size": 0 değerini ayarlayabilirsiniz / ayarlamalısınız.
— Anton

1
Olası birçok değeriniz languagevarsa , tüm değerleri aldığınızdan emin olmak için size=0ve eklemek isteyebileceğinizi shard_size=0unutmayın . Bkz elasticsearch.org/guide/en/elasticsearch/reference/current/...
— Dror

3
Sanırım bu cevap OP'ye değinmiyor. Orijinal soru, sayılmayan farklı değerler istiyor . Bir şey mi kaçırıyorum?
— bhurlow

4
@BHBH, Cevap farklı değerler sağlıyor. Bunlar "anahtar" değerleridir, yani "10", "11" ve "12". (toplamalar> diller> kovalar> anahtar ...)
— Anton

9

Elasticsearch 1.1+, size benzersiz bir sayı verecek Cardinality Aggregation'a sahiptir

Bunun aslında bir tahmin olduğunu ve doğruluğun yüksek kardinalite veri kümeleri ile azalabileceğini unutmayın, ancak testlerimde genellikle oldukça doğrudur.

Doğruluğu precision_thresholdparametre ile de ayarlayabilirsiniz . Takas veya tabii ki bellek kullanımıdır.

Dokümanlardan alınan bu grafik, daha yüksek bir değerin nasıl precision_thresholdçok daha doğru sonuçlara yol açtığını göstermektedir.


Eşik vs bağıl hata


2
Cardinality Aggregation , bir terim varsa sonuçlarda görüneceğini garanti ediyor mu (sayı> = 1 ile)? Veya büyük bir veri kümesinde yalnızca bir kez görünen bazı terimleri gözden kaçırabilir mi?
— mark

2
@mark ayarladığınız hassasiyet eşiğine bağlıdır. Eşik ne kadar yüksekse ıskalama şansı o kadar azdır. Hassas eşik ayarında 40.000'lik bir sınır olduğunu unutmayın. Bu, bundan daha yüksek bir veri kümesinin bir tahmin olacağı ve dolayısıyla tek değerin gözden
— kaçabileceği

12
Bu cevabın yanlış olduğuna inanıyorum. Kardinalite toplama mükemmel bir araçtır. Bununla birlikte, görev, kaç farklı terim olduğunu tahmin etmek değil, terimleri kendileri almaktı.
— Anton

4

Ben de kendim için bu tür bir çözüm arıyorum. Toplama açısından referans buldum .

Dolayısıyla, buna göre doğru çözüm şudur.

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

Ancak aşağıdaki hatayla karşılaştıysanız:

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

Bu durumda, aşağıdaki gibi isteğe " KEYWORD " eklemeniz gerekir :

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

4

her languagealan benzersiz değeri için ilk belgeyi almak istiyorsanız , bunu yapabilirsiniz:

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

1

Tüm benzersiz değerleri herhangi bir yaklaşım olmadan veya sihirli bir sayı ( size: 500) belirlemeden elde etmek istiyorsanız , COMPOSITE AGREGATION (ES 6.5+) kullanın .

Gönderen Resmi belgelerin :

"İç içe geçmiş bir terim kümesindeki tüm terimleri veya tüm terim kombinasyonlarını almak istiyorsanız , terimler toplamasında alanın öneminden daha büyük bir boyut ayarlamak yerine olası tüm terimleri sayfalandırmaya izin veren KOMPOZİT TOPLAMAYI kullanmalısınız . terim toplama, en üst terimleri döndürmek içindir ve sayfalandırmaya izin vermez. "

JavaScript'te uygulama örneği:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.