java - tutorial - ElasticSearch devuelve solo documentos con valores distintos
instalar elasticsearch (4)
ElasticSearch no proporciona ninguna consulta mediante la cual pueda obtener documentos distintos basados en un valor de campo.
Idealmente, debería haber indexado el mismo documento con el mismo tipo e id, ya que ElasticSearch utiliza estos dos elementos para proporcionar un id único de _uid a un documento. La identificación única es importante no solo por su forma de detectar documentos duplicados sino también por actualizar el mismo documento en caso de cualquier modificación en lugar de insertar una nueva. Para obtener más información sobre la indexación de documentos, puede leer esto .
Pero definitivamente hay una solución alternativa para su problema. Dado que está utilizando el cliente java api, puede eliminar los documentos duplicados en función de un valor de campo por su cuenta. De hecho, le da más flexibilidad para realizar operaciones personalizadas en las respuestas que recibe de 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);
}
}
Por lo tanto, tendrá un mapa de objetos searchHit únicos en su mapa.
También puede crear un mapeo de objetos y usarlo en lugar de SearchHit.
Espero que esto resuelva tu problema. Por favor, perdónenme si hay algún error en el código. Este es solo un código pseudo-ish para que comprenda cómo puede resolver su problema.
Gracias
Digamos que tengo esta información
{
"name" : "ABC",
"favorite_cars" : [ "ferrari","toyota" ]
}, {
"name" : "ABC",
"favorite_cars" : [ "ferrari","toyota" ]
}, {
"name" : "GEORGE",
"favorite_cars" : [ "honda","Hyundae" ]
}
Cada vez que consulto estos datos cuando busco personas cuyo vehículo favorito es toyota, devuelve estos datos
{
"name" : "ABC",
"favorite_cars" : [ "ferrari","toyota" ]
}, {
"name" : "ABC",
"favorite_cars" : [ "ferrari","toyota" ]
}
el resultado es Dos registros de con un nombre de ABC. ¿Cómo selecciono solo documentos distintos? El resultado que quiero obtener es solo esto
{
"name" : "ABC",
"favorite_cars" : [ "ferrari","toyota" ]
}
Aquí está mi consulta
{
"fuzzy_like_this_field" : {
"favorite_cars" : {
"like_text" : "toyota",
"max_query_terms" : 12
}
}
}
Estoy usando ElasticSearch 1.0.0. con el cliente java api
Puede eliminar duplicados usando agregaciones . Con la agregación de términos, los resultados se agruparán por un campo, por ejemplo, name
, que también proporcionará un recuento de las ocurrencias de cada valor del campo, y clasificará los resultados por este conteo (descendente).
{
"query": {
"fuzzy_like_this_field": {
"favorite_cars": {
"like_text": "toyota",
"max_query_terms": 12
}
}
},
"aggs": {
"grouped_by_name": {
"terms": {
"field": "name",
"size": 0
}
}
}
}
Además de los hits
, el resultado también contendrá los buckets
con los valores únicos en key
y con el recuento en 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
} ]
}
}
}
Tenga en cuenta que el uso de agregaciones será costoso debido a la eliminación duplicada y la clasificación de resultados.
Para un solo fragmento esto se puede manejar usando un filtro personalizado que también se ocupa de la paginación. Para manejar el caso de uso anterior, podemos usar el soporte de script de la siguiente manera:
- Definir un filtro de script personalizado. Para esta discusión asuma que se llama AcceptDistinctDocumentScriptFilter
- Este filtro personalizado toma una lista de claves principales como entrada.
- Estas claves primarias son los campos cuyos valores se usarán para determinar la unicidad de los registros.
- Ahora, en lugar de usar la agregación, utilizamos la solicitud de búsqueda normal y pasamos el filtro de script personalizado a la solicitud.
- Si la búsqueda ya tiene definido un filtro / criterio de consulta, añada el filtro personalizado utilizando el operador AND lógico.
- A continuación se muestra un ejemplo que utiliza una pseudo sintaxis si la solicitud es: select * from myindex where file_hash = ''hash_value'' y luego agrega el filtro personalizado como:
select * from myindex donde file_hash = ''hash_value'' AND AcceptDistinctDocumentScriptFilter (params = [''file_name'', ''file_folder''])
Para la búsqueda distribuida esto es complicado y necesita un complemento para enganchar en la fase de CONSULTA. Más detalles aquí .
@JRL es casi correcto. Necesitarás una agregación en tu consulta. Esto le dará una lista de los mejores 10000 "favorite_cars" en su objeto ordenado por ocurrencia.
{
"query":{ "match_all":{ } },
"size":0,
"Distinct" : {
"Cars" : {
"terms" : { "field" : "favorite_cars", "order": { "_count": "desc"}, "size":10000 }
}
}
}
También vale la pena señalar que va a querer que su campo "favorite_car" no se analice para obtener "McLaren F1" en lugar de "McLaren", "F1".
"favorite_car": {
"type": "string",
"index": "not_analyzed"
}