Elasticsearch 索引
Elasticsearch 索引
索引管理操作
Elasticsearch 索引管理主要包括如何进行索引的创建、索引的删除、副本的更新、索引读写权限、索引别名的配置等等内容。
索引删除
ES 索引删除操作向 ES 集群的 http 接口发送指定索引的 delete http 请求即可,可以通过 curl 命令,具体如下:
1 | curl -X DELETE http://{es_host}:{es_http_port}/{index} |
如果删除成功,它会返回如下信息,具体示例如下:
1 | curl -X DELETE http://10.10.10.66:9200/my_index?pretty |
为了返回的信息便于读取,增加了 pretty 参数:
1 | { |
索引别名
ES 的索引别名就是给一个索引或者多个索引起的另一个名字,典型的应用场景是针对索引使用的平滑切换。
首先,创建索引 my_index,然后将别名 my_alias 指向它,示例如下:
1 | PUT /my_index |
也可以通过如下形式:
1 | POST /_aliases |
也可以在一次请求中增加别名和移除别名混合使用:
1 | POST /_aliases |
需要注意的是,如果别名与索引是一对一的,使用别名索引文档或者查询文档是可以的,但是如果别名和索引是一对多的,使用别名会发生错误,因为 ES 不知道把文档写入哪个索引中去或者从哪个索引中读取文档。
ES 索引别名有个典型的应用场景是平滑切换,更多细节可以查看 Elasticsearch(ES)索引零停机(无需重启)无缝平滑切换的方法。
Settings 详解
Elasticsearch 索引的配置项主要分为静态配置属性和动态配置属性,静态配置属性是索引创建后不能修改,而动态配置属性则可以随时修改。
ES 索引设置的 api 为 **__settings
_**,完整的示例如下:
1 | PUT /my_index |
固定属性
- **_
index.creation_date
_**:顾名思义索引的创建时间戳。 - **_
index.uuid
_**:索引的 uuid 信息。 - **_
index.version.created
_**:索引的版本号。
索引静态配置
- **_
index.number_of_shards
**:索引的主分片数,默认值是 **5
**。这个配置在索引创建后不能修改;在 es 层面,可以通过 **es.index.max_number_of_shards
** 属性设置索引最大的分片数,默认为 **1024
_**。 - **_
index.codec
**:数据存储的压缩算法,默认值为 **LZ4
**,可选择值还有 **best_compression
_**,它比 LZ4 可以获得更好的压缩比(即占据较小的磁盘空间,但存储性能比 LZ4 低)。 - **_
index.routing_partition_size
_**:路由分区数,如果设置了该参数,其路由算法为:( hash(_routing) + hash(_id) % index.routing_parttion_size ) % number_of_shards
。如果该值不设置,则路由算法为hash(_routing) % number_of_shardings
,_routing
默认值为_id
。
静态配置里,有重要的部分是配置分析器(config analyzers)。
index.analysis
:分析器最外层的配置项,内部主要分为 char_filter、tokenizer、filter 和 analyzer。
- **_
char_filter
_**:定义新的字符过滤器件。 - **_
tokenizer
_**:定义新的分词器。 - **_
filter
_**:定义新的 token filter,如同义词 filter。 - **_
analyzer
_**:配置新的分析器,一般是 char_filter、tokenizer 和一些 token filter 的组合。
- **_
索引动态配置
- **_
index.number_of_replicas
**:索引主分片的副本数,默认值是 **1
_**,该值必须大于等于 0,这个配置可以随时修改。 - **_
index.refresh_interval
**:执行新索引数据的刷新操作频率,该操作使对索引的最新更改对搜索可见,默认为 **1s
**。也可以设置为 **-1
_** 以禁用刷新。更详细信息参考 Elasticsearch 动态修改 refresh_interval 刷新间隔设置。
Mapping 详解
在 Elasticsearch 中,**Mapping
**(映射),用来定义一个文档以及其所包含的字段如何被存储和索引,可以在映射中事先定义字段的数据类型、字段的权重、分词器等属性,就如同在关系型数据库中创建数据表时会设置字段的类型。
Mapping 会把 json 文档映射成 Lucene 所需要的扁平格式
一个 Mapping 属于一个索引的 Type
- 每个文档都属于一个 Type
- 一个 Type 有一个 Mapping 定义
- 7.0 开始,不需要在 Mapping 定义中指定 type 信息
映射分类
在 Elasticsearch 中,映射可分为静态映射和动态映射。在关系型数据库中写入数据之前首先要建表,在建表语句中声明字段的属性,在 Elasticsearch 中,则不必如此,Elasticsearch 最重要的功能之一就是让你尽可能快地开始探索数据,文档写入 Elasticsearch 中,它会根据字段的类型自动识别,这种机制称为动态映射,而静态映射则是写入数据之前对字段的属性进行手工设置。
静态映射
静态映射是在创建索引时手工指定索引映射。静态映射和 SQL 中在建表语句中指定字段属性类似。相比动态映射,通过静态映射可以添加更详细、更精准的配置信息。
如何定义一个 Mapping
1 | PUT /books |
动态映射
动态映射是一种偷懒的方式,可直接创建索引并写入文档,文档中字段的类型是 Elasticsearch 自动识别的,不需要在创建索引的时候设置字段的类型。在实际项目中,如果遇到的业务在导入数据之前不确定有哪些字段,也不清楚字段的类型是什么,使用动态映射非常合适。当 Elasticsearch 在文档中碰到一个以前没见过的字段时,它会利用动态映射来决定该字段的类型,并自动把该字段添加到映射中,根据字段的取值自动推测字段类型的规则见下表:
JSON 格式的数据 | 自动推测的字段类型 |
---|---|
null | 没有字段被添加 |
true or false | boolean 类型 |
浮点类型数字 | float 类型 |
数字 | long 类型 |
JSON 对象 | object 类型 |
数组 | 由数组中第一个非空值决定 |
string | 有可能是 date 类型(若开启日期检测)、double 或 long 类型、text 类型、keyword 类型 |
下面举一个例子认识动态 mapping,在 Elasticsearch 中创建一个新的索引并查看它的 mapping,命令如下:
1 | PUT books |
此时 books 索引的 mapping 是空的,返回结果如下:
1 | { |
再往 books 索引中写入一条文档,命令如下:
1 | PUT books/it/1 |
文档写入完成之后,再次查看 mapping,返回结果如下:
1 | { |
使用动态 mapping 要结合实际业务需求来综合考虑,如果将 Elasticsearch 当作主要的数据存储使用,并且希望出现未知字段时抛出异常来提醒你注意这一问题,那么开启动态 mapping 并不适用。在 mapping 中可以通过 dynamic
设置来控制是否自动新增字段,接受以下参数:
- **
true
**:默认值为 true,自动添加字段。 - **
false
**:忽略新的字段。 - **
strict
**:严格模式,发现新的字段抛出异常。
基础类型
类型 | 关键字 |
---|---|
字符串类型 | string、text、keyword |
数字类型 | long、integer、short、byte、double、float、half_float、scaled_float |
日期类型 | date |
布尔类型 | boolean |
二进制类型 | binary |
范围类型 | range |
复杂类型
类型 | 关键字 |
---|---|
数组类型 | array |
对象类型 | object |
嵌套类型 | nested |
特殊类型
类型 | 关键字 |
---|---|
地理类型 | geo_point |
地理图形类型 | geo_shape |
IP 类型 | ip |
范围类型 | completion |
令牌计数类型 | token_count |
附件类型 | attachment |
抽取类型 | percolator |
Mapping 属性
Elasticsearch 的 mapping 中的字段属性非常多,具体如下表格:
| 属性名 | 描述 |
| :- | :- | |
| type
| 字段类型,常用的有 text、integer 等等。 |
| index
| 当前字段是否被作为索引。可选值为 **_true
**,默认为 true。 |
| **store
** | 是否存储指定字段,可选值为 **true
** | **false
**,设置 true 意味着需要开辟单独的存储空间为这个字段做存储,而且这个存储是独立于 **_source
** 的存储的。 |
| **norms
** | 是否使用归一化因子,可选值为 **true
** | **false
**,不需要对某字段进行打分排序时,可禁用它,节省空间;_type 为 text 时,默认为 true_;而 type 为 keyword 时,默认为 false_。 |
| **index_options
** | 索引选项控制添加到倒排索引(Inverted Index)的信息,这些信息用于搜索(Search)和高亮显示:**_docs
:只索引文档编号(Doc Number);freqs
:索引文档编号和词频率(term frequency);positions
:索引文档编号,词频率和词位置(序号);offsets
:索引文档编号,词频率,词偏移量(开始和结束位置)和词位置(序号)。默认情况下,被分析的字符串(analyzed string)字段使用 positions_,其他字段默认使用 docs_。此外,需要注意的是 index_option 是 elasticsearch 特有的设置属性;临近搜索和短语查询时,_index_option 必须设置为 offsets_,同时高亮也可使用 postings highlighter。 |
| **term_vector
** | 索引选项控制词向量相关信息:no
:默认值,表示不存储词向量相关信息;yes
:只存储词向量信息;with_positions
:存储词项和词项位置;with_offsets
:存储词项和字符偏移位置;with_positions_offsets
**:存储词项、词项位置、字符偏移位置。_term_vector 是 lucene 层面的索引设置。 |
| similarity
| 指定文档相似度算法(也可以叫评分模型):**_BM25
**:ES 5 之后的默认设置。 |
| **copy_to
** | 复制到自定义 _all 字段,值是数组形式,即表明可以指定多个自定义的字段。 |
| **analyzer
** | 指定索引和搜索时的分析器,如果同时指定 search_analyzer 则搜索时会优先使用 search_analyzer_。 |
| **search_analyzer
** | 指定搜索时的分析器,搜索时的优先级最高。 |
| null_value
| 用于需要对 Null 值实现搜索的场景,只有 Keyword 类型支持此配置。 |
索引查询
多个 index、多个 type 查询
Elasticsearch 的搜索 api 支持一个索引(index)的多个类型(type)查询以及多个索引(index)的查询。
例如,我们可以搜索 twitter 索引下面所有匹配条件的所有类型中文档,如下:
1 | GET /twitter/_search?q=user:shay |
我们也可以搜索一个索引下面指定多个 type 下匹配条件的文档,如下:
1 | GET /twitter/tweet,user/_search?q=user:banon |
我们也可以搜索多个索引下匹配条件的文档,如下:
1 | GET /twitter,elasticsearch/_search?q=tags:wow |
此外我们也可以搜索所有索引下匹配条件的文档,用_all 表示所有索引,如下:
1 | GET /_all/_search?q=tags:wow |
甚至我们可以搜索所有索引及所有 type 下匹配条件的文档,如下:
1 | GET /_search?q=tags:wow |
URI 搜索
Elasticsearch 支持用 uri 搜索,可用 get 请求里面拼接相关的参数,并用 curl 相关的命令就可以进行测试。
如下有一个示例:
1 | GET twitter/_search?q=user:kimchy |
如下是上一个请求的相应实体:
1 | { |
URI 中允许的参数:
名称 | 描述 |
---|---|
q | 查询字符串,映射到 query_string 查询 |
df | 在查询中未定义字段前缀时使用的默认字段 |
analyzer | 查询字符串时指定的分词器 |
analyze_wildcard | 是否允许通配符和前缀查询,默认设置为 false |
batched_reduce_size | 应在协调节点上一次减少的分片结果数。如果请求中潜在的分片数量很大,则应将此值用作保护机制,以减少每个搜索请求的内存开销 |
default_operator | 默认使用的匹配运算符,可以是AND或者OR,默认是OR |
lenient | 如果设置为 true,将会忽略由于格式化引起的问题(如向数据字段提供文本),默认为 false |
explain | 对于每个 hit,包含了具体如何计算得分的解释 |
_source | 请求文档内容的参数,默认 true;设置 false 的话,不返回_source 字段,可以使用_source_include和_source_exclude参数分别指定返回字段和不返回的字段 |
stored_fields | 指定每个匹配返回的文档中的存储字段,多个用逗号分隔。不指定任何值将导致没有字段返回 |
sort | 排序方式,可以是fieldName、fieldName:asc或者fieldName:desc的形式。fieldName 可以是文档中的实际字段,也可以是诸如_score 字段,其表示基于分数的排序。此外可以指定多个 sort 参数(顺序很重要) |
track_scores | 当排序时,若设置 true,返回每个命中文档的分数 |
track_total_hits | 是否返回匹配条件命中的总文档数,默认为 true |
timeout | 设置搜索的超时时间,默认无超时时间 |
terminate_after | 在达到查询终止条件之前,指定每个分片收集的最大文档数。如果设置,则在响应中多了一个 terminated_early 的布尔字段,以指示查询执行是否实际上已终止。默认为 no terminate_after |
from | 从第几条(索引以 0 开始)结果开始返回,默认为 0 |
size | 返回命中的文档数,默认为 10 |
search_type | 搜索的方式,可以是dfs_query_then_fetch或query_then_fetch。默认为query_then_fetch |
allow_partial_search_results | 是否可以返回部分结果。如设置为 false,表示如果请求产生部分结果,则设置为返回整体故障;默认为 true,表示允许请求在超时或部分失败的情况下获得部分结果 |
查询流程
在 Elasticsearch 中,查询是一个比较复杂的执行模式,因为我们不知道那些 document 会被匹配到,任何一个 shard 上都有可能,所以一个 search 请求必须查询一个索引或多个索引里面的所有 shard 才能完整的查询到我们想要的结果。
找到所有匹配的结果是查询的第一步,来自多个 shard 上的数据集在分页返回到客户端之前会被合并到一个排序后的 list 列表,由于需要经过一步取 top N 的操作,所以 search 需要进过两个阶段才能完成,分别是 query 和 fetch。