一、数据结构
es是文档型的存储方式,一条数据就是一个文档,对于用户来说就是一条JSON.
一个索引下面,有多个文档,一个文档里面有多个字段(灵活的,非结构化的,
也就是每个文档的字段都可以不一样)。
二、集群(Cluster)/节点(Node)/分片(Shards)/副本(Replicasedit)
集群:
实际上就是多个es实例,启动后,只要cluster.name是相同的,
相互之间网络关系也是通的,就是一个es集群。
节点:
实际上就是一个es实例,es的数据存储和搜索等功能都是通过这些具体的实例来实现的。
分片;
一个索引(index)里面的数据可能比较多,不适合单节点存储,索引设置分片,
不同的分片落在不同的节点上。实际上就是对索引数据的水平拆分,
分布方式以及如何将其文档聚合回搜索请求的机制完全由 Elasticsearch 管理,
对用户而言是透明的。
副本:
一个分片可以分为0-N个副本,不同的副本落在不同的节点上,
写入数据是从分片的主副本写入,然后同步到不同的节点的分片的从副本上,
所有的副本都可以进行查询。
小结:
一个es实例,会存在某些index(索引,相当于mysql的库)里面的文档数据过多,
造成单机瓶颈,因为es实例除了维护文档数据,还需要维护倒排索引等信息,
单机数据量过多会造成磁盘空间不够和搜索效率下降等问题。
所以引入了集群,多个es实例的cluster.name是相同的,就组成了一个集群。
一个集群内部,同一个index(索引,只是一个逻辑上的概念)数据,可以通过分片
将数据散落在不同的节点(物理节点,服务器)。就相当于对index里面的数据进行水平
拆分。
但是单个分片数据,有可能又有单点故障的问题,所以每个分片可以设置多个副本,散落在
不同的节点上。
类似于关系型数据库:数据库集群,假如有个用户表,我担心数据量过大,
我新建了多个用户表(即 Shard),将用户信息数据切分成多份,
然后根据某种规则分到这些用户表中,我又担心某个表会出现异常造成数据丢失,
我又将每个表分别备份了一次(即 Replica )。
三、倒排索引
实际上就是通过对文本的分词,生成这种形式的索引: 分词——>所有包含此分词的文档id/词频(Term出现的次数)/偏移量(offset)数组
倒排索引具体的样式:
1、Term(单词)
文本通过分词器分析之后,形成的多个单词
2、Term Dictionary(单词字典):
顾名思义,它里面维护的是Term,可以理解为Term的集合
3、Term Index(单词索引):
为了更快的找到某个单词,为单词建立索引
4、Posting List(倒排列表):
可以想成py里面的字典,单词就是key, value是一个数组,
这个数组里面是一系列的元组(文档id、词频(Term出现的次数)、偏移量(offset))
5、倒排索引的寻址过程
分词之后,会根据分出来的词生成一个term index(分词索引),查找的时候,
会先根据这个term index去找到Term Dictionary(分词字典)中的term,
再根据term找到对应的Posting List(倒排列表)
四、关键属性、字段说明
1、查询返回字段说明:
{
"took": 1, //整个搜索请求花费多少毫秒
"timed_out": false,
"_shards": { //指示搜索了多少分片,以及搜索成功和失败的分片的计数
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": { //用来实际搜索结果集
"total": 1, // 搜索返回条数
"max_score": 0.83355963, //搜索结果匹配度
"hits": [ //查询完整的数据 以_score降序排序
{
"_index": "test", //索引
"_type": "test", //类型
"_id": "xtoffH0BS_BXL2CbFNQ_", //索引数据id
"_score": 0.83355963, // 衡量文档与查询的匹配程度
"_source": { // 结果原数据
"name": "新浪军事22"
}
}
]
}
}
2、创建索引
# 指定mapping创建方式
PUT translated_documents
{
"mappings": {
"translated_documents": { # 7版本之前指的是 类型type,7版本之后可以用_doc替换
"properties": {
"documentId": {
"type": "keyword" # keyword 不参与分词
},
"translation": {
"type": "text", # keyword 参与分词,不能用于排序使用,如何想用于排序需要另外设置keyword字段
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart",
"fields": { # 对于text类型的字段可以单独存储一份 用于后面的排序使用
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"createTime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss" # 指定时间格式后,只能存储指定格式的时间,java中的date类型不能直接存储,需要转换成对应的类型
},
"updateTime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"isDelete": {
"type": "integer"
}
}
}
}}
3、更新文档
# 自动生成唯一 _id :
POST /test/test
{
"name":"我是谁,谁是我"
}
# 返回结果:
{
"_index": "test",
"_type": "test",
"_id": "gLKe4X4BLI5cjpF7njkO", //自动生成的id
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
# 手动设置id
PUT /test/test/465?op_type=create
{
"name":"我是谁,谁是我"
}
或
PUT /test/test/465/_create
{
"name":"我是谁,谁是我"
}
如果创建新文档的请求成功执行则返回
{
"_index": "test",
"_type": "test",
"_id": "465",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
另一方面,如果具有相同的 _index 、 _type 和 _id 的文档已经存在,Elasticsearch 将会返回 409 Conflict 响应码,以及如下的错误信息:
{
"error": {
"root_cause": [
{
"type": "document_already_exists_exception",
"reason": "[blog][123]: document already exists",
"shard": "0",
"index": "website"
}
],
"type": "document_already_exists_exception",
"reason": "[blog][123]: document already exists",
"shard": "0",
"index": "website"
},
"status": 409
}
4、更新文档
es文档是不可改变的,更新文档实际的操作是先查出旧文档的json,然后更新这个json,再删除旧文档,最后再新增一个新的文档
# 更新整个文档,如果文档字段不在更新字段中,则会被舍弃
PUT /test/test/465
{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"
}
# 返回结果
{
"_index": "test",
"_type": "test",
"_id": "465",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
# 更新 文档的部分字段
POST /test/test/465/_update
{
"doc" : {
"tags" : [ "testing" ],
"title": "天天向上"
}
}
# 返回结果
{
"_index": "test",
"_type": "test",
"_id": "465",
"_version": 4,
"result": "updated",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
5、删除文档
更具id删除文档
DELETE /website/blog/123
# 返回结果
{
"_index": "test",
"_type": "test",
"_id": "uZOYM34BLI5cjpF7dwsz",
"_version": 6,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 8,
"_primary_term": 1
}
# 更具指定条件删除文档
POST test/_delete_by_query
{
"query": {
"match": {
"name": "新浪军事22"
}
}
}
# 返回结果
{
"took": 477,
"timed_out": false,
"total": 4,
"deleted": 4,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0,
"failures": []
}
6、条件查询
GET /test/test/_search
{
"query" : {
"match" : {
"name" : "我谁"
}
}
}
# 备注: match:分词匹配;
match_phrase:精确匹配一系列单词或者_短语
match_all: 匹配所有文档,相当于不做筛选
match_phrase_prefix: 最左前缀查询
multi_match: 多字段查询
"multi_match": {
"query": "天天向上",
"fields": ["title","text"]
}