ElasticSearch 入门实战 、索引操作、文档操作

核心概念

节点

一个节点就是一个ElasticSearch的实例,注意,一个节点≠一台服务器,因为一台服务器可以运行多个ES进程

在这里插入图片描述



角色Roles

ES的角色分类:

  • 主节点 active master

    一个集群只有一个,主要作用的对集群的管理

  • 候选节点master-eligible

    主节点宕机,候选节点参与选举

  • 数据节点 data node

    保存已编入索引的文档的分片。数据节点处理数据相关操作,如 CRUD、搜索和聚合。这些操作是 I/O 密集型、内存密集型和 CPU 密集型的。监控这些资源并在它们过载时添加更多数据节点非常重要。

  • 预处理节点ingest-node

    数据写入之前的预处理操作

如果node.reles为缺省配置,那么当前节点具备所有的角色



索引index

在ES中,索引类似于Mysql中的表(仅针对 ES 7.x 以后版本),只是类似 索引并不等于表

在ES中,索引在不同的环境下有以下几个意思:

  • 表示源文件数据

    当做数据的载体,类似于数据表。通常说集群中有User索引就表示当前ES服务中存在User这一张“表”

  • 表示索引文件

    比如倒排索引,目的是加速文件的检索。索引文件和源数据文件是完全独立的,互不影响。

  • 表示创建数据的动作

    新增一条数据,可以所是索引了一个文档,或索引了一条数据



索引的组成部分:

  • aliases:索引别名
  • mappings:映射,定义了索引包含的哪些字段,以及字段的类型、长度、分词器等
  • settings:索引设置,比如分片数量、副本数量等

在这里插入图片描述



类型type

ElasticSearch7.x之后的版本已删除此概念

在之前的版本中,一个索引可以包含多个类型,每个类型代表了不同的文档结构。从ES7.X开始,类型已经被弃用,一个索引只有一个类型

ES7.X

  • 不推荐在请求中指定类型。

    索引文档不再需要文档type。新的索引API适用于PUT {index}/_doc/{id}于显示ID 和 PUT {index}/_doc自动生成id。在ES7.x中 _doc是路径的永久部分,表示端点名称,而不是文档类型

  • 索引创建、索引模板和映射API中的include_type_name参数将默认为false,完全设置参数将导致弃用警告

  • _default_映射类型被删除 。

ES8.X

  • 不再支持在请求中指定类型
  • include_type_name参数被删除。



文档document

文档是ES中最小数据单元。是一个具有结构化JSON格式的记录,文档可以被索引并进行搜索、更新、删除操作

在这里插入图片描述

文档元数据中,字段以下划线开头,为系统字段,用于标注文档相关信息

  • _index:文档所属索引名

  • _type:文档所属的类型名

  • _id: 文档唯一id

  • _version:文档版本号,修改/删除操作改字段都会+1

  • _seq_no:和version一样文档数据更改,该字段值自增。Shard级别严格递增,保存后写入DOC的_seq_no大于先写入DOC的_seq_no

  • _primary_term:恢复数据时处理多个文档的_seq_no一样时的冲突,避免Primary Shard上写入的数据被覆盖。每当Primary Sharding重新分配时该字段+1

  • _source:文档的原始JSON数据



ElasticSearch索引操作

参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/index.html

创建索引

PUT /索引名称



命名规范:

  • 以小写字母命名
  • 不要用驼峰命名
  • 多个单词用下划线分割

ES的索引创建成功后,以下属性将不可更改

  • 索引名称
  • 主分片数量
  • 字段类型



创建索引

PUT /sys_user

执行结果

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "sys_user"
}



查询索引

GET /索引名称



#查询索引
GET /sys_user

#es_db是否存在
HEAD /sys_user



删除索引

DELETE /索引名



设置settings

创建索引的时候指定 settings

PUT <index_name>
{
  "settings": {}
}



创建索引时可以设置分片数和副本数

