Elasticsearch 入门(二)
一 精确值 VS 全文
Elasticsearch 中的数据可以概括的分为两类:精确值和全文。
精确值 如它们听起来那样精确。例如日期或者用户 ID,但字符串也可以表示精确值,例如用户名或邮箱地址。对于精确值来讲,Foo 和 foo 是不同的,2014 和 2014-09-15 也是不同的。
另一方面,全文 是指文本数据(通常以人类容易识别的语言书写),例如一个推文的内容或一封邮件的内容。
全文通常是指非结构化的数据,但这里有一个误解:自然语言是高度结构化的。问题在于自然语言的规则是复杂的,导致计算机难以正确解析。例如,考虑这条语句:
May is fun but June bores me.
它指的是月份还是人?
精确值很容易查询。结果是二进制的:要么匹配查询,要么不匹配。这种查询很容易用 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 使用一种称为 包含下面的过程:
- 首先,将一块文本分成适合于倒排索引的独立的 词条 ,
- 之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall
分析器执行上面的工作。 分析器 实际上是将三个功能封装到了一个包里:
- 字符过滤器
- 首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将
&转化成 `and`。 - 分词器
- 其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
- Token 过滤器
- 最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化
Quick),删除词条(例如, 像a`, `and`, `the等无用词),或者增加词条(例如,像jump和leap这种同义词)。
Elasticsearch提供了开箱即用的字符过滤器、分词器和token 过滤器。 这些可以组合起来形成自定义的分析器以用于不同的目的。
内置分析器
但是, Elasticsearch还附带了可以直接使用的预包装的分析器。 接下来我们会列出最重要的分析器。为了证明它们的差异,我们看看每个分析器会从下面的字符串得到哪些词条:
"Set the shape to semi-transparent by calling set_trans(5)"
- 标准分析器 :它根据 Unicode 联盟 定义的 单词边界 划分文本。删除绝大部分标点。最后,将词条小写。它会产生
-
set, the, shape, to, semi, transparent, by, calling, set_trans, 5
- 简单分析器:简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生
-
set, the, shape, to, semi, transparent, by, calling, set, trans
- 空格分析器:空格分析器在空格的地方划分文本。它会产生
-
Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
- 语言分析器:特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如, 英语分析器附带了一组英语无用词,它们会被删除,这个分词器可以提取英语单词的 词干 。
set, shape, semi, transpar, call, set_tran, 5(注意看transparent`、 `calling和set_trans已经变为词根格式。)
测试分析器
有些时候很难理解分词的过程和实际被存储到索引中的词条,特别是你刚接触 Elasticsearch。为了理解发生了什么,你可以使用 analyze API 来看文本是如何被分析的。在消息体里,指定分析器和要分析的文本:
{
"_index" : "accounts",
"_type" : "person",
"_id" : "1",
"_version" : 2,
"found" : true,
"_source" : {
"user" : "张三",
"title" : "工程师",
"desc" : "数据库管理,软件开发"
}
}
curl 'localhost:9200/accounts/person/1/_termvectors?fields=desc'
结果中每个元素代表一个单独的词条:
{ "_index": "accounts", "_type": "person", "_id": "1", "_version": 2, "found": true, "took": 29, "term_vectors": { "desc": { "field_statistics": { "sum_doc_freq": 7, "doc_count": 1, "sum_ttf": 7 }, "terms": { "库": { "term_freq": 1, "tokens": [{ "position": 2, "start_offset": 2, "end_offset": 3 }] }, "开发": { "term_freq": 1, "tokens": [{ "position": 6, "start_offset": 8, "end_offset": 10 }] }, "数据": { "term_freq": 1, "tokens": [{ "position": 1, "start_offset": 0, "end_offset": 2 }] }, "数据库": { "term_freq": 1, "tokens": [{ "position": 0, "start_offset": 0, "end_offset": 3 }] }, "管理": { "term_freq": 1, "tokens": [{ "position": 3, "start_offset": 3, "end_offset": 5 }] }, "软件": { "term_freq": 1, "tokens": [{ "position": 5, "start_offset": 6, "end_offset": 8 }] }, "软件开发": { "term_freq": 1, "tokens": [{ "position": 4, "start_offset": 6, "end_offset": 10 }] } } } } }
token 是实际存储到索引中的词条。 position 指明词条在原始文本中出现的位置。 start_offset 和 end_offset 指明字符在原始字符串中的位置。