使用Elasticsearch快速介绍全文搜索
1. 概述
全文搜索查询并对文档执行语言搜索。它包括单个或多个单词或短语,并返回匹配搜索条件的文档。
ElasticSearch 是一个基于Apache Lucene 的搜索引擎,Apache Lucene是一个免费的开源信息检索软件库。它提供了一个分布式全文搜索引擎,带有 HTTP Web 界面和无模式 JSON 文档。
本文检查 ElasticSearch REST API 并演示仅使用 HTTP 请求的基本操作。
2. 设置
要在您的机器上安装 ElasticSearch,请参阅官方设置指南 。
RESTfull API 在端口 9200 上运行。让我们使用以下 curl 命令测试它是否正常运行:
curl -XGET 'http://localhost:9200/'
如果您观察到以下响应,则说明实例正在正常运行:
{
"name": "NaIlQWU",
"cluster_name": "elasticsearch",
"cluster_uuid": "enkBkWqqQrS0vp_NXmjQMQ",
"version": {
"number": "5.1.2",
"build_hash": "c8c4c16",
"build_date": "2017-01-11T20:18:39.146Z",
"build_snapshot": false,
"lucene_version": "6.3.0"
},
"tagline": "You Know, for Search"
}
3. 索引文件
ElasticSearch 是面向文档的。它存储和索引文档。索引创建或更新文档。建立索引后,您可以搜索、排序和过滤完整的文档,而不是行列数据。这是一种完全不同的数据思考方式,也是 ElasticSearch 可以执行复杂全文搜索的原因之一。
文档表示为 JSON 对象。大多数编程语言都支持 JSON 序列化,并已成为 NoSQL 运动使用的标准格式。它简单、简洁、易于阅读。
我们将使用以下随机条目来执行全文搜索:
{
"title": "He went",
"random_text": "He went such dare good fact. The small own seven saved man age."
}
{
"title": "He oppose",
"random_text":
"He oppose at thrown desire of no. \
Announcing impression unaffected day his are unreserved indulgence."
}
{
"title": "Repulsive questions",
"random_text": "Repulsive questions contented him few extensive supported."
}
{
"title": "Old education",
"random_text": "Old education him departure any arranging one prevailed."
}
在我们可以索引一个文档之前,我们需要决定在哪里存储它。可以有多个索引,而这些索引又包含多种类型。这些类型包含多个文档,每个文档都有多个字段。
我们将使用以下方案存储我们的文档:
- text:索引名称。
- article:类型名称。
- id:此特定示例文本条目的 ID。
要添加文档,我们将运行以下命令:
curl -XPUT 'localhost:9200/text/article/1?pretty'
-H 'Content-Type: application/json' -d '
{
"title": "He went",
"random_text":
"He went such dare good fact. The small own seven saved man age."
}'
这里我们使用id=1,我们可以使用相同的命令和递增的 id 添加其他条目。
4. 检索文件
添加完所有文档后,我们可以使用以下命令检查集群中有多少文档:
curl -XGET 'http://localhost:9200/_count?pretty' -d '
{
"query": {
"match_all": {}
}
}'
此外,我们可以通过以下命令使用其 id 获取文档:
curl -XGET 'localhost:9200/text/article/1?pretty'
我们应该从弹性搜索中得到以下答案:
{
"_index": "text",
"_type": "article",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"title": "He went",
"random_text":
"He went such dare good fact. The small own seven saved man age."
}
}
正如我们所看到的,这个答案与使用 id 1 添加的条目相对应。
5. 查询文件
好的,让我们使用以下命令执行全文搜索:
curl -XGET 'localhost:9200/text/article/_search?pretty'
-H 'Content-Type: application/json' -d '
{
"query": {
"match": {
"random_text": "him departure"
}
}
}'
我们得到以下结果:
{
"took": 32,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1.4513469,
"hits": [
{
"_index": "text",
"_type": "article",
"_id": "4",
"_score": 1.4513469,
"_source": {
"title": "Old education",
"random_text": "Old education him departure any arranging one prevailed."
}
},
{
"_index": "text",
"_type": "article",
"_id": "3",
"_score": 0.28582606,
"_source": {
"title": "Repulsive questions",
"random_text": "Repulsive questions contented him few extensive supported."
}
}
]
}
}
正如我们所见,我们正在寻找*“他离开”,我们得到两个不同分数的结果。第一个结果很明显,因为文本内部有执行的搜索,我们可以看到我们有1.4513469*的分数。
检索到第二个结果是因为目标文档包含单词“him”。
默认情况下,ElasticSearch 根据相关性分数对匹配结果进行排序,即每个文档与查询的匹配程度。请注意,第二个结果的得分相对于第一个命中较小,表明相关性较低。
6. 模糊搜索
模糊匹配将两个“模糊”相似的词视为同一个词。首先,我们需要定义模糊的含义。
Elasticsearch 支持使用 fuzziness 参数指定的最大编辑距离为 2。fuzziness 参数可以设置为 AUTO,这会导致以下最大编辑距离:
- 0表示一个或两个字符的字符串
- 1表示三个、四个或五个字符的字符串
- 2表示超过五个字符的字符串
您可能会发现编辑距离为2会返回看似不相关的结果。
您可能会获得更好的结果和更好的性能,最大模糊度为 1。距离是指 Levenshtein 距离,它是用于测量两个序列之间差异的字符串度量。非正式地,两个单词之间的Levenshtein 距离 是单字符编辑的最小数量。
好的,让我们进行模糊搜索:
curl -XGET 'localhost:9200/text/article/_search?pretty' -H 'Content-Type: application/json' -d'
{
"query":
{
"match":
{
"random_text":
{
"query": "him departure",
"fuzziness": "2"
}
}
}
}'
结果如下:
{
"took": 88,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 1.5834423,
"hits": [
{
"_index": "text",
"_type": "article",
"_id": "4",
"_score": 1.4513469,
"_source": {
"title": "Old education",
"random_text": "Old education him departure any arranging one prevailed."
}
},
{
"_index": "text",
"_type": "article",
"_id": "2",
"_score": 0.41093433,
"_source": {
"title": "He oppose",
"random_text":
"He oppose at thrown desire of no.
\ Announcing impression unaffected day his are unreserved indulgence."
}
},
{
"_index": "text",
"_type": "article",
"_id": "3",
"_score": 0.2876821,
"_source": {
"title": "Repulsive questions",
"random_text": "Repulsive questions contented him few extensive supported."
}
},
{
"_index": "text",
"_type": "article",
"_id": "1",
"_score": 0.0,
"_source": {
"title": "He went",
"random_text": "He went such dare good fact. The small own seven saved man age."
}
}
]
}
}'
正如我们所看到的,模糊性给了我们更多的结果。
我们需要谨慎使用模糊性,因为它往往会检索看起来不相关的结果。