2015-11-26 4 views
1

Я пытаюсь развернуть свою голову, когда я буду использовать анализаторы, фильтры и запросы. Я прочитал статью «Поиск в глубине» на сайте elastic.co и получил лучшее понимание, но примеры наивны для моего варианта использования и все еще немного запутанны.Понимание анализаторов, фильтров и запросов в Elasticsearch

Учитывая У меня есть документы с множеством ингредиентов, содержащий любое сочетание digestive biscuits, biscuits, cheese и chocolate, я пытаюсь выяснить, что это лучший способ, чтобы проанализировать эти данные, а также выполнять поиск по нему.

Вот простой набор документов:

[{ 
    "ingredients": ["cheese", "chocolate"] 
}, { 
    "ingredients": ["chocolate", "biscuits"] 
}, { 
    "ingredients": ["cheese", "biscuits"] 
}, { 
    "ingredients": ["chocolate", "digestive biscuits"] 
}, { 
    "ingredients": ["cheese", "digestive biscuits"] 
}, { 
    "ingredients": ["cheese", "chocolate", "biscuits"] 
}, { 
    "ingredients": ["cheese", "chocolate", "digestive biscuits"] 
}] 

(я намеренно не смешивать biscuits и digestive biscuits здесь, я объясню, в мес.)

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

У меня есть отображение, как например:

{ 
    "properties": { 
     "ingredients": { 
      "type": "string", 
      "analyzer": "keyword" 
     } 
    } 
} 

Проблемы я столкнулся здесь, что biscuits не соответствует digestive biscuits и biscuit ничего не найдено.

Я знаю, что мне нужно проанализировать поле с помощью анализатора snowball, но я очень не уверен, как это сделать.

Нужен ли мне многопольный подход? Нужно ли мне также запрашивать фильтры? Результаты, которые я хотел бы видеть, являются:

  • biscuit соответствие как biscuits и digestive biscuits (причем последний набрал меньше)
  • biscuits соответствие как biscuits и digestive biscuits (причем последний набрал меньше)
  • digestive соответствие digestive biscuits
  • digestive biscuits соответствующий сам и biscuits (последний заниженный нижний)

Кроме того, бросая любой другой термин в случайном порядке, как я могу справиться с этим? Использовать фильтр или запрос?

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

ответ

4

Прежде всего, я предлагаю читать это: https://www.elastic.co/guide/en/elasticsearch/guide/current/stemming.html

Он обсуждает точную проблему вы столкнулись.

Чтобы исправить это, вы должны использовать пользовательский анализатор (он создается с использованием фильтров символов, токенизатора и фильтров). Анализатор выделяет токены из текстового блока.

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

PUT /test 
{ 
    "settings": { 
    "analysis": { 
     "analyzer": { 
     "my_analyzer_custom": { 
      "type": "custom", 
      "tokenizer": "standard", 
      "filter": [ 
      "asciifolding", 
      "lowercase", 
      "kstem" 
      ] 
     } 
     } 
    } 
    }, 
    "mappings": { 
    "data": { 
     "properties": { 
     "ingredients": { 
      "type": "string", 
      "analyzer": "my_analyzer_custom" 
     } 
     } 
    } 
    } 
} 

Этот анализатор будет разделить текст с помощью стандартного Tokenizer и применять эти фильтры:

  • asciifolding - нормализует буквы с диакритическими знаками (é => е)
  • lowercase - нижний регистр лексемы, так что поиски не чувствительны к регистру
  • kstem - фильтр, который нормализует токены к их корневым формам (не идеален, но делает хорошую работу). В этом случае это будет нормализовать печенье в печенье

Так что ваши данные выборки:

