ES 数据管理2

目录:

一、 文档批量操作

二、 DSL 语言高级查询

三、文档映射

四、 核心类型

五、 keyword 与 text 映射类型的区别

六、创建静态映射时 指定  text 类型的 ik 分词器

七、对已存在的 mapping 映射进行修改

八、 Elasticsearch 乐观并发控制

 

本文以 8.2.0 版本为例

一、 文档批量操作

  1、 批量获取文档数据, 通过 _mget 的 API 来实现的 

    1.1 、 URL 中不指定 index 和 type,   可以通过ID批量获取不同index的数据

      请求参数:   docs: 文档数组参数

              _index: 指定index      _id: 指定id      _source: 指定要查询的字段

GET _mget
{
"docs": [
{
"_index": "es_db","_id": 1
},
{
"_index": "es_db","_id": 2
}
]
}

响应结果如下:

{
  "docs" : [
    {
      "_index" : "es_db",
      "_id" : "1",
      "found" : false
    },
    {
      "_index" : "es_db",
      "_id" : "2",
      "_version" : 3,
      "_seq_no" : 7,
      "_primary_term" : 2,
      "found" : true,
      "_source" : {
        "name" : "douger chueng",
        "age" : 18
      }
    }
  ]
}

    1.2 、 在 URL 中指定 index, 可以通过ID批量获取指定index的数据

GET /es_db/_mget
{
"docs": [
{
"_type":"_doc",
"_id": 3
},
{
"_type":"_doc",
"_id": 4
}
]
}

  2、 批量操作文档数据, 通过 _bulk 的API 来实现

    请求参数:  第一行参数为指定操作的类型及操作对象(index, id);

          第二行参数才是操作的数据

    主要操作有: create、index、delete 和 update

    2.1 、批量创建文档  create , 如果不指定 _id, 则会自动生成随机串为id

POST _bulk
{"create":{"_index":"es_db",  "_id":3}}
{"id":3,"title":"douger","content":"douger666","tags":["java", "面向对象"],"create_time":1554015482530}
{"create":{"_index":"es_db",  "_id":4}}
{"id":4,"title":"mick","content":"mickNB","tags":["java", "面向对象"],"create_time":1554015482530}

    2.2 、 普通创建 或 全量替换 index

POST _bulk
{"index":{"_index":"es_db",  "_id":3}}
{"id":3,"title":"cheung","content":"douger666","tags":["java", "面向对象"],"create_time":1554015482530}
{"index":{"_index":"es_db",  "_id":4}}
{"id":4,"title":"lei","content":"mickNB","tags":["java", "面向对象"],"create_time":1554015482530}

    2.3 、 批量修改

POST _bulk
{"update":{"_index":"es_db", "_id":3}}
{"doc":{"title":"吸星大法"}}
{"update":{"_index":"es_db", "_id":4}}
{"doc":{"title":"Go语言万岁"}}

    2.4 、 批量删除

POST _bulk
{"delete":{"_index":"es_db",  "_id":3}}
{"delete":{"_index":"es_db",  "_id":4}}

 

二、 DSL 语言高级查询

  Domain Specific Language (DSL) 领域专用语言:  叶子查询子句复核查询子句

 

 

   1、 无条件查询 :  查询所有, 或者使用 match_all 表示所有

GET /es_db/_doc/_search
{
"query":{
"match_all":{}
}
}

  2、 有查询条件

    2.1、 叶子条件查询(但字段查询条件)

      2.1.1 模糊匹配

        match: 通过 match 关键词模糊匹配条件内容

        prefix: 前缀匹配

        regexp: 通过正则表达式来匹配数据

        match 的复杂用法:

          query: 指定匹配的值

          operator: 匹配条件类型

            and : 条件分词后都要匹配

            or : 条件分词后有一个匹配即可(默认)  

          minmum_should_match: 指定最小匹配的数量

      2.1.2 精确匹配

        term: 单个条件相等

        terms: 单个字段属于某个值数组内的值

        range: 字段属于某个范围内的值

        exists: 某个字段的值是否存在

        ids: 通过 ID 批量查询

    2.2、 组合条件查询(多条件查询)

      bool : 个条件之间有 and, or 或 not 的关系

        must: 各个条件都必须满足, 即各条件是 and 的关系

        should: 各条件有一个满足即可, 即各条件是 or 的关系

        must_not : 不满足所有条件, 即各条件是 not 的关系

        filter: 不计算相关度评分, 他不计算 _score 即相关度评分, 效率更高

      constant_score: 不计算相关度评分

      must/filter/shoud/must_not 等子条件是通过 term/ terms / range / ids/ exists / match 等叶子条件为参数的

 

    2.3 、 链接查询(多文档合并查询)

      父子文档查询  parent/child

      嵌套文档查询  nested

 

    2.4 、 DSL 查询语句:   查询DSL (query DSL) 和  过滤DSL (filter DSL)

      

      在查询上下文中,查询会回答这个问题——“这个文档匹不匹配这个查询,它的相关度高么?”
      如何验证匹配很好理解,如何计算相关度呢?ES中索引的数据都会存储一个_score分值,分值越高就代表越匹配。另外关于某个搜索的分值计算还是很复杂的,因此也需要    一定的时间
 
      在过滤器上下文中,查询会回答这个问题——“这个文档匹不匹配?”
      答案很简单,是或者不是。它不会去计算任何分值,也不会关心返回的排序问题,因此效率会高一点。
      过滤上下文 是在使用filter参数时候的执行环境,比如在bool查询中使用must_not或者filter
      另外,经常使用过滤器,ES会自动的缓存过滤器的内容,这对于查询来说,会提高很多性能
 
    2.5、 Query 方式查询
 
