elasticsearch consulta bool combinar deve com OR

181

Atualmente, estou tentando migrar um aplicativo baseado em solr para elasticsearch.

Eu tenho essa consulta lucene

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

Tanto quanto eu entendo isso é uma combinação de cláusulas MUST combinadas com OR booleano:

"Obtenha todos os documentos que contêm (foo AND bar no nome) OR (foo AND bar no info). Depois desse filtro, resulta pelo estado de condição = 1 e aprimora os documentos que têm uma imagem."

Eu tenho tentado usar uma consulta bool com MUST, mas não consigo obter OR booleano em cláusulas must. Aqui está o que eu tenho:

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 você pode ver, as condições DEVE para "informações" estão ausentes.

Alguém tem uma solução?

Muito obrigado.

** ATUALIZAÇÃO **

Atualizei minha consulta elasticsearch e me livrei dessa pontuação de função. Meu problema básico ainda existe.

Jesse
fonte
1
Há uma boa documentação sobre combinando ElasticSearch consultas de aqui: elastic.co/guide/en/elasticsearch/guide/current/...
Mr.Coffee

Respostas:

426
  • OR é escrito deve
  • E é soletrado deve
  • NOR está escrito não deve

Exemplo:

Você deseja ver todos os itens que são (redondo E (vermelho OU azul)):

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

Você também pode executar versões mais complexas do OR, por exemplo, se desejar corresponder a pelo menos 3 de 5, você pode especificar 5 opções em "should" e definir um "minimum_should" de 3.

Agradeço a Glen Thompson e Sebastialonso por descobrirem onde meu ninho não estava bem antes.

Agradecemos também a Fatmajk por apontar que "termo" se torna "correspondência" no ElasticSearch 6.

Daniel Fackrell
fonte
2
Puxar o shouldpara o nível superior boole incluir um minimum_should_match: 1trabalho?
Sid
18
Quando tento este exemplo, volto [term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]. De alguma forma, isso depende da versão?
precisa saber é o seguinte
26
Por que eles não adicionam um exemplo e explicação tão simples nos documentos? O exemplo da documentação é muito confuso.
Nikhil Owalekar
21
Após 6 meses, lendo toda a documentação do Elastic, é a primeira vez que entendo completamente como implementar lógica booleana. A documentação oficial carece de clareza na minha opinião.
Sebastialonso
3
@Amir Que imprecisões posso limpar para você? No contexto mostrado acima, o padrão minimum_shouldé 1, e o boolagrupamento resulta em que esse grupo seja verdadeiro se pelo menos um item corresponder, falso se nenhum corresponder. Minha motivação para criar essa resposta foi que eu estava resolvendo exatamente esse tipo de problema, e a documentação disponível e até mesmo as respostas que eu encontrava em sites como esse não eram úteis na melhor das hipóteses, então continuei pesquisando até sentir que tinha uma compreensão bastante sólida do que estava acontecendo. Congratulo-me com quaisquer sugestões construtivas sobre como melhorar ainda mais a resposta.
Daniel Fackrell
69

Finalmente consegui criar uma consulta que faz exatamente o que eu queria:

Uma consulta booleana aninhada filtrada. Não sei por que isso não está documentado. Talvez alguém aqui possa me dizer?

Aqui está a 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
        }
      }    
    }
  }
}

Em pseudo-SQL:

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

Lembre-se de que depende da análise do campo do documento e dos mapeamentos de como name = foo é tratado internamente. Isso pode variar de um comportamento difuso a estrito.

"minimum_should_match": 1 diz que pelo menos uma das instruções should deve ser verdadeira.

Esta declaração significa que sempre que houver um documento no conjunto de resultados que contenha has_image: 1, ele será impulsionado pelo fator 100. Isso altera a ordem dos resultados.

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

Divirtam-se rapazes :)

Jesse
fonte
28
Puta merda. Alguém tem uma solução melhor? Obrigado por postar isso, mas isso é absolutamente complexo demais para obter um OR lógico em uma consulta.
Nackjicholson
thnx, você salvou o meu dia)
cubbiu 28/10
3
Essa consulta não é apenas desnecessariamente longa, está usando sintaxe obsoleta. A resposta de @ daniel-fackrell deve ser a aceita.
Eric Alford
4
@EricAlford Esta resposta de 2015 é baseada em uma versão anterior do ES. Sinta-se livre para fornecer uma solução melhor.
Jesse
1
Idéia: Assuma o controle / bifurque o ElasticSearch, reescreva-o de maneira amigável e adicione uma linguagem de consulta simples, WIN! Nós só precisamos de financiamento. Estou dentro! Quem mais ?
Sliq 30/09/19
16

É assim que você pode aninhar várias consultas bool em uma consulta externa usando o Kibana,

bool indica que estamos usando boolean

deve é para AND

deveria é para OU

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

É assim que você pode aninhar uma consulta no ES

Existem mais tipos em "bool", como -

  1. Filtro

  2. Não deve

niranjan harpale
fonte
Sua resposta é exatamente correta, mas é um pouco desajeitada, é uma pequena sugestão para você, se quiser - você deve editá-la corretamente. Provavelmente, isso lhe dará mais respostas nesta resposta :) Tenha um bom dia.
Dhwanil Patel 30/04
6

Recentemente, eu tive que resolver esse problema também e, após várias tentativas e erros, vim com isso (em PHP, mas mapeia diretamente para o 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]]
        ]
    ]
]

Que mapeia para algo assim no 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>

A chave em tudo isso é a minimum_should_matchconfiguração. Sem isso, filtersubstitui totalmente oshould .

Espero que isso ajude alguém!

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

Em mustvocê precisa adicionar a matriz de condições de consulta com a qual deseja trabalhar ANDe em shouldvocê precisa adicionar a condição de consulta com a qual deseja trabalharOR .

Você pode verificar isso: https://github.com/Smile-SA/elasticsuite/issues/972

alakh kumar
fonte
0

Se você estava usando o analisador de consulta padrão ou Lucene do Solr, pode sempre colocá-lo em uma consulta de string 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)"
    }
  }
}

Dito isto, convém usar uma consulta booleana , como a que você já postou, ou até mesmo uma combinação das duas.

Radu Gheorghe
fonte