Поиск по нескольким полям с разными типами


(Anton Vorontsov) #1

Здравствуйте.

Как правильно организовать поиск по разным полям?

У меня есть индекс
orders

  • order_number (long)
  • domain_id (long)
  • first_name (string)
  • last_name (string)

1.К примеру если поисковый запрос "18000" то в первую очередь нужно точное совпадение по полю order_number
2. Если поисковый запрос "Артемов Артем", то ищем по полям first_name, last_name применяя fuzzy
3. Если выбран фильтр по домену (domain_id =3) применить его тоже в этом запросе, отфильтровав все записи по domain_id =3

Возможно ли объединение match и multi_match?

Возможно я неверно понимаю, и правильно иначе?


(Igor Motov) #2

Я бы преобразовал 1 и 2 в match и добавил их как should элементы в bool с подходящим boost-ом. А 3 я бы добавил как filter в тот-же самый bool. Можно это все как multi_match выразить, но там возможностей меньше, и если вы парсите запросы, что бы понять что в них находится, то уж лучше сразу формулировать запрос bool.


(Anton Vorontsov) #3

Несколько раз прочел документацию, и не смог понять до конца как работают must и should.

Правильно ли я понимаю что must (обязан) означает точное совпадение?
Тогда как работает should (следует)?

Еще один вопрос:
у меня все запросы приходят через одно поле поиска где может быть как имя, фамилия так и номер заказа. а еще в поиске может быть индекс (423040) что может совпасть с номером заказа. Видимо тут нужно сделать приоритет номера заказа в таком случае?


(Igor Motov) #4

А вы поэкспериментируйте. Поставьте elasticsearch и kibana, проиндексируйте несколько документов и посмотрите, что возвращается. Надо только обратить внимание на то, что поведение should зависит от параметра minimum_should_match. В свою очередь значение по умолчанию для minimum_should_match зависит от наличия must и must_not в запросе. Если must и must_not присутствуют, то minimum_should_match равен 0, если нет - то 1. Когда minimum_should_match равен 1, то по крайней мере один should должен совпадать для того, чтобы документ попал в результат, то есть should работает как "или". Если minimum_should_match равен 0, то should на выборку результатов не влияет, но совпадения увеличивают _score, и если вы сортирует по _score, то соответсвенно порядок документов в результате. Когда minimum_should_match равен 2, то как минимум два should должны совпадать, и как в случае с 0 и 1, если больше should совпадает, то _score увеличивается.

Видимо тут нужно сделать приоритет номера заказа в таком случае?

... либо добавить 1000000 ко всем номерам заказов, чтобы их формат с индексами не мог совпасть.


(Anton Vorontsov) #5

нумерацию уже изменить не могу. Решил попробовать внедрить префиксы поиска:
О18000
И423042

и для них уже делать точные совпадения


(Igor Motov) #6

Я думаю, что в этом случае надо искать по заказам с большим приоритетом. Заказ с определенным номером всегда один, а покупателей с одним и тем же индексом - может быть много. Так что для пользователя, которому нужен индекс, пропустить первую запись не так уж сложно.


(Anton Vorontsov) #7

согласен. Обработчики заказов подтвердили ваши слова.


(Anton Vorontsov) #8

Игорь, поставил кибану и попробовал различные запросы:

Еще один вопрос:
Администратор вводит запрос с индексом и именем, и хочет получить результаты по релевантности. Сначала все заказы где такой индекс и имя клиента, потом индекс, и потом только имя. Но такой запрос вообще не выдает ни одного результата. Правильно ли я понимаю что верный вариант разбить строку запроса на текст и число, и подставить уже эти подстроки по полям:

postcode: численная часть
name: строковая часть

пытаюсь такой запрос построить. 


# query string: 111675 артем
GET orders/_search
{
  "query": { 
    "bool": { 
      "should": [
        { "term" : { 
          "order_number" : {
            "boost": 2,
            "value": "111675 артем"
          }} 
        },
        { "term" : { 
          "postcode" : {
            "boost": 1,
            "value": "111675 артем"
          }} 
        },
        { "fuzzy" : { "firstname" : "111675 артем" } },
        { "fuzzy" : { "lastname" : "111675 артем" } }
      ],
      "minimum_should_match" : 1,
      "filter": [ 
        { "term":  { "domain_id": 3 }}
      ]
    }
  }
}

Если же представить что я распарсил строку поиска и сделал такой запрос, то все становится верным.

Или же можно как то избежать парсинга и получить такой же результат?

# query string: 111675 артем
GET orders/_search
{
  "query": { 
    "bool": { 
      "should": [
        { "term" : { 
          "order_number" : {
            "boost": 2,
            "value": "111675"
          }} 
        },
        { "term" : { 
          "postcode" : {
            "boost": 1,
            "value": "111675"
          }} 
        },
        { "fuzzy" : { "firstname" : "артем" } },
        { "fuzzy" : { "lastname" : "артем" } }
      ],
      "minimum_should_match" : 1,
      "filter": [ 
        { "term":  { "domain_id": 3 }}
      ]
    }
  }
}

(Igor Motov) #9

Это происходит потому, что запросы term и fuzzy не анализируют запрос.


(system) #10

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.