ElasticSearch - Devuelve valores únicos


122

¿Cómo obtendría los valores de todos languageslos registros y los haría únicos?

Registros

PUT items/1
{ "language" : 10 }

PUT items/2
{ "language" : 11 }

PUT items/3
{ "language" : 10 }

Consulta

GET items/_search
{ ... }

# => Expected Response
[10, 11]

Cualquier ayuda sería genial.


1
fields: [languages]dará solo los valores del campo dado, pero hacerlos únicos es probablemente más fácil de hacer en código. Aunque puede haber una agregación útil que puede hacerlo por usted.
Ashalynd

1
Para aquellos que investigan este tema, también hay una discusión útil aquí: encontrar valores distintos, no recuentos distintos en Elasticsearch
blong

Respuestas:


165

Puede usar los términos agregación .

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

Una búsqueda devolverá algo como:

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

El sizeparámetro dentro de la agregación especifica el número máximo de términos para incluir en el resultado de la agregación. Si necesita todos los resultados, configúrelo en un valor que sea mayor que la cantidad de términos únicos en sus datos.


2
"fields" : ["language"]trae de vuelta el mismo resultado. ¿Puede ampliar su respuesta para ver si el marco de agregación puede devolver solo los valores del idioma? #=> [10, 11, 10]
ChuckJHardy

1
@CharlesJHardy, no tiene el mismo resultado. Los datos que está buscando están bajo la clave "agregaciones". Edité mi respuesta con un resultado de ejemplo. También puede / debe establecer "tamaño": 0, para no incluir ninguno de los documentos, solo los resultados agregados que desea.
Anton

1
Tenga en cuenta que si tiene muchos valores posibles, languagees posible que desee agregar size=0y shard_size=0, para asegurarse de obtener todos los valores. Ver elasticsearch.org/guide/en/elasticsearch/reference/current/…
Dror

3
Creo que esta respuesta no aborda el OP. La pregunta original quiere valores distintos , no cuenta. ¿Me estoy perdiendo de algo?
bhurlow

44
@BHBH, la respuesta proporciona los valores distintos. Son los valores "clave", es decir, "10", "11" y "12". (agregaciones> langs> cubos> clave ...)
Anton

9

Elasticsearch 1.1+ tiene la agregación de cardinalidad que le dará un recuento único

Tenga en cuenta que en realidad es una aproximación y la precisión puede disminuir con los conjuntos de datos de alta cardinalidad, pero en general es bastante precisa en mis pruebas.

También puede ajustar la precisión con el precision_thresholdparámetro. La compensación, o curso, es el uso de memoria.

Este gráfico de los documentos muestra cómo un valor más alto precision_thresholdconduce a resultados mucho más precisos.


Error relativo vs umbral


2
¿La agregación de cardinalidad garantiza que si existe un término, aparecerá en los resultados (con un recuento> = 1)? ¿O podría pasar por alto algunos términos que solo aparecen una vez en un gran conjunto de datos?
marca el

2
@mark depende del umbral de precisión que establezca. Cuanto mayor sea el umbral, menor será la posibilidad de que se pierda. Tenga en cuenta que hay un límite de 40,000 en la configuración del umbral de precisión. Lo que significa que, un conjunto de datos más alto que eso, habrá una estimación y, por lo tanto, puede perderse el valor único
Sundar

12
Creo que esta respuesta es incorrecta. La agregación de cardinalidad es una excelente herramienta. Sin embargo, la tarea era recuperar los términos en sí mismos, no estimar cuántos términos diferentes hay.
Anton

4

si desea obtener el primer documento para cada languagevalor único de campo, puede hacer esto:

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

3

Estoy buscando este tipo de solución para mí también. Encontré referencia en términos de agregación .

Entonces, de acuerdo con lo siguiente, es la solución adecuada.

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

Pero si te encuentras con el siguiente error:

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

En ese caso, debe agregar " PALABRA CLAVE " en la solicitud, como se indica a continuación:

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

1

Si desea obtener todos los valores únicos sin ninguna aproximación o establecer un número mágico ( size: 500), use AGREGACIÓN COMPUESTA (ES 6.5+) .

De la documentación oficial :

"Si desea recuperar todos los términos o todas las combinaciones de términos en una agregación de términos anidados , debe usar la AGREGACIÓN COMPUESTA que permite paginar sobre todos los términos posibles en lugar de establecer un tamaño mayor que la cardinalidad del campo en la agregación de términos. la agregación de términos debe devolver los términos principales y no permite la paginación ".

Ejemplo de implementación en 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);

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.