Elasticsearch(二):进阶检索
文章目录
- 一、SearchAPI
- 二、Query DSL
- 2.1 基本语法格式
- 2.2 匹配查询 match
- 2.3 模糊查询&分页查询
- 2.4 返回部分字段 _source
- 2.5 复合查询 bool
- 2.6 结果过滤 filter
- 2.7 非全文检索字段 term
- 2.8 排序 sort
- 2.9 高亮查询 highlight
- 2.10 聚合查询 aggs
- 三、映射 Mapping
- 3.1 Mapping 简介
- 3.2 Dynamic Mapping
- 3.3 数据类型
- 3.4 nested 扁平化数据问题
- 3.5 表数据迁移
- 四、分词
- 五、Elasticsearch搜索原理
一、SearchAPI
ES
支持两种基本方式检索∶
- 通过使用
REST request URI
发送搜索参数(uri
+检索参数) - 通过使用
REST request body
来发送它们(uri
+请求体)
① URI
GET bank/_search?q=*&sort=account_number:asc
② 请求体
GET bank/_search
{"query": {"match_all": {}},"sort": [{"account_number": {"order": "desc"}}]
}
二、Query DSL
2.1 基本语法格式
Elasticsearch
提供了一个可以执行查询的Json
风格的 DSL (domain-specific language
领域特定语言),这个被称为Query DSL
,该查询语言非常全面。
- 一个查询语句的典型结构
QUERY_NAME:{ARGUMENT: VALUE,ARGUMENT: VALUE,...
}
- 如果是针对某个字段,那么它的结构如下:
l
QUERY_NAME:{FIELD_NAME: [ARGUMENT: VALUE,ARGUMENT: VALUE,...}
}
2.2 匹配查询 match
基本数据类型(非字符串会精确匹配),字符串会分词匹配。
使用match_phrase
不进行分词。
GET bank/_search
{"query": {"match": {"lastname": "Barron"}}
}
说明:使用multi_match
表示多字段满足其一即返回结果。
GET bank/_search
{"query": {"multi_match": {"query": "mill", "fields": ["state","address"]}}
}
2.3 模糊查询&分页查询
GET bank/_search
{"query": {"fuzzy": {"city": "Lopezo"}},"from": 0,"size": 1
}
2.4 返回部分字段 _source
GET bank/_search
{"query": {"match": {"lastname": "Barron"}},"_source": "{firstname,lastname}"
}
2.5 复合查询 bool
must
和must not
的条件必须一致,should
不要求一致,当时会影响相关得分。
GET bank/_search
{"query": {"bool": {"must": [{"match": {"firstname": "Forbes"}}],"must_not": [{"match": {"firstname": "Jack"}}],"should": [{"match": {"age": "28"}}]}}
}
2.6 结果过滤 filter
filter
不会计算相关性得分,只起过滤作用。
按照范围过滤如下:
GET bank/_search
{"query": {"bool": {"must": [{"match": {"firstname": "Forbes"}}],"filter": {"range": {"age": {"gte": 10,"lte": 30}}}}}
}
2.7 非全文检索字段 term
和match
一样。匹配某个属性的值。全文检索字段用match
,其他非text
字段匹配用term
。
GET bank/_search
{"query": {"term": {"age": "28"}}
}
2.8 排序 sort
GET bank/_search
{"query": {"match_all": {}},"sort": [{"account_number": {"order": "desc"}}]
}
2.9 高亮查询 highlight
GET bank/_search
{"query": {"match": {"lastname": "Bates"}},"highlight": {"fields": {"lastname":{}},"pre_tags": ["<span style='color:red'>"],"post_tags": ["</span>"]}
}
2.10 聚合查询 aggs
对查询结果进行聚合分析。field
是聚合的字段,size
代表预期的分类数
① 搜索address中包含mill的所有人的年龄分布以及平均年龄
GET bank/_search
{"query": {"match": {"address": "mill"}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 100}},"ageAvg": {"avg": {"field": "age"}}}
}
② 按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
GET bank/_search
{"query": {"match_all": {}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 100},"aggs": {"balanceAvg": {"avg": {"field": "balance"}}}}}
}
③ 查出所有年龄分布,并且这些年龄段中M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资
GET bank/_search
{"query": {"match_all": {}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 100},"aggs": {"genderAgg": {"terms": {"field": "gender.keyword","size": 2},"aggs": {"balanceAvg": {"avg": {"field": "balance"}}}},"balanceAvg2": {"avg": {"field": "balance"}}}}}
}
三、映射 Mapping
3.1 Mapping 简介
定义数据库中的表的结构的定义,通过mapping
来控制索引存储数据的设置,不进行配置时,自动创建的mapping
。
作用:
- 定义
Index
下的字段名(Field Name
) - 定义字段的类型,比如数值型、字符串型、布尔型等
- 定义倒排索引相关的配置,比如
documentId
、记录position
、打分等
创建Mapping:GET /china/_mapping
自定义Mapping
:
PUT my_store
{"mappings":{"book":{"dynamic":false, "properties":{ "title":{"type":"text", "index_options": "docs"},"content":{"type":"keyword", "index": true}}}}
}
属性说明:
① dynamic
true
:允许自动新增字段(默认的配置)false
:不允许自动新增字段,但是文档可以正常写入,无法对字段进行查询操作strict
:文档不能写入(如果写入会报错)
② index
Index
属性,控制当前字段是否索引,默认为true
,即记录索引,false
不记录,即不可以搜索,比如:手机号、身份证号等敏感信息,不希望被检索
③ Index_options
用于控制倒排索引记录的内容,有如下4中配置:
docs
:只记录docid
freqs
:记录docid
和term frequencies
(词频)position
:记录docid
、term frequencies
、term position
Offsets
:记录docid
、term frequencies
、term position
、character offsets
text
类型默认配置为position
,其默认认为docs
。记录的内容越多,占用的空间越大。
3.2 Dynamic Mapping
Elasticsearch
依靠json
文档字段类型来实现自动识别字段类型,支持的类型
JSON类型 | es类型 |
---|---|
null | 忽略 |
boolean | boolean |
浮点类型 | float |
整数 | long |
object | object |
array | 由第一个非null值的类型决定 |
string | 匹配为日期则设为data类型(默认开启) 匹配为数字的话设为float或long类型(默认关闭) 设为text类型,并附带keyword的子字段 |
注意:mapping
中的字段类型一旦设定后,禁止修改
原因:Lucene
实现的倒排索引生成后不允许修改(提高效率)。如果要修改字段的类型,需要从新建立索引,然后做reindex
操作
3.3 数据类型
① 核心数据类型
字符串型:text
、keyword
数值型:long
、integer
、short
、byte
、double
、float
、half_float
、scaled_float
日期类型:date
布尔类型:boolean
二进制类型:binary
范围类型:integer_range
、float_range
、long_range
、double_range
、date_range
② 复杂数据类型
数组类型:array
对象类型:object
嵌套类型:nested object
③ 地理位置数据类型
geo_point
(点)、geo_shape
(形状)
④ 专用类型
记录IP地址:ip
实现自动补全:completion
记录分词数:token_count
记录字符串hash值:murmur3
⑤ 多字段特性multi-fields
允许对同一个字段采用不同的配置,比如分词,例如对人名实现拼音搜索,只需要在人名中新增一个子字段为pinyin
即可。
3.4 nested 扁平化数据问题
首先我们创建一个数据,并查看她的数据类型
PUT my_index/_doc/1
{"group" : "fans","user" : [ {"first" : "John","last" : "Smith"},{"first" : "Alice","last" : "White"}]
}GET my_index/_mapping
此时我们查询Alice Smith
用户竟然能查出来。
原因如下:
解决这种问题我们需要使用nested
类型,删除index
重建创建index
并查看数据类型
DELETE my_indexPUT my_index
{"mappings": {"properties": {"user": {"type": "nested" }}}
}GET my_index/_mapping
此时已经不会出现扁平化导致的问题。
案例:
表结构
PUT product
{"mappings": {"properties": {"attrs": {"type": "nested","properties": {"attrId": {"type": "long"},"attrName": {"type": "keyword","index": false,"doc_values": false},"attrValue": {"type": "keyword"}}}}}
}
查询语句
--错误
GET /product/_search
{"query": {"bool": {"filter": {"term": {"attrs.attrId": "1"}}}}
}
--正确
GET /product/_search
{"query": {"bool": {"filter": {"nested": {"path": "attrs","query": {"bool": {"must": [{"term": {"attrs.attrId": {"value": "1"}}}]}}}}}}
}
3.5 表数据迁移
POST _reindex
{"source": {"index": "fromTable"},"dest": {"index": "toTable"}
}
四、分词
分词是指将文本转换成一系列单词(term
or
token
)的过程,也可以叫做文本分析,在ElasticSsearch
里面称为Analysis
。
分词机制:
- Character Filter:对原始文本进行处理,例:去除html标签、特殊字符等;
- Tokenizer:将原始文本进行分词,例:天气预报–>天气,预报;
- Token Filters:分词后的关键字进行加工,例:转小写、删除语气词、近义词和同义词等
Elasticsearch
自带的分词器:
分词器(Analyzer) | 特点 |
---|---|
Standard(es默认) | 支持多语言,按词切分并做小写处理 |
Simple | 按照非字母切分,小写处理 |
Whitespace | 按照空格来切分 |
Stop | 去除语气助词,如the、an、的、这等 |
Keyword | 不分词 |
Pattern | 正则分词,默认\w+,即非字词符号做分割符 |
Language | 常见语言的分词器(30+) |
中文分词:
分词器名称 | 介绍 | 特点 | 地址 |
---|---|---|---|
IK | 实现中英文单词切分 | 自定义词库 | https://github.com/medcl/elasticsearch-analysis-ik |
Jieba | python流行分词系统,支持分词和词性标注 | 支持繁体、自定义、并行分词 | http://github.com/sing1ee/elasticsearch-jieba-plugin |
Hanlp | 由一系列模型于算法组成的java工具包 | 普及自然语言处理在生产环境中的应用 | https://github.com/hankcs/HanLP |
THULAC | 清华大学中文词法分析工具包 | 具有中文分词和词性标注功能 | https://github.com/microbun/elasticsearch-thulac-plugin |
使用standard
分词器
standard
支持对英文的分词,并不支持中文分词。
使用IK
分词器
安装:解压IK
分词器安装包至elasticsearch
下plugins
文件夹中,并重命名文件夹为analysis-ik
。
IK
提供了两个分词算法ik_smart
和ik_max_word
,其中ik_smart
为最少切分,ik_max_word
为最细粒度划分。
五、Elasticsearch搜索原理
[Term、Posting List]
Elasticsearch
使用倒排索引提升了查询效率。Elasticsearch
分别为每个field
都建立了一个倒排索引,Kate
、 John
、 24
、 Female
这些叫term
,而[1,2]
就是Posting List
。Posting List
就是一个int
的数组,存储了所有符合某个term
的文档id
。
Posting List
可以记录的数据:
- DocId:文档
id
,文档的原始信息 - TF:单词频率,记录该词再文档中出现的次数,用于后续相关性算分
- Position:位置,记录
Field
分词后,单词所在的位置,从0开始 - Offset:偏移量,记录单词在文档中开始和结束位置,用于高亮显示等
[Term Dictionary]
Elasticsearch
为了能快速找到某个term
,将所有的term
排个序,二分法查找term
,logN
的查找效率,就像通过字典查找一样,这就是Term Dictionary
。
[Term Index]
B-Tree
通过减少磁盘寻道次数来提高查询性能,Elasticsearch
也是采用同样的思路,直接通过内存查找term
,不读磁盘,但是如果term
太多,Term Dictionary
也会很大,放内存不现实,于是有了Term Index
,就像字典里的索引页一样,A
开头的有哪些term
,分别在哪页,可以理解Term Index
是一颗树:
这棵树不会包含所有的term
,它包含的是term
的一些前缀。通过Term Index
可以快速地定位到Term Dictionary
的某个offset
,然后从这个位置再往后顺序查找。
所以Term Index
不需要存下所有的term
,而仅仅是他们的一些前缀与Term Dictionary
的block
之间的映射关系,再结合FST
(Finite State Transducers
)的压缩技术,可以使Term Index
缓存到内存中。从Term Index
查到对应的Term Dictionary
的block
位置之后,再去磁盘上找term
,大大减少了磁盘随机读的次数。
[压缩]
Elasticsearch
使用FST
压缩Term Index
外,Elasticsearch
要求Posting List
是有序的,对Posting List
也有压缩技巧。 当Posting List
至少有百万个文档id
时, 此时对其压缩变得极其有意义。
[Frame Of Reference]
Step 1:Delta-encode
—— 增量编码
只记录元素与元素之间的增量,于是Posting List
由[73,300,302,332,343,372]变为[73,227.2,30,11,29]
Step 2:Split into blocks
—— 分割成块
Lucene
里每个块是256个文档ID
,这样可以保证每个块,增量编码后,每个元素都不会超过256(1 byte
)
Step 3:Bit packing
—— 按需分配空间
对于第一个块,[73, 227, 2],最大元素是227,需要 8bit
,只分配 8bit
的空间;
但是对于第二个块,[30, 11, 29],最大的元素才30,只需要5 bit
,只分配 5bit
的空间。
[Roaring bitmaps]
在Lucene
有多个查询条件,需要快速求出多个Posting List
的共同交集,通过使用Roaring bitmaps
算法后两个Posting List
做位运算即可求出交集。
假设有这样一个数组[3,6,7,10]
,我们使用bitmaps
算法表示为[0,0,1,0,0,1,1,0,0,1]
。
Roaring bitmaps
将posting list
按照65535为界限分块,第一块所包含的文档id范围在0~65535(2^16)
之间,第二块的id范围是65536~131071
,这样解决了Bitmap
的缺点:存储空间随着文档个数线性增长。
Elasticsearch(二):进阶检索相关推荐
- 弹性搜索(elasticsearch)进阶--服务维护
弹性搜索(elasticsearch)最新入门攻略 弹性搜索(elasticsearch)进阶–服务维护 系统配置 由于es再设计的时候就注重尽量减少调优项,基本不需要开发人员依据运行环境进行专门的调 ...
- Elasticsearch 4: 相关性检索和组合查询
目录 1. 相关性评分 2. 相关度模型 2.1 布尔模型 2.2 向量空间模型 2.3 概率模型 2.4 语言模型 3. TF/IDF 4. BM25 4.1 词频饱和度 4.2 长度归一化 5. ...
- elasticsearch 的高级检索以及 Ik分词器的配置和使用
首先准备测试数据 这是测试数据 点击去获取 使用上一篇我们安装的 kibana 将他们批量插入到es中 POST /bank/account/_bulk 数据插入成功之后可以在 psotman 调用 ...
- 用 mongodb + elasticsearch 实现中文检索
2019独角兽企业重金招聘Python工程师标准>>> 而 elasticsearch 可以很好的支持各种语言的全文检索,但我们暂时又不想切换到 elasticsearch 作为后端 ...
- PopUpWindow使用详解(二)——进阶及答疑
相关文章: 1.<PopUpWindow使用详解(一)--基本使用> 2.<PopUpWindow使用详解(二)--进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...
- 从二值检索到层次竞买图——让搜索广告关键词召回焕然新生
丨目录: · 背景 · 广告改写的历史与新目标 · 从两阶段到一段式:二值海选 · 从一段式到联合召回:层次竞买图 · 关键词召回的业务思考 本文主要分享过去一年我们在搜索广告召回的传统领域--关键词 ...
- java es scroll,Elasticsearch Scroll分页检索案例分享
Elasticsearch Scroll分页检索案例分享 1.准备工作 2.定义scroll检索dsl 首先定义一个简单的scroll dsl检索脚本 { ## 这里都是用常量在操作,实际场景中可以参 ...
- 《算法零基础100讲》(第20讲) 进制转换(二) - 进阶[C语言题解]
文章目录 一. 知识普及 1.1 atoi 1.2 log 1.3 pow 1.4 floor 二. 进阶题解 168. Excel表列名称 171. Excel 表列序号 483. 最小好进制 一. ...
- Elasticsearch(二)
Elasticsearch(二) 一. analysis与analyzer analysis,文本分析是将全文本转换为一系列单词的过程,也叫分词.analysis是通过analyzer(分词器)来 ...
- [解题报告](第20讲) 进制转换(二) - 进阶
零.写在前面 这是打卡的第二十天,今天题目还是有点难度的,不过就是题量下来了,可以沉淀一下之前的题目了,主要知识点在<算法零基础100讲>(第20讲) 进制转换(二) - 进阶https: ...
最新文章
- 区块链智能合约solidity入门
- DOS系统里,分屏显示目录的命令是什么??
- 自己喜欢的shell终端配置
- 前端学习(3022):vue+element今日头条管理-首页layont布局
- 剑指offer:12-17记录
- 面试问题汇总 精选 分析 解答 职业规划 part 2
- 网络数据采集技术—Java网络爬虫入门与实战 书稿纠错
- 基于JAVA+SpringMVC+Mybatis+MYSQL的共享单车管理系统
- java servlet jsp 实例_Servlet+JSP例子
- 论文阅读:A Progressive Architecture With Knowledge Review Network for Salient Object Detection
- [转载] python跨行 print:多用(),换行符\要小心,少用+或者不用(其它程序代码跨行用\就行,不能用括号)
- php数据入库流程,php数据库操作
- 软件项目详细设计方案怎么写?
- ad建集成库_AD16创建集成库的步骤
- CPU压力测试工具cpuburn
- 分享一下最近合成游戏源码
- oracle biee资料库,Hello oracle BIEE 资料
- c语言中 结构体对象,C语言中结构体详解
- 【2019.05】腾讯防水墙滑动验证码破解 python + selenium + OpenCV
- System.setOut(ps)重定义了输出流后,如何重定向控制台输出
热门文章
- MISFIT SHINE2评测相比一代的SHINE更加实用:也许是目前最好的智能手环
- php用户注册登录6,【php】ThinkPHP6通过Ucenter实现注册登录
- 1. 数理统计---数理统计基本概念
- 基于 RSSHub 搭建 RSS 生成器(群晖 Docker)
- 怎么配置内网IP SSL证书?
- 用excel函数COUNTIF实现两列数据对比找出不同数据
- 生物信息学在线服务器,48个实用的生信在线工具强烈推荐,不看是你的损失!...
- 一边裁员、一边招聘,领导到底想干啥?
- 马云回应豪宅谣言;淘宝上线了三架波音747进行拍卖;迪拜投1.4亿美元建模拟火星丨价值早报
- ES6最详细/易懂教程