1、精确值VS全文
Elasticsearch 中的数据可以概括的分为两类:精确值和全文。
精确值 如它们听起来那样精确,例如日期或者用户 ID,但字符串也可以表示精确值,例如用户名或邮箱地址。对于精确值来讲,Foo
和 foo
是不同的,2014
和 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 首先 分析 文档,之后根据结果创建 倒排索引 。
2、倒排索引
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 | | X The | X | brown | X | X dog | X | dogs | | X fox | X | foxes | | X in | | X jumped | X | lazy | X | X leap | | X over | X | X quick | X | summer | | X the | X | ------------------------
如果我们想搜索 quick brown
,两个文档都匹配,但是第一个文档比第二个匹配度更高。如果我们使用仅计算匹配词条数量的简单 相似性算法 ,那么,我们可以说,对于我们查询的相关性来讲,第一个文档比第二个文档更佳。
但是,目前的倒排索引有一些问题:使用前面的索引搜索 +Quick +fox
不会得到任何匹配文档(+
前缀表明这个词必须存在),因为只有同时出现 Quick
和 fox
的文档才满足这个查询条件。
如果我们将词条规范为标准模式,那么我们可以找到与用户搜索的词条不完全一致,但具有足够相关性的文档。例如:
Quick
可以小写化为quick
。foxes
可以 词干提取 --变为词根的格式-- 为fox
。类似的,dogs
可以为提取为dog
。jumped
和leap
是同义词,可以索引为相同的单词jump
。
现在索引看上去像这样:
Term Doc_1 Doc_2 ------------------------- brown | X | X dog | X | X fox | X | X in | | X jump | X | X lazy | X | X over | X | X quick | X | X summer | | X the | X | X ------------------------
这还远远不够。我们搜索 +Quick +fox
仍然 会失败,因为在我们的索引中,已经没有 Quick
了。但是,如果我们对搜索的字符串使用与 content
域相同的标准化规则,会变成查询 +quick +fox
,这样两个文档都会匹配!
Note:你只能搜索在索引中出现的词条,所以索引文本和查询字符串必须标准化为相同的格式。
分词和标准化的过程称为 分析 。
3、分析与分析器
分析 包含下面的过程:
- 首先,将一块文本分成适合于倒排索引的独立的 词条 ,
- 之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 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)"
标准分析器
标准分析器是Elasticsearch默认使用的分析器。它是分析各种语言文本最常用的选择。它根据 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)
语言分析器
特定语言分析器可用于很多语言,它们可以考虑指定语言的特点。例如, 英语
分析器附带了一组英语无用词(常用单词,例如 and
或者 the
,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干 。
英语
分词器会产生下面的词条:
set, shape, semi, transpar, call, set_tran, 5
注意看 transparent、 calling
和 set_trans
已经变为词根格式。
什么时候使用分析器?
当我们 索引 一个文档,它的全文域被分析成词条以用来创建倒排索引。 但是,当我们在全文域 搜索 的时候,我们需要将查询字符串通过 相同的分析 过程 ,以保证我们搜索的词条格式与索引中的词条格式一致。当你查询一个 精确值 域时,不会分析查询字符串, 而是搜索你指定的精确值。
指定分析器
当Elasticsearch在你的文档中检测到一个新的字符串域 ,它会自动设置其为一个全文字符串
域,使用标准
分析器对它进行分析。
你不希望总是这样。可能你想使用一个不同的分析器,适用于你的数据使用的语言。有时候你想要一个字符串域就是一个字符串域--不使用分析,直接索引你传入的精确值,例如用户ID或者一个内部的状态域或标签。
要做到这一点,我们必须手动指定这些域的映射。
4、映射
索引中每个文档都有类型,每种类型都有它自己的映射 ,或者模式定义 。映射定义了类型中的域,每个域的数据类型,以及Elasticsearch如何处理这些域。映射也用于配置与类型有关的元数据。
Elasticsearch 支持 如下简单域类型:
- 字符串:
string
- 整数 :
byte
,short
,integer
,long
- 浮点数:
float
,double
- 布尔型:
boolean
- 日期:
date
当你索引一个包含新域的文档--之前未曾出现-- Elasticsearch 会使用 动态映射 ,通过JSON中基本数据类型,尝试猜测域类型,使用如下规则:
JSON type | 域 type |
布尔型: |
|
整数: |
|
浮点数: |
|
字符串,有效日期: |
|
字符串: |
|
5、复杂核心域类型
https://www.elastic.co/guide/cn/elasticsearch/guide/cn/complex-core-fields.html