elastsearch bool query комбінувати must з OR


181

На даний момент я намагаюся перенести додаток на основі solr на еластичний пошук.

У мене цей запит на люцені

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

Наскільки я розумію, це комбінація ОБОВ'ЯЗКОВИХ пропозицій у поєднанні з булевими АБО:

"Отримати всі документи, що містять (foo AND bar in name) OR (foo AND bar in info). Після цього фільтруйте результати за умовою state = 1 та збільшуйте документи, що мають зображення."

Я намагаюся використовувати запит bool з ОБОВ'ЯЗКОВО, але мені не вдається отримати булеві АБО в застереження 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
            }
          }
        }
      ]
    }
  }
}

Як бачите, ОБОВ'ЯЗКОВІ умови для "інформації" відсутні.

Хтось має рішення?

Дуже дякую.

** ОНОВЛЕННЯ **

Я оновив запит на еластичний пошук і позбувся цього показника функції. Моя базова проблема все ще існує.


1
Існує гарна документація на комбінуванні ElasticSearch запитів тут: elastic.co/guide/en/elasticsearch/guide/current / ...
Mr.Coffee

Відповіді:


426
  • АБО написано слід
  • І пишеться обов'язково
  • NOR пишеться не слід

Приклад:

Ви хочете побачити всі елементи, які є (круглі І (червоний АБО синій)):

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

Ви також можете зробити більш складні версії АБО, наприклад, якщо ви хочете відповідати принаймні 3 з 5, ви можете вказати 5 варіантів під "слід" і встановити "мінімальний_шудл" з 3.

Дякую Глену Томпсону та Себастіалонсо, що вони виявили, де моє гніздування раніше не було.

Дякуємо також Fatmajk за те, що вони зазначили, що "термін" стає "збігом" у ElasticSearch 6.


2
Чи витягуватимете його shouldна верхній рівень boolі включаєте minimum_should_match: 1роботу?
Sid

18
Коли я спробую цей приклад, я повертаюся [term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]. Чи залежить від цього якось версія?
DanneJ

26
Чому вони не додають такий простий приклад і пояснення в документи! Приклад з документації дуже заплутаний.
Nikhil Owalekar

21
Через 6 місяців, читаючи всю еластичну документацію, це перший раз, коли я повністю розумію, як реалізувати булеву логіку. На мою думку, офіційна документація не має ясності.
Себастіалонсо

3
@Amir Які неточності я можу прибрати для вас? У контексті, показаному вище, за замовчуванням minimum_shouldдорівнює 1, і завершення цього boolрезультату в цій групі є істинним, якщо принаймні один елемент відповідає, помилковий, якщо жоден не відповідає. Моя мотивація до створення цієї відповіді полягала в тому, що я вирішував саме таку проблему, і наявна документація та навіть відповіді, які я міг знайти на таких сайтах, в кращому випадку не були корисними, тому я продовжував дослідження, поки не відчув, що маю досить чітке розуміння того, що відбувалося. Я з радістю вітаю будь-які конструктивні вказівки щодо того, як я можу вдосконалити відповідь далі.
Даніель Факрелл

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

Будь ласка, майте на увазі, що залежно від аналізу вашого поля документа та відображень того, яким чином обробляється ім'я = foo, здійснюється внутрішня обробка. Це може варіюватися від нечіткої до суворої поведінки.

"minimum_should_match": 1 каже, що принаймні одна з заяв повинна бути істинною.

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

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

Веселіться хлопці :)


28
О ні. Хтось має краще рішення? Дякуємо, що опублікували це, але це абсолютно занадто складна складова для досягнення Логічного АБО у запиті.
nackjicholson

thnx, ти врятував мені день)
cubbiu

3
Цей запит не лише надзвичайно довгий, він використовує застарілий синтаксис. @ daniel-fackrell відповідь має бути прийнятою.
Ерік Алфорд

4
@EricAlford Ця відповідь з 2015 року базується на більш ранній версії ES. Не соромтеся запропонувати краще рішення.
Джессі

1
Ідея: перейміть / роздрібніть ElasticSearch, перепишіть його зручним для користувача способом, додайте до нього просту мову запитів, WIN! Нам просто потрібно фінансування. Я з вами! Хто ще ?
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. не повинен


Ваша відповідь точно правильна, але це трохи незграбно, це невелика пропозиція для вас, якщо вам подобається - ви повинні її правильно відредагувати. Напевно, це вам більше подобається на цю відповідь :) Приємного дня.
Dhwanil Patel

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/isissue/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.