# 创建索引时指定分片数为3, 每个主分片的副本数量为 2
PUT /sys_user
{
  "settings": {
    "number_of_shards": 3, 
    "number_of_replicas": 2
  }
}
# 创建索引时可以指定IK分词器作为默认分词器
PUT /sys_user
{
  "settings": {
    "number_of_shards": 3, 
    "number_of_replicas": 2,
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  }

在这里插入图片描述



静态索引设置

只能在创建索引时或在关闭状态的索引上设置

  • index.number_of_shards,索引的主分片的个数,默认为 1



动态索引设置

可以使用 _setting实时更改的配置

  • index.number_of_replicas:每个主分区的副本数。默认为1,允许配置为0
  • index.refresh_interval:执行刷新操作的频率,默认为1s. 可以设置 -1 为禁用刷新。
  • index.max_result_window:from + size 搜索此索引 的最大值,默认为 10000。

使用 _setting 只能修改允许动态修改的配置项

PUT /sys_user/_settings
{
  "index": {
    "number_of_replicas": 1
  }
}



设置Mappings

ES中的Mappings类似于关系型数据库的表结构

在 Mapping 里也包含了一些属性,比如字段名称、类型、字段使用的分词器、是否评分、是否创建索引等属性,并且在 ES 中一个字段可以有多个类型。ES中Mapping可以分为动态映射和静态映射。

# 查看整个索引信息
GET /<index_name>

# 查看完整的索引 mapping
GET /<index_name>/_mappings

# 查看索引中指定字段的 mapping
GET /<index_name>/_mappings/field/<field_name>



注意事项:

  • ES没有隐式类型转换
  • ES不支持类型修改
  • 生产环境劲浪避免使用动态映射



动态映射

关系型数据库中需要先建表、定义字段的类型,然后才能插入数据。而ES不需要事先定义Mapping映射,在文档写入时会根据字段自动识别类型,这种称为动态映射

自动类型推断规则

其中text会分词后创建倒排索引,而keyword不会分词,直接使用现有的数据建立的另一种索引

在这里插入图片描述



# 删除原来的索引
DELETE /sys_user

# 创建文档(ES根据数据类型, 会自动创建映射)
POST /sys_user/_doc/1
{
  "username": "hushang",
  "age": 24,
  "address": "广州天河公园"
}

#获取文档映射
GET /sys_user/_mapping

在这里插入图片描述



静态映射

在文档写入之前,创建索引时就指定索引中每个字段的类型、分词器等参数

# 删除原索引
DELETE /sys_user

PUT /sys_user
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  }, 
  "mappings": {
    "properties": {
      "username": {
        "type": "keyword"
      },
      "age": {
        "type": "long",
        "index": false
      },
      "address": {
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}



常用Mapping参数配置
参数名称释义
analyzer指定分析器,只有 text 类型字段支持。
copy_to该参数允许将多个字段的值复制到组字段中,然后可以将其作为单个字段进行查询
dynamic控制是否可以动态添加新字段,支持以下四个选项:
true:(默认)允许动态映射
false:忽略新字段。这些字段不会被索引或搜索,但仍会出现在_source返回的命中字段中。这些字段不会添加到映射中,必须显式添加新字段。
runtime:新字段作为运行时字段添加到索引中,这些字段没有索引,是_source在查询时加载的。
strict:如果检测到新字段,则会抛出异常并拒绝文档。必须将新字段显式添加到映射中。
doc_values为了提升排序和聚合效率,默认true,如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用doc值以节省磁盘空间(不支持 text 和 annotated_text)
eager_global_ordinals用于聚合的字段上,优化聚合性能。
enabled是否创建倒排索引,可以对字段操作,也可以对索引操作,如果不创建索引,任然可以检索并在_source元数据中展示,谨慎使用,该状态无法修改。
fielddata查询时内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为fielddata数据结构,并且创建倒排索引保存到堆中
fields给 field 创建多字段,用于不同目的(全文检索或者聚合分析排序)
format用于格式化代码,如
“data”:{ “type”: “data”, “format”: “yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis” }
index是否对创建对当前字段创建倒排索引,默认 true,如果不创建索引,该字段不会通过索引被搜索到,但是仍然会在 source 元数据中展示。
norms是否禁用评分(在filter和聚合字段上应该禁用)
null_value为 null 值设置默认值
search_analyzer设置单独的查询时分析器



案例,address字段禁用倒排索引

DELETE /sys_user

PUT /sys_user
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  }, 
  "mappings": {
    "properties": {
      "username": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "address": {
        "type": "text",
        "index": false        #  address字段禁用倒排索引
      }
    }
  }
}

# 查询一下索引信息
GET /sys_user

