Вопрос по агрегации и скорости


(leov) #1

Здравствуйте
возникла у меня задача анализа логов поисковых запросов
решил попробовать реализовать это в эластике
но первые попытки показали довольно невысокую скорость 3-4сек
подскажите пожалуйста может у меня завышенные ожидания
или я что-то не так сделал

мапинг простой

"search_log": {
  "properties": {
    "added": {
      "type" : "date",
      "format" : "date"
    },
    "results": {
      "type": "long"
    },
    "what": {
      "type" : "string",
      "index" : "not_analyzed"
    },
    "_what": {
      "type" : "string",
      "analyzer" : "ru_analyzer"
    }
  }
}

what два раза потому как по анализированной фразе надо искать
а по неанализированной группировать
если группировать по анализированной то группирует по отдельным словам
вот так попытался выкрутится. может не совсем правильно
подскажите если можно лучше

запрос тоже

"aggs": {
  "search_frase": {
    "terms": {
      "field" : "what",
      "size" : 0
    },
    "aggs": {
      "max_results":{
        "max":{
          "field": "results"
        }
      }
    }
  }
},
"size":"0"

всего должно быть 20млн документов
но залил пока только 8.5 млн (там внешние проблемы с базой и еще с bulk в php пока не разобрался)
и вот на том что залито запрос 4сек работает
подскажите пожалуйста в чем я ошибаюсь


(leov) #2

разобрался с bulk перезалил все 20млн за два часа с небольшим
еще хуже стало - по всему массиву 8 сек результат выдает


(Igor Motov) #3

Это проще было бы сделать с помощью опции fields.

Какая машина, какие на ней диски? Вы не могли бы запустить hot_threads в эти 8 сек и прислать сюда ее вывод?


(leov) #4
::: [Nekra][9a9YPC1BRLyvirP5P70Sow][www.site.ru][inet[/62.210.169.39:19300]]{max_local_storage_nodes=1, master=true}
   Hot threads at 2018-12-03T14:53:00.082Z, interval=500ms, busiestThreads=3, ignoreIdleThreads=true:
   
   104.9% (524.5ms out of 500ms) cpu usage by thread 'elasticsearch[Nekra][search][T#11]'
     5/10 snapshots sharing following 17 elements
       org.elasticsearch.search.aggregations.bucket.terms.GlobalOrdinalsStringTermsAggregator.collect(GlobalOrdinalsStringTermsAggregator.java:128)
       org.elasticsearch.search.aggregations.AggregationPhase$AggregationsCollector.collect(AggregationPhase.java:161)
       org.elasticsearch.common.lucene.MultiCollector.collect(MultiCollector.java:60)
       org.apache.lucene.search.Weight$DefaultBulkScorer.scoreAll(Weight.java:193)
       org.apache.lucene.search.Weight$DefaultBulkScorer.score(Weight.java:163)
       org.apache.lucene.search.BulkScorer.score(BulkScorer.java:35)
       org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:621)
       org.elasticsearch.search.internal.ContextIndexSearcher.search(ContextIndexSearcher.java:191)
       org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:309)
       org.elasticsearch.search.query.QueryPhase.execute(QueryPhase.java:117)
       org.elasticsearch.search.SearchService.executeFetchPhase(SearchService.java:391)
       org.elasticsearch.search.action.SearchServiceTransportAction$11.call(SearchServiceTransportAction.java:333)
       org.elasticsearch.search.action.SearchServiceTransportAction$11.call(SearchServiceTransportAction.java:330)
       org.elasticsearch.search.action.SearchServiceTransportAction$23.run(SearchServiceTransportAction.java:559)
       java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
       java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
       java.lang.Thread.run(Thread.java:745)
     2/10 snapshots sharing following 15 elements
       org.apache.lucene.search.ReqExclScorer.nextDoc(ReqExclScorer.java:50)
       org.apache.lucene.search.Weight$DefaultBulkScorer.scoreAll(Weight.java:192)
       org.apache.lucene.search.Weight$DefaultBulkScorer.score(Weight.java:163)
       org.apache.lucene.search.BulkScorer.score(BulkScorer.java:35)
       org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:621)
       org.elasticsearch.search.internal.ContextIndexSearcher.search(ContextIndexSearcher.java:191)
       org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:309)
       org.elasticsearch.search.query.QueryPhase.execute(QueryPhase.java:117)
       org.elasticsearch.search.SearchService.executeFetchPhase(SearchService.java:391)
       org.elasticsearch.search.action.SearchServiceTransportAction$11.call(SearchServiceTransportAction.java:333)
       org.elasticsearch.search.action.SearchServiceTransportAction$11.call(SearchServiceTransportAction.java:330)
       org.elasticsearch.search.action.SearchServiceTransportAction$23.run(SearchServiceTransportAction.java:559)
       java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
       java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
       java.lang.Thread.run(Thread.java:745)
     3/10 snapshots sharing following 10 elements
       org.elasticsearch.search.internal.ContextIndexSearcher.search(ContextIndexSearcher.java:191)
       org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:309)
       org.elasticsearch.search.query.QueryPhase.execute(QueryPhase.java:117)
       org.elasticsearch.search.SearchService.executeFetchPhase(SearchService.java:391)
       org.elasticsearch.search.action.SearchServiceTransportAction$11.call(SearchServiceTransportAction.java:333)
       org.elasticsearch.search.action.SearchServiceTransportAction$11.call(SearchServiceTransportAction.java:330)
       org.elasticsearch.search.action.SearchServiceTransportAction$23.run(SearchServiceTransportAction.java:559)
       java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
       java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
       java.lang.Thread.run(Thread.java:745)

(Igor Motov) #5

