ES v7.17搜索安装和使用
时间:2023-3-1 22:48 作者:wen 分类: 其它
[TOC]
docker ES安装
docker network create elastic
docker pull docker.elastic.co/elasticsearch/elasticsearch:7.17.6
docker run --name es01-test --net elastic -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.17.6
docker Kibana安装
docker pull docker.elastic.co/kibana/kibana:7.17.6
docker run --name kib01-test --net elastic -p 127.0.0.1:5601:5601 -e "ELASTICSEARCH_HOSTS=http://es01-test:9200" docker.elastic.co/kibana/kibana:7.17.6
注意: kibana也是不能用root用户启动
启动ES
# linux 启动
./bin/elasticsearch -d
# ES默认不能用root用户启动, 添加-Des.insecure.allow.root=true允许root启动
# -d 后台启动
bin/elasticsearch -Des.insecure.allow.root=true -d
# 作为守护程序运行
./bin/elasticsearch -d -p pid
# 关闭服务
pkill -F pid
注意:es默认不能用root用户启动, 生产环境建议为elasticsearch创建
# 为elasticsearch创建用户并赋予相应权限
adduser es
passwd es
chown -R es:es elasticsearch-x.xx.x
配置
# es开启远程访问
vim config/elasticsearch.yml
network.host:0.0.0.0
# 修改jvm配置
vim jvm.options
-Xms4g
-Xmx4g
# 调整虚拟内存
vim /etc/sysctl.conf
追加虚拟内存:
vm.max_map_count=262144
保存退出之后执行如下命令:
sysctl -p
清理
# docker 停止
docker stop es01-test
docker stop kib01-test
# 删除网络和容器
docker network rm elastic
docker rm es01-test
docker rm kib01-test
启动ES服务常见错误解决方案
[1]:max file descriptions [4096] for elasticsearch process is too low. increase to at least [65536]
es因为需要大量的创建索引文件, 需要大量的打开系统的文件, 所有我们需要解除linux系统当中打开文件最大数目的限制, 不然es启动就会抛错
# 切换root用户
vim /etc/security/limits.conf
末尾添加如下配置:
* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096
cat API
GET /
# 查看单节点的shard分配整体情况
GET /_cat/allocation?v
# 查看各shard的详细情况
GET _cat/shards/{index}?v
# 查看master节点信息
GET _cat/master?v
# 查看所有节点信息
GET _cat/nodes?v
# 查看集群中所有index的详细信息
GET _cat/indices?v
# 查看集群中指定index的详细信息
GET _cat/indices/{index}?v
# 查看当前集群的doc数量
GET _cat/count?v
# 查看指定索引的doc数量
GET _cat/count/{index}?v
# 查看集群当前状态:红,绿,黄
GET _cat/health?v
# es默认分词设置是standard,会单字拆分
POST _analyze
{
"analyzer": "standard",
"text": "中华人民共和国"
}
# ik_smart:会做最粗粒度的拆分,比如名字
POST _analyze
{
"analyzer": "ik_smart",
"text": "中华人民共和国"
}
# ik_max_word:会将文本做最细粒度拆分
POST _analyze
{
"analyzer": "ik_max_word",
"text": "中华人民共和国"
}
# icu_analyzer:unicode支持,中文分词良好
POST _analyze
{
"analyzer": "icu_analyzer",
"text": "中华人民共和国"
}
# 指定ik分词器
PUT /es_db
{
"settings": {
"index": {
"analysis.analyzer.default.type":"ik_max_word"
}
}
}
ES安装插件
# 查看已安装的插件
bin/elasticsearch-plugin list
# 安装插件
bin/elasticsearch-plugin install analysis-icu
# 删除插件
bin/elasticsearch-plugin remove analysis-icu
离线安装
本地下载相应的插件, 解压,然后手动上传到elasticsearch的plugin目录,然后重启ES实例就可以了.
创建索引的时候可以指定默认分词器
PUT /es_db
{
"settings":{
"index":{
"analysis.analyzer.defult.type":"ik_max_word"
}
}
}
索引操作
- 索引命名必须小写,不能以下划线开头
- 格式:PUT /索引名称
# 创建索引
PUT /es_db
# 查询索引
GET /es_db
# es_db是否存在
HEAD /es_db
# 删除索引
DELETE /es_db
# 创建索引时可以设置分片数和副本数
PUT /es_db
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
# 修改索引配置
PUT /es_db/_settings
{
"index": {
"number_of_replicas": 1
}
}
# 打开索引
POST /es_db/_open
# 关闭索引
POST /es_db/_close
文档操作
并发场景下修改文档
- seq_no 和 primary_term 是对version的优化,7.x版本的ES默认使用这种方式控制版本, 所有当在高并发环境下使用乐观锁机制修改文档时,要带上当前文档的seq_no和primary_term进行更新:
POST /es_db/_doc/2?if_seq_no=21&if_primary_term=6
{
"name": "李四xxx"
}
添加文档
- 格式: [PUT|POST] /索引名称/[_doc|_create]/id
# 创建文档,指定id
# 如果id不存在,创建新的文档,否则先删除现有文档,再创建新的文档,版本会增加
PUT /es_db/_doc/1
{
"name": "张三",
"sex": 1,
"age": 25,
"address": "广州天河公园",
"remark": "Java developer"
}
# 创建文档,es生成id
POST /es_db/_doc
{
"name": "张三",
"sex": 1,
"age": 25,
"address": "广州天河公园",
"remark": "Java developer"
}
# create 如果id已经存在,会失败
POST /es_db/_create/1
{
"name": "张三",
"sex": 1,
"age": 25,
"address": "广州天河公园",
"remark": "Java developer"
}
- 注意:POST和PUT都能起到创建/更新的作用,PUT需要对一个具体的资源进行操作页就是要确定id才能进行更新/创建,而POST是可以针对整个资源集合进行操作的, 如果不写id就由ES生成一个唯一的id进行创建新的文档, 如果填了id那就针对这个id的文档进行创建/更新
修改文档
- 全量更新, 整个json都会替换
- 格式:[PUT|POST] /索引名称/_doc/id
如果文档存在,现有文档会被删除,新的文档会被索引
POST /es_db/_doc/1
{
"name": "张三",
"sex": 1,
"age": 25,
"address": "广州天河公园",
"remark": "Java developer"
}
- 局部更新,格式POST /索引名称/update/id
- update不会删除原来的文档, 而是实现真正的数据更新
# 部分更新:在原有文档上更新
POST /es_db/_update/1
{
"doc": {
"age": 28
}
}
# 批量更新
POST /es_db/_update_by_query
{
"query": {
"match": {
"_id": 1
}
},
"script": {
"source": "ctx._source.age = 30"
}
}
查询文档
- 格式: GET /索引名称/_doc/id
# 查询文档
GET /es_db/_doc/1
# 查询前10条文档
GET /es_db/_search
# 精确查找
GET /es_db/_search
{
"query": {
"term": {
"name": {
"value": "张三"
}
}
}
}
# 匹配查询
GET /es_db/_search
{
"query": {
"match": {
"address": "长沙"
}
}
}
删除文档
- 格式: DELETE /索引名称/_doc/id
DELETE /es_db/_doc/1
批量写入
批量对文档进行写操作是通过_bulk的API来实现的
- 请求方式: POST
- 请求地址: _bulk
- 请求参数: 通过_bulk操作文档, 一般至少有两行参数(或偶数行参数)
- 第一行参数为指定操作的类型及操作的对象(index,type和id)
- 第二行参数才是操作的数据
参数类似于:
{"actionName":{"_index":"indexName","_type":"typeName","_id":"id"}}
{"field1":"value1","field2":"value2"}
- actionName:表示操作类型,主要有create,index,delete和update
批量创建文档create
POST _bulk
{"create":{"_index":"article","_type":"_doc","_id":3}}
{"id":3,"title":"fox老师","content":"fox老师666","tags":["java","面向对象"],"create_time":"1554015482530"}
{"create":{"_index":"article","_type":"_doc","_id":4}}
{"id":4,"title":"mark老师","content":"mark老师NB","tags":["java","面向对象"],"create_time":"1554015482530"}
普通创建或全量替换index
POST _bulk
{"index":{"_index":"article","_type":"_doc","_id":3}}
{"id":3,"title":"fox老师","content":"fox老师666","tags":["java","面向对象"],"create_time":"1554015482530"}
{"index":{"_index":"article","_type":"_doc","_id":4}}
{"id":4,"title":"mark老师","content":"mark老师NB","tags":["java","面向对象"],"create_time":"1554015482530"}
批量删除delete
{"delete":{"_index":"article","_type":"_doc","_id":3}}
{"delete":{"_index":"article","_type":"_doc","_id":4}}
批量修改update
{"update":{"_index":"article","_type":"_doc","_id":3}}
{"doc":{"title":"ES打法"}}
{"update":{"_index":"article","_type":"_doc","_id":4}}
{"doc":{"title":"ES打法xxx"}}
组合应用
POST _bulk
{"delete":{"_index":"article","_type":"_doc","_id":3}}
{"create":{"_index":"article","_type":"_doc","_id":3}}
{"id":3,"title":"fox老师","content":"fox老师666","tags":["java","面向对象"],"create_time":"1554015482530"}
批量读取
es的批量查询可以使用mget和msearch两种.其中mget是需要我们知道它的id,可以指定不同的index,也可以指定指定值source. msearch可以通过字段查询来进行一个批量查找.
_mget
# 可以通过ID批量获取不同index和type的数据
GET _mget
{
"docs": [
{
"_index": "es_db",
"_id": 1
},
{
"_index": "article",
"_id": 4
}
]
}
# 可以通过ID批量获取es_db的数据
GET /es_db/_mget
{
"docs": [
{
"_id": 1
},
{
"_id": 4
}
]
}
# 简化后
GET /es_db/_mget
{
"ids":["1","2"]
}
_msearch
在_msearch中, 请求格式和_bulk类似. 查询一条数据需要两个对象, 第一个设置index和type, 第二个设置查询语句. 查询语句和search相同. 如果只是查询一个index, 我们可以在URL中带上index, 这样, 如果查该index可以直接用空对象表示
GET /es_db/_msearch
{}
{"query":{"match_all":{}},"form":0,"size":2}
{"index":"article"}
{"query":{"match_all":{}}}
ES检索原理分析
索引的原理
索引是加速数据查询的重要手段,其核心原理是通过不断的缩小想要获取数据的范围来筛选出最终想要的结果, 同时把随机的事件变成顺序的事件.
倒排索引
当数据写入ES时, 数据将会通过分词被切分为不同的term, ES将term与其对于的文档列表建立一种映射关系, 这种结构就是倒排索引. 为了进一步提升索引的效率, ES在term的基础上利用term的前缀或者后缀构建了term index,用于对term本身进行索引. 这样当我们去搜索某个关键词时, ES首先根据它的前缀或者后缀迅速缩小关键词在term dictionary中的范围, 大大减少了磁盘IO的次数.
- 单词词典(term Dictionary): 记录所有文档的单词, 记录单词到倒排列表的关联关系
- 倒排记录(Posting List): 记录单词对应的文档结合,有倒排索引组成
- 倒排索引项(Posting):
- 文档ID
- 词频TF: 该单词在文档中出现的次数,用户相关性评分
- 位置(Position): 单词在文档中分词的位置.用于短语搜索(match phrase query)
- 偏移(Offset): 记录单词的开始结束位置, 实现高亮显示
ES高级查询Query DSL
ES中提供了一种强大的检索数据方式, 这种检索方式称之为Query DSL(domain Specified Language) , Query DSL是利用REST API 传递JSON格式的请求体(RequestBody)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁.
语法:
GET /es_db/_doc/_search
{json请求体数据}
# 可以简化为
GET /es_db/_search
{json请求体数据}
查询所有match_all
使用match_all,默认只会返回10条数据.
原因: _search查询默认采用的是分页查询, 每页记录数size的默认值为10. 如果想显示更多数据,指定size
GET /es_db/_search
# 等同于
GET /es_db/_search
{
"query":{
"match_all": {}
}
}
返回指定条数size
size关键字: 指定查询结果中返回指定条数. 默认返回值10条
GET /es_db/_search
{
"query":{
"match_all": {}
},
"size": 10
}
size最大数值默认设置为10000
PUT /es_db/_settings
{
"index.max_result_window": "20000"
}
# 修改现有所有的索引, 但新增的索引,还是默认的10000
PUT /_all/_settings
{
"index.max_result_window": "20000"
}
# 查看所有索引中的index.max_result_window值
GET /_all/_settings/index.max_result_window
分页查询form
form关键字: 用来指定起始返回位置, 和size关键字连用可实现分页效果
GET /es_db/_search
{
"query":{
"match_all": {}
},
"size": 10,
"form": 5
}
分页查询scroll
改动index.max_result_window参数大小,只能解决一时的问题, 当索引的数据量持续增加时, 在查询全量数据时还是会出现问题. 而且会增加ES服务器内存大结果集消耗完的风险. 最佳实践还是根据异常提示中的采用scroll api更高效的请求大量数据集.
# 查询命令中新增scroll=1m, 说明采用游标查询,保持游标查询窗口1分钟
GET /es_db/_search/scroll=1m
{
"query": {
"match_all": {}
},
"size": 200
}
采用游标id查询:
# scroll_id 的值就是上一个请求中返回的_scroll_id的值
GET /_search/scroll
{
"scroll": "1m",
"scroll_id": "FGxxx"
}
指定字段排序sort
注意:会让得分失效
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
]
}
# 排序,分页
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
],
"form": 10,
"size": 5
}
返回指定字段_source
_source关键字: 是一个数组, 在数组中用来指定展示那些字段
GET /es_db/_search
{
"query": {
"match_all": {}
},
"_source": ["name","address"]
}
match
match在匹配是会对所查询的关键词进行分词, 然后按分词匹配查询
match支持以下参数:
- query: 指定匹配的值
- operator: 匹配条件类型
- and: 条件分词后都要匹配
- or: 条件分词后有一个匹配即可(默认)
- minmum_should_match:最低匹配度, 即条件在倒排索引中最低的匹配度
# 模糊匹配
# or
GET /es_db/_search
{
"query": {
"match": {
"address": "广州公园"
}
}
}
# and
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "广州公园",
"operator": "and"
}
}
}
}
# 最少满足2个匹配词
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "广州白云山公园",
"minimum_should_match": 2
}
}
}
}
短语查询match_phrase
match_phrase查询分析文本并根据分析的文本创建一个短语查询. match_phrase 会将检索关键词分词. match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序相同, 而且默认必须都是连续的.
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": "广州白云山"
}
}
}
# slop 允许间隔几个
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": {
"query": "广州白云",
"slop": 1
}
}
}
}
多字段查询multi_match
可以根据字段类型,决定是否使用分词查询,得分最高的在前面
GET /es_db/_search
{
"query": {
"multi_match": {
"query": "长沙张龙",
"fields": ["address","name"]
}
}
}
注意: 字段类型分词,将查询条件分词之后进行查询, 如果该字段不分词就会将查询条件作为整体进行查询
query_string
允许我们在单个查询字符串中指定and|or|not条件, 同时也和multi_match query一样,支持多字段搜索. 和match类似, 但是match需要指定字段名, query_string是在所有字段中搜索, 范围更广泛.
注意: 查询字段分词就将查询条件分词查询,查询字段不分词将查询条件不分词查询
- 未指定字段查询
GET /es_db/_search
{
"query": {
"query_string": {
"query": "张三 OR 橘子洲"
}
}
}
- 指定单个字段查询
GET /es_db/_search
{
"query": {
"query_string": {
"default_field": "address",
"query": "白云山 OR 橘子洲"
}
}
}
- 指定多个字段查询
GET /es_db/_search
{
"query": {
"query_string": {
"field": ["address","name"],
"query": "张三 OR (广州 AND 王五)"
}
}
}
simple_query_string
类似query_string,但是会忽略错误的语法, 同时只支持部分查询语法, 不支持and or not, 会当作字符串处理, 支持部分逻辑:
- + 代替and
- | 代替or
- - 代替not
关键词查询term
term(精确查询), 用来查询没有被进行分词的数据类型, Term是表达语意的最小单位, 搜索和利用统计语言模型进行自然语言处理都需要处理Term.match在匹配时会对所查找的关键词进行分词,然后按分词匹配查询, 而Term会直接对关键词进行查找.一般模糊查找的时候,多用match,而精确查找时可以使用term.
- ES默认使用分词器为标准分词器(StandardAnalyzer), 标准分词器对于英文单词分词, 对于中文单字分词.
- 在ES的mapping Type中keyword,date,integer,long,double,boolean or ip 这些类型不分词,只有text类型分词.
GET /es_db/_search
{
"query": {
"term": {
"address": {
"value": "长沙"
}
}
}
}
# 采用term精确查询, 查询字段映射类型为keyword
GET /es_db/_search
{
"query": {
"term": {
"address.keyword": {
"value": "广州白云山公园"
}
}
}
}
在ES中,term查询,对输入不做分词, 会将输入作为一个整体, 在倒排索引中查找准确的词项, 并且使用相关度算分公式为每个包含该词项的文档进行相关度算分.
可以通过constant_score将查询转换成一个filtering,避免算分, 并利用缓存, 提高性能.
- 将Query转成Filter,忽略TF-IDF计算, 避免相关性算分的开销
- Filter可以有效利用缓存
GET /es_db/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"address.keyword": {
"value": "广州白云山公园"
}
}
},
"boost": 1.2
}
}
}
应用场景: 对bool,日期,数字,结构化的文本可以利用term做精确匹配
GET /es_db/_search
{
"query": {
"term": {
"age": {
"value": "28"
}
}
}
}
term处理多值字段,term查询是包含, 不是等于
prefix前缀搜索
它会对分词后的term进行前缀搜索
- 他不会分析要搜索字符串, 传入的前缀就是想要查找的前缀
- 默认状态下, 前缀查询不做相关度计算, 它只是将所有匹配的文档返回, 然后赋予所有相关分数值为1.它的行为更像一个过滤器而不是查询.两者实际的区别就是过滤器是可以被缓存的,二前缀查询不行.
GET /es_db/_search
{
"query": {
"prefix": {
"address": {
"value": "广州"
}
}
}
}
通配符查询widcard
通配符查询: 工作原理和prefix相同,只不过它不是只比较开头,它能支持更为复杂的匹配模式.
GET /es_db/_search
{
"query": {
"wildcard": {
"address": {
"value": "*白*"
}
}
}
}
范围查询range
- range: 范围关键字
- gte: 大于等于
- lte: 小于等于
- gt: 大于
- lt: 小于
- now: 当前时间
GET /es_db/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 30
}
}
}
}
日期range
POST /product/_bulk
{"index":{"_id":1}}
{"price":100,"date":"2021-01-01","productId":"XHDK-1293"}
{"index":{"_id":2}}
{"price":200,"date":"2022-01-01","productId":"KDKE-5421"}
GET /product/_search
{
"query": {
"range": {
"date": {
"gte": "now-1y"
}
}
}
}
多id查询dis
ids 关键字: 值为数组类型, 用来根据一组id获取多个对应的文档
GET /es_db/_search
{
"query": {
"ids": {
"values": [1,2]
}
}
}
模糊查询fuzzy
在实际的搜索中, 我们有时候会打错字, 从而导致搜索不到. 在ES中,我们可以使用fuzziness属性来进行模糊查询, 从而达到搜索有错别字的情形.
fuzzy查询会用到两个重要的参数, fuzziness, prefix_length
- fuzziness: 表示输入的关键字通过几次操作可以转变成为ES库里面的对应field字段
- 操作是指: 新增一个字符,删除一个字符,修改一个字符,每次操作可以记做编辑距离为1
- 如中文集团到中威集团编辑距离就是1,只需要修改一个字符
- 该参数默认值为0,即不开启模糊查询
- 如果fuzziness值在这里设置为2,会把编辑距离为2的东东集团也查询出来
- prefix_length: 表示限制输入关键字和ES对应查询field的内容开头的第n哥字符必须完全匹配,不允许错别字匹配
- 如这里等于1,则表示开头的字必须匹配,不匹配则不返回
- 默认值也是0
- 加大prefix_lenght的值可以提供效率和准确率.
GET /es_db/_search
{
"query": {
"fuzzy": {
"address": {
"value": "白运山",
"fuzziness": 1
}
}
}
}
注意:fuzzy模糊查询最大模糊错误必须在0-2之间
- 搜索关键词长度为2,不允许存在模糊
- 搜索关键词长度为3-5,允许1次模糊
- 搜索关键词长度大于5,允许最大2次模糊
高亮查询highlight
highlight 关键字:可以让符合条件的文档的关键词高亮.
highlight 相关属性:
- pre_tags:前缀标签
- post_tags:后缀标签
- tags_schema: 设置为style可以使用内置高亮样式
- require_field_match: 多字段高亮需要设置为false
GET /es_db/_search
{
"query": {
"match": {
"address": "白云山"
}
},
"highlight": {
"pre_tags": "<em style='color:red;'>",
"post_tags": "</em>",
"fields": {
"*":{}
}
}
}
# 多字段高亮
GET /es_db/_search
{
"query": {
"match": {
"address": "白云山"
}
},
"highlight": {
"pre_tags": ["<em style='color:red;'>"],
"post_tags": ["</em>"],
"require_field_match": "false",
"fields": {
"name":{},
"address": {}
}
}
}
相关性和相关性算分
搜索是用户和搜索引擎的对话, 用户关心的是搜索结果的相关性
- 是否可以找到所有相关的内容
- 有多少不相关的内容被返回
- 文档的打分是否合理
- 结合业务需求,平衡结果排名
如何衡量相关性:
- Precision(查准率): 尽可能返回较少的无关文档
- Recall(查全率): 尽量返回较多的相关文档
- Ranking: 是否能够按照相关度进行排序
相关性(Relevance)
搜索的相关算分, 描述了一个文档和查询语句匹配的程度.ES会对每个匹配查询条件的结果进行算分_score.
打分的本质是排序, 需要把最符合用户需求的文档排在前面.ES5之前,默认的相关性算分采用TF-IDF,现在采用BM25.
什么是TF-IDF
TF-IDF(term frequency-inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术.TF是词频(Term Frequency),IDF是逆文本频率指数(Inverse Document Frequency)。
-
TF-IDF被公认为是信息检索领域最重要的发明, 除了在信息检索, 在文献分类和其它相关领域有非常广泛的应用
- TF是词频(Term Frequency)
- 检索词在文档中出现的频率越高, 相关性也越高
- IDF是逆向文件频率(Inverse Document Frequency)
- 每个检索词在索引中出现的频率,频率越高,相关性越低
- 字段长度归一值(field-length norm)
- 字段的长度是多少? 字段越短, 字段的权重越高. 检索词出现在一个内容短的title要比同于的词出现在一个内容长度的content字段权重更大.
以上三个因素------词频(term frequency) , 逆向文件频率(Inverse Document Frequency) , 字段长度归一值(field-length norm)------是在索引时计算并存储的,最后将它们结合在一起计算单个词在特定文档中的权重.
什么是BM25
- 从ES 5开始, 默认算法改为BM25
- 和经典的TF-IDF相比,当TF无限增加时,BM25算分会趋于一个数值
通过Expain API查看TF-IDF
GET /es_db/_search
{
"query": {
"match": {
"address": "白云山"
}
},
"explain": true
}
Boosting Relevance
boosting 是控制相关性的一种手动.
参数boost的含义:
- 当boost>1时, 打分的相关度相对性提升
- 当0<boost<1时, 打分的权重相对性降低
- 当boost<0时,贡献负分
返回匹配positive查询的文档并降低匹配negative查询的文档相似度分. 这样就可以在不排除某些文档的前提下对文档进行查询, 搜索结果中存在只不过相似度分数相比正常匹配的要低.
GET /es_db/_search
{
"query": {
"boosting": {
"positive": {
"term": {
"address": {
"value": "白云"
}
}
},
"negative": {
"term": {
"name": {
"value": "王五"
}
}
},
"negative_boost": 0.2
}
}
}
布尔查询Bool Query
一个bool查询, 是一个或多个查询子句组合, 总共包含4种子句, 其中2种会影响算分, 2种不影响算分.
- must: 相当于&&, 必须匹配,贡献算分
- should: 相当于||, 选择性匹配, 贡献算分
- must_not: 相当于!, 必须不能匹配, 不贡献算分
- filter: 必须匹配,不贡献算分
在ES中,有Query和Filter两种不同的Context
- Query Context: 相关性算分
- Filter Context: 不需要算分(Yes or No),可以利用cache,获得更好的性能
相关性并不是全文本索引的专利, 也适用于yes|no的子句,匹配的子句越多,相关性分越高, 如果多条查询子句被合并为一条复合查询语句,比如bool查询,则每个子句计算得出的评分会被合并到总的相关性评分中.
bool查询语法
- 子查询可以任意顺序出现
- 可以嵌套多个查询
- 如果你的bool查询中, 没有must条件,should中必须至少满足一条查询
GET /es_db/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"address": "广州"
}
},
{
"match": {
"name": "王五"
}
}
],
"should": [
{
"match": {
"address": "白云山"
}
}
],
"minimum_should_match": 1
}
}
}
控制字段的相关性(boosting)
POST /blogs/_bulk
{"index":{"_id":1}}
{"title":"Apple iPad","content":"Apple iPad,Apple iPad"}
{"index":{"_id":2}}
{"title":"Apple iPad,Apple iPad","content":"Apple iPad"}
GET /blogs/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "apple,ipad",
"boost": 2
}
}
},
{
"match": {
"content": {
"query": "apple,ipad",
"boost": 1
}
}
}
]
}
}
}
文档映射(mapping)
Mapping类似数据库中的schema的定义,作用如下:
- 定义索引中的字段的名称
- 定义字段的数据类型, 例如字符串,数值,布尔等
- 字段,倒排索引的相关配置(Analyzed or Not Analyzed,Analyzer)
ES中Mapping映射可以分为动态映射和静态映射.
动态映射:
在文档写入ES时, 会根据文档字段自动识别类型,这种机制称之为动态映射
# 动态映射
PUT /user/_doc/1
{
"name":"fox",
"age":32,
"address":"湖北武汉"
}
# 查询文档映射
GET /user/_mapping
静态映射:
是ES中事先定义好映射,包含文档的各个字段类型, 分词器等, 这种凡事称之为静态映射
PUT /user
{
"mappings": {
"properties": {
"name":{
"type": "keyword"
},
"address": {
"type": "text",
"analyzer": "ik_max_word"
},
"age":{
"type": "integer"
}
},
}
能否后期更改mapping的字段类型?
两种情况:
- 新增加字段
- dynamic设为true时, 一旦有新增字段的文档写入, mapping也同时被更新
- dynamic设为false, mapping不会被更新, 新增字段的数据无法被索引, 但是信息会出现在_source中
- dynamic设置成strict(严格控制策略),文档写入失败,抛出异常
- 对已有字段, 一旦已经有数据写入, 就不再支持修改字段定义
对已存在的mapping映射进行修改
具体方法:
- 如果要推倒现有映射, 你得重新建立一个静态索引
- 然后把之前索引里的数据导入到新的索引里
- 删除原创建的索引
- 为新索引起个别名,为原索引名
PUT /user1
{
"mappings": {
"properties": {
"name":{
"type": "keyword"
},
"address": {
"type": "text",
"analyzer": "ik_max_word"
},
"age":{
"type": "integer"
}
}
}
}
POST _reindex
{
"source": {
"index": "user"
},
"dest": {
"index": "user1"
}
}
DELETE /user
PUT /user1/_alias/user
注意:通过这几个步骤就实现了索引的平滑过渡, 并且是零停机
常用Mapping参数配置
- index: 控制当前字段是否被索引, 默认为true,如果设置为false, 该字段不可被搜索
PUT /user1
{
"mappings": {
"properties": {
"name":{
"type": "keyword",
"index": false
},
"address": {
"type": "text",
"analyzer": "ik_max_word"
},
"age":{
"type": "integer"
}
}
}
}
-
有四种不同基本的index_options配置, 控制倒排索引记录的内容
- docs: 记录doc id
- freqs: 记录doc id和term frequencies(词频)
- positions: 记录doc id/term frequencies/ term position(默认)
- offsets: doc id/term frequencies/ term position/character offects
text类型默认记录positions, 其它默认为docs, 记录内容越多, 占用存储空间越大
PUT /user1
{
"mappings": {
"properties": {
"name":{
"type": "keyword",
},
"address": {
"type": "text",
"analyzer": "ik_max_word",
"index_options":"offsets"
},
"age":{
"type": "integer"
}
}
}
}
- null_value: 需要对null值进行搜索, 只有keyword类型支持设计null_value
PUT /user1
{
"mappings": {
"properties": {
"name":{
"type": "keyword",
"null_value":"NULL"
},
"address": {
"type": "text",
"analyzer": "ik_max_word",
"index_options":"offsets"
},
"age":{
"type": "integer"
}
}
}
}
- copy_to:将字段的数值拷贝到目标字段, 满足一些特定的搜索需求, copy_to的目标字段不出现在_source中.
PUT /user1
{
"mappings": {
"properties": {
"name":{
"type": "keyword",
"copy_to":"full_address"
},
"address": {
"type": "text",
"analyzer": "ik_max_word",
"copy_to":"full_address"
},
"age":{
"type": "integer"
}
}
}
}
Index Template
index template 可以通过你设定mapping和setting, 并按照一定的规则, 自动匹配到新创建的索引上.
- 模板仅在一个索引被新创建时, 才会产生作用. 修改模板不会影响已创建的索引
- 你可以设定多个索引模板, 这些设置会被"merge"在一起
- 你可以指定"order"的数值, 控制"merging"的过程
PUT /_template/template_default
{
"index_patterns": ["*"],
"order": 0,
"version": 1,
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
# 关闭日期探测
PUT /_template/template_test
{
"index_patterns": ["test*"],
"order": 0,
"version": 1,
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"date_detection": false,
"numeric_detection": true
}
}
标签: elasticsearch