web-dev-qa-db-fra.com

requête elasticsearch bool moissonneuse-batteuse doit avec OR

J'essaie actuellement de migrer une application basée sur solr vers elasticsearch.

J'ai cette requête lucene

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

Autant que je sache, il s’agit d’une combinaison de clauses MUST et de booléens OU: 

"Obtenez tous les documents contenant (nom foo AND bar) OR (foo AND bar in info). Après cela, filtrez les résultats en fonction de l’état de la condition = 1 et optimisez les documents contenant une image."

J'ai essayé d'utiliser une requête booléenne avec MUST mais je ne parviens pas à insérer un booléen OR dans les clauses must. Voici ce que j'ai

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

Comme vous pouvez le constater, les conditions MUST pour "info" sont manquantes.

Quelqu'un a-t-il une solution?

Merci beaucoup.

** METTRE À JOUR **

J'ai mis à jour ma requête elasticsearch et je me suis débarrassé de ce score de fonction. Mon problème de base existe toujours.

96
Jesse

J'ai finalement réussi à créer une requête qui fait exactement ce que je voulais avoir:

Une requête booléenne imbriquée filtrée . Je ne sais pas pourquoi cela n'est pas documenté. Peut-être que quelqu'un ici peut me le dire?

Voici la requête:

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

N'oubliez pas que cela dépend de l'analyse de votre champ de document et des mappages de la manière dont name = foo est géré en interne. Cela peut aller d'un comportement flou à un comportement strict.

"minimum_should_match": 1 dit, qu'au moins une des déclarations devrait être vraie.

Cette déclaration signifie que chaque fois qu'un document dans le jeu de résultats contient has_image: 1, il est multiplié par 100, ce qui modifie le classement des résultats.

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

Amusez-vous les gars :)

53
Jesse
  • OU est orthographié devrait
  • ET est orthographié must
  • NI est orthographié should_not

Exemple:

Vous voulez voir tous les éléments qui sont (rond ET (rouge OR bleu)):

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

Vous pouvez également créer des versions plus complexes de OR, par exemple si vous souhaitez en faire correspondre au moins 3 sur 5, vous pouvez spécifier 5 options sous "devrait" et définir un "minimum_should" de 3.

Merci à Glen Thompson et à Sebastialonso d’avoir trouvé où ma nidification n’était pas juste avant.

Merci également à Fatmajk pour avoir signalé que "terme" devient "match" dans ElasticSearch 6.

229
Daniel Fackrell

En utilisant ce qui précède, je reçois 

[term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]

Cela a fonctionné pour moi

Mise à jour pour Elasticsearch 5.6.4 +

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

ElasticSearch est vraiment horrible quand il s’agit de requêtes simples comme AND, OR ou IN. Cependant, vous pouvez utiliser la méthode intelligente et écrire votre requête en SQL, puis la convertir en syntaxe ElasticSearch avec cet excellent outil en ligne:

Convertisseur SQL en ElasticSearch

https://www.toolsbuzz.com/query-converter

Tu peux me remercier plus tard :)

10
Sliq

J'ai récemment eu à résoudre ce problème aussi, et après beaucoup d'essais et d'erreurs, je l'ai trouvé (en PHP, mais directement sur le 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]]
        ]
    ]
]

Ce qui correspond à quelque chose comme ça 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 clé dans tout cela est le paramètre minimum_should_match. Sans cela, la filter remplace totalement la should

J'espère que cela aide quelqu'un!

2
Benjamin Dowson

Voici comment vous pouvez imbriquer plusieurs requêtes bool dans une requête bool externe en utilisant Kibana,

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

Voici comment imbriquer une requête dans ES Il y a plus de types dans "bool" comme - 1. Filtre 2. must_not

1
niranjan harpale
$filterQuery = $this->queryFactory->create(QueryInterface::TYPE_BOOL, ['must' => $queries,'should'=>$queriesGeo]);

Dans must, vous devez ajouter le tableau de conditions de requête que vous souhaitez utiliser avec AND et dans should, vous devez ajouter la condition de requête que vous souhaitez utiliser avec OR.

Vous pouvez vérifier ceci: https://github.com/Smile-SA/elasticsuite/issues/972

0
alakh kumar