Какая машина и какие на ней диски (SSD или HDD)?


(leov) #6

120GB SSD

Процессор: 1xIntel C2750 2.40GHz
Ядра/Потоки: 8/8
Память: Выбрано 8GB DDR3 ECC


(leov) #7

еще надо добавить что эластик очень старый

version
number "1.7.4"

(Igor Motov) #8

С этого надо было начинать! :slight_smile: А почему такая старая версия?


(leov) #9

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

вы хотите сказать что на новом эластике будет лучше?


(Igor Motov) #10

Анализатор русской морфологии работает вплоть до 5.X. 1.7.4 был выпущен 3 года тому назад. С тех пор все внутренности связанные с агрегацией почти полностью переписали. Я уже даже толком не помню, что там было в 1.7.

А сколько вы elasticsearch из этих 8GB дали?


(leov) #11

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

про память не скажу, надо самому спрашивать.
там freebsd и я в нем мало чего понимаю
htop там запустил и вижу что эластик использует
чуть меньше 3G какого-то VIRT (столбец такой)
и еще 1.3G какого-то RES (не знаю что конкретно это значит)
хотя MEM% всего 16

я все жду что наводящие вопросы приведут к ответу на изначальный вопрос
я слишком много жду от эластика?
на таком железе на таком объеме и такой версии он быстрее не поедет?
или я что-то неправильно сделал в конфигурации индекса и запроса?
я уж думаю может все эти 20 млн надо по годам разбить на разные индексы
они в разные шарды лягут и смогут параллельно обработаться....
дайте какие-то рекомендации пожалуйста
задача собственно в несколько строк ставится
посоветуйте как ее надо оптимально решать


(Igor Motov) #12

Я спросил про память чтобы понять правильно-ли сконфигурирован сервер. Запустите, пожалуйста, node info и node stats там должна эта информация быть.

Все зависит от данных, как они поступают, как часто меняется запрос и т.д. В современных версиях добавлено несколько дополнительных слоев кеширования, поэтому при правильной настройке, эти запросы могут быть вообще практически мгновенными. В этом случае, например, разбиение по годам будет иметь смысл если у вас один и тот же запрос периодически повторяется - в индексах за предыдущие годы он будет закеширован. Но в 1.7 это выключено по умолчанию и там оно не так эффективно.

Кстати, когда вы получаете ответ от elasticsearch, сколько там терминов возвращается и что elasticsearch пишет в поле took в ответе?

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


(leov) #13

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

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

задача максимально инкапсулирована.
данные не меняются вообще,
только дополняются по ~10тыс в день, но для простоты можно принять что не изменяются вовсе
данные это просто лог поисковых запросов - слово, два, пять, ну редко до 10 может, по моему до 255 символов + дата + количество результатов запроса (последним можно пренебречь)
задача примитивная - анализировать сколько за какой период каких запросов приходило
максимальный запрос я привел без условий - он самый долгий
а в принципе там будут задаваться даты начала и конца и поисковое слово

вот ни разу не хочу чтобы вы решали за меня практические задачи
но очень хотелось бы увидеть как по правильному должна решаться вот такая конкретная и часто существующая задача
а то всякие use case тут на вебинарах рассматриваются
и заканчивается картинками в кибане. оно конечно красиво
но нужен конкретный пример большого объема чего-то примитивного на конкретном небольшом железе
и показ как все это быстро анализируется, группируется, ищется
вот этого очень не хватает

вот с русским языком чего делать, как искать всякие словоформы?
я так и не понимаю как можно на последних эластиках без русской морфологии
всегда говорят match .... ну и что он найдет? нотариус, нотариальный, нотариусы
одно найдет, а надо всё


(leov) #14

_nodes
_node_stats


(Igor Motov) #15

Понятно. Я бы рекомендовал:

  • перейти на последнюю версии из 5.x серии
  • разбить индекс на кварталы или месяцы
  • правильно настроить сервер в соответствии с документацией
  • тестировать не по первому запросу, а после нескольких запросов, когда сервер "прогреется"

Русская морфология есть для всех версий до 6.x. В 6.x можно использовать hunspell.


(leov) #16

спасибо

-с версией вопрос тяжелый. будем стремиться к этому

-сейчас я залил эту информацию просто в еще один тип в имеющемся индексе
вы рекомендуете создать для этого новый индекс, группу индексов
именовав их типа stat_idx_2015_01...
я правильно вас понял?

-документацию буду изучать

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

-hunspell буду изучать. спасибо

а вообще, чисто ваше мнение, чего можно ждать вот на таком железе и на таких вот данных?
если я вот сяду и начну его целенаправленно мучить подобными запросами
какие took я могу ожидать в самом худшем случае?


(Igor Motov) #17

без версии другие рекомендации работать будут плохо, потому что работа с многими индексами была оптимизирована в 5.0

Суть в том, чтобы большинство индексов не менялось. Тип - это просто поле, на оптимизацию оно никак не влияет. Поиск по типу это все равно что поиск по индексу с фильтром. Добавление записей с новым типом никак не отличается от добавления новых записей с тем же типом.

Судя по node info неправильно настроены swap и jvm heap в данный момент.

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

Вас волнует время выполнения одного запроса или пропускная способность в случае поступления нескольких запросов одновременно? Какая цель?


(leov) #18

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


(Igor Motov) #19

Значит время выполнения одного запроса важнее. В этом случае несколько индексов или шард должны помочь.

Конкретную цифру сказать не могу, надо тестировать.


(leov) #20

вы просто как политик или адвокат :slight_smile:
и самое плохое что вообще нигде нет подобных оценок (или я что-то пропустил)
ну и как тут можно понять стоит ли дальше что-то оптимизировать?