Ускорение запросов Elasticsearch благодаря фильтру запросов с повторяющимися терминами - PullRequest
1 голос
/ 20 апреля 2019

Мне нужно будет узнать время совпадения между одним тегом и другим фиксированным набором тегов в целом. У меня есть 10000 различных отдельных тегов, и внутри фиксированного набора тегов есть 10 тысяч тегов. Я перебираю все отдельные теги в фиксированном наборе контекста тегов с фиксированным диапазоном времени. У меня всего 1 миллиард документов внутри индекса с 20 осколками.

Вот запрос эластичного поиска, эластичный поиск 6.6.0:

es.search(index=index, size=0, body={ 
        "query": {
          "bool": {
              "filter": [
                  {"range": {
                      "created_time": {
                       "gte": fixed_start_time,  
                       "lte": fixed_end_time, 
                       "format": "yyyy-MM-dd-HH"
                       }}},
                        {"term": {"tags": dynamic_single_tag}},
                        {"terms": {"tags": {
                            "index" : "fixed_set_tags_list",
                            "id" : 2,
                            "type" : "twitter",
                            "path" : "tag_list"
                        }}}
                       ]

                }
          }, "aggs": {
             "by_month": {
              "date_histogram": {
                  "field": "created_time",
                  "interval": "month",
                              "min_doc_count": 0,
                              "extended_bounds": {
                                  "min": two_month_start_time,
                                  "max": start_month_start_time}

              }}}
        }) 

Мой вопрос: существует ли какое-либо решение, которое может иметь кэш внутри упругого поиска для фиксированного набора из 10 тыс. Терминов запроса и фильтра временного диапазона, который может ускорить время запроса? Потребовалось 1,5 секунды для одного тега для моего запроса выше.

1 Ответ

1 голос
/ 22 апреля 2019

То, что вы видите, - это нормальное поведение для агрегаций Elasticsearch (на самом деле, довольно хорошая производительность, если у вас есть 1 миллиард документов).

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

Но, вероятно, стоит попытаться отправить эти 10К-запросы и посмотреть, сработает ли встроенное кэширование Elasticsearch.

Позвольте мне объяснить более подробно каждый из этих вариантов.

Использование filter агрегация

Во-первых, давайте обрисуем, что мы делаем в исходном запросе ES:

  • фильтровать документы с помощью create_time в определенном временном окне;
  • фильтровать документы, содержащие нужный тег dynamic_single_tag;
  • также фильтрует документы, у которых есть хотя бы один тег из списка fixed_set_tags_list;
  • посчитайте, сколько таких документов существует за каждый месяц в определенный период времени.

Производительность - это проблема, потому что у нас есть 10 000 тегов для таких запросов.

Здесь мы можем переместить filter на dynamic_single_tag из запроса в агрегаты:

POST myindex/_doc/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "terms": { ... } }
      ]
    }
  },
  "aggs": {
    "by tag C": {
      "filter": {
        "term": {
          "tags": "C" <== here's the filter
        }
      },
      "aggs": {
        "by month": {
          "date_histogram": {
            "field": "created_time",
            "interval": "month",
            "min_doc_count": 0,
            "extended_bounds": {
              "min": "2019-01-01",
              "max": "2019-02-01"
            }
          }
        }
      }
    }
  }
}

Результат будет выглядеть примерно так:

  "aggregations" : {
    "by tag C" : {
      "doc_count" : 2,
      "by month" : {
        "buckets" : [
          {
            "key_as_string" : "2019-01-01T00:00:00.000Z",
            "key" : 1546300800000,
            "doc_count" : 2
          },
          {
            "key_as_string" : "2019-02-01T00:00:00.000Z",
            "key" : 1548979200000,
            "doc_count" : 0
          }
        ]
      }
    }

Теперь, если вы спрашиваете, как это может помочь производительности, вот хитрость: добавить больше таких filter агрегатов для каждого тега: "by tag D", "by tag E" и т. Д.

Улучшение будет достигнуто за счет выполнения «пакетных» запросов, , объединяющих много начальных запросов в один . Возможно, нецелесообразно помещать все 10 тыс. Из них в один запрос, но даже партии по 100 тегов на запрос могут изменить правила игры.

(Примечание: примерно такое же поведение можно достичь с помощью агрегации terms с параметром фильтра include.)

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

переиндексировать документы

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

POST _reindex
{
  "source": {
    "index": "myindex",
    "type": "_doc",
    "query": {
      "bool": {
        "filter": [
          {
            "range": {
              "created_time": {
                "gte": "fixed_start_time",
                "lte": "fixed_end_time",
                "format": "yyyy-MM-dd-HH"
              }
            }
          },
          {
            "terms": {
              "tags": {
                "index": "fixed_set_tags_list",
                "id": 2,
                "type": "twitter",
                "path": "tag_list"
              }
            }
          }
        ]
      }
    }
  },
  "dest": {
    "index": "myindex_reduced"
  }
}

Этот запрос создаст новый индекс myindex_reduced, содержащий только те элементы, которые удовлетворяют первым 2 пунктам фильтрации.

На этом этапе исходный запрос может быть выполнен без этих двух предложений.

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

Загрузка данных и обработка вне Elasticsearch

Если честно, этот вариант использования больше похож на работу для панд . Если вы используете аналитику данных, я бы предложил использовать scroll API для извлечения данных на диск, а затем обработать их произвольным скриптом.

В python это может быть так же просто, как использовать .scan() вспомогательный метод из библиотеки elasticsearch.

Почему бы не попробовать метод грубой силы?

Elasticsearch уже попытается помочь вам с вашим запросом по request cache. Он применяется только к чисто агрегационным запросам (size: 0), поэтому должен работать в вашем случае.

Но это не так, потому что содержимое запроса всегда будет другим (весь JSON запроса используется в качестве ключа кэширования , и у нас есть новый тег в каждом запросе). Начнет играть другой уровень кэширования.

Elasticsearch в значительной степени опирается на кэш файловой системы , что означает, что под капотом наиболее часто используемые блоки файловой системы будут кэшироваться (практически загружаться в ОЗУ). Для конечного пользователя это означает, что «разогрев» будет происходить медленно и с объемом подобных запросов.

В вашем случае агрегация и фильтрация будут выполняться в 2 полях: create_time и tags.Это означает, что после выполнения, возможно, 10 или 100 запросов с разными тегами, время отклика упадет с 1,5 с до чего-то более терпимого.

Чтобы продемонстрировать свою точку зрения, вот график Vegeta из моего исследования производительности Elasticsearch по тому же запросу с большими агрегатами, отправленными с фиксированным RPS:

Filesystem cache kicks in

Как видите, изначально запрос принимал ~10 секунд, а после 100 запросов он уменьшился до блестящих 200 мс.

Я бы определенно предложил попробовать этот подход "грубой силы", потому что, если он работает, он хорош, если нет - он ничего не стоит.

Надеюсь, это поможет!

...