PUT /test/data/1 
{ 
    "ingredients": ["cheese", "chocolate"] 
} 
PUT /test/data/2 
{ 
    "ingredients": ["chocolate", "biscuits"] 
} 
PUT /test/data/3 
{ 
    "ingredients": ["cheese", "biscuits"] 
} 
PUT /test/data/4 
{ 
    "ingredients": ["chocolate", "digestive biscuits"] 
} 
PUT /test/data/5 
{ 
    "ingredients": ["cheese", "digestive biscuits"] 
} 
PUT /test/data/6 
{ 
    "ingredients": ["cheese", "chocolate", "biscuits"] 
} 
PUT /test/data/7 
{ 
    "ingredients": ["cheese", "chocolate", "digestive biscuits"] 
} 

И этот запрос:

GET /test/_search 
{ 
    "query": { 
    "dis_max": { 
     "tie_breaker": 0.7, 
     "boost": 1.5, 
     "queries": [ 
     { 
      "match": { 
      "ingredients": { 
       "query": "digestive biscuits", 
       "type": "phrase", 
       "boost": 5 
      } 
      } 
     }, 
     { 
      "match": { 
      "ingredients": { 
       "query": "digestive biscuits", 
       "operator": "and", 
       "boost": 3 
      } 
      } 
     }, 
     { 
      "match": { 
      "ingredients": { 
       "query": "digestive biscuits" 
      } 
      } 
     } 
     ] 
    } 
    } 
} 

Я использовал Dis Max Query в этом случае. Вы видите, что есть массив запросов? Мы задаем несколько запросов там, и он возвращает документ с наивысшим баллом. Из документации:

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

Так что в данном случае я указал три запроса:

  • Phrase Match. Запрос должен совпадать с условиями и позициями.
  • Соответствие с "operator": "and", значит все условия должны совпадать, независимо от их расположения.
  • Простой вопрос о матче. Это означает, что любой токен должен соответствовать

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

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

4

Вот как я подхожу к этой проблеме.Я создал индекс со следующими настройками

POST food_index 
{ 
    "settings": { 
    "analysis": { 
     "analyzer": { 
     "my_custom_analyzer": { 
      "tokenizer": "standard", 
      "filter": [ 
      "lowercase", 
      "english_possessive_stemmer", 
      "light_english_stemmer", 
      "asciifolding" 
      ] 
     } 
     }, 
     "filter": { 
     "light_english_stemmer": { 
      "type": "stemmer", 
      "language": "light_english" 
     }, 
     "english_possessive_stemmer": { 
      "type": "stemmer", 
      "language": "possessive_english" 
     } 
     } 
    } 
    }, 
    "mappings": { 
    "your_type": { 
     "properties": { 
     "ingredients": { 
      "type": "string", 
      "analyzer": "my_custom_analyzer" 
     } 
     } 
    } 
    } 
} 
  • lowercase фильтр в нижнем регистре все слова, как следует из названия, это поможет матч Булочки в печенье
  • possessive_english удаляет 's от слов, так что мы может соответствовать biscuit's до бисквит
  • light_english, чтобы остановить слова. Это менее агрессивное и использует kstem токены фильтра
  • asciifolding обрабатывать диакритические (я не думаю, что это полезно, но это до вас)

После этого я вставил документы, предоставленные в вопросах. Я думаю, вам нужно просто query string query. Это удовлетворит все ваши требования в отношении scoring документов.

{ 
    "query": { 
    "query_string": { 
     "default_field": "ingredients", 
     "query": "digestive biscuits" 
    } 
    } 
} 

Это дало мне именно то, о чем вы просили. Попробуйте эти настройки и запросите с помощью своего набора данных и сообщите мне, если у вас возникнут какие-либо проблемы.

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

+0

Большое спасибо! Хотя ваш ответ почти такой же, я собираюсь ответить dis_max на Evaldas Buinauskas, так как он дает мне больше возможностей для поиска. Это не означает, что это менее справедливо. – designermonkey

+0

рад, что я мог бы помочь. 'dis_max' - это, безусловно, путь, так как он даст вам больше возможностей – ChintanShah25

Смежные вопросы