elasticsearch bool query combine must with OR

181

Actualmente estoy tratando de migrar una aplicación basada en solr a elasticsearch.

Tengo esta consulta lucene

(( 
    name:(+foo +bar) 
    OR info:(+foo +bar) 
)) AND state:(1) AND (has_image:(0) OR has_image:(1)^100)

Por lo que entiendo, esta es una combinación de cláusulas DEBE combinadas con OR booleano:

"Obtenga todos los documentos que contengan (foo AND bar en el nombre) OR (foo AND bar en la información). Después de eso, el filtro resulta por estado de condición = 1 y aumenta los documentos que tienen una imagen".

He estado tratando de usar una consulta bool con DEBE, pero no puedo obtener OR booleana en cláusulas must. Esto es lo que tengo:

GET /test/object/_search
{
  "from": 0,
  "size": 20,
  "sort": {
    "_score": "desc"
  },
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "foo"
          }
        },
        {
          "match": {
            "name": "bar"
          }
        }
      ],
      "must_not": [],
      "should": [
        {
          "match": {
            "has_image": {
              "query": 1,
              "boost": 100
            }
          }
        }
      ]
    }
  }
}

Como puede ver, faltan condiciones para "información".

¿Alguien tiene una solución?

Muchas gracias.

** ACTUALIZACIÓN **

He actualizado mi consulta de Elasticsearch y me he deshecho de esa puntuación de función. Mi problema base todavía existe.

Jesse
fuente
1
Hay una buena documentación en la combinación de Elasticsearch consultas aquí: elastic.co/guide/en/elasticsearch/guide/current/...
Mr.Coffee

Respuestas:

426
  • O se escribe debe
  • Y se deletrea debe
  • NOR se escribe should_not

Ejemplo:

Desea ver todos los elementos que son (redondos Y (rojo O azul)):

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {"shape": "round"}
                },
                {
                    "bool": {
                        "should": [
                            {"term": {"color": "red"}},
                            {"term": {"color": "blue"}}
                        ]
                    }
                }
            ]
        }
    }
}

También puede hacer versiones más complejas de OR, por ejemplo, si desea hacer coincidir al menos 3 de 5, puede especificar 5 opciones en "debería" y establecer un "mínimo_deberinto" de 3.

Gracias a Glen Thompson y Sebastialonso por encontrar dónde mi anidación no estaba del todo bien antes.

Gracias también a Fatmajk por señalar que "término" se convierte en "coincidencia" en ElasticSearch 6.

Daniel Fackrell
fuente
2
¿Llevarlo shouldal nivel superior boole incluir una minimum_should_match: 1obra?
Sid
18
Cuando pruebo este ejemplo vuelvo [term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]. ¿De alguna manera esto depende de la versión?
DanneJ
26
¿Por qué no agregan un ejemplo tan simple y una explicación en los documentos? El ejemplo de la documentación es muy confuso.
Nikhil Owalekar
21
Después de 6 meses, leyendo toda la documentación de Elastic, esta es la primera vez que entiendo completamente cómo implementar la lógica booleana. La documentación oficial carece de claridad en mi opinión.
Sebastialonso
3
@Amir ¿Qué imprecisiones puedo limpiar para ti? En el contexto que se muestra arriba, el valor predeterminado minimum_shouldes 1, y envolviendo eso boolresulta en que ese grupo sea verdadero si al menos un elemento coincide, falso si ninguno coincide. Mi motivación para crear esta respuesta fue que estaba resolviendo exactamente este tipo de problema, y ​​la documentación disponible e incluso las respuestas que pude encontrar en sitios como este fueron inútiles en el mejor de los casos, así que seguí investigando hasta que sentí que tenía una comprensión bastante sólida. de lo que estaba pasando. Agradezco cualquier sugerencia constructiva sobre cómo puedo mejorar aún más la respuesta.
Daniel Fackrell
69

Finalmente logré crear una consulta que hace exactamente lo que quería tener:

Una consulta booleana anidada filtrada. No estoy seguro de por qué esto no está documentado. Tal vez alguien aquí puede decirme?

Aquí está la consulta:

GET /test/object/_search
{
  "from": 0,
  "size": 20,
  "sort": {
    "_score": "desc"
  },
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "term": {
                "state": 1
              }
            }
          ]
        }
      },
      "query": {
        "bool": {
          "should": [
            {
              "bool": {
                "must": [
                  {
                    "match": {
                      "name": "foo"
                    }
                  },
                  {
                    "match": {
                      "name": "bar"
                    }
                  }
                ],
                "should": [
                  {
                    "match": {
                      "has_image": {
                        "query": 1,
                        "boost": 100
                      }
                    }
                  }
                ]
              }
            },
            {
              "bool": {
                "must": [
                  {
                    "match": {
                      "info": "foo"
                    }
                  },
                  {
                    "match": {
                      "info": "bar"
                    }
                  }
                ],
                "should": [
                  {
                    "match": {
                      "has_image": {
                        "query": 1,
                        "boost": 100
                      }
                    }
                  }
                ]
              }
            }
          ],
          "minimum_should_match": 1
        }
      }    
    }
  }
}

