Разнообразие результатов поиска в ElasticSearch 7.5 - PullRequest
1 голос
/ 16 января 2020

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

Catalog 1 - Product 1
Catalog 1 - Product 2
Catalog 1 - Product 3
...
Catalog 1 - Product x
Catalog 2 - Product 1
...

Это не оптимально, так как я хочу также указать пользователю на другие каталоги, не имея его просматривать на нескольких страницах результатов поиска, содержащих все товары одного и того же каталога. Поэтому я попытался использовать diversified_sampler-aggregation , который вместе с дочерним элементом top_hits-aggregation казался именно тем решением, которое я хочу:

POST /myIndex/_search?typed_keys=true
{
  "query": {
    "query_string": {
      "fields": [
        "title^2",
        "description^2",
        "descriptionOriginal^0.01"
      ],
      "query": "*someSearchTerm*"
    }
  },
  "size": 0,
  "aggs": {
    "aggDiversifiedSampler": {
      "diversified_sampler": {
        "shard_size": 100000,
        "field": "catalogId",
        "max_docs_per_value": 3
      },
      "aggs": {
        "aggTopHits": {
          "top_hits": {
            "from": 0,
            "size": 50,
            "sort": [
              {
                "_score": {
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

Разбиение на страницы осуществляется через свойства "size" и "from" внутренней агрегации top_hits. Результаты поиска могут быть получены из коллекции значений внутреннего top_hits-агрегата - поэтому я установил размер самого запроса равным 0.

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

Catalog 1 - Product 1
Catalog 1 - Product 2
Catalog 1 - Product 3
Catalog 2 - Product 1
Catalog 2 - Product 2
Catalog 2 - Product 3
...
Catalog x - Product 1
Catalog x - Product 2
Catalog x - Product 3

... и затем все заканчивается.

Кажется, что diversified_sampler не деформируется после достижения последнего каталога и так далее результаты из отдельных каталогов не появятся. Я хочу что-то вроде этого:

Catalog 1 - Product 1
Catalog 1 - Product 2
Catalog 1 - Product 3
Catalog 2 - Product 1
Catalog 2 - Product 2
Catalog 2 - Product 3
...
Catalog x - Product 1
Catalog x - Product 2
Catalog x - Product 3
Catalog 1 - Product 4
Catalog 1 - Product 5
Catalog 1 - Product 6
Catalog 2 - Product 4
Catalog 2 - Product 5
Catalog 2 - Product 6
...

Есть идеи? Моя техника с использованием diversified_sampler не увенчалась успехом, но я не мог придумать что-то еще. Может, какая-нибудь причудливая сортировка запроса на основе сценариев? Не знаю Переупорядочение на основе клиента не вариант, потому что я не хочу, чтобы упругая поисковая подкачка была нарушена. Мне нужна страница, чтобы поддерживать производительность - поисковый индекс составляет около 18 ГБ, содержащий 900 тыс. Документов ...

1 Ответ

1 голос
/ 20 января 2020

Я думаю, что нашел решение без агрегации diversified_sampler с использованием сортировки по сценарию:

POST /myIndex/_search?typed_keys=true
{
  "query": {
    "query_string": {
      "fields": [
        "title^2",
        "description^2",
        "descriptionOriginal^0.01"
      ],
      "query": "*someSearchTerm*"
    }
  },
  "sort": [{
      "_script": {
        "script": {
          "source": "Math.round(_score / params.fuzziness) * params.fuzziness",
          "params": {
            "fuzziness": 2
          }
        },
        "type": "number",
        "order": "desc"
      }
    }, {
      "_script": {
        "script": {
          "source": "if(doc['catalogId'].value != params.cid) {params.cid=doc['catalogId'].value;params.sort=0;return params.count=0;} else {return (++params.count % params.grpSize == 0) ?++params.sort : params.sort;}",
          "params": {
            "cid": 0,
            "sort": 0,
            "count": 0,
            "grpSize": 3
          }
        },
        "type": "number",
        "order": "asc"
      }
    }, {
      "_score": {
        "order": "desc"
      }
    }
  ]
}

При первой сортировке по сценарию я предварительно сортирую свои документы, чтобы результаты находились в определенном падении диапазона _score все вместе. Это контролируется параметром нечеткости. Затем я сортирую эти диапазоны, используя скрипт-сортировку, так что всегда берутся следующие 3 (контролируемые параметром grpSize) документа на каждый идентификатор каталога, а затем увеличивают порядок сортировки. (Не знаю, опасно ли использовать параметры скрипта как «глобальные» переменные ... Я чувствую себя немного неловко с этим ...)

Вот сценарий в более читабельном виде представление:

if(doc['catalogId'].value != params.cid) {
  params.cid = doc['catalogId'].value;
  params.sort = 0;
  return params.count = 0;
} else {
  return (++params.count % params.grpSize == 0) ? ++params.sort : params.sort;
}

И последнее, но не менее важное: документы с одинаковым _score-range и sort-order сортируются по их действительному _score.

Решение не требует реальной производительности -Влияние (по крайней мере, на мой индекс) и дает вполне ожидаемые результаты.

Пожалуйста, не стесняйтесь публиковать идеи и оптимизации!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...