注:此文档仅适用于 Elasticsearch > 5.0 版本
一个 Elasticsearch 集群可以包含多个索引,相应的每个索引可以包含多个类型。这些不同的类型存储着多个 文档,每个文档又有多个字段,每一个文档都有一个唯一的_id的属性,因此索引、 类型 、_id 这三个属性可以定位到一个具体的文档。
一个索引类似于传统关系数据库中的一个数据库,是一个存储关系型文档的地方。但是,与关系型数据库不同,Elasticsearch 一次查询可以同时搜索多个数据库的数据。
创建索引
默认情况下,我们可以通过添加一个新的文档来创建一个新的索引,但是此时创建的索引采用的是默认的配置,新的字段通过动态映射的方式被添加到类型映射。如果需要对这个建立索引的过程做更多的控制:我们想要确保这个索引有数量适中的主分片,合适的映射关系和分析器,我们需要手动创建索引。
如果你想禁止自动创建索引,你可以通过在
config/elasticsearch.yml
的每个节点下添加下面的配置:action.auto_create_index: false
PUT /my_index
{
"settings": {
"number_of_shards" : 1,
"number_of_replicas" : 0
},
"mappings": {
"type_one": { ... any mappings ... },
"type_two": { ... any mappings ... },
...
}
}
settings
下有下面几个重要的设置:
number_of_shards
每个索引的主分片数,默认值是 5
。这个配置在索引创建后不能修改,因此这个数值需要仔细考虑斟酌。分片类似于数据库中的分库分表,在集群中,同一个索引的分片会均匀的分布在集群的节点中。
举个例子,如果当前集群中有3个节点,设置了 number_of_shards
为3,则3个分片就会均匀的分布在3个节点上,查询时,可以并行查询3个节点。但是,如果集群增加到 6 个节点,这时由于 number_of_shards
不能修改,就不能利用到 6 个节点了。因此,在设计之初就要考虑好 number_of_shards
怎么设置,考虑是否留一定余地。
number_of_replicas
每个主分片的副本数(即备份),默认值是 1
。这个配置是可以随时修改。在开发环境下可以将这个数值设置为0,以减少磁盘空间的消耗。生产环境下,根据节点数和看情况选择合适的值,值越大,磁盘空间消耗越大。
我们可以用 update-index-settings
API 动态修改副本数:
PUT /my_index/_settings
{
"number_of_replicas": 1
}
refresh_interval
在 Elasticsearch 中,当添加一个文档到这个文档可以被搜索需要一个过程,这个过程叫做需要消耗很大的资源,因此不是每次添加文档 Elasticsearch 都会执行写入这个操作。因此 Elasticsearch 会在一定的窗口期内集中大量文档一起进行 ,默认情况下这个窗口期为 1s。
这就是为什么我们说 Elasticsearch 是近实时搜索,文档的变化不是立即对搜索可见的,但会在1秒之后变为可见。
但并不是每种情况都需要每秒刷新。可能你正在使用 Elasticsearch 索引大量日志文件,你可能想优化索引速度而不是近实时搜索,可以通过设置 refersh_interval
,降低每个索引的刷新频率。
PUT /my_index
{
"settings": {
"refresh_interval": "30s"
}
}
translog
translog 也称事务日志,在每一次对 Elasticsearch 进行操作时均进行了日志记录。translog 主要用于保证 Elasticsearch 的可靠性。当服务器宕机时,Elasticsearch 可以根据事务日志进行恢复。
将 translog 持久化到磁盘的过程,在 Elasticsearch 称为 flush。默认情况下是每 5 秒或者每次写请求完成之后执行一次 flush。
在每次请求后都执行 flush 会带来一些性能损失,因此对于一些大容量的偶尔丢失几秒数据问题也不太严重的集群,可以使用异步 fsync 的方式提高性能。比如,写入的数据被缓存到内存中,在每 5 秒执行一次 fsync。
这个行为可以通过设置 durability
参数为 async
来启用:
PUT /my_index/_settings
{
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"
}
这个选项可以针对索引单独设置,也可以动态修改。如果你决定使用异步 translog 的话,你需要保证发生宕机时,丢掉 sync_interval
时间段的数据也无所谓。
删除索引
# 删除索引
DELETE /my_index
# 你也可以这样删除多个索引
DELETE /index_one,index_two
DELETE /index_*
# 删除全部索引:
DELETE /_all
DELETE /*
查询索引信息
GET /twitter
Mappings
类型在 Elasticsearch 中表示一类相似的文档,类似于数据库中的表。类型由名称和映射组成。
映射,就像数据库中的 schema ,描述了文档可能具有的字段或属性 、 每个字段的数据类型以及 Lucene 是如何索引和存储这些字段的。
映射的最高一层被称为根对象 ,它可能包含下面几项:
- 一个 properties 节点,列出了文档中可能包含的每个字段的映射
- 各种元数据字段,它们都以一个下划线开头,例如
_type
、_id
和_source
- 设置项,控制如何动态处理新的字段,例如
analyzer
、dynamic_date_formats
和dynamic_templates
- 其他设置,可以同时应用在根对象和其他
object
类型的字段上,例如enabled
、dynamic
和include_in_all
使用 PUT 添加或更新 mappings,GET 方法获取 mappings。
PUT my_index
{
"mappings": {
"_source": { "enabled": false },
"_all": { "enabled": false },
"my_type": {
"properties": {
"tags": { "type": "keyword" }
}
}
}
}
# 获取指定 type 的 mapping
GET /twitter/_mapping/tweet
# 获取所有的 mapping
GET /_mapping
元数据字段
每一个文档都有与之关联的元数据,例如 _type
、 _id
和 _source
。在创建映射的时候,可以自定义这些元数据的行为。
(1)文档标识:
文档标识与四个元数据字段相关:
_id
:文档的 ID 字符串
_type
:文档的类型
_index
:文档的索引
_uid
:_type
和 _id
连接在一起构造成 type#id
(2)原数据
_source
:默认地,Elasticsearch 在 _source
字段存储代表文档体的JSON字符串。然而,存储 _source
字段的确要使用磁盘空间。因此可以使用下面的方法禁用 _source
字段。
PUT /my_index
{
"mappings": {
"my_type": {
"_source": { "enabled": false }
}
}
}
(3)索引
_field_names
:_field_names
字段包含了文档中所有除 null 之外的字段名称,主要用于 exists
查询。使用 _field_names
会增加创建索引的时间,如果你不需要使用 exists
查询,可以禁用 _field_names
。
PUT /my_index
{
"mappings": {
"_doc": {
"_field_names": { "enabled": false }
}
}
}
_all
:一个把其它字段值当作一个大字符串来索引的特殊字段(在最新的 6.0 版本中,_all
已经取消,因此不建议使用)。 如果你不再需要 _all
字段,你可以通过下面的映射来禁用:
PUT /my_index/_mapping/my_type
{
"my_type": {
"_all": { "enabled": false }
}
}
字段类型
核心类型
text
:字符串类型,用于全文索引的字段,例如一篇文章或评论。
keyword
:keyword 用于结构化查询的字段。
long
, integer
, short
, byte
, double
, float
, half_float
, scaled_float
:数字类型
date
:时间类型
常用的时间类型 format 有:epoch_millis(时间戳,精确到毫秒)、epoch_second(时间戳,精确到秒)
boolean
:布尔类型
binary
:二进制类型
复杂类型
array
:json 中的数组,里面可以包含 string
、integers
、array
、objects
,如果是 array
object
,里面包含的对象或数组不会被索引。
object
:对象
nested
:array 对象,里面的包含的对象字段会被索引。
其它具体的字段类型,可以查看官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/5.0/mapping-types.html
dynamic
当 Elasticsearch 遇到文档中以前未遇到的字段,它用动态映射来确定字段的数据类型并自动把新的字段添加到类型映射。
有时这是想要的行为有时又不希望这样。通常没有人知道以后会有什么新字段加到文档,但是又希望这些字段被自动的索引。也许你只想忽略它们。如果Elasticsearch是作为重要的数据存储,可能就会期望遇到新字段就会抛出异常,这样能及时发现问题。
可以用 dynamic
配置来控制这种行为 ,可接受的选项如下:
-
true
: 动态添加新的字段--缺省 -
false
: 忽略新的字段 -
strict
: 如果遇到新字段抛出异常
例如下面这个例子:如果遇到新字段,对象 my_type
就会抛出异常。而内部对象 stash
遇到新字段就会动态创建新字段。
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic": "strict",
"properties": {
"title": { "type": "string"},
"stash": {
"type": "object",
"dynamic": true
}
}
}
}
}
把
dynamic
设置为false
时,不会改变_source
的字段内容。_source
仍然包含被索引的整个文档。只是新的字段不会被加到映射中也不可搜索。
缺省映射
通常,一个索引中的所有类型共享相同的字段和设置。 _default_
映射更加方便地指定通用设置,而不是每次创建新类型时都要重复设置。 _default_
映射是新类型的模板。在设置 _default_
映射之后创建的所有类型都将应用这些缺省的设置,除非类型在自己的映射中明确覆盖这些设置。
例如,我们可以使用 _default_
映射为所有的类型禁用 _all
字段, 而只在 blog
类型启用:
PUT /my_index
{
"mappings": {
"_default_": {
"_all": { "enabled": false }
},
"blog": {
"_all": { "enabled": true }
}
}
}
更新 mapping
当需要新增类型或新增字段时,只需要重新 PUT 新的索引信息即可。但是当我们需要添加新的分析器或对已有字段修改时,Elasticsearch 是不允许这样做的,如果你那么做的话,结果就是那些已经被索引的数据就不正确, 搜索也不能正常工作。
这个时候就需要创建新的索引,然后数据重新导入。如果你的索引开启了 _source
字段,则可以使用 reindex
功能快速进行这个过程。
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
索引别名
索引别名就像一个快捷方式或软连接,可以指向一个或多个索引,也可以给任何一个需要索引名的API来使用。别名 带给我们极大的灵活性,允许我们做下面这些:
- 在运行的集群中可以无缝的从一个索引切换到另一个索引
- 给多个索引分组 (例如,
last_three_months
) - 给索引的一个子集创建
视图
下面例子展示如何创建索引别名和删除索引别名。
POST /_aliases
{
"actions": [
{ "remove": { "index": "my_index_v1", "alias": "my_index" }},
{ "add": { "index": "my_index_v2", "alias": "my_index" }}
]
}
通过下面的操作可以查看已经创建的别名信息。
# 查看这个别名指向哪个索引
GET /*/_alias/my_index
# 哪些别名指向这个索引
GET /my_index_v1/_alias/*
索引模板
在日志类应用中,通常会根据日志的时间分配到不同的索引中。例如:2017-01-02 的日志分配到 log-20170102
的索引中。这样做有几个好处,(1)按照时间划分,按天查询或统计的速度会比较快(2)如果2018年的日志比2017年的日志多,可以调整2018年日志的分片数,以提高效率。
在日志类应用中,如果每次都手动创建索引会比较麻烦,这时就可以使用索引模板功能让 Elasticsearch 根据模板自动创建索引。
下面例子创建了一个 my_logs
的索引模板,此模板适用于所有以 logs-
开头的索引,新创建的索引会被自动添加到 last_3_months
这个别名中。多个模板同时匹配,以 order
顺序倒排,order
越大,优先级越高。
PUT /_template/my_logs
{
"template": "logs-*",
"order": 0,
"settings": {
"number_of_shards": 1
},
"mappings": {
"_default_": {
"_all": {
"enabled": false
}
}
},
"aliases": {
"last_3_months": {}
}
}
在运行过程中,如果需要修改模板则可以运行上面的例子,修改里面的参数。完成之后,创建新索引的配置项会跟着发生变化,已经创建了的索引不会发生变化。
查看模板和删除模板的方法如下:
# 删除模板
DELETE /_template/template_1
# 查看所有模板
GET /_template
# 查看指定名称的模板
GET /_template/template_1
参考资料:
- Elasticsearch mapping 设计总结
- Elasticsearch: 权威指南
- Elasticsearch 官方文档
- elasticsearch中 refresh 和flush区别