前言
Elasticsearch会自动创建索引,但是要较好的应用Elasticsearch的话,必须要了解Elasticsearch索引的相关管理。(Elasticserch权威指南读书笔记)
创建索引
我们可以通过Elasticsearch的接口来手动的创建索引。
PUT /index
{
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
},
"@version": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"id": {
"type": "long"
},
"name": {
"type": "text",
"search_analyzer": "ik_max_word",
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"create_time": {
"type": "long"
},
"update_time": {
"type": "long"
}
}
}
}
这里我们重点介绍4种映射:
1、普通数字索引映射
"wish_num": {
"type": "long"
}
非常简单,把字段wish_num
定义为long就可以了。搜索使用可以对wish_num
进行检索。
2、非索引字段
"product_official_id": {
"type": "text",
"index": false
}
这种类型的字段,我们在查询结果里面需要它,但是我们并不会使用这个字段来做检索,那么我们可以加一个index:false,这样可以让Elasticsearch不对这个字段建立索引,节省空间。Elasticsearch的索引非常占空间。
3、长文字全文检索
"introduction": {
"type": "text",
"search_analyzer": "ik_max_word",
"analyzer": "ik_max_word"
}
类型为text,并且指定了分词器与搜索时候的分词器。我们这里使用了中文的ik分词器,它有ik_smart跟ik_max_word两种方式,具体区别可以自行搜索了解。通常我们使用ik_max_word较多。
4、全文检索+关键字定义
"name": {
"type": "text",
"search_analyzer": "ik_max_word",
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
与长文字检索几乎相同,但是我们发现底下还多了一个fields字段,里面定义了keyword。它与长文字全文检索的差异是:定义了keyword的字段,可以用来做排序与聚合,而text则不行。这样的字段我们通常会加在标签、游戏名、类型、开发者这类可以用来归类排序数据的文字字段上。
如果有需要的话,可以通过配置config/elasticsearch.yml中的参数来关闭Elasticsearch的自动创建索引。
action.auto_create_index: false
删除索引
索引的删除那就很简单了:
#指定索引名称进行删除
DELETE /index_name
#根据索引名称 批量删除
DELETE /index_one,index_two
#使用通配符 批量删除
DELETE /index_*
#删除所有索引
DELETE /_all
#删除所有索引
DELETE /*
注意:为了防止误删,可以设置只能通过指定索引名称进行删除。
action.destructive_requires_name: true
索引设置
我们可以通过修改配置来自定义索引。不过除非你理解这些配置的作用,不然不要轻易的修改它。
这里简单了解一下最重要的两个参数:
- number_of_shards:每个索引的主分片数,默认值是5。这个配置在索引创建后不能修改。
- number_of_replicas:每个主分片的副本数,默认值是1。对于活动的索引库,这个配置可以随时修改。
创建1个主分片,2个副分片的索引:
PUT /my_temp_index
{
"settings": {
"number_of_shards" : 1,
"number_of_replicas" : 2
}
}
动态修改副分片数量为3:
PUT /my_temp_index/_settings
{
"number_of_replicas": 3
}
配置分析器
索引除了主副分片之外,最重要的可能就是analysis的设置了。
Elasticsearch默认使用standard分析器,对于大部分的语言来说,它都是一个不错的选择,它包括了:
- standard分词器,通过单词边界分割输入的文本。
- standard语汇单元过滤器,目的是整理分词器触发的语汇单元(但是目前什么都没做)。
- lowercase语汇单元过滤器,转换所有的语汇单元为小写。
- stop 语汇单元过滤器,删除停用词(对搜索相关性影响不大的常用词,如a、the 、and等 )。
注意:默认情况下,停用词过滤器是被禁用的。如需启用它,你可以通过创建一个基于standard分析器的自定义分析器并设置stopwords参数。
如官方案例,创建了一个新的分析器es_std,并使用预定义的西班牙语停用词列表:
PUT /spanish_docs
{
"settings": {
"analysis": {
"analyzer": {
"es_std": {
"type": "standard",
"stopwords": "_spanish_"
}
}
}
}
}
进行索引测试:
GET /spanish_docs/_analyze?analyzer=es_std
El veloz zorro marrón
返回结果:
{
"tokens" : [
{ "token" : "veloz", "position" : 2 },
{ "token" : "zorro", "position" : 3 },
{ "token" : "marrón", "position" : 4 }
]
}
已经将西班牙语停用词El移除。
自定义分析器
虽然Elasticsearch带有一些现成的分析器,然而在分析器上Elasticsearch真正的强大之处在于,你可以通过在一个适合你的特定数据的设置之中组合字符过滤器、分词器、词汇单元过滤器来创建自定义的分析器。
创建自定义分析器
和我们之前配置es_std分析器一样,我们可以在analysis下的相应位置设置字符过滤器、分词器和词单元过滤器:
PUT /my_index
{
"settings": {
"analysis": {
"char_filter": { ... custom character filters ... },
"tokenizer": { ... custom tokenizers ... },
"filter": { ... custom token filters ... },
"analyzer": { ... custom analyzers ... }
}
}
}
作为示范,让我们一起来创建一个自定义分析器吧,这个分析器可以做到下面的这些事:
- 使用html清除,字符过滤器移除HTML部分。
- 使用一个自定义的映射字符过滤器把&替换为and:
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": [ "&=> and "]
}
}
- 使用标准分词器分词。
- 小写词条,使用小写词过滤器处理。
- 使用自定义停止词过滤器移除自定义的停止词列表中包含的词:
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": [ "the", "a" ]
}
}
我们的分析器定义用我们之前已经设置好的自定义过滤器组合了已经定义好的分词器和过滤器:
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": [ "html_strip", "&_to_and" ],
"tokenizer": "standard",
"filter": [ "lowercase", "my_stopwords" ]
}
}
汇总起来,完整的 创建索引 请求 看起来应该像这样:
PUT /my_index
{
"settings": {
"analysis": {
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": [ "&=> and "]
}},
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": [ "the", "a" ]
}},
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": [ "html_strip", "&_to_and" ],
"tokenizer": "standard",
"filter": [ "lowercase", "my_stopwords" ]
}}
}}}
索引被创建以后,使用 analyze API 来 测试这个新的分析器:
GET /my_index/_analyze?analyzer=my_analyzer
The quick & brown fox
下面的缩略结果展示出我们的分析器正在正确地运行:
{
"tokens" : [
{ "token" : "quick", "position" : 2 },
{ "token" : "and", "position" : 3 },
{ "token" : "brown", "position" : 4 },
{ "token" : "fox", "position" : 5 }
]
}
这个分析器现在是没有多大用处的,除非我们告诉 Elasticsearch在哪里用上它。我们可以像下面这样把这个分析器应用在一个 string 字段上:
PUT /my_index/_mapping/my_type
{
"properties": {
"title": {
"type": "string",
"analyzer": "my_analyzer"
}
}
}
动态映射
遇到文档中以前未遇到的字段,它用dynamic mapping来确定字段的数据类型并自动把新的字段添加到类型映射。
但是实际业务中,可能这并不符合我们的要求,幸运的是可以用dynamic配置来控制这种行为 ,可接受的选项如下:
- true:动态添加新的字段(es默认值)
- false:忽略新的字段
- strict:如果遇到新字段抛出异常
官方案例:
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic": "strict",
"properties": {
"title": { "type": "string"},
"stash": {
"type": "object",
"dynamic": true
}
}
}
}
}
这样设置的话,如果遇到新字段,对象 my_type 就会抛出异常,但是内部对象 stash 遇到新字段就会动态创建新字段。
自定义动态映射
其实Elasticsearch的主动映射是一个很好的功能,只是可能它映射的类型不是我们需要的,这时我们可以自定义动态映射的规则。
日期检测
比如我们有一个字段是string类型的,但是Elasticsearch获取到的第一个数据为2014-01-01,那它就会被映射成日期的类型,而其它无法被识别成日期的数据将会造成一个异常。
为了防止这种情况,可以考虑关闭日期的自动映射:
PUT /my_index
{
"mappings": {
"my_type": {
"date_detection": false
}
}
}
如此一来。这个映射,字符串将始终作为 string 类型。如果你需要一个 date 字段,你必须手动添加。
动态模板
我们可以使用dynamic_templates完全控制新检测生成字段的映射。你甚至可以通过字段名称或数据类型来应用不同的映射。
模板按照顺序来检测;第一个匹配的模板会被启用。
例如,我们给string类型字段定义两个模板:
- es :以 _es 结尾的字段名需要使用spanish分词器。
- en :所有其他字段使用english分词器。
官方案例:
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic_templates": [
{ "es": {
"match": "*_es",
"match_mapping_type": "string",
"mapping": {
"type": "string",
"analyzer": "spanish"
}
}},
{ "en": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "string",
"analyzer": "english"
}
}}
]
}}}
其它
- match_mapping_type:允许你应用模板到特定类型的字段上,就像有标准动态映射规则检测的一样, (例如 string 或 long)。
- match:参数只匹配字段名称,path_match 参数匹配字段在对象上的完整路径,所以 address.*.name 将匹配这样的字段:
{
"address": {
"city": {
"name": "New York"
}
}
}
- unmatch/path_unmatch:用于未被匹配的字段。
缺省映射
通常,一个索引中的所有类型共享相同的字段和设置。 default 映射更加方便地指定通用设置,而不是每次创建新类型时都要重复设置。 default 映射是新类型的模板。在设置 default 映射之后创建的所有类型都将应用这些缺省的设置,除非类型在自己的映射中明确覆盖这些设置。
例如,我们可以使用 default 映射为所有的类型禁用 _all 字段, 而只在 blog 类型启用:
PUT /my_index
{
"mappings": {
"_default_": {
"_all": { "enabled": false }
},
"blog": {
"_all": { "enabled": true }
}
}
}
重建索引
Elasticsearch索引一旦建立,不能添加新的分析器或者对现有的字段做改动,只能重建索引。
我们应该建立一个新的索引,然后将旧索引的数据迁移到新的索引中:
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
索引别名和零停机
索引别名的主要功能:
- 零停机的重建索引
- 给多个索引分组
- 给索引的一个子集创建视图
别名的使用:
# 创建一个索引
PUT /my_index_v1
# 给索引添加一个别名
PUT /my_index_v1/_alias/my_index
# 查看这个别名指向哪些索引
GET /*/_alias/my_index
# 查看这个索引的别名
GET /my_index_v1/_alias/*
零停机的切换索引:
POST /_aliases
{
"actions": [
{ "remove": { "index": "my_index_v1", "alias": "my_index" }},
{ "add": { "index": "my_index_v2", "alias": "my_index" }}
]
}