一、基本概念
由于Elasticsearch也是基于Lucene实现,因此它的许多概念和Luncene相似,关于Lucene的知识,可以参考文章:
Lucene初探——基于Lucene 6.6.2。
1.1 Node、Cluster
Elasticsearch本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。单个 Elastic 实例称为一个节点(node)
。一组节点构成一个集群(cluster)
。
1.2 Index
Elasticsearch会索引所有字段,经过处理后写入一个倒排索引(Inverted Index)
。查找数据的时候,直接查找该索引。
所以,Elasticsearch 数据管理的顶层单位就叫做 Index(索引)
,它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。
下面的命令可以查看当前节点的所有 Index。
http://localhost:9200/_cat/indices?v
当我们插入数据的时候,如果有超出我们结构化的数据的时候,索引默认会自动更新数据,我们可以在创建索引时指定dynamic
属性的默认值:
- true:默认,可以自动创建索引,插入数据字段不符合的话就创建新的索引。
- false:不自动创建索引,当插入数据不符合默认属性的时候,忽略新插入的不符合的字段的值。
- strict:精确的,不允许插入不符合默认属性的值,如果不符合,直接报错。
1.3 Document
Index 里面单条的记录称为 Document(文档)
。许多条 Document 构成了一个 Index。Document 使用 JSON
格式表示,下面是一个例子。
{
"name": "jitwxs",
"sex": "1",
"email": "jitwxs@foxmail.com"
}
同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。
1.4 Type
Document 可以分组,比如某个 Index ,可以按城市分组(北京和上海),也可以按气候分组(晴天和雨天)。这种分组就叫做Type
,它是虚拟的逻辑分组,用来过滤 Document。
不同的 Type 应该有相似的结构(schema),举例来说,id字段不能在这个组是字符串,在另一个组是数值。
性质完全不同的数据应该存成两个 Index,而不是一个 Index 里面的两个 Type。下面的命令可以列出每个 Index 所包含的 Type:
http://localhost:9200/_mapping?pretty=true
根据规划,Elasticsearch 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。
1.5 文档字段属性
1.5.1 字段数据类型
字段的数据类型由字段的属性type指定,ElasticSearch支持的基础数据类型主要有:
- 字符串类型:keyword和text
- keyword:数据类型用来建立电子邮箱地址、姓名、邮政编码和标签等数据类型,不需要进行分词。可以被用来检索过滤、排序和聚合。keyword 类型字段只能用本身来进行检索。
- text:Text 数据类型被用来索引长文本,这些文本会被分析,在建立索引前会将这些文本进行分词,转化为词的组合,建立索引。比如你配置了IK分词器,那么就会进行分词,搜索的时候会搜索分词来匹配这个text文档。但是:text 数据类型不能用来排序和聚合。
- 数值类型:字节(byte)、2字节(short)、4字节(integer)、8字节(long)、float、double;
- 布尔类型:boolean,值是true或false;
- 时间/日期类型:date,用于存储日期和时间;
- 二进制类型:binary;
- IP地址类型:ip,以字符串形式存储IPv4地址;
- 特殊数据类型:token_count,用于存储索引的字数信息
1.5.2 字段的公共属性
index
:该属性控制字段是否编入索引被搜索,取值为true或false。在5.X版本之前该属性共有三个有效值:analyzed、no和not_analyzed:
analyzed:(默认属性)表示该字段被分析,编入索引,产生的token能被搜索到;not_analyzed:表示该字段不会被分析,使用原始值编入索引,在索引中作为单个词;no:不编入索引,无法搜索该字段;
store
:指定是否将字段的原始值写入索引,默认值是no,字段值被分析,能够被搜索,但是,字段值不会存储,这意味着,该字段能够被查询,但是不会存储字段的原始值。boost
:字段级别的助推,默认值是1,定义了字段在文档中的重要性/权重;include_in_all
:该属性指定当前字段是否包括在_all字段中,默认值是ture,所有的字段都会包含_all字段中;如果index=no,那么属性include_in_all无效,这意味着当前字段无法包含在_all字段中。copy_to
:该属性指定一个字段名称,ElasticSearch引擎将当前字段的值复制到该属性指定的字段中;doc_values
:文档值是存储在硬盘上的索引时(indexing time)数据结构,对于not_analyzed字段,默认值是true,analyzed string字段不支持文档值;fielddata
:字段数据是存储在内存中的查询时(querying time)数据结构,只支持analyzed string字段;null_value
:该属性指定一个值,当字段的值为NULL时,该字段使用null_value代替NULL值;在ElasticSearch中,NULL 值不能被索引和搜索,当一个字段设置为NULL值,ElasticSearch引擎认为该字段没有任何值,使用该属性为NULL字段设置一个指定的值,使该字段能够被索引和搜索。
1.5.3 字符串类型常用的其他属性
analyzer
:该属性定义用于建立索引和搜索的分析器名称,默认值是全局定义的分析器名称,该属性可以引用在配置结点(settings)中自定义的分析器;search_analyzer
:该属性定义的分析器,用于处理发送到特定字段的查询字符串;ignore_above
:该属性指定一个整数值,当字符串字段(analyzed string field)的字节数量大于该数值之后,超过长度的部分字符数据将不能被analyzer处理,不能被编入索引;对于 not analyzed string字段,超过长度的部分字符将被忽略,不会被编入索引。默认值是0,禁用该属性;position_increment_gap
:该属性指定在相同词的位置上增加的gap,默认值是100;index_options
:索引选项控制添加到倒排索引(Inverted Index)的信息,这些信息用于搜索(Search)和高亮显示:
- docs:只索引文档编号(Doc Number)
- freqs:索引文档编号和词频率(term frequency)
- positions:索引文档编号,词频率和词位置(序号)
- offsets:索引文档编号,词频率,词偏移量(开始和结束位置)和词位置(序号)
- 默认情况下,被分析的字符串(analyzed string)字段使用positions,其他字段使用docs;
二、索引操作
2.1 结构化索引和非结构化索引
- 结构化索引:类似MySQL,我们会对索引结构做预定义,包括字段名,字段类型等
- 非结构化索引:类似Mongodb,索引结构未知,根据具体的数据来update索引的mapping
结构化相比非结构化,更易优化,性能好些;非结构化相较灵活,只是频繁update索引mapping会有一定的性能损耗。
本文下面的索引操作均是结构化索引,即指明了索引的具体结构。
2.2 创建索引
请求方式: PUT
请求路径: ES服务的IP:端口/要创建的索引名
假设我要创建一个user索引,拥有字段name、age、create_date,数据类型分别为字符串、数值、日期。那么请求内容如下:
{
"settings":{
"number_of_shards":5, //分片数
"number_of_replicas":1 //备份数
},
//映射文件
"mappings":{
//类型名
"novel":{
//文档的所有字段以及类型
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"integer"
},
"create_date":{
"type":"date",
"format":"yyyy-MM-dd HH:mm:ss || yyyy-MM-dd" //日期格式化允许的类型
}
}
}
}
}
响应内容如下:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "user"
}
2.3 删除索引
请求方式: DELETE
请求路径: ES服务的IP:端口/要删除的索引名
对于本例就是: DELETE localhost:9200/user
,这里我就不演示了。
2.4 重建索引
如果你的索引后期要修改,那么你只能重建一个你要修改成的索引,然后将数据复制到新的索引中。
请求方式: POST
请求路径: ES服务的IP:端口/_reindex
POST localhost:9200/_reindex
{
"source": {
"index": "old_index"
},
"dest": {
"index": "new_index"
}
}
三、数据操作
3.1 插入数据
当你创建的索引是非结构化的索引的时候,你可以随意插入你想要的字段作为属性。并且你每次插入的字段值可以是不一致的,索引会自动更新mapping,来适应数据。但是每次插入会耗费性能来做这些事情。
当你创建的索引是结构化的索引的时候,你如果插入的数据不符合你创建的mapping,那么也会自动更新mapping来适应你添加的数据,不会出现添加不上数据的情况。但是不建议这么做。
3.1.1 指定ID
请求方式: PUT
请求路径: ES服务的IP:端口/索引名/类型名/id
3.1.2 不指定ID
请求方式: POST
请求路径: ES服务的IP:端口/索引名/类型名
3.2 查看数据
请求方式: GET
请求路径: ES服务的IP:端口/索引名/类型名/ID
返回的数据中,found字段表示查询成功,_source字段返回原始记录。
3.3 修改数据
3.3.1 直接修改
请求方式: POST
请求路径: ES服务的IP:端口/索引名/类型名/ID/_update
请求体:
{
"doc": {
"name": "zhangsan",
"age": 16,
"create_date": "2018-05-20"
}
}
3.3.2 使用脚本修改
请求方式: POST
请求路径: ES服务的IP:端口/索引名/类型名/ID/_update
请求体:
{
"script": {
"lang": "painless",
"inline": "ctx._source.age += 1"
}
}
方法是POST,路径跟上面一致,需要注意的是,但是请求体的时候,使用的是script,,inline
字段的值时可以对属性进行计算。
3.3.3 使用脚本并指定参数修改
请求方式: POST
请求路径: ES服务的IP:端口/索引名/类型名/ID/_update
请求体:
{
"script": {
"lang": "painless",
"inline": "ctx._source.age = params.newAge",
"params": {
"newAge": 28
}
}
}
inline中的参数可以使用params中的参数。
3.4 删除数据
请求方式: DELETE
请求路径: ES服务的IP:端口/索引名/类型名/ID