# term 精确匹配
POST /es_db/_search { "query": { "term": { "title": "mick" } } } #SQL select * from es_db where title = 'mick';
# 信息模糊匹配, match 根据字段的分词器,进行分词查询
POST /es_db/_search
{
"from": 0,
"size": 2, 
"query": {
"match": {
"address": "广州"
}
}
}

#SQL select * from user where address like '%广州%' limit 0,2;
# 多字段模糊匹配查询 与 精准查询
POST /es_db/_search
{
"query":{
"multi_match":{
"query":"张三",
"fields":["address","name"]
}
}
}

#SQL select * from student where name like '%张三%' or address like '%张三%' ;
# 未指定字段条件查询 query_string , 含 AND 与 OR 条件

POST /es_db/_search
{
"query":{
"query_string":{
"query":"广州 OR 长沙"
}
}
}
# 指定字段条件查询 query_string , 含 AND 与 OR 条件

POST /es_db/_doc/_search
{
"query":{
"query_string":{
"query":"admin OR 长沙",
"fields":["name","address"]
}
}
}

  范围查询: 

    注:  json 请求中字符串部分字段的含义: 

        range : 范围关键字

        gte : 大于等于

        lte : 小于等于

        gt : 大于

        lt : 小于

        now : 当前时间

POST /es_db/_doc/_search
{
"query" : {
"range" : {
"age" : {
"gte":25,
"lte":28
}
}
}
}
#
SQL: select * from user where age between 25 and 28

# 分页、输出字段、排序综合查询

POST /es_db/_doc/_search
{
"query" : {
"range" : {
"age" : {
"gte":25,
"lte":28
}
}
},
"from": 0,
"size": 2,
"_source": ["name", "age", "book"],
"sort": {"age":"desc"}
}

    2.6、 Filter 过滤方式查询, 不回计算相关性分值,也不会对结果排序,查询结果可以被缓存。

POST /es_db/_doc/_search
{
"query" : {
"bool" : {
"filter" : {
"term":{
"age":25
}
}
}
}
}    

总结:

1、 match

match:模糊匹配,需要指定字段名,但是输入会进行分词,比如"hello world"会进行拆分为hello和world,然后匹配,如果字段中包含hello或者world,或者都包含的结果都会被查询出来,也就是说match是一个部分匹配的模糊查询。查询条件相对来说比较宽松。
 
2、term
term: 这种查询和match在有些时候是等价的,比如我们查询单个的词hello,那么会和match查询结果一样,但是如果查询"hello world",结果就相差很大,因为这个输入不会进行分词,就是说查询的时候,是查询字段分词结果中是否有"hello world"的字样,而不是查询字段中包含"hello world"的字样。当保存数据"hello world"时,elasticsearch会对字段内容进行分词,"hello world"会被分成hello和world,不存在"hello world",因此这里的查询结果会为空。这也是term查询和match的区别。

 3、match_phase

match_phase:会对输入做分词,但是需要结果中也包含所有的分词,而且顺序要求一样。以"hello world"为例,要求结果中必须包含hello和world,而且还要求他们是连着的,顺序也是固定的,hello that world不满足,world hello也不满足条件。
 
4、query_string
query_string:和match类似,但是match需要指定字段名,query_string是在所有字段中搜索,范围更广泛
 

