К сожалению, многие ранние рецепты пива в Интернете не обязательно должны быть легко усваиваемыми; то есть, эти рецепты представляют собой неструктурированные смешанные списки направлений и ингредиентов, которые часто изначально составляются в письме или сообщении на форуме.
Поэтому, хотя эти рецепты трудно легко поместить в традиционные хранилища данных (якобы для облегчения поиска), они идеально подходят для ElasticSearch в их нынешнем виде.
Соответственно, представьте индекс ElasticSearch, полный рецептов пива, поскольку… ну… мне нравится делать пиво (и пить его тоже).
Во-первых, я добавлю несколько рецептов пива в ElasticSearch с помощью клиента ElasticSearch от Node (обратите внимание, что код это CoffeeScript, хотя). Я добавлю эти рецепты пива в индекс beer_recipes
следующим образом:
Добавление рецепта пива
1
2
3
4
5
6
7
8
9
|
beer_1 = { name: "Todd Enders' Witbier" , style: "wit, Belgian ale, wheat beer" , ingredients: "4.0 lbs Belgian pils malt, 4.0 lbs raw soft red winter wheat, 0.5 lbs rolled oats, 0.75 oz coriander, freshly ground Zest from two table oranges and two lemons, 1.0 oz 3.1% AA Saaz, 3/4 corn sugar for priming, Hoegaarden strain yeast" } client.index( 'beer_recipes' , 'beer' , beer_1).on( 'data' , (data) -> console.log(data) ).exec() |
Обратите внимание, что интересная часть документа JSON с рецептом, названная beer_1
находится в поле ingredients
. Это поле представляет собой большую строку ценного текста (вы можете представить, как эта строка была по существу телом электронного письма). Таким образом, хотя поле ingredients
не структурировано, это то, что люди захотят искать.
Я добавлю еще один рецепт для хорошей меры:
Добавление второго рецепта пива
1
2
3
4
5
6
7
8
9
|
beer_2 = { name: "Wit" , style: "wit, Belgian ale, wheat beer" , ingredients: "4 lbs DeWulf-Cosyns 'Pils' malt, 3 lbs brewers' flaked wheat (inauthentic; will try raw wheat nest time), 6 oz rolled oats, 1 oz Saaz hops (3.3% AA), 0.75 oz bitter (Curacao) orange peel quarters (dried), 1 oz sweet orange peel (dried), 0.75 oz coriander (cracked), 0.75 oz anise seed, one small pinch cumin, 0.75 cup corn sugar (priming), 10 ml 88% food-grade lactic acid (at bottling), BrewTek 'Belgian Wheat' yeast" } client.index( 'beer_recipes' , 'beer' , beer_2).on( 'data' , (data) -> console.log(data) ).exec() |
Это жаркое лето, и я думаю, что я хотел бы сделать пиво с лимоном в качестве ингредиента (чтобы было ясно: я хочу использовать лимонную цедру, которая получается из кожуры лимона). Поэтому, естественно, мне нужно найти (т.е. найти ) рецепт с лимонами в нем.
Следовательно, я буду искать в своем индексе рецепты, которые содержат слово «лимон», вот так:
В поисках лимона
1
2
3
4
5
6
7
8
9
|
query = { "query" : { "term" : { "ingredients" : "lemon" } } } client.search( 'beer_recipes' , 'beer' , query).on( 'data' , (data) -> data = JSON.parse(data) for doc in data.hits.hits console.log doc._source.style console.log doc._source.name console.log doc._source.ingredients ).exec() |
Но ничего не появляется — нет результатов! Почему это?
Если вы внимательно посмотрите на предыдущий пример кода (в частности, JSON-документ beer_1
), то увидите, что в тексте есть слово «лимоны» (т. beer_1
«… Два апельсина в таблице и два лимона…»). Оказывается, по умолчанию, способ, которым значения индексируются ElasticSearch, лимон не обязательно совпадает — лимон делает, хотя.
В поисках лимонов
1
2
3
4
5
6
7
8
9
|
query = { "query" : { "term" : { "ingredients" : "lemons" } } } client.search( 'beer_recipes' , 'beer' , query).on( 'data' , (data) -> data = JSON.parse(data) for doc in data.hits.hits console.log doc._source.style console.log doc._source.name console.log doc._source.ingredients ).exec() |
И вот, этот поиск возвращает хит! Но это неудобно, если не сказать больше. В основном слова в поле ingredients
маркируются как есть . Следовательно, поиск «лимонов» работает, а «лимон» — нет. Примечание: существуют различные механизмы поиска, и поиск по запросу «lemon *» должен был дать результат.
Когда документ добавляется в индекс ElasticSearch , его поля анализируются и преобразуются в токены . Когда вы выполняете поиск по индексу, вы ищете по этим токенам. Как ElasticSearch токенизирует документ, настраивается.
Доступны различные анализаторы ElasticSearch — от языковых анализаторов, которые позволяют поддерживать поиск не на английском языке, до снежного анализатора, который преобразует слово в его корень (или основа, и этот процесс создания основы из слова называется основанием), получая более простой токен. Например, снежный ком из «лимонов» будет «лимоном». Или, если бы слова «стуки» и «стук» были в анализируемом документе «снежный ком», оба термина имели бы «стук» в качестве основы.
Вы можете изменить способ токенизации документов с помощью API отображения индекса следующим образом:
Изменение отображения для индекса с помощью cURL
1
2
3
4
5
6
7
8
|
"beer" : { "properties" : { "ingredients" : { "type" : "string" , "analyzer" : "snowball" } } } } }' |
Обратите внимание, что приведенное выше отображение указывает, что поле ingredients
будет анализироваться с помощью анализатора снежного кома. Также обратите внимание, что вы должны изменить отображение индекса, прежде чем начать добавлять в него документы! Итак, в этом случае мне нужно будет удалить индекс, выполнить приведенный выше вызов сопоставления, а затем повторно добавить эти два рецепта.
Теперь я могу начать поиск рецептов ингредиента «лимон» или «лимоны».
Поиск лимона сейчас работает!
1
2
3
4
5
6
7
8
9
|
query = { "query" : { "term" : { "ingredients" : "lemon" } } } client.search( 'beer_recipes' , 'beer' , query).on( 'data' , (data) -> data = JSON.parse(data) for doc in data.hits.hits console.log doc._source.style console.log doc._source.name console.log doc._source.ingredients ).exec() |
Имейте в виду, что снежный ком может непреднамеренно сделать ваши результаты поиска менее актуальными . Длинные слова можно превратить в более общие, но совершенно разные слова. Например, если вы снежный ком документа, который содержит слово «секстант», слово «секс» будет в качестве основы. Таким образом, поиск «секстант» также вернет документы, содержащие слово «секс» (и наоборот).
ElasticSearch помещает мощную поисковую систему в ваши сцепления; Кроме того, немного продумав, как анализируется содержимое документа, вы сделаете поиск более актуальным.