# Почему не работает dfs\_query\_then\_fetch?

**URL:** <https://discuss.elastic.co/t/dfs-query-then-fetch/262474>\
**Category:** Вопросы на русском языке\
**Created:** [January 28, 2021, 10:24am UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474 "2021-01-28T10:24:19Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [January 28, 2021, 10:24am UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/1 "2021-01-28T10:24:19Z")

</div>

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

> **[Understanding "Query Then Fetch" vs "DFS Query Then Fetch"](https://www.elastic.co/blog/understanding-query-then-fetch-vs-dfs-query-then-fetch)**

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

```auto
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, две шарды, одна реплика.

Ответ один:

> **[{ "took" : 7, "timed\_out" : false, "\_shards" : { "total" : 2, -...](https://pastebin.com/d10F8G5m)**
>
> Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.

  
Ответ два:  

> **[{ "took" : 4, "timed\_out" : false, "\_shards" : { "total" : 2, -...](https://pastebin.com/kPRYkKH6)**
>
> Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [January 28, 2021, 4:39pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/2 "2021-01-28T16:39:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [January 29, 2021, 9:24am UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/3 "2021-01-29T09:24:05Z")

</div>

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

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

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [January 29, 2021, 2:18pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/4 "2021-01-29T14:18:25Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [January 29, 2021, 8:18pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/5 "2021-01-29T20:18:53Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [January 29, 2021, 8:52pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/6 "2021-01-29T20:52:05Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [January 30, 2021, 7:15pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/7 "2021-01-30T19:15:35Z")

</div>

> [@Igor\_Motov](#):
>
> В какой версии elasticsearch был создан этот индекс?

```auto
"version" : {
  "created" : "6081099"
}

```

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

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 1, 2021, 2:55pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/8 "2021-02-01T14:55:03Z")

</div>

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

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

```

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

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [February 1, 2021, 7:16pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/9 "2021-02-01T19:16:23Z")

</div>

```auto
{
  "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
            }
          }
        ]
      }
    }
  }
}

```

> [@Igor\_Motov](#):
>
> добавить текст запроса в параметр `preference` .

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

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 1, 2021, 7:50pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/10 "2021-02-01T19:50:46Z")

</div>

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

> [@GreenX](#):
>
> наверное можно просто hash запроса добавлять

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [February 1, 2021, 8:12pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/11 "2021-02-01T20:12:51Z")

</div>

> [@Igor\_Motov](#):
>
> Я ожидал более большой разницы в `deleted` , но она есть и может вносить изменения в score, так как idf включает в себя удаленные документы.

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [February 1, 2021, 8:17pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/12 "2021-02-01T20:17:11Z")

</div>

> [@Igor\_Motov](#):
>
> `/_stats?level=shards&filter_path=indices.*.shards.*.docs`

```auto
{
  "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 млк. документов и разница другая.

---

<div class="post-metadata">

**Author:** ![mayya](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mayya/32/83147_2.png) [@mayya](https://discuss.elastic.co/u/mayya)\
**Post date:** [February 2, 2021, 11:27am UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/13 "2021-02-02T11:27:35Z")

</div>

Согласна с Игорем, к сожалению ничего нельзя сделать кроме как использования [preference](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-preference.html). Вот [здесь](https://github.com/elastic/elasticsearch/issues/3578) релевантная дискуссию в github.

C версии 7.10 еще можно использовать [point in time](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/point-in-time-api.html) который всегда будет использовать одни и те же шарды если они доступны.

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [February 2, 2021, 1:52pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/14 "2021-02-02T13:52:49Z")

</div>

> [@mayya](#):
>
> Согласна с Игорем, к сожалению ничего нельзя сделать кроме как использования [preference](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-preference.html). Вот [здесь](https://github.com/elastic/elasticsearch/issues/3578) релевантная дискуссию в github.

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

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

> [@mayya](#):
>
> C версии 7.10 еще можно использовать [point in time](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/point-in-time-api.html) который всегда будет использовать одни и те же шарды если они доступны.

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

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

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 2, 2021, 2:56pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/15 "2021-02-02T14:56:27Z")

</div>

> [@GreenX](#):
>
> Получается и в `dfs-query-then-fetch` особого смысла нет, раз он не гарантирует незменность результата в индексе где удаляются документы

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [February 2, 2021, 3:03pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/16 "2021-02-02T15:03:13Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 2, 2021, 3:20pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/17 "2021-02-02T15:20:48Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [February 2, 2021, 3:34pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/18 "2021-02-02T15:34:16Z")

</div>

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

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

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 2, 2021, 4:59pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/19 "2021-02-02T16:59:44Z")

</div>

> [@GreenX](#):
>
> какая то фантастическая утопия.

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

> [@GreenX](#):
>
> Еще я не нахожу "крутилку", как заставить более агрессивно работать automerge.

Официальных крутилок нет. Неофициально, можно покрутить [`index.merge.policy.expunge_deletes_allowed`](https://github.com/elastic/elasticsearch/blob/master/server/src/main/java/org/elasticsearch/index/MergePolicyConfig.java#L49), [`index.merge.policy.deletes_pct_allowed`](https://github.com/elastic/elasticsearch/blob/master/server/src/main/java/org/elasticsearch/index/MergePolicyConfig.java#L85) и `index.merge.policy.reclaim_deletes_weight`. Крутить надо осторожно, так как это может вызвать очень агрессивную реакцию. Перед тем как крутить, лучше всего ознакомится с теорией того, [как это все работает](https://www.elastic.co/blog/lucenes-handling-of-deleted-documents).

---

<div class="post-metadata">

**Author:** ![GreenX](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/greenx/32/51751_2.png) [@GreenX](https://discuss.elastic.co/u/GreenX)\
**Post date:** [February 2, 2021, 7:40pm UTC](https://discuss.elastic.co/t/dfs-query-then-fetch/262474/20 "2021-02-02T19:40:22Z")

</div>

> [@Igor\_Motov](#):
>
> Либо хранение логов, записей с обязательным сроком хранение и т.д. Что для одних - фантастическая утопия, для других - реалии жизни.

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

[Next page](https://discuss.elastic.co/t/dfs-query-then-fetch/262474.md?page=2)
