ES知识点

ES知识点

更多参考官方文档

https://www.elastic.co/guide/cn/elasticsearch/guide/current/structured-search.html

查询 所有索引

get /_cat/indices_

查看节点健康

 get /_cat/health?v_

查询 索引 的设置

GET /user/_settings

查看 索引的 mapping

GET user/_mapping

添加索引

put /test1

添加一条文档

如果已经存在 那么就全部覆盖
PUT /test1/d1/1
 {
 "age":1,
 "name":"zs",
 "bri":"2018-08-08"
 }
备注1:如果已经存在就全覆盖修改。
备注2:如果 只需要插入,不修改 着 在后面 加上 /_create (这时候会提示已经存在),post 不能带_create

修改一条文档

POST /test1/d1/2
{
  "age":1,
  "name":"zs",
  "bri":"2018-08-08"
}
  备注1: post 虽然叫做修改,但是 在带有id 的情况下 和 put 几乎一样(id 存在就是 全量 修改,不存在就是 新增)。
  备注2: 可以 使用  POST /test1/d1  不带id 的方式 自动生成id,put 不支持不带id的写法。
  备注3 post 可以 指定_update  ,并且 可以带_create。
  备注4:post 可以部分更新 专用名字  partial update 
  
POST /test1/d1/5/_update
{
  "doc":{
 "age":2
  }
}

删除一条文档

DELETE  test1/d1/5

删除一个索引

DELETE  test1

查询一条文档

get user/student/2

搜索文档

get user/_search   
或者 
get user/student/_search  
备注:查询可以不指定 type 的类型 

url 的查询

get user/_search?-q=name2 
+q是默认的,
-q是 不存在这样的数据,没有指定查询字段,
使用的是 一个特殊的 包含全部字段的字段查询。

url指定字段 的查询

get user/student/_search?q=name:n5 
备注:+q=name:n5&q=name:n5
url query 的方式很难适应 复杂查询 所以我们一般使用  json 格式的请求体的方式 备注:es restful 风格api 的 get 请求 支持请求体

查询所有记录

get /user/student/_search
{
    "query":{
      "match_all": {}
    }
}

term

结构化字段查询,匹配一个值,且输入的值不会被分词器分词
{
    "query":{
        "term":{
            "foo": "hello world"
        }
    }
}

query_string

查询解析输入并在运算符周围分割文本。每个文本部分彼此独立地分析
GET /_search
{
    "query": {
        "query_string" : {
            "default_field" : "content",
            "query" : "(new york city) OR (big apple)"
        }
    }
}

添加ik分词器

docker 安装
docker exec -it es bash
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.10.1/elasticsearch-analysis-ik-7.10.1.zip
非docker
1)下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
2)解压,将解压后的elasticsearch文件夹拷贝到elasticsearch-7.10.1\plugins下,并重命名文件夹为analysis-ik (其他名字也可以,目的是不要重名)
3)重新启动ElasticSearch,即可加载IK分词器

指定过滤条件

get /user/student/_search
{
    "query":{
      "match": {
        "name": "n5"
      }
    }
}

范围查询

get /user/student/_search
{
    "query":{
      "range": {
        "bri": {
          "gte": 10,
          "lte": 20
        }
      }
    }
}

短语匹配match_phrase

就像用于全文搜索的的match查询一样,当你希望寻找邻近的单词时,match_phrase查询可以帮你达到目的
GET /my_index/my_type/_search
{
    "query": {
        "match_phrase": {
            "title": "quick brown fox"
        }
    }
}

多条件的复合查询

备注:bool 里面的 都是一些 条件 ,must 必须瞒足,should 只要要满足 minimum_should_match 个 条件是ture ,filter 只是过滤 不计入评分。
get /user/student/_search
{
    "query":{
      "bool": {
        "must": [
          { 
           "match": {
             "province": "河南"
             }
          }
        ],
        "should": [
          {
           "match": {
             "city": "郑州"
           },
            "match": {
             "city": "洛阳"
           }
          }
        ],
        "minimum_should_match": 1
      }
      "range": {
        "bri": {
          "gte": 10,
          "lte": 20
        }
      }
    }
}

查询分页

备注1:深分页问题,效率会很低,劲量避免深分页。
备注2:深分页:如果要查询出 每页 100 条,的第 100 页数据数据( 9900 - 10000 ),如果是去5 个节点查询,那么会在 每个节点查询出 第 9900- 10000 条数据,然后 汇总到 坐标几点,然后排序后取出 9900-10000 条,这样做非常占 资源。
get /user/student/_search
{
    "query":{
      "match_all": {}
    },
    "from":3,
    "size":2
}

scroll 游标查询

