查询和过滤
叶查询子句:在特定的字段上查找特定的值,比如 match term rang 可以理解为单条件查询
复合查询字句:包含其他叶查询或复合查询,可以理解为多条件查询.
查询: query 用于检索内容与条件是否匹配,并计算_score份数
过滤:filter不计算匹配得分,只是简单的决定文档是否匹配,主要用于过滤结构化数据 如时间 状态 类型等字段
简单查询
我们索引数据的结构
{
"_index": "meadin",
"_type": "industry_news",
"_id": "Ly93d3cudHJhdmVsZGFpbHkuY24vYXJ0aWNsZS8xMzcwNzQ=",
"_score": 16.389927,
"_source": {
"id": "Ly93d3cudHJhdmVsZGFpbHkuY24vYXJ0aWNsZS8xMzcwNzQ=",
"title": "美团发布全国首个《在线平台酒店预售服务规范》标准",
"synopsis": "4月13日,美团发布业内首个《在线平台酒店预售服务规范》(以下简称标准),从预售服务要求、流程、监督和评价...",
"source": "环球旅讯",
"newsUrl": "https://www.traveldaily.cn/article/137074",
"newsIssueTime": "2020-04-14T06:56:45+0800",
"createDate": "2020-04-13",
"context": """
<p>4月13日,美团发布业内首个《在线平台酒店预售服务规范》(以下简称标准),从预售服务要求、流程
"dateSource": 112
}
GET /meadin/industry_news/_search
{
"query": {
"bool": {
"must": [
{"match": {"title": "酒店" }},
{"match": {"context": "洲际"}}
],
"filter": {
"range": {
"newsIssueTime": {
"gte":"2020-03-01T21:51:04Z",
"lte": "2020-05-01T21:51:04Z"
}
}
}
}
}
}
相当于sql语句
select * from industry_news where title like %酒店% and content like %洲际% and newsIssueTime between '' and ''
match
查询默认是分词的 {“match”: {“title”: “酒店” }} 和 {“match”: {“title”: “酒店这里是被分词的” }}第二个条件比第一个条件查询到的结果只会多不会少,{“match”: {“title”: “酒店这里是被分词的” }} 可以理解为
{“match”: {“title”: “酒店” }} {“match”: {“title”: “这里” }} {“match”: {“title”: “分词” }} 三个条件查到 的结果的总和
lucece倒排索引
根据关键字找到所在的索引的ID 酒店 ->1 酒店这里是被分词的->1,2,4
match的模糊查询
GET /meadin/industry_news/_search
{
"query": {
"match": {
"newsUrl": {
"query": "article 137074",
"fuzziness": 1,
"operator": "and"
}
}
}
}
fuzziness参数的表示最大的编辑距离 默认是2
ac abc 编辑差一个字符
ad abcd 编辑差2个字符
编辑距离越小则两个字符串越像 我们使用fuzziness 一般都是设置为1
fuzzy 的模糊查询
GET /meadin/industry_news/_search
{
"query": {
"fuzzy": {
"source.keyword": "环球讯"
}
}
}
fuzzy 的模糊查询和term查询有点像 也是不分词的查询 fuzzy虽然不分词可以模糊匹配
环球讯 -> “source”: “环球旅讯” 可以匹配到这个, 但是如果是term查询就匹配不到了
match短语查询 match_parse
GET /meadin/industry_news/_search
{
"query": {
"match_phrase": {
"title": "目前公司业务覆盖全国"
}
}
}
match_parse被查询的词"目前公司业务覆盖全国" 不会被分词,es拿着整个句子去索引里面匹配
“title”: “达实智能:目前公司业务覆盖全国” 这条消息是可以匹配到的.title字段在存储的时候会被分词,在倒排序索引中会有"目前公司业务覆盖全国" 所以可以查得到
如果把这里的match_phrase 改成term 是查不到的
如果这里把title 改成title.keyword也是查不到的
所以可以证明 “目前公司业务覆盖全国” 是title字段在倒排索引中的一个关键词
match 前缀查询
匹配以专家开头的标题的文章
GET /meadin/industry_news/_search
{
"query": {
"match_phrase_prefix": {
"title": "专家"
}
}
}
macth多字段查询
GET /meadin/industry_news/_search
{
"query": {
"multi_match": {
"query": "资本",
"type": "best_fields",
"fields": ["title^3","synopsis","context"]
}
}
}
在title synopisi contect 三个字段中查询 任意一个满足条件都会返回,title^3 计算份数的时候title字段的重要性是其他字段的三倍,多匹配查询内部的执行方式 根据 type 类型
默认就是best_fields:查找匹配任何字段的文章,但是使用最佳匹配字段的score
most_fields:查找匹配任何字段的文档,接合每个字段的score
cross_fields:用相同的分析器处理字段,把这些字段当做一个大的字段.
phrase:每个字段上运行短语匹配查询,接合每个字段的score
phrase_prefix:在每个字段是上运行短语前缀查询,结合每个字段的score
trem 查询(字段查询)
精准的查询,对查询结果不做相关性排序.常用语结构化数据 如 数字 日期 枚举
单个字段查询
select * from table where type=1
GET /meadin/industry_news/_search
{
"query": {
"term": {
"dateSource": 79
}
}
}
多字段查询
select * from table where type in (19,20,79)
GET /meadin/industry_news/_search
{
"query": {
"terms": {
"dateSource": [19,20,79]
}
}
}
范围查询
GET /meadin/industry_news/_search
{
"query": {
"range": {
"dateSource": {
"gte": 10,
"lte": 20
}
}
}
}
复合查询
复合查询就是将多个叶子查询组合到一起,组合方式有多种
must 必须出现在匹配的文档中 并且会影响匹配得分
filter 必须出现在匹配的文当中 不影响匹配得分
should 应该出现在匹配的文档中 匹配一个或多个should里面的条件(可以通过minimum_should_match参数设置 默认最少匹配一个)
must_not 必须不出现在匹配的文档中
GET /meadin/industry_news/_search
{
"query": {
"bool": {
"should": [
{
"constant_score": {
"filter": {
"term": {
"context": "洗浴"
}
},
"boost": 1.2
}
},
{
"constant_score": {
"filter": {
"term": {
"context": "电视"
}
},
"boost": 1.2
}
}
]
}
}
}
查询context字段包含洗浴 或者 电视 的文档 constant_score 表示不计算词频 同一个词出现一次和出现多次得分是一样的,这样的查询场景 我们关心的是包含的要查询的内容多不多.好比 查找一家酒店 要求这个酒店 有 洗浴 电视 wifi 等 出现的项目越多排名越靠前
查询的优化
filter
GET meadin/industry_news/_search
{
"query": {
"bool": {
"must": {
"match": {
"text": "quick brown fox"
}
},
"filter": {
"term": {
"status": "1"
}
}
}
}
}
- 为每一个倒排索引构建一个 bitset(用来做缓存的二进制数组) 如下图
- 根据查询条件 “status”: “1” 找到对应的 bitset [1,0,1] 通过bitset找到对应的数据doc1 和 doc3把数据返回给客户端
- cache bitset 跟踪query 在最近的256个query中超过一定次数使用的bitset会被缓存起来,以备下次使用
- bitset的查询是在query查询开始的时候 进行的,这样可以过滤掉大部分内容
- 以后只要有相同的filter 就会直接定位到相应的bitset