# 添加一个文档
POST /sys_user/_doc/1
{
  "username": "hushang",
  "age": 24,
  "address": "广州天河公园"
}

# 通过关键词进行搜索,就会发现报错了
GET /sys_user/_search
{
  "query": {
    "match": {
      "address": "广州"
    }
  }
}



在这里插入图片描述



dynamic设为true时,一旦有新增字段的文档写入,Mapping 也同时被更新;dynamic设置成strict(严格控制策略),文档写入失败,抛出异常

PUT /sys_user
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  }, 
  "mappings": {
    "dynamic": "strict",			# dynamic的值设置为strict
    "properties": {
      "username": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "address": {
        "type": "text"
      }
    }
  }
}

# 添加一条文档, 其中加了一个sex性别字段
POST /sys_user/_doc/1
{
  "username": "hushang",
  "age": 24,
  "address": "广州天河公园",
  "sex": "男"
}

报错信息如下

在这里插入图片描述



修改dynamic后再次插入文档成功

PUT /sys_user/_mapping
{
  "dynamic": true
}



注意:对已有字段,一旦已经有数据写入,就不再支持修改字段定义

  • Lucene 实现的倒排索引,一旦生成后,就不允许修改

  • 如果希望改变字段类型,可以利用 reindex API,重建索引



使用reindex重建索引

具体使用步骤:

  • 如果想推到现有的映射,需要重新创建一个索引
  • 把之前索引的数据导入到新索引中
  • 删除老索引
  • 为新索引起一个别名,为原索引

通过这几个步骤可以实现索引的平滑过渡,并且是零停机

# 创建一个新索引
PUT /sys_user2
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  },
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "username": {
        "type": "keyword"
      },
      "age": {
        "type": "long",
        "index": false
      },
      "address": {
        "type": "text"
      },
      "sex": {
        "type": "text",
        "index": false
      }
    }
  }
}


# 把之前索引的数据导入到新索引中
POST _reindex
{
  "source": {
    "index": "sys_user"
  },
  "dest": {
    "index": "sys_user2"
  }
}


# 删除原索引
DELETE /sys_user


# 为新索引起一个别名,为原索引
PUT /sys_user2/_aliases/sys_user

在这里插入图片描述



错误示范

如果新索引中没有包含老索引的所有字段,那么就会报错,如下所示

# sys_user索引中有username、age、address、sex四个字段, 新索引只有前面三个字段
PUT /sys_user2
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  },
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "username": {
        "type": "keyword"
      },
      "age": {
        "type": "long",
        "index": false
      },
      "address": {
        "type": "text"
      }
    }
  }

# 然后在进行reindex就会报错
POST _reindex
{
  "source": {
    "index": "sys_user"
  },
  "dest": {
    "index": "sys_user2"
  }
}

在这里插入图片描述



ES文档操作

示例数据

PUT /sys_user
{
    "settings" : {
        "index" : {
            "analysis.analyzer.default.type": "ik_max_word"
        }
    }
}

PUT /sys_user/_doc/1
{
"name": "张三",
"sex": 1,
"age": 25,
"address": "广州天河公园",
"remark": "java developer"
}
PUT /sys_user/_doc/2
{
"name": "李四",
"sex": 1,
"age": 28,
"address": "广州荔湾大厦",
"remark": "java assistant"
}

PUT /sys_user/_doc/3
{
"name": "王五",
"sex": 0,
"age": 26,
"address": "广州白云山公园",
"remark": "php developer"
}

PUT /sys_user/_doc/4
{
"name": "赵六",
"sex": 0,
"age": 22,
"address": "长沙橘子洲",
"remark": "python assistant"
}

PUT /sys_user/_doc/5
{
"name": "张龙",
"sex": 0,
"age": 19,
"address": "长沙麓谷企业广场",
"remark": "java architect assistant"
}    
    
PUT /sys_user/_doc/6
{
"name": "赵虎",
"sex": 1,
"age": 32,
"address": "长沙麓谷兴工国际产业园",
"remark": "java architect"
}    

PUT /sys_user/_doc/7
{
"name": "李虎",
"sex": 1,
"age": 32,
"address": "广州番禺节能科技园",
"remark": "java architect"
}

PUT /sys_user/_doc/8
{
"name": "张星",
"sex": 1,
"age": 22,
"address": "武汉东湖高新区未来智汇城",
"remark": "golang developer"
}



