Почему не работает dfs_query_then_fetch?

Давным-давно, была проблема: выполняя один и тот же запрос мы получали разный список документов. Оказалось из-за близости _score два документна меняли местами в зависимости от того на какой шард уйдет запрос.
Тогда я изменил search_type на dfs-query-then-fetch и всё, насколько я помню, полечилось - _score считался в глобальном смысле и был всегда одинаков.

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

curl -s -H "content-type: application/json" "http://localhost:9200/help3/searchtype/_search?search_type=dfs_query_then_fetch&pretty=true" -d'{
   "from": 0,
   "size": 3,
   "_source": false,
   "query": {
     "match": {
        "content.original": {
           "query": "интернет"
        }
     }
   }
}'

Как понять почему игнорируется тип поиска? ES 6.8.10, две шарды, одна реплика.

Ответ один:


Ответ два:
1 Like

Похоже что, словарь терминов на репликах отличается от праймари по какой-то причине. Попробуйте сбросить количество реплик до 0 и потом увеличить до нужного количества.

Дык судя по описанию dfs... и должен устанять эту проблему, раз учитываеются все термы на всех шардах. Сумма то не меняется. У меня такое впечатление, что search_type просто игнорируется, но как в этом убидиться пока не придумал.

А как это полечить разово понятно, _forcemerge?max_num_segments=1 тоже помогает.
Но это разовая акция, а проблема повторяется на нескольких кластерах, следовательно постоянно.

DFS идет по всем шардам, то есть выбирает одну шарду с каждым номером (либо праймари, либо одну из реплик). Поэтому если реплика рассинхронизировались, то score будет прыгать. Можно провести такой эксперимент - запустить запрос несколько раз без DFS, посмотреть какие score будут генерироваться, записать все разные варианты. Потом повторить с DFS и посмотреть - те же цифры получаются или нет.

Цыфры разные. Два варианта с DFS и два по дефолту. Получается вообще нет гараинтии, что ответ будет тот же, соответвенно очередность документов, даже в неизмененном индексе? BUG? Что с этим делать, т.к. у меня такая ситуация на всех кластерах оказывается. Документы часто обновляюься, но это вроде базовые хотелки, чтобы ответ был повторяем.

Да это баг. Возможно уже исправленный. В какой версии elasticsearch был создан этот индекс? Праймари и реплика должны быть идентичны.

"version" : {
  "created" : "6081099"
}

И похоже тоже есть в 7090199.

Мне удалось у себя воспроизвести. Если запустить

GET help3/_stats?level=shards&filter_path=indices.*.shards.*.docs

то что оно вам выдает?

Кстати, другое временное решение - это добавить текст запроса в параметр preference. Тогда elasticsearch не будет прыгать по шардам для данного запроса.

1 Like
{
  "indices": {
    "help3": {
      "shards": {
        "0": [
          {
            "docs": {
              "count": 3144,
              "deleted": 1341
            }
          },
          {
            "docs": {
              "count": 3144,
              "deleted": 1340
            }
          }
        ],
        "1": [
          {
            "docs": {
              "count": 3235,
              "deleted": 204
            }
          },
          {
            "docs": {
              "count": 3235,
              "deleted": 204
            }
          }
        ]
      }
    }
  }
}

Спасбио за совет, не обратил внимания на эту опцию. Правда, у нас запрос может быть очень длинный, наверное можно просто hash запроса добавлять.

Я ожидал более большой разницы в deleted, но она есть и может вносить изменения в score, так как idf включает в себя удаленные документы. И количество удаленных документов зависит от того, как происходит merge, который происходит независимо на всех шардах, за исключением случая, когда вы делаете force_merge и убираете все документы.

Можно и hash. От этого значения будет все равно hash рассчитан и на основе этого hash-а будут выбран набор шард, который не будет менятся. То есть он должен быть постоянен для запроса и различен между запросами - для равномерного распределения запросов. Можно так же использовать user id или session id.

1 Like

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

{
  "indices" : {
    "doc-2021-01" : {
      "shards" : {
        "0" : [
          {
            "docs" : {
              "count" : 549026,
              "deleted" : 10981
            }
          },
          {
            "docs" : {
              "count" : 549026,
              "deleted" : 11616
            }
          }
        ],
        "1" : [
          {
            "docs" : {
              "count" : 550460,
              "deleted" : 11539
            }
          },
          {
            "docs" : {
              "count" : 550460,
              "deleted" : 12368
            }
          }
        ],
        "2" : [
          {
            "docs" : {
              "count" : 549987,
              "deleted" : 10874
            }
          },
          {
            "docs" : {
              "count" : 549987,
              "deleted" : 10990
            }
          }
        ],
        "3" : [
          {
            "docs" : {
              "count" : 549237,
              "deleted" : 11360
            }
          },
          {
            "docs" : {
              "count" : 549237,
              "deleted" : 10660
            }
          }
        ]
      }
    }
  }
}

Вот с другого кластера, тут больше 2 млк. документов и разница другая.

Согласна с Игорем, к сожалению ничего нельзя сделать кроме как использования preference. Вот здесь релевантная дискуссию в github.

C версии 7.10 еще можно использовать point in time который всегда будет использовать одни и те же шарды если они доступны.

Звучит так, что это фундаментальный баг. Все знают о проблеме, но её не решить просто так. Issues то есть, но закрыты с отпиской "юзайте preference - чинить не будем". Почему-то все думали, что в неизмененном индексе _score должен быть не изменен. :slight_smile:

Получается и в dfs-query-then-fetch особого смысла нет, раз он не гарантирует незменность результата в индексе где удаляются документы.

Я думаю, при таком подходе, возможно, нам бы хватило простого _search?scroll, но для этого надо сильно переделывать логику работы приложения.

А PIT надо еще тестировать на производительность - всегда найдется тот кто сделает 837 snapshot-а и будет жалосться на производительнолсть ФС.

dfs-query-then-fetch нужен для более правильного расчета количества документов, содержащих ключевые слова из запроса.

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

Результат правильный получается, если нет удаленных документов. В противном случае, оба результата неправильные и они могут отличаться.

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

Еще я не нахожу "крутилку", как заставить более агрессивно работать automerge. Ладно бы они были и постепенно уходили, а так если нагрузки нет удаленные документы так и будут висеть не обработанными.

Либо хранение логов, записей с обязательным сроком хранение и т.д. Что для одних - фантастическая утопия, для других - реалии жизни. :slight_smile:

Официальных крутилок нет. Неофициально, можно покрутить index.merge.policy.expunge_deletes_allowed, index.merge.policy.deletes_pct_allowed и index.merge.policy.reclaim_deletes_weight. Крутить надо осторожно, так как это может вызвать очень агрессивную реакцию. Перед тем как крутить, лучше всего ознакомится с теорией того, как это все работает.

Ну в логах то - да :wink: Тоже активно используем, но там ведь важнее просто фильтрация, а не _score.