En pseudo-SQL:

SELECT * FROM /test/object
WHERE 
    ((name=foo AND name=bar) OR (info=foo AND info=bar))
AND state=1

Tenga en cuenta que depende del análisis de campo de su documento y las asignaciones de cómo se maneja internamente name = foo. Esto puede variar de un comportamiento difuso a estricto.

"minimum_should_match": 1 dice que al menos una de las declaraciones debe ser verdadera.

Estas declaraciones significan que cada vez que hay un documento en el conjunto de resultados que contiene has_image: 1 se ve reforzado por el factor 100. Esto cambia el orden de los resultados.

"should": [
  {
    "match": {
      "has_image": {
        "query": 1,
        "boost": 100
      }
    }
   }
 ]

Que se diviertan chicos :)

Jesse
fuente
28
Santo cielo. ¿Alguien tiene una solución mejor? Gracias por publicar esto, pero eso es absolutamente demasiada complejidad para lograr un OR lógico en una consulta.
nackjicholson
gracias, me salvaste el día)
cubbiu
3
Esta consulta no solo es innecesariamente larga, sino que utiliza una sintaxis obsoleta. La respuesta de @ daniel-fackrell debería ser la aceptada.
Eric Alford
44
@EricAlford Esta respuesta de 2015 se basa en una versión anterior de ES. Siéntase libre de proporcionar una mejor solución.
Jesse
1
Idea: tomar el control / bifurcar ElasticSearch, reescribirlo de una manera fácil de usar, agregarle un lenguaje de consulta simple, ¡GANE! Solo necesitamos fondos. ¡Estoy dentro! Quién más ?
Sliq
16

Así es como puede anidar múltiples consultas bool en una consulta bool externa usando Kibana,

bool indica que estamos usando boolean

must es para AND

debería es para OR

GET my_inedx/my_type/_search
{
    "query" : {
       "bool": {             //bool indicates we are using boolean operator
            "must" : [       //must is for **AND**
                 {
                   "match" : {
                         "description" : "some text"  
                     }
                 },
                 {
                    "match" :{
                          "type" : "some Type"
                     }
                 },
                 {
                    "bool" : {          //here its a nested boolean query
                          "should" : [  //should is for **OR**
                                 {
                                   "match" : {
                                       //ur query
                                  }
                                 },
                                 { 
                                    "match" : {} 
                                 }     
                               ]
                          }
                 }
             ]
        }
    }
}

Así es como puede anidar una consulta en ES

Hay más tipos en "bool" como -

  1. Filtrar

  2. no debe

niranjan harpale
fuente
Su respuesta es exactamente correcta, pero es un poco torpe, es una pequeña sugerencia para usted si lo desea: debe editarla correctamente. Probablemente te da más como en esta respuesta :) Que tengas un buen día.
Dhwanil Patel
6

Recientemente tuve que resolver este problema también, y después de MUCHA prueba y error se me ocurrió esto (en PHP, pero se asigna directamente al DSL):

'query' => [
    'bool' => [
        'should' => [
            ['prefix' => ['name_first' => $query]],
            ['prefix' => ['name_last' => $query]],
            ['prefix' => ['phone' => $query]],
            ['prefix' => ['email' => $query]],
            [
                'multi_match' => [
                    'query' => $query,
                    'type' => 'cross_fields',
                    'operator' => 'and',
                    'fields' => ['name_first', 'name_last']
                ]
            ]
        ],
        'minimum_should_match' => 1,
        'filter' => [
            ['term' => ['state' => 'active']],
            ['term' => ['company_id' => $companyId]]
        ]
    ]
]

Lo que se asigna a algo como esto en SQL:

SELECT * from <index> 
WHERE (
    name_first LIKE '<query>%' OR
    name_last LIKE '<query>%' OR
    phone LIKE  '<query>%' OR
    email LIKE '<query>%'
)
AND state = 'active'
AND company_id = <query>

La clave de todo esto es la minimum_should_matchconfiguración. Sin esto, el filtertotalmente anula el should.

¡Espero que esto ayude a alguien!

Benjamin Dowson
fuente
0
$filterQuery = $this->queryFactory->create(QueryInterface::TYPE_BOOL, ['must' => $queries,'should'=>$queriesGeo]);

En mustlo que necesita para agregar la matriz condición de consulta que desea trabajar con ANDy en shouldlo que necesita para agregar la condición de consulta que desea trabajar con OR.

Puede verificar esto: https://github.com/Smile-SA/elasticsuite/issues/972

Alakh Kumar
fuente
0

Si estaba usando el analizador de consultas predeterminado de Solr o Lucene, casi siempre puede ponerlo en una consulta de cadena de consulta:

POST test/_search
{
  "query": {
    "query_string": {
      "query": "(( name:(+foo +bar) OR info:(+foo +bar)  )) AND state:(1) AND (has_image:(0) OR has_image:(1)^100)"
    }
  }
}

Dicho esto, es posible que desee utilizar un consulta booleana , como la que ya publicó, o incluso una combinación de las dos.

Radu Gheorghe
fuente