2016-07-14 2 views
1

Я индексирую метрические имена в эластичном поиске. Метрические имена имеют вид foo.bar.baz.aux. Вот индекс, который я использую.Сводка терминов (для достижения иерархической огранки) производительность запросов медленная

{ 
    "index": { 
     "analysis": { 
      "analyzer": { 
       "prefix-test-analyzer": { 
        "filter": "dotted", 
        "tokenizer": "prefix-test-tokenizer", 
        "type": "custom" 
       } 
      }, 
      "filter": { 
       "dotted": { 
        "patterns": [ 
         "([^.]+)" 
        ], 
        "type": "pattern_capture" 
       } 
      }, 
      "tokenizer": { 
       "prefix-test-tokenizer": { 
        "delimiter": ".", 
        "type": "path_hierarchy" 
       } 
      } 
     } 
    } 
} 

{ 
    "metrics": { 
     "_routing": { 
      "required": true 
     }, 
     "properties": { 
      "tenantId": { 
       "type": "string", 
       "index": "not_analyzed" 
      }, 
      "unit": { 
       "type": "string", 
       "index": "not_analyzed" 
      }, 
      "metric_name": { 
       "index_analyzer": "prefix-test-analyzer", 
       "search_analyzer": "keyword", 
       "type": "string" 
      } 
     } 
    } 
} 

выше индекс создает следующие условия для метрической имени foo.bar.baz

foo 
bar 
baz 
foo.bar 
foo.bar.baz 

Если у меня есть куча метрик, как показано ниже

a.b.c.d.e 
a.b.c.d 
a.b.m.n 
x.y.z 

Я должен написать запрос, чтобы захватить n-й уровень токенов. В приведенном выше примере

for level = 0, I should get [a, x] 
for level = 1, with 'a' as first token I should get [b] 
       with 'x' as first token I should get [y] 
for level = 2, with 'a.b' as first token I should get [c, m] 

Я не мог думать ни о каком другом способе, кроме как писать агрегирование терминов. Чтобы определить маркеры уровня 2 a.b, вот запрос, который я придумал.

time curl -XGET http://localhost:9200/metrics_alias/metrics/_search\?pretty\&routing\=12345 -d '{ 
     "size": 0, 
     "query": { 
     "term": { 
      "tenantId": "12345" 
     } 
     }, 
     "aggs": { 
      "metric_name_tokens": { 
       "terms": { 
        "field" : "metric_name", 
        "include": "a[.]b[.][^.]*", 
        "execution_hint": "map", 
        "size": 0 
       } 
      } 
     } 
    }' 

Это приведет к следующим ковшим. Я разбираю вывод и захватываю [c, m].

"buckets" : [ { 
    "key" : "a.b.c", 
    "doc_count" : 2 
    }, { 
    "key" : "a.b.m", 
    "doc_count" : 1 
} ] 

Пока все хорошо. Запрос отлично подходит для большинства арендаторов (обратите внимание на запрос tenantIdterm). Для некоторых арендаторов, которые имеют большие объемы данных (около 1 мили), производительность очень медленная. Я предполагаю, что все условия агрегирования требуют времени.

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

+0

Мне непонятно, что вам нужно. Вам нужны подсчеты? Или вам нужны c и m? Или вам нужны документы, содержащие: a.b.c.d.e - a.b.c.d - a.b.m.n? –

+0

Мне просто нужны c и m. – Chandra

+0

@JettroCoenradie Мне просто нужны c и m. В основном, что такое следующий уровень возможных токенов для данного префикса. – Chandra

ответ

1

Некоторые предложения:

  • «зеркало» фильтр на агрегатах уровне в части запроса, а также. Таким образом, для согласования a.b., используйте следующее в качестве запроса и сохранить тот же Aggs раздел:
"bool": { 
    "must": [ 
    { 
     "term": { 
     "tenantId": 123 
     } 
    }, 
    { 
     "prefix": { 
     "metric_name": { 
      "value": "a.b." 
     } 
     } 
    } 
    ] 
} 

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

  • изменение "size": 0 от агрегатов до "size": 100. После тестирования вы упомянули, что это не имеет значения
  • удалите "execution_hint": "map" и пусть Elasticsearch использует значения по умолчанию. После тестирования вы упомянули, что значение по умолчанию execution_hint было намного хуже.
  • Единственное, что я мог подумать, это уменьшить давление во время поиска, переместив его во время индексации. Что я имею в виду: при индексировании, в вашем собственном приложении или любом используемом вами методе индексирования, разбивайте текст, который нужно индексировать программным образом (а не ES), и индексируйте каждый элемент в иерархии в отдельном поле.Например, a.b в field2, a.b.c в field3 и так далее. Это для того же документа. Затем во время поиска вы просматриваете определенные поля в зависимости от текста поиска. Однако вся эта идея требует дополнительной работы за пределами ES.

Из всех предложений, приведенных выше первого, оказали наибольшее влияние: запрос времени ответа улучшился с 23 секунд до 11 секунд.

+0

В соответствии с вашими предложениями для строк abcde, abxy, я буду индексировать индексы [a], [ab], [abc], [abcd], [abcde], [abx], [abxy] отдельно, затем как искать получить все жетоны, которые следуют за префиксом ab? – Chandra

+0

Для документа у вас будет такая структура: '{" tenantId ": 123," metric_name1 ": [" a "," x "]," metric_name2 ": [" ab "," xy "]," metric_name3 ": [ "ABC", "АВМ", "XYZ"], "metric_name4": [ "ABCD", "ABMN"], "metric_name5": [ "ABCDE"]} '. Все поля 'metric_name *' будут использовать анализатор 'keyword' или все, что не будет разделять его. Сам запрос (поскольку вы хотите, чтобы ваши пользователи могли искать 'ab * .d', а не только запросы' prefix'), должны быть чем-то вроде '' query_string ': { "default_field": "metric_name *", " query ":" ab * .d " }'. –

+0

агрегированные будет что-то вроде этого, хотя ' "Aggs": { "metric_name_tokens": { "терминов": { "поля": "metric_name3", "размера": 0 } } }'. Итак, в основном, для поиска 'a.b. *. D' вас интересует то, что происходит после' a.b.'. И вы будете использовать поле «metric_name3» (одно с тремя уровнями иерархии). Мне было бы любопытно, что посмотреть, какую производительность вы получаете, из запроса 'query_string'. Агрегационная часть будет намного легче. –