三、 文档映射

 
  动态映射 和 静态映射。
    动态映射: elasticsearch 根据文档字段自动识别类型,这种机制称之为动态映射
    静态映射: 事先定义好映射,包含文档的各字段类型、分词器等,这种方式称之为静态映射
 

 

# 设置文档静态映射
# 其中 index 表示是否在倒排索引中包含该数据, store 表示是否在数据存储中包含该数据, 如果需要当作查询条件但不需要显示为结果,则可为false.
PUT /es_db { "mappings":{ "properties":{ "name":{"type":"keyword","index":true,"store":true}, "sex":{"type":"integer","index":true,"store":true}, "age":{"type":"integer","index":true,"store":true}, "book":{"type":"text","index":true,"store":true}, "address":{"type":"text","index":true,"store":true} } } }

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

 

 四、 核心类型

  字符串: string , string 包含 text 和 keyword.

    text:该类型被用来索引长文本,在创建索引前会将这些文本进行分词,转化为词的组合,建立索引;允许es来检索这些词,text类型不能用来排序和聚合

    keyword: 该类型不能分词,可以被用来检索过滤、排序和聚合,keyword类型不可用text进行分词模糊检索

  数值型: long, integer, short, byte, double, float

  日期型: date

  布尔型: boolean

 

五、 keyword 与 text 映射类型的区别

  将 book 字段设置为 keyword 映射 (只能精准查询, 不能分词查询,能聚合、排序)
  将 book 字段设置为 text 映射能模糊查询, 能分词查询,不能聚合、排序)
 

六、 创建静态映射时 指定  text 类型的 ik 分词器

PUT /es_db
{
"mappings":{
"properties":{
"name":{"type":"keyword","index":true,"store":true},
"sex":{"type":"integer","index":true,"store":true},
"age":{"type":"integer","index":true,"store":true},
"book":{"type":"text","index":true,"store":true,"analyzer":"ik_smart","search_analyzer":"ik_smart"},
"address":{"type":"text","index":true,"store":true}
}
}
}

 

七、 对已存在的 mapping 映射进行修改

  1、 重新建立一个新的索引

  2、 把之前索引的数据导入新的索引里

  3、删除原创建的索引

  4、为新索引起个别名 - 原索引名

# 迁移数据
POST _reindex
{
"source": {
"index": "db_index"
},
"dest": {
"index": "db_index_2"
}
}

DELETE /db_index

PUT /db_index_2/_alias/db_index
注意: 通过这几个步骤就实现了索引的平滑过渡,并且是零停机
 

八、 Elasitcsearch 乐观并发控制

 
  Elasticsearch 8.x 版本 使用 if_seq_no=版本值&if_primary_term=文档位置
    _seq_no : 文档版本号 ,作用同 _version
    _primary_term : 文档所在位置
POST /es_db/_doc/1
{
"id": 1,
"name": "douger",
"desc": "金仙之下无敌手",
"create_date": "2022-07-04"
}

POST /es_db/_update/1
{
"doc": {
"name": "独角大王"
}
}

GET /es_db/_doc/1
---------------------结果----------------------------------
{
  "_index" : "es_db",
  "_id" : "1",
  "_version" : 2,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "id" : 1,
    "name" : "独角大王",
    "desc" : "金仙之下无敌手",
    "create_date" : "2022-07-04"
  }
}
-------------------------------------------------------


POST /es_db/_update/1/?if_seq_no=1&if_primary_term=1
{
"doc": {
"name": "徐小凤传奇"
}    
}
GET /es_db/_doc/1
---------------------结果----------------------------------
{
  "_index" : "es_db",
  "_id" : "1",
  "_version" : 3,
  "_seq_no" : 2,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "id" : 1,
    "name" : "徐小凤传奇",
    "desc" : "金仙之下无敌手",
    "create_date" : "2022-07-04"
  }
}

-------------------------------------------------------


# 更新报错,应为 _seq_no 已经改变了
POST /es_db/_update/1/?if_seq_no=1&if_primary_term=1
{
"doc": {
"name": "轩辕大陆"
}    
}
  _primary_term: 每当Primary Shard发生重新分配时,比如重启,Primary选举等,_primary_term会递增1

    _primary_term: 主要是用来恢复数据时处理当多个文档的_seq_no一样时的冲突,比如当一个shard宕机了,raplica需要用到最新的数据,就会根据_primary_term和_seq_no这两个值来拿到最新的document

 

 

posted @ 2022-07-04 17:40  长弓射大狗  阅读(75)  评论(0编辑  收藏  举报