【转】Elasticsearch学习笔记
一、常用术语
索引(Index)、类型(Type)、文档(Document)
- 索引Index是含有相同属性的文档集合。索引在ES中是通过一个名字来识别的,且必须是英文字母小写,且不含中划线(-);可类比于 MySQL 中的 database ;在 7.0中,由于类型(Type)的移除,我们可以理解为,一个索引就是一张 table。
- 一个索引中可以定义一个或多个类型Type,文档必须属于一个类型;可类比于 MySQL 中的 table;
- 文档Document是可以被索引的基本数据单位。文档是Elasticsearch中最小的数据存储单位。可类比于 MySQL 中 一个table 中的一行记录
注意事项:
从ES6.0开始,官方便不建议一个索引中创建多个类型;在ES7.0中,更是移除了类型(Type)这个概念。为什么呢?
在Elasticsearch索引中,不同类型(Type)中具有相同名称的字段在内部由相同的Lucene字段支持。一个index中多个Type在Lucene中会有许多问题。具体的可以参考官方说明:Removal of mapping types
节点Node、集群Cluster
- 节点:一个ES运行实例,是集群的的构成单元
- 集群:由1个(只有1个节点也是1个集群)或多个节点组成,对外提供服务
分片Shard(集群—提高吞吐与计算性能)、副本Replica(主从—提高可用性)
- 在ES中,每个索引都有多个分片,每个分片都是一个Lucene索引。假设一个索引的数据量很大,就会造成硬盘压力很大,同时,搜索速度也会出现瓶颈。我们可以将一个索引分为多个分片,从而分摊压力;分片同时还允许用户进行水平地扩展和拆分,以及分布式的操作,可以提高搜索以及其他操作的效率。
- 拷贝一份分片,就完成了分片的备份。备份的好处是,当一个主分片出现问题时,备份的分片就能代替工作,从而提高了ES的可用性。同时,备份的分片还可以执行搜索操作,以分摊搜索的压力。ES禁止同一个分片的主分片和副本分片在同一个节点上。
RESTful API
Elasticsearch 集群对外提供 RESTful API
- REST - REpresentational State Transfer
- URI 指定资源,如Index、Document等
- Http Method 指明资源操作类型,如GET、POST、PUT、DELETE等
倒排索引
-
正排索引
倒排索引组成
倒排索引是搜索引擎的核心,主要包含两部分:
- 单词词典(Term Dictionary)
- 记录所有文档的单词,一般都比较大
- 记录单词到倒排列表的关联信息
- 单词字典的实现一般是用B+Tree,能兼顾内存与磁盘性能,保障增删改查高效
- 倒排列表(Posting List)
- 倒排列表(Posting List)记录了单词对应的文档集合,由倒排索引项(Posting)组成
- 倒排索引项(Posting)主要包含如下信息:
- 文档ld,用于获取原始信息
- 单词频率(TF,Term Frequency),记录该单词在该文档中的出现次数,用于后续相关性算分
- 位置(Position),记录单词在文档中的分词位置(多个),用于做词语搜索(Phrase Query)
- 偏移(Offset),记录单词在文档的开始和结束位置,用于做高亮显示
ES中的倒排索引
es存储的是一个json格式的文档,其中包含多个字段,每个字段会有自己的倒排索引。
相关性算分
相关性算分是指文档与查询语句间的相关度,英文为 relevance
- 通过倒排索引可以获取与查询语句相匹配的文档列表,那么如何将最符合用户查询需求的文档放到前列呢?
- 本质是一个排序问题,排序的依据是相关性算分
相关性算分的几个重要概念
- Term Frequency(TF)词频,即单词在该文档中出现的次数。词频越高,相关度越高
- Document Frequency(DF)文档频率,即单词出现的文档数
- Inverse Document Frequency(IDF)逆向文档频率,与文档频率相反,简单理解为1/DF。即单词出现的文档数越少,相关度越高
- Field-length Norm 文档越短,相关性越高
使用 explain 参数查看具体的计算方法
- es的算分是按照shard进行的,即shard的分数计算是相互独立的,所以在使用explain的时候注意分片数
-
可以通过设置索引的分片数为1来避免这个问题
ES中的相关性算分模型
- TF/IDF 模型
- BM25 模型5.x之后的默认模型
TF/IDF 模型
BM25 模型
二、Document API
1. 文档是一个Json Object,由字段(Field)组成,常见数据类型如下:
- 字符串:text,keyword(不分词)
- 数值型:long,integer,short byte,double,float,half float,scaled_float
- 布尔:boolean
- 日期:date
- 二进制:binary
- 范围类型:integer_range,float_range,long_range,double_range,date_range
2. 文档元数据,用于标注文档的相关信息
- _index:文档所在的索引名
- _type:文档所在的类型名(7.0后默认_doc)
- _id:文档唯一id
- _uid:组合id,由_type和_id组成(6.x_type不再起作用,因此同_id值一样),默认禁用
- _source:文档的原始Json数据,可以从这里获取每个字段的内容
- _all:整合所有字段内容到该字段,默认禁用
3. 每个文档有唯一的_Id标识
- 自行指定
- es自动生成
4. 文档API
- es有专门的Document API,创建文档,查询文档,更新文档,删除文档
创建文档(创建文档时,如果索引不存在,es会自动创建对应的index和type)
- 指定id创建文档
PUT /test_index/_doc/1
{
"username":"zhangsan",
"age":1
}
- 不指定id创建文档
POST /test_index/_doc
{
"username":"lisi",
"sex":2
}
查询文档
- 指定要查询的文档id
GET /test_index/_doc/1
- 搜索所有文档,用到_search
GET /test_index/_search # GET /test_index/_doc/_search在高版本提示类型已过期,因此不用指定type了
批量增删改查文档
- ES允许一次创建多个文档,从而减少网络传输开销,提升写入速率,endpoint为_bulk
- index 用于创建文档,文档已存在则更细文档
- create 同样可以创建文档,文档已存在则返回错误
- delete 用于删除文档
- update 用于更新文档,文档不存在则返回错误
- 在es6.0之后的版本可以省略_type,官方已舍弃_type这个概念
POST _bulk
{"index":{"_index":"test_index","_id":"3"}}
{"username":"alfred","age":10}
{"create":{"_index":"test_index","_id":"3"}}
{"username":"alfred2","age":110}
{"delete":{"_index":"test_index","_id":"1"}}
{"update":{"_id":"2","_index":"test_index"}}
{"doc":{"age":"20"}}
返回:
{
"took" : 18,
"errors" : true,
"items" : [
{
"index" : {
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 4,
"_primary_term" : 1,
"status" : 200
}
},
{
"create" : {
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"status" : 409,
"error" : {
"type" : "version_conflict_engine_exception",
"reason" : "[3]: version conflict, document already exists (current version [2])",
"index_uuid" : "jjJIqT7QSeaYcOeWxxY-og",
"shard" : "0",
"index" : "test_index"
}
}
},
{
"delete" : {
"_index" : "test_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 3,
"result" : "not_found",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 5,
"_primary_term" : 1,
"status" : 404
}
},
{
"update" :