Сортировка результатов по максимальному числу совпадащих фильтров

Здравствуйте!
Есть индекс специалистов, у специалистов есть, например, ключевые навыки (множественное поле). Пользователь в фильтре выбирает ключевые навыки - например, PHP, JS, Java. Так вот специалисты, у которых например, совпадают три навыка, должны выдаваться в списке выше, чем те, у кого совпадает два.

{"query":{"nested":{"path":"key_skills","query":{"bool":{"should":[{"term":{"key_skills.slug":"kn-zr-1"}},{"term":{"key_skills.slug":"key-skill-01"}}],"minimum_should_match":1}}}},"from":0,"size":10000,"_source":["index","key_skills"],"sort":"_score"}

В теории, по-умолчанию эластик так и должен работать. Когда я провожу тесты и заполняю поле key_skills предопределенным набором значений: [ks1] или [ks1, ks2] или [ks1, ks2, ks3] - то все работает. Однако, когда в поле реальные данные из базы - сортировка не верная.

Более того, я проводил эксперимент на одном специалисте и происходит мистика. У него три ключевых скила key-skill-1, key-skill-01, key-skill-20.

Когда я делаю запрос с одним фильтром "key_skills.slug":"key-skill-01", получаю оценку 10.14

{"query":{"bool":{"must":[{"nested":{"path":"key_skills","query":{"bool":{"should":[{"term":{"key_skills.slug":"key-skill-01"}}],"minimum_should_match":1}}}},{"term":{"index":"219"}}]}},"from":0,"size":10000,"_source":["index","key_skills"],"sort":"_score"}

Если же я делаю запрос с двумя значениями в фильтре, оценка понижается до 9.7

{"query":{"bool":{"must":[{"nested":{"path":"key_skills","query":{"bool":{"should":[{"term":{"key_skills.slug":"key-skill-01"}},{"term":{"key_skills.slug":"key-skill-1"}}],"minimum_should_match":1}}}},{"term":{"index":"219"}}]}},"from":0,"size":10000,"_source":["index","key_skills"],"sort":"_score"}

Как сказал, старик Кларк: "Любая достаточно развитая технология неотличима от магии." :slight_smile:

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

То что вы хотите, можно добиться либо настроив scripted similarity, которая возвращает только doc.freq, либо завернуть все запросы в terms в constant_score.

{
  "query": {
    "nested": {
      "path": "key_skills",
      "query": {
        "bool": {
          "should": [
            {
              "constant_score": {
                "filter": {
                  "term": {
                    "key_skills.slug": "kn-zr-1"
                  }
                }
              }
            },
            {
              "constant_score": {
                "filter": {
                  "term": {
                    "key_skills.slug": "key-skill-01"
                  }
                }
              }
            }
          ],
          "minimum_should_match": 1
        }
      }
    }
  },
  "from": 0,
  "size": 10000,
  "_source": [
    "index",
    "key_skills"
  ],
  "sort": "_score"
}

Да вот никак эта магия контролю не поддается только :slight_smile: Применил constant_score, как вашем примере и почему-то всем документам проставилась оценка - 1, вне зависимости от того, сколько значений совпало. Видимо, придется смотреть в сторону scripted similarity

Ну это на волшебника еще немного поучиться надо :slight_smile: Вы constant_score вокруг всего запроса поставили, или завернули каждый отдельный запрос term в constant_score, как показано в моем примере?

Сделал как на вашем примере, но работать не хотело. Но в общем я вопрос решил, дело в nested поле. Я делал запрос nested внутри него несколько should, внутри каждого по одному term. А нужно сделать несколько should, внутри каждого один nested с одним term внутри.

{"query":{"bool":{"should":[{"nested":{"path":"key_skills","query":{"term":{"key_skills.slug":"key-skill-01"}}}},{"nested":{"path":"key_skills","query":{"term":{"key_skills.slug":"key-skill-02"}}}},{"nested":{"path":"key_skills","query":{"term":{"key_skills.slug":"key-skill-0389439"}}}},{"nested":{"path":"key_skills","query":{"term":{"key_skills.slug":"google-analytics"}}}}],"minimum_should_match":1}},"from":0,"size":10000,"_source":["index","key_skills"]}