Эластичный поисковый запрос bool объединяется с OR


181

В настоящее время я пытаюсь перенести приложение на основе solr вasticsearch.

У меня есть этот запрос Lucene

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

Насколько я понимаю, это комбинация предложений MUST в сочетании с логическим ИЛИ:

«Получить все документы, содержащие (foo AND bar в названии) ИЛИ (foo AND bar в info). После этого фильтра результаты по состоянию состояния = 1 и повысить документы, которые имеют изображение.»

Я пытался использовать запрос bool с MUST, но мне не удалось получить логическое ИЛИ в выражениях must. Вот что у меня есть:

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

Как видите, НЕОБХОДИМО, чтобы условия для «информации» отсутствовали.

у кого-нибудь есть решение?

Огромное спасибо.

** ОБНОВИТЬ **

Я обновил свой запросasticsearch и избавился от этой функциональной оценки. Моя базовая проблема все еще существует.


1
Хорошая документация по объединению запросов ElasticSearch здесь : astic.co/guide/en/elasticsearch/guide/current/…
Mr.Coffee,

Ответы:


427
  • ИЛИ пишется следует
  • И пишется должен
  • NOR пишется не должен

Пример:

Вы хотите увидеть все элементы (круглые И (красные ИЛИ синие)):

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

Вы также можете делать более сложные версии ИЛИ, например, если вы хотите сопоставить по крайней мере 3 из 5, вы можете указать 5 опций в поле «следует» и установить «минимум_шуль» в 3.

Спасибо Глену Томпсону и Себастьянсонсо за то, что они обнаружили, что мое гнездование было не совсем правильным.

Спасибо также Фатмайку за то, что он указал, что «термин» становится «совпадением» в ElasticSearch 6.


2
Будет ли тянуть shouldв верхний уровень bool, и в том числе minimum_should_match: 1работа?
Сид

18
Когда я попробую этот пример, я вернусь [term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]. Это как-то зависит от версии?
DanneJ

26
Почему бы им не добавить такой простой пример и объяснение в документах! Пример из документации очень запутанный.
Нихил Овалекар

21
Через 6 месяцев, прочитав всю документацию Elastic, я впервые полностью понимаю, как реализовать логическую логику. Официальной документации не хватает ясности на мой взгляд.
Себастьянсо

3
@Amir Какие неточности я могу исправить для вас? В показанном выше контексте значение по умолчанию minimum_shouldравно 1, и в boolрезультате переноса этой группы будет значение true, если хотя бы один элемент соответствует, и false, если ни один не соответствует. Моим мотивом для создания этого ответа было то, что я решал именно такую ​​проблему, и доступная документация и даже ответы, которые я мог найти на сайтах, подобных этому, были в лучшем случае бесполезны, поэтому я продолжал исследовать, пока не почувствовал, что у меня есть достаточно твердое понимание о том, что происходило. Я с радостью приветствую любые конструктивные указания о том, как я могу улучшить ответ.
Дэниел Факрелл,

69

Мне наконец удалось создать запрос, который делает именно то, что я хотел:

Отфильтрованный вложенный логический запрос. Я не уверен, почему это не задокументировано. Может быть, кто-то здесь может сказать мне?

Вот запрос:

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

В псевдо-SQL:

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

Помните, что от анализа полей документа и отображений зависит, как name = foo обрабатывается внутренне. Это может варьироваться от нечеткого до строгого поведения.

«imum_should_match »: 1 говорит, что по крайней мере одно из утверждений must должно быть истинным.

Это утверждение означает, что всякий раз, когда в наборе результатов есть документ, содержащий has_image: 1, он увеличивается в 100 раз. Это меняет порядок следования результатов.

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

Веселитесь, ребята :)


28
Святое дерьмо. У кого-нибудь есть лучшее решение? Спасибо за публикацию, но это слишком сложная задача, чтобы получить логическое ИЛИ в запросе.
Nackjicholson

спасибо, вы спасли мой день)
cubbiu

3
Этот запрос не только излишне длинен, но и использует устаревший синтаксис. Ответ @ daniel-fackrell должен быть принятым.
Эрик Олфорд,

4
@EricAlford Этот ответ 2015 года основан на более ранней версии ES. Не стесняйтесь предложить лучшее решение.
Джесси

1
Идея: Возьмите / раздайте ElasticSearch, переписайте его в удобной для пользователя форме, добавьте к нему простой язык запросов, ВЫИГРАЙ! Нам просто нужно финансирование. Я в! Кто еще ?
Sliq

16

Вот как вы можете вкладывать несколько запросов bool в один внешний запрос bool, используя Kibana,

bool указывает, что мы используем логическое значение

должен для И

должен для ИЛИ

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

Вот как вы можете вложить запрос в ES

Есть больше типов в "bool", как -

  1. Фильтр

  2. не должен


Ваш ответ в точности правильный, но он немного неуклюжий, для вас это небольшое предложение, если хотите - вы должны отредактировать его правильно. Вероятно, это дает вам больше похоже на этот ответ :) Хорошего дня.
Дванил Патель

6

Недавно мне тоже пришлось решить эту проблему, и после МНОГО проб и ошибок я придумал это (в PHP, но отображается напрямую в 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]]
        ]
    ]
]

Который сопоставляется с чем-то вроде этого в 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>

Ключ во всем этом - minimum_should_matchнастройка. Без этого тот filterполностью перекрывает should.

Надеюсь, это поможет кому-то!


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

В mustвам нужно добавить условие запроса массив , который вы хотите работать с ANDи в shouldвам нужно добавить условие запроса , который вы хотите работать с OR.

Вы можете проверить это: https://github.com/Smile-SA/elasticsuite/issues/972


0

Если вы использовали анализатор запросов Solr по умолчанию или Lucene, вы всегда можете поместить его в запрос строки запроса:

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)"
    }
  }
}

Тем не менее, вы можете использовать логический запрос , например, тот, который вы уже опубликовали, или даже их комбинацию.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.