Table of Contents generated with DocToc
Elasticsearch 使用 Lucene (开源全文检索库) 进行索引和搜索。
Lucene 成熟、高性能、可扩展、轻量级以及强大的功能而广受青睐。Lucene 内核可以创建为独立的Java库且不依赖第三方代码,用户可以使用它提供的所见即所得的全文检索功能进行索引和搜索操作。
Lucene 还有很多扩展,如多语言处理、拼写检查、高亮显示等等。
Lucene 的架构:
- 文档(document):索引与搜索的主要数据载体,它包含一个或多个字段,存放将要写入索引或将从索引搜索出来的数据。
- 字段(field):文档中的一个片段,它包括两个部分:字段的名称和内容。
- 词项(term):搜索时的一个单位,代表文本中的某个词。
- 词条(token):词项在字段中的一次出现,包括词项的文本、开始和结束的位移及类型。
Lucene 将写入索引的所有信息组织成倒排索引(inverted index)。该结构是一种将词项映射到文档的数据结构,例如:
- Elasticsearch Server (文档1)
- MasteringElasticsearch (文档2)
- Apache solr 4 Cookbook (文档3)
索引后的结构示意图如下:
词项 | 计数 | 文档 |
---|---|---|
4 | 1 | 3 |
Apache | 1 | 3 |
Cookbook | 1 | 3 |
Elasticsearch | 2 | 1, 2 |
Mastering | 1 | 1 |
Server | 1 | 1 |
Solr | 1 | 3 |
实际中 Lucene 创建的索引更为复杂,索引中还包含了其他信息,如词向量(为单个字段创建的小索引,存储该字段中所有的词条)、各字段的原始信息、文档删除标记等。
每个索引由多个段(segment)组成,每个段只会被创建一次但会被查询多次。索引期间,段一经创建就不会被修改。如,文档被删除后,删除信息被单独保存在一个文件中,而段本身没有修改。
多个段可以合并在一起,成为段合并(segment merge)。段合并要么强制执行,要么由 Lucene 的内在机制原定在某个时刻进行。合并操作非常消耗I/O,且合并期间有些不再使用的信息也会被清理,例如被删除的文档。
分析包括:
- 将文档中的数据转换为倒排索引,
- 将查询串转换为可用于搜索的词项。
文本分析由分析器执行,分析器由分词器(tokenizer)、过滤器(filter)和字符串映射器(character mapper)组成:
- 分词器:将文本切割成词条,其中包括携带各种额外信息的词项。如词项在原始文本中的位置、词项的长度等。分词器的成功是词条流,一条条地推送给过滤器处理。
- 过滤器:过滤器可以为0个或多个,用于处理词条流中的词条(移除、修改、新增词条)。Lucene提供了许多现成的过滤器:
- 小写过滤器:将所有词条转换为小写。
- ASCII过滤器:移除词条中的非ASCII字符。
- 同义词过滤器:根据同义词,将一个词条转换为另一个。
- 多语言词干还原过滤器:将词条的文本规约为其词根形式。
- 字符串映射器:调用分词器之前的文本预处理操作,如HTML文本去标签。
在索引阶段,Lucene 会根据选择的分析器来处理文档中的内容,可以根据不同的字段选择不用的分析器。检索阶段,如果使用了某个查询分析器(query parser),查询串就会被分析。索引阶段和检索阶段到文本分析要采用相同的分析器,只有查询分析出来的词项和索引中的词项能匹配上,才会返回预期的文档集。
Lucene 中,一个查询通常被分割为词项与操作符。词项可以是单个词,也可以是一个短语(用双引号括起来的组次词)。如果设置了查询分析过程,那么分析器将会对查询的所有词项进行处理。
布尔操作符用于连接多个词项,构成从句(clause):
布尔操作符 | 作用 | 例子 |
---|---|---|
AND | 仅当AND左右两边的词项都在文档中出现时,文档才匹配当前从句 | apache AND lucene |
OR | 包含当前从句中的任意词项均视为与该从句匹配 | apache OR lucene |
NOT | 与当前从句匹配的文档必须不包含NOT后的词项 | lucene NOT elasticsearch |
此外,还有一些操作符:
操作符 | 作用 | 例子 |
---|---|---|
+ | 只有包含+后的词项的文档才会被视为与从句匹配 | +lucene apche:必须包含lucene,但apache可出现可不出现 |
- | 与从句匹配的文档不能出现-后的词项 | +lucene-elasticsearch:包含lucene但不包含elasticsearch |
Lucene 的所有数据都不存储在字段(field)中,字段又是文档的组成单位。为了实现对某个字段的查询,用户需要提供字段名称,在加上冒号以及将要在该字段中执行查询的从句:
title: elasticsearch
也可以在一个字段中同时使用多个从句:
title: (+elasticsearch +"mastering book")
修饰符(modifier)可以修改传入查询对象的词项。最常见的就是通配符(wildcard):?
和 *
。
Lucene 还支持模糊查询(fuzzy and proximity),使用~
字符其后紧跟一个整数值。~
后的整数值确定了近似词项与原始词项的最大编辑距离。如writer~2
,可以匹配包含writer
和writers
的文档。
~
用于短语,其后的整数值表示词项之间的可以接受的最大距离。如title: "mastering elasticsearch"~2
可以匹配包含mastering elasticsearch
和mastering book elasticsearch
的文档。
^
字符并以一个浮点数对词项加权(boosting),以提高该词项的重要程度。默认的词项权重为1。
另外,name: [Adam to Adria]
可以按照字典序查询结余两者之间的词项。price: [10.00 TO 15.00]
查询前闭后开的文档。
反斜杠对特殊字符进行转义,如abs\"efg
。
Elasticsearch 将它的数据存储在一个或多个索引中。Elasticsearch 中的索引可能由一个或多个Lucene 索引构成,具体细节由分片(shard)、复制(replica)机制及其配置决定。
文档(document)由字段构成,每个字段都有字段名以及一个或多个字段值。文档没有固定的模式或强制的结构,Elasticsearch 的文档最后都存储为 Lucene 的文档。
文档在写入索引前要先分析,将文本分割为词条。此外,Elasticsearch 也提供了各种特性,如排序时所需的字段内容信息。这就是映射(mapping)扮演的角色,存储这些元信息。
Elasticsearch 中每个文档都有一个与之对应的类型(type)定义。这允许用户在一个索引中存储多种文档类型,并为不同文档类型提供不同的映射。
单个的Elasticsearch 服务实例成为节点(node)。
多个节点协同处理,就构成了集群(cluster)。集群可以支撑更多的负载,也提供了不间断提供服务的能力。
Elasticsearch 将数据散布在多个物理 Lucene 索引上,这些 Lucene 索引被称为分片(shard),而散布分片的过程称为分片处理(sharding)。Elasticsearch 会自动完成分片处理,并让这些分片呈现一个大索引的样子。
副本(replica)解决了访问压力过大时单机无法处理所有请求的问题,即为每个分片创建冗余的副本。
集群状态中,索引设置的各种信息会被收集起来,并在网关(gateway)中被持久化。
Elasticsearch具有以下主要特征:
- 合理的默认配置。包括内置的发现(如字段类型检查)和自动配置功能。
- 默认的分布式工作模式。
- 对等架构(P2P)可以避免单点故障。节点间相互交换数据、监控操作。
- 易于扩充新节点。
- 没有对索引中的数据结构做任何限制。
- 准实时(Near Real Time,NRT)搜索和版本同步。
Elasticsearch节点启动时,采用广播技术来发现同一集群中的其他节点并与之连接。
集群中会有一个节点被选为master,负责集群的状态管理及在集群拓扑变化时做出反应,分发索引分片至相应节点上。从用户角度,master并不比其他节点重要,所有操作都可以发送给任意节点。如有必要,任意节点都可以并行发送子查询至其它节点,合并搜索结果然后返回给用户。这一切并不需要经过master。
master会读取集群的状态信息,并在必要时进行恢复处理。该阶段,管理节点会检查所有索引分片并决定哪些分片将用于主分片。然后整个集群进入黄色状态。这时可以查询,但系统的吞吐量等情况未知。
如果某个主分片的副本数过少,master决定创建分片和副本。如果一切顺利,集群进入绿色状态。
集群正常工作时,master会监控所有可用节点。如果某节点在预定义的超时时间内没有响应,那么就开启错误处理。对于每个丢失的主分片,一个新的主分片将会从原来的副本中脱颖而出。新分片和副本的放置策略是可配置的。
Elasticsearch有一个精巧的REST API,另外还有Java API(Elasticsearch内部使用Java API进行通信)。
-
索引数据。主要有四种方式:
- 索引API
- bulk API
- UDP bulk API
- 插件(river)
建索引操作只能发生在主分片上。建索引的请求会被转发到拥有正确的主分片的节点。
-
查询数据。查询分为两个阶段:分散(scatter)和合并(gather)。分散阶段把query分发到包含相关文档的多个分片中去执行查询。合并阶段从众多分片中收集结果,然后合并、排序、后续处理,再返回给客户端。
-
所应配置
-
系统管理和监控
下一章: [2. 查询DSL进阶](2. 查询DSL进阶.md)