令人遗憾的是,许多早期的互联网啤酒配方不一定采用易于消化的格式。 也就是说,这些食谱是通常在电子邮件或论坛帖子中最初组成的非结构化的方向和成分混合列表。
因此,尽管很难轻松地将这些配方放入传统的数据存储中(表面上看是为了更轻松地进行搜索),但是它们对于当前形式的ElasticSearch来说是完美的。
因此,想象一下一个充满啤酒配方的ElasticSearch索引,因为……嗯……我喜欢酿造啤酒(也喝啤酒)。
首先,我将使用Node的ElasticSearch Client将一些啤酒配方添加到ElasticSearch中(请注意,代码虽然是CoffeeScript )。 我将这些啤酒配方添加到beer_recipes
索引中,如下所示:
添加啤酒食谱
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()
请注意,如何在ingredients
字段中找到食谱JSON文档的有趣部分,即beer_1
。 该字段基本上是一大串有价值的文本(您可以想象此字符串本质上是电子邮件的正文)。 因此,尽管ingredients
字段是非结构化的,但人们显然仍希望进行搜索。
我将再添加一个食谱以达到良好的效果:
添加第二份啤酒食谱
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()
这是一个炎热的夏日,我想我想用柠檬作为原料制作啤酒(要清楚:我想用柠檬皮(它是由柠檬皮制成的))。 因此,自然地,我需要查找(即搜索 )其中含有柠檬的食谱。
因此,我将在索引中搜索包含“柠檬”一词的食谱,如下所示:
寻找柠檬
query = { "query" : { "term" : { "ingredients" : "lemon" } } }client.search('beer_recipes', 'beer', query).on('data', (data) ->data = JSON.parse(data)for doc in data.hits.hitsconsole.log doc._source.styleconsole.log doc._source.nameconsole.log doc._source.ingredients
).exec()
但是什么都没有显示-没有结果! 这是为什么?
如果仔细查看前面的代码示例(具体来说是beer_1
JSON文档),您会发现文本中有“柠檬”一词(即“……两个橙子和两个柠檬……”)。 事实证明,默认情况下,ElasticSearch索引值的方式, 柠檬不一定要匹配- 柠檬却可以。
寻找柠檬
query = { "query" : { "term" : { "ingredients" : "lemons" } } }client.search('beer_recipes', 'beer', query).on('data', (data) ->data = JSON.parse(data)for doc in data.hits.hitsconsole.log doc._source.styleconsole.log doc._source.nameconsole.log doc._source.ingredients
).exec()
瞧,此搜索返回了成功! 但这至少是不便的。 基本上, ingredients
字段中的单词按原样标记。 因此,搜索“柠檬”有效,而“柠檬”无效。 注意:有多种搜索机制,对“ lemon *”的搜索应已返回结果。
将文档添加到ElasticSearch索引后,将分析其字段并将其转换为tokens 。 对索引执行搜索时,将对这些标记进行搜索。 ElasticSearch如何标记文档是可以配置的。
可以使用不同的ElasticSearch分析器-从允许您支持非英语语言搜索的语言分析器到雪球分析器,后者将一个单词转换为其词根(或词干,并且从词创建词干的过程称为词干 ),产生一个更简单的令牌。 例如,“柠檬”雪球将是“柠檬”。 或者,如果在经过雪球分析的文档中有“敲门”和“敲门”一词,则这两个词都将以“敲门”为词干。
您可以通过索引映射API更改文档的标记方式,如下所示:
使用cURL更改索引的映射
curl -XPUT 'http://localhost:9200/beer_recipes' -d '{ "mappings" : {"beer" : {"properties" : {"ingredients" : { "type" : "string", "analyzer" : "snowball" }}}}
}'
请注意,以上映射如何指定将通过雪球分析器分析ingredients
字段。 另请注意, 在开始向其中添加文档之前 ,必须更改索引的映射! 因此,在这种情况下,我需要删除索引,运行上面的映射调用,然后重新添加这两个配方。
现在,我可以开始在配方中搜索“柠檬”或“柠檬”成分。
现在搜索柠檬有效!
query = { "query" : { "term" : { "ingredients" : "lemon" } } }client.search('beer_recipes', 'beer', query).on('data', (data) ->data = JSON.parse(data)for doc in data.hits.hitsconsole.log doc._source.styleconsole.log doc._source.nameconsole.log doc._source.ingredients
).exec()
请记住, 滚雪球可能会无意间使搜索结果的相关性降低 。 可以将长词变成更常见但完全不同的词。 例如,如果您将包含单词“ sextant”的文档滚雪球,则单词“ sex”将作为词干。 因此,搜索“ sextant”也将返回包含单词“ sex”的文档(反之亦然)。
ElasticSearch为您提供了强大的搜索引擎; 另外,略微考虑了如何分析文档的内容,您将使搜索事件更加相关。
翻译自: https://www.javacodegeeks.com/2013/09/understanding-elasticsearch-analyzers.html