我们很少确切的匹配整个全文文本。我们想在全文中查询包含查询文本的部分。不仅如此,我们还期望搜索引擎能理解我们 的意图,例:
为了方便在全文文本字段中进行这些类型的查询,Elasticsearch首先对文本分析(analyzes),然后使用结果建立一个倒排索 引
1. 倒排索引
Elasticsearch使用一种叫做倒排索引(inverted index)的结构来做快速的全文搜索。倒排索引由在文档中出现的唯一的单词列 表,以及对于每个单词在文档中的位置组成。
例如,我们有两个文档,每个文档 content 字段包含:
1. The quick brown fox jumped over the lazy dog
2. Quick brown foxes leap over lazy dogs in summer
我们将词为统一为标准格式,这样就可以找到不是确切匹配查询,但是足以相似从而可以关联的文档
例如:
现在的索引:
例如:我们要搜索 “+Quick +fox” ,查询将变成 “+quick +fox” ,这样就可以匹配到两个文档。
这很重要。你只可以找到确实存在于索引中的词,所以索引文本和查询字符串都要标准化为相同的形式。
这个表征化和标准化的过程叫做分词(analysis)
2. 标准分析器
标准分析器是Elasticsearch默认使用的分析器。对于文本分析,它对于任何语言都是最佳选择(译者注:就是没啥特殊需 求,对于任何一个国家的语言,这个分析器就够用了)。它根据Unicode Consortium的定义的单词边界(word boundaries) 来切分文本,然后去掉大部分标点符号。最后,把所有词转为小写。
例:“Set the shape to semi-transparent by calling set_trans(5)”
分析后:
set, the, shape, to, semi, transparent, by, calling, set_trans, 5
当我们索引(index)一个文档,全文字段会被分析为单独的词来创建倒排索引
用 analyze API来查看文本是如何被分析的。在查询字符串参数中指定要使用的分析器,被分析的文本做为请求体:
token 是一个实际被存储在索引中的词。
position 指明词在原文本中是第几个出现的。
start_offset 和 end_offset 表示词 在原文本中占据的位置。
3. 映射
索引中每个文档都有一个类型(type)。 每个类型拥有自己的映射(mapping)或者模式定义 (schema definition)。一个映射定义了字段类型,每个字段的数据类型,以及字段被Elasticsearch处理的方式。映射还用于 设置关联到类型上的元数据。
Elasticsearch支持以下简单字段类型:
当你索引一个包含新字段的文档——一个之前没有的字段——Elasticsearch将使用动态映射猜测字段类型,这类型来自于 JSON的基本数据类型,使用以下规则:
3.1 查看映射
我们可以使用 _mapping 后缀来查看Elasticsearch中的映射。
结果:
3.2 自定义字段映射
string 类型的字段,默认的,考虑到包含全文本,它们的值在索引前要经过分析器分析,并且在全文搜索此字段前要把查询 语句做分析处理。
对于 string 字段,两个最重要的映射参数是 index 和 analyer 。
3.2.1 index
index 参数控制字符串以何种方式被索引。它包含以下三个值当中的一个:
string 类型字段默认值是 analyzed 。如果我们想映射字段为确切值,我们需要设置它为 not_analyzed :
其他简单类型—— long 、 double 、 date 等等——也接受 index 参数,但相应的值只能是 no 和 not_analyzed ,它们 的值不能被分析。
3.2.2 分析
对于 analyzed 类型的字符串字段,使用 analyzer 参数来指定哪一种分析器将在搜索和索引的时候使用。默认的, Elasticsearch使用 standard 分析器,但是你可以通过指定一个内建的分析器来更改它,例 如 whitespace 、 simple 或 english 。
3.3 更新映射
**你可以向已有映射中增加字段,但你不能修改它。如果一个字段在映射中已经存在,这可能意味着那个字段的数据已 经被索引。如果你改变了字段映射,那已经被索引的数据将错误并且不能被正确的搜索到。
**
我们可以更新一个映射来增加一个新字段,但是不能把已有字段的类型那个从 analyzed 改到 not_analyzed
为了演示两个指定的映射方法,让我们首先删除索引 gb :
然后创建一个新索引,指定 tweet 字段的分析器为 english :
再后来,我们决定在 tweet 的映射中增加一个新的 not_analyzed 类型的文本字段,叫做 tag ,使用 _mapping 后缀:
注意到我们不再需要列出所有的已经存在的字段,因为我们没法修改他们。我们的新字段已经被合并至存在的那个映射中。
3.4 测试映射
你可以通过名字使用 analyze API测试字符串字段的映射。对比这两个请求的输出:
tweet 字段产生两个词, “black” 和 “cat” , tag 字段产生单独的一个词 “Black-cats” 。换言之,我们的映射工作正常。
4. 复合核心字段类型
除了之前提到的简单的标量类型,JSON还有 null 值,数组和对象,所有这些Elasticsearch都支持:
4.1 多值字段
我们想让 tag 字段包含多个字段,。我们可以索引一个标签数组来代替单一字符串:
对于数组不需要特殊的映射。任何一个字段可以包含零个、一个或多个值,同样对于全文字段将被分析并产生多个词。
言外之意,这意味着数组中所有值必须为同一类型。你不能把日期和字符窜混合。如果你创建一个新字段,这个字段索引了 一个数组,Elasticsearch将使用第一个值的类型来确定这个新字段的类型。
当你从Elasticsearch中取回一个文档,任何一个数组的顺序和你索引它们的顺序一致。你取回的 _source 字段的顺序同样与 索引它们的顺序相同。
然而,数组是做为多值字段被索引的,它们没有顺序。在搜索阶段你不能指定“第一个值”或者“最后一个值”。倒不如把数组当 作一个值集合(gag of values)
4.2 空字段
当然数组可以是空的。这等价于有零个值。事实上,Lucene没法存放 null 值,所以一个 null 值的字段被认为是空字段。
4.3 多层对象
我们需要讨论的最后一个自然JSON数据类型是对象(object)
内部对象(inner objects)经常用于嵌入一个实体或对象里的另一个地方。例如,做在 tweet 文档中 user_name 和 user_id 的替 代,我们可以这样写:
4.3.1 内部对象的映射
Elasticsearch 会动态的检测新对象的字段,并且映射它们为 object 类型,将每个字段加到 properties 字段下