指定 scroll=时间 ,指定保存的分钟数,第一次发起请求放回的不是数据,而是 _scroll_id ,后面通过 _scroll_id 去请求数据,非常适合大批量查询。
get /user/student/_search?scroll=1m
{
    "query":{
      "match_all": {}
    },
    "size":2
}
通过 _scroll_id 去请求数据
GET /_search/scroll
{
    "scroll": "1m",
    "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAIuFkRMbVZ0WFdvU1ZHWEJuelFIQk4tdFEAAAAAAAACLBZETG1WdFhXb1NWR1hCbnpRSEJOLXRRAAAAAAAAAi0WRExtVnRYV29TVkdYQm56UUhCTi10UQAAAAAAAAO1FlQwSkJqVng5UVpPUTIwbWw0a0NKV3cAAAAAAAADthZUMEpCalZ4OVFaT1EyMG1sNGtDSld3"
}

自定义返回结果( _source )

GET /user/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["name","age","province","city"]
}

post_filter 和 query 的 区别

语法上没区别,唯一的在于 filter 不评分,所以 filter  比 query  快很多 ,filter 和query  可以共存。
GET /user/_search
{
  "post_filter": {
    "match_all": {}
  },
  "_source": ["bri"]
}

聚合函数 平均值 总数量

GET  user/student/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "total_count": {
      "value_count": {
        "field": "age"
      }
    },
    "pjz":{
      "avg": {
        "field": "age"
      }
    }
  } 
}

分组查询

GET  user/student/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "fz": {
      "terms": {
        "field": "age"
      }
    }
  }
}

量查询 _mget

#批量查询
GET /_mget
{
  "docs":[
    {
      "_index":"user",
      "_type":"student",
      "_id":1
    },
    {
      "_index":"user",
      "_type":"student",
      "_id":2
    },
    {
      "_index":"user",
      "_type":"student",
      "_id":3
    }
  ]
}

备注:_mget 如果请求url 里面有 index 和 type 后面 的 请求体里面就可以不写 index 和type

#批量查询
GET /user/_mget
{
  "docs":[
    {
      "_type":"student",
      "_id":1
    },
    {
      "_type":"student",
      "_id":2
    },
    {
      "_type":"student",
      "_id":21111111
    }
  ]
}

批处理 bulk

 bulk的格式:action:index/create/update/delete 后面如果有请求体就跟上请求体

GET _bulk
{"create":{"_index":"user","_type":"student","_id":"100"}}
{ "name": "zhaoer","age": 7,  "sex": "nn"}
{"update":{"_index":"user","_type":"student","_id":"100"}}
{"doc":{ "name": "zhaoer","age": 7,  "sex": "nn"}}
{"delete":{"_index":"user","_type":"student","_id":"100"}}
{"index":{"_index":"user","_type":"student"},"_id":"100"}
{"doc":{ "name": "zhaoer","age": 7,  "sex": "nn"}}

  备注1:delete 没有请求体。

​ 备注2:create 和 update 只有在指定的状态才能成功 create 创建 ,update 更新。

  备注3 ,批处理中的一个 失败不影响 其他的 执行。

  备注4 ,update 需要 doc 包一层

  备注5 ,index 有create 和 update 的 功能,并且支持 又或者 没有 doc 包一层都支持。

es 的删除是 是假删除并且在下一次merge的时候真删除

并发处理

 使用的乐观锁 在 后面加上 version

POST  /user/student/1?version=3
{
  "name":"zyk",
  "age":0
}

备注:只有version = 当前记录的version的时候才能修改成功

自动控制 version

通过version_type指定 
version_type=external 要求 version 大于当前的version ,
version_type=internal 这个是默认值 ,必须等于当前的值
version_type=external_gte  大于等于当前的version
version_type=force 废弃
POST  /user/student/1?version_type=external&version=505
{
  "name":"zyk",
  "age":0
}  

consistency 写一致性的等级

consistency=one 只要主节点活着就可以写
consistency=all 所有主节点和副本节点都活着
consistency=quorun 所有主节点都活着,并且有超过一半的节点(primary shard + replica shard )活着 ,这个是默认值,而且只有在有副本节点的时候才生效
等待 这时候可以指定 timeout 来指定等待时间timeout=30s

动态mapping

根据第一次存入的数据,动态的决定这个字段的 mapping 类型,并且决定索引行为,后面类型不符合就没法存入,mapping 里面的 类型不能修改,只能添加新的
put /test2/t/1
{
  "age":1,
  "name":"name",
  "bri":"2017-09-09",
  "isDel":true,
  "amount":0.1
}

GET /test2/_mapping

指定mapping

只能给新的索引指定 ,或者 个新的字段指定
PUT /test2/_mapping/t
{
  "properties": {
          "age": {
            "type": "long"
          },
          "amount": {
            "type": "float"
          },
          "bri": {
            "type": "date"
          },
          "isDel": {
            "type": "boolean"
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
}

指定索引的setting

备注:number_of_shards 不能修改
PUT test3
{
   "settings": {
      "index": {
        "number_of_shards": "3",
        "number_of_replicas": "1"
      }
    }
   
}

PUT test4/_settings
{
  "index": {
        "number_of_replicas": "4"
      }
} 

preference 指定节点查询

preference = _primary,_primart_first,_local,_only_node:xyz,_prefer_node:xyz,_shard:2,3

routing

默认是通过id 路由的。 可以让类似的结果在同一个 shard 上。
curl -XPOST 'http://localhost:9200/store/order?routing=user123' -d 
' { "productName": "sample", "customerID": "user123" }'

searche_type

1、query and fetch
向索引的所有分片(shard)都发出查询请求,各分片返回的时候把元素文档(document)和计算后的排名信息一起返回。这种搜索方式是最快的。因为相比下面的几种搜索方式,这种查询方法只需要去shard查询一次。但是各个shard返回的结果的数量之和可能是用户要求的size的n倍。

2、query then fetch(默认的搜索方式)
如果你搜索时,没有指定搜索方式,就是使用的这种搜索方式。这种搜索方式,大概分两个步骤,第一步,先向所有的shard发出请求,各分片只返回排序和排名相关的信息(注意,不包括文档document),然后按照各分片返回的分数进行重新排序和排名,取前size个文档。然后进行第二步,去相关的shard取document。这种方式返回的document可能是用户要求的size的n倍,此处勘误,这是原博客中的错误,经测试 query then fetch 方式返回的数量就是 查询是 setSize()的数量

3、DFS query and fetch
这种方式比第一种方式多了一个初始化散发(initial scatter)步骤,有这一步,据说可以更精确控制搜索打分和排名。这种方式返回的document与用户要求的size是相等的。同样勘误 DFS query and fetch 返回结果的数量是 分片数*size

4、DFS query then fetch
比第2种方式多了一个初始化散发(initial scatter)步骤。这种方式返回的document与用户要求的size是相等的。

Bouncing Results

 搜索同一query,结果ES返回的顺序却不尽相同,这就是请求轮询到不同分片,而未设置排序条件,相同相关性评分情况下,由于评分采用的算法时TF(term frequency)和IDF(inverst document frequecy) 算出的总分在不同的shard上时不一样的,那么就造成了默认按照_score的分数排序,导致会出现结果不一致的情况。查询分析时将所有的请求发送到所有的shard上去。可用设置preference为字符串或者primary shard插叙等来解决该问题。preference还可以指定任意值,探后通过这个值算出查询的节点

给索引取别名

**多个索引可以使用同一个别名**
put user/_aliases/user_al
或者:
POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "user",
        "alias": "user_a"
      }
    },
    {
      "add": {
        "index": "user",
        "alias": "user_b"
      }
    }
  ]
} 

查询别名

get /user/_alias

删除别名

POST /_aliases
{
  "actions": [
    {
      "remove": {
        "index": "user",
        "alias": "user_a"
      }
    },
    {
      "remove": {
        "index": "test",
        "alias": "user_b"
      }
    }
  ]
}

自定义分词器

PUT /user5
{
  "settings":{
    "analysis": {
      "char_filter": {
        "my_char_filter":{
          "type":"mapping",
          "mappings":["&=> and"]
        }
      },
      "filter": {
        "my_filter":{
          "type":"stop",
          "stopwords":["the","a"]
        }
      },
      "analyzer": {
        "my_analyzer":{
          "type":"custom",
          "char_filter":[ "my_char_filter" ],
          "filter":["my_filter"],
          "tokenizer":"standard"
        }
      }
    }
  } 
}
解释:定义了一个 char_filter 名叫 my_char_filter,类型是 mapping 把& 转成 and 
定义了一个 filter 名叫 my_filter ,类型是停用词,把 the ,a 去掉
定义了一个分析器 名叫 my_analyzer, 类型是自定义,它使用了 char_filter 是 my_char_filter ,它使用的 filter 是 my_filter ,它使用的 分词器是 标准分词器。 

例子二:

PUT /user9
{
  "settings":{
    "analysis": {
      "char_filter": {
        "my_char_filter":{
          "type":"mapping",
          "mappings":["& => and", "pingguo => pingg"]
        }
      },
      "filter": {
        "my_filter":{
          "type":"stop",
          "stopwords":["the","a"]
        }
      },
      "analyzer": {
        "my_analyzer":{
          "type":"custom",
          "char_filter":[ "my_char_filter" ],
          "filter":["my_filter"],
          "tokenizer":"standard"
        }
      }
    }
  } 
}
 
GET /user9/_analyze
{
  "analyzer":"my_analyzer",
  "text":" a d&og is in the house pingguo"
}  

自定义动态mapping

PUT my_index1
{
  "mappings": {
    "_doc":{
      "dynamic":"strict",
      "properties":{
        "name":{
          "type":"text"
        },
        "user":{
          "type":"object",
          "dynamic":"true"
        }
         
      }
    }
  }
}

GET my_index1/_doc/1
{
 "name":"name1",
 "user":{
   "name":"n1",
   "age":10
 },
 "age":2
}

mapping的第一层,也就是 properties的 那一层,不允许动态映射,有新的字段就报错,
user的那一层,允许动态映射,有新的字段就根据 新的第一次的值,指定类型。
dynamic = false 的时候 会存进去,但是我试了一次,不管 1 还是 "1"都可以存进去,但是 也可以查看得到,但是好像搜索不到。

document 写入原理

每次写请求写入到 内存 buffer ,当 写到一定程度的时候,刷新,buffer 写到 lucene 的 segment,大概1 秒一次。segment 会吧数据写到 oscache ,然后执行 fsysc 命令吧 欧式chache 写到disk中。删除的时候是加删除,在index segment 中创建一个.del文件,在一定时候index segment 合并的时候,会删除这个del文件。更新,先执行删除,然后在执行插入。值得注意的是,没个一秒 buffer 提交一次,并且产生一个新的 segment,而且,这时候会出发 segment 到 oscache 的提交。数据提交到 os cache 的 以后就可以搜索到了,所以这就是 1 秒 近实时的原因。可以给index指定刷新的时间。 refresh_interval,并且 es 还会写 tranlog(写buffer的同时)文件,这个文件可以避免丢失。每次提交会创建一个tranlog 文件,提交完成会删除原来的 tranlog 文件。在提交以后记录会写到新的 tranlog 中。

查看文本在某分词器上的分词结果

GET /user/_analyze
{
  "analyzer": "standard",
  "text":  " a dog is in the house"
}

给指定字段指定分词器

put /user3/_mapping/student
{
  "properties":{
    "name":{
      "type":"text",
      "analyzer":"standard"
    }
  }  
} 

dynamic 策略

true (遇到陌生字段就 dynamic mapping )
false(遇到陌生字段就忽略)
strict(遇到陌生字段就报错)

手动使索引merge

post /my_index/_optimize?max_num_segments=1

关于 primary shard 和 replica shard

 primary shard:
 es 对数据进行切片 ,吧一个索引的 数据 分成多份 ,每一份数据就是一个 primary shard, primary shard 的数量只能在创建索引的时候指定,因为后期 修改 primary shard 数量 会乱 文档id 计算 文档所在 shard 的 结果。
 replica shard: 
 副本节点,多个副本节点可以提高数据的安全性,并且可以分担 primary shard 的查询 负载。
备注: 修改只能发生在 primary shard ,查询可以发生在任意 shard 。

遇到 Fielddata is disabled on text fields by default 异常的 解决方案

因为text类型默认没有正排索引,所以不支持排序 和聚合 ,遇到这种 异常的时候 需要制定 开启正排索引。
倒排索引用于搜索,正排索引用于排序和聚合。

开启正排索引的方法。

put user/_mapping/student/
{
  "properties": {
    "sex": {
      "type":"text",
      "fielddata":true
    }
  }
}

其他知识点

1.mapping 里面 keyword 的可以指定 text 的子类型
如果 字段类型是 json ,那么这个字段的类型就是 object ,或者说是docment 这时候 mapping 里面是 映射了一个property
2.es 2.X 的 时候string 现在改成 keyword 和 text ,keyword 是存不分词的 的关键数据,text 存大数据,要分词,
可以指定个text 类型 指定fields 来指定 一个 不分词的原文,用于 排序聚合, 和2.X的 raw 类似。
"name": {
           "type": "text",
           "fields": {
             "keyword": {
               "type": "keyword"
             }
           }
         }
3.query phase 指的的查询的 查询请求,->坐标节点分发请求到对应 shard ,然后 结果汇总到 坐标节点的过程
4.fetch phase 指的是 查询结果的doc id 到各个 shard 取文档的过程
5.timeout 指定多少时间之内要返回,到了时间一定会返回,即便没有查询完,只返回查到的部分
6.type 其实就是一个 隐藏的 field 
7.mapping root object 就是指 索引mapping 的json对象

  

posted @ 2021-09-06 14:26  动力暖暖  阅读(99)  评论(0)    收藏  举报