索引文档

索引文档也就是新增文档数据

[PUT或POST] /索引名/[_doc或_create]/文档id 
{
     "FIELD": "TEXT"
}



# 创建文档,指定id,如果id不存在,创建新的文档,否则先删除现有文档,再创建新的文档,版本会增加
PUT /sys_user/_doc/1
{
  "name": "张三",
  "sex": 2,
  "age": 18,
  "address": "广州天河公园",
  "remark": "java developer"
}

#创建文档,ES生成id  需要使用post请求
POST /sys_user/_doc
{
  "name": "张11",
  "sex": 1,
  "age": 11,
  "address": "广州天河公园",
  "remark": "java developer"
}



在这里插入图片描述



在这里插入图片描述



PUT 和 POST请求都能进行创建/修改操作。PUT请求需要指定id 对一个具体的资源进行操作,而POST是可以对整个资源集合进行操作的

POST请求如果在url中不指定id那就是ES自动生成一个id,如果url中填了id那就针对这个id文档进行创建/更新



在这里插入图片描述



在这里插入图片描述



查询文档

# 根据id查询文档
GET /索引名/_doc/文档id

# 条件查询
GET /索引名/_doc/_search

ES对条件查询提供了两种方式

  • REST风格的请求URL,直接在URL中将参数传递过去 (了解即可)
  • 封装到RequestBody中,这种方式可以定义更加易读的JSON格式



URI Query(了解即可)

#通过URI搜索,使用“q”指定查询字符串,“query string syntax” KV键值对

#条件查询, 如要查询age等于28岁的 _search?q=*:***
GET /es_db/_doc/_search?q=age:28

#范围查询, 如要查询age在25至26岁之间的 _search?q=***[** TO **]  注意: TO 必须为大写
GET /es_db/_doc/_search?q=age[25 TO 26]

#查询年龄小于等于28岁的 :<=
GET /es_db/_doc/_search?q=age:<=28
#查询年龄大于28前的 :>
GET /es_db/_doc/_search?q=age:>28

#分页查询 from=*&size=*
GET /es_db/_doc/_search?q=age[25 TO 26]&from=0&size=1

#对查询结果只输出某些字段 _source=字段,字段
GET /es_db/_doc/_search?_source=name,age

#对查询结果排序 sort=字段:desc/asc
GET /es_db/_doc/_search?sort=age:desc



DSL Query

DSL(Domain Specific Language领域专用语言)查询是使用Elasticsearch的查询语言来构建查询的方式。

# match 匹配查询,会对查询文本分词后匹配 
GET /sys_user/_search
{
  "query": {
    "match": {
      "address": "广州天河"
    }
  }
}

# 上方可以直接省略 _doc , 也是一样的
GET /sys_user/_doc/_search
{
  "query": {
    "match": {
      "address": "广州天河"
    }
  }
}


# term 词项查询,属于精确查询,不会对查询文本分词
GET /sys_user/_search
{
  "query": {
    "term": {
      "address": "广州天河"
    }
  }
}



更新文档

  • 全量更新,使用PUT或POST /索引名/_doc/文档id

    这种方式会先将现有的文档删除,然后索引一个新文档

    在这里插入图片描述



  • 部分更新,使用_update ,格式 POST /索引名/_update/文档id

    _update 文档必须已经存在,更新只会对相应字段做增量修改

    在这里插入图片描述



  • 使用 _update_by_query 更新文档
# 更新复合条件的文档
POST /sys_user/_update_by_query
{
  "query": {
    "match": {
      "_id": "1"
    }
  },
  "script": {
    "source": "ctx._source.age = 24",
    "lang": "painless"
  }
}

# 查询
GET /sys_user/_doc/1



在这里插入图片描述



在这里插入图片描述



  • 并发场景下修改文档

_seq_no_primary_term是对_version的优化,7.X版本的ES默认使用这种方式控制版本,所以当在高并发环境下使用乐观锁机制修改文档时,要带上当前文档的_seq_no_primary_term进行更新:

# 方式一
POST /es_db/_doc/2?if_seq_no=20&if_primary_term=6
{
  "name": "李四xxx"
}



# 方式二
POST /sys_user/_update_by_query
{
  "query": {
    "match": {
      "_id": "1",
      "_seq_no": 17,
      "_primary_term": 5
    }
  },
  "script": {
    "source": "ctx._source.age = 25",
    "lang": "painless"
  }
}



删除文档

DELETE /索引名/_doc/文档id

在这里插入图片描述



文档批量操作

批量操作可以减少网络连接产生的开销,提高性能

  • 支持再一次API调用中,对不同的索引进行操作
  • 操作中单条失败,并不会影响其他操作
  • 返回结果包含了每一条操作执行的结果



批量写入

批量对文档进行写操作是通过_bulk的API来实现的

  • 请求方式:POST

  • 请求地址:_bulk

  • 请求参数:通过_bulk操作文档,一般至少有两行参数(或偶数行参数)

    • 第一行参数为指定操作的类型及操作的对象(index,type和id)
    • 第二行参数才是操作的数据

参数类似于:

# actionName:表示操作类型,主要有create,index,delete和update
{"actionName":{"_index":"indexName", "_type":"typeName","_id":"id"}}
{"field1":"value1", "field2":"value2"}



批量创建文档create

使用create

POST _bulk
{"create":{"_index":"sys_user","_type":"_doc","_id":10}}
{"name":"王五1","sex":0,"age":26,"address":"广州白云山公园","remark":"php developer"}
{"create":{"_index":"sys_user","_type":"_doc","_id":11}}
{"name":"王五2","sex":0,"age":26,"address":"广州白云山公园","remark":"php developer"}



普通创建或全量替换index

使用index。如果id指定文档不存在则创建,如果id指定文档存在则全量修改源文档,也也就是先删除再新增

POST _bulk
{"index":{"_index":"sys_user","_type":"_doc","_id":10}}
{"name":"王五1","sex":0,"age":26}
{"index":{"_index":"sys_user","_type":"_doc","_id":11}}
{"name":"王五2","sex":0,"age":26,"address":"广州白云山公园"}



批量修改update

使用update

POST _bulk
{"update":{"_index":"sys_user","_type":"_doc","_id":10}}
{"doc":{"name":"王五11","sex":1}}
{"update":{"_index":"sys_user","_type":"_doc","_id":11}}
{"doc":{"name":"王五22","sex":1,"age":45,"address":"广州白云山公园111"}}



批量删除delete

使用delete,此时就不需要在添加 field和value这些数据了

POST _bulk
{"delete":{"_index":"sys_user","_type":"_doc","_id":10}}
{"delete":{"_index":"sys_user","_type":"_doc","_id":11}}



组合应用

可以把createindexupdatedelete结合使用

POST _bulk
{"index":{"_index":"sys_user","_type":"_doc","_id":10}}
{"name":"李四","sex":1,"age":21,"address":"广州荔湾大厦","remark":"java assistant"}
{"index":{"_index":"sys_user","_type":"_doc","_id":11}}
{"name":"李四11","sex":1,"age":21,"address":"广州荔湾大厦11","remark":"java assistant"}
{"update":{"_index":"sys_user","_type":"_doc","_id":10}}
{"doc":{"name":"王五","sex":0}}
{"delete":{"_index":"sys_user","_type":"_doc","_id":11}}



批量查询

ES的批量查询可以使用_mget_msearch两种方式

  • _mget:需要我们知道文档id,可以指定不同的index,也可以指定返回值source
  • _msearch:通过字段查询来进行一个批量的查找

_mget案例

# 可以通过ID批量获取不同index的数据
GET _mget
{
  "docs": [
    {
      "_index": "sys_user",
      "_id": 10
    },
    {
      "_index": "article",
      "_id": 4
    }
  ]
}

# 根据id批量获取一个索引下的多个文档
GET /sys_user/_mget
{
  "docs": [
    {"_id": 3},
    {"_id": 4}
  ]
}

# 上面可以简化
GET /sys_user/_mget
{
  "ids": [3, 4]
}



_msearch,它的使用和_bulk类似,查询一条数据需要两个对象,第一个设置查询的索引,第二个设置查询语句。查询语句和search相同。

如果只查询一个index,我们可以在rul中带上index,这样如果查询该index就可以直接用空对象表示

GET /sys_user/_msearch
{}
{"query": {"match_all": {}}, "from": 0, "size": 2}
{"index": "article"}
{"query": {"match": {"title": "老师"}}}

在这里插入图片描述

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值