目录
第1关:Elasticsearch搜索
任务描述
本关任务:根据所学知识,完成 Elasticsearch 文档的相关搜索。
相关知识
为了完成本关任务,你需要掌握:
什么是空搜索;
多索引、多类型如何搜索;
如何做到分页搜索;
什么是轻量搜索。
Elasticsearch 不只会存储(stores)文档,为了能被搜索到也会为文档添加索引(indexes),这也是为什么我们使用结构化的 JSON 文档,而不是无结构的二进制数据。
文档中的每个字段都将被索引并且可以被查询。不仅如此,在简单查询时,Elasticsearch 可以使用所有(all) 这些索引字段,以惊人的速度返回结果。这是你永远不会考虑用传统数据库去做的一些事情。
搜索(search) 可以做到:
在类似于 gender 或者 age 这样的字段上使用结构化查询,join_date 这样的字段上使用排序,就像 SQL 的结构化查询一样;
全文检索,找出所有匹配关键字的文档并按照相关性(relevance)排序后返回结果。
代码
#!/bin/bash
# 请在此处编写命令
# ********** Begin ********** #
curl -H "Content-Type: application/json" -XGET 'http://localhost:9200/store/books/_search?q=+title:(Kingdoms+Margin)&pretty'
# ********** End ********** #
第2关:Elasticsearch映射和分析
任务描述
本关任务:根据所学知识,使用 IK 分词器对文本内容进行分词。
相关知识
为了完成本关任务,你需要掌握:
Elasticsearch 精确值和全文;
倒排索引;
分析与分析器。
Elasticsearch 精确值和全文
当摆弄索引里面的数据时,我们发现一些奇怪的事情。一些事情看起来被打乱了:在我们的索引中有四条索引是包含 2014 的,只有一条包含日期 2014-09-15 ,但是看一看下面查询命中的总数 (total):
/_search?q=2014 # 4 条
/_search?q=2014-09-15 # 1 条
/_search?q=publish_date:2014-09-15 # 1 条
/_search?q=publish_date:2014 # 0 条
为什么在 _all 字段查询日期返回所有推文,而在 date 字段只查询年份却没有返回结果?为什么我们在 _all 字段和 publish_date 字段的查询结果有差别?
推测起来,这是因为数据在 _all 字段与 publish_date 字段的索引方式不同。所以,通过请求 store 索引中 books 类型的映射(或模式定义),让我们看一看 Elasticsearch 是如何解释我们文档结构的:
curl -H "Content-Type: application/json" -XGET 'http://localhost:9200/store/_mapping/books?pretty'
执行结果:
{
"store" : {
"mappings" : {
"books" : {
"properties" : {
"name" : {
"properties" : {
"first" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"last" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"price" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"publish_date" : {
"type" : "date"
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
基于对字段类型的猜测, Elasticsearch 动态为我们产生了一个映射。这个响应告诉我们 publish_date 字段被认为是 date 类型的。由于 _all 是默认字段,所以没有提及它。但是我们知道 _all 字段是 string 类型的。
所以 publish_date 字段和 string 字段索引方式不同,因此搜索结果也不一样。这完全不令人吃惊。你可能会认为核心数据类型 strings、numbers、Booleans 和 dates 的索引方式有稍许不同。没错,他们确实稍有不同。
但是,到目前为止,最大的差异在于代表精确值(它包括 string 字段)的字段和代表 全文的字段。这个区别非常重要——它将搜索引擎和所有其他数据库区别开来。
Elasticsearch 中的数据可以概括的分为两类:精确值和全文。
精确值:如它们听起来那样精确。例如日期或者用户 ID,但字符串也可以表示精确值,例如用户名或邮箱地址。对于精确值来讲,Foo 和 foo 是不同的,2014 和 2014-09-15 也是不同的。
另一方面,全文是指文本数据(通常以人类容易识别的语言书写),例如一个推文的内容或一封邮件的内容。
例如,考虑这条语句:
May is fun but June bores me.
May 指的是月份还是人?
精确值很容易查询。结果是二进制的:要么匹配查询,要么不匹配。这种查询很容易用 SQL 表示:
WHERE name = "John Smith"
AND user_id = 2
AND date > "2014-09-15"
查询全文数据要微妙的多。我们问的不只是“这个文档匹配查询吗”,而是“该文档匹配查询的程度有多大?”换句话说,该文档与给定查询的相关性如何?
我们很少对全文类型的域做精确匹配。相反,我们希望在文本类型的域中搜索。不仅如此,我们还希望搜索能够理解我们的意图 :
搜索 UK ,会返回包含 United Kindom 的文档;
搜索 jump ,会匹配 jumped,jumps,jumping,甚至是 leap;
搜索 johnny walker 会匹配 Johnnie Walker, johnnie depp 应该匹配 Johnny Depp;
搜索 fox news hunting 应该返回福克斯新闻( Foxs News )中关于狩猎的故事,同时, fox hunting news 应该返回关于猎狐的故事;
为了促进这类在全文域中的查询,Elasticsearch 首先分析文档,之后根据结果创建 倒排索引。接下来,我们会讨论倒排索引和分析过程。
倒排索引
Elasticsearch 使用一种称为倒排索引的结构,它适用于快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。
例如,假设我们有两个文档,每个文档的 content 域包含如下内容:
The quick brown fox jumped over the lazy dog
Quick brown foxes leap over lazy dogs in summer
为了创建倒排索引,我们首先将每个文档的 content 域拆分成单独的 词(我们称它为 词条 或 tokens),创建一个包含所有不重复词条的排序列表,然后列出每个词条出现在哪个文档。结果如下所示:
Term Doc_1 Doc_2
-------------------------
Quick | | √
The | √ |
brown | √ | √
dog | √ |
dogs | | √
fox | √ |
foxes | | √
in | | √
jumped | √ |
lazy | √ | √
leap | | √
over | √ | √
quick | √ |
summer | | √
the | √ |
------------------------
现在,如果我们想搜索 quick brown ,我们只需要查找包含每个词条的文档:
Term

最低0.47元/天 解锁文章
2938

被折叠的 条评论
为什么被折叠?



