版本:elasticSearch7.6.1
借鉴:https://blog.csdn.net/weixin_41910694/article/details/109407919
1.原始数据
POST /forum/_doc/_bulk
{ "index": { "_id": 1 }}
{ "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2017-01-01" }
{ "index": { "_id": 2 }}
{ "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2017-01-02" }
{ "index": { "_id": 3 }}
{ "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2017-01-01" }
{ "index": { "_id": 4 }}
{ "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2017-01-02" }
# 删除索引
DELETE forum
2. term,filter使用
根据用户ID搜索帖子
GET /forum/_search
{
"query": {
"term": {
"userID": "1"
}
}
}
指定查询出的结果所得的分数
GET /forum/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"userID": "1"
}
},
"boost": 1.3
}
}
}
- query:搜索
- constant_score:常量分数,指定查询出的结果所得的分数
- filter:过滤
- term:对搜索文本不分词,直接拿去倒排索引中匹配,你输入的是什么,就去匹配倒排索引什么,相当于SQL中的单个where条件
3. bool组合多个filter条件来搜索数据
搜索发帖日期为2017-01-01,或者帖子ID为KDKE-B-9947-#kL5的帖子,同时要求帖子的ID绝对不为XHDK-A-1293-#fJ3
这里有个小插曲,一开始我用【错误答案中的dsl】查出来的结果是错误的。结果是XHDK-A-1293-#fJ3、JODL-X-1937-#pV7,这两条都是2017-01-01的数据,看样子articleID的条件都没有生效。
这个错误产生的原因是,ElasticSearch5.0以后,字符串类型有重大变更,移除了string类型,string字段被拆分成两种新的数据类型: text和keyword。如果不指定类型,ElasticSearch字符串的字段(如新增字段articleID)将默认被同时映射成text和keyword类型,会自动创建下面的动态映射(dynamic mappings):
# articleID为text类型;articleID.keyword为keyword类型
{
"articleID": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
# 可以使用以下dsl看分词后的结果
GET /_analyze
{
"text": ["KDKE-B-9947-#kL5"]
}
# 可以使用以下dsl看索引的结果
GET /forum/_mapping
所以错误答案中的dsl的term+articleID,虽然对输入是不分词的,但是由于articleID是text类型,搜索结果被分词了,所以也就找不到了。
正确答案1中使用match_phrase+articleID,是因为结果是被分词的,而且match_phrase是对输入也会分词的,并且结果要包含match_phrase分词后的所有短语+顺序一致,所以也能匹配上。
正确答案2中使用term+articleID.keyword,是因为结果是keyword不分词,而且term对输入也部分此,所以也能匹配上。
错误答案:
GET /forum/_search
{
"query": {
"bool": {
"must_not": [
{
"term": {
"articleID": {
"value": "XHDK-A-1293-#fJ3"
}
}
}
],
"should": [
{
"term": {
"postDate": {
"value": "2017-01-01"
}
}
},
{
"term": {
"articleID":{
"value": "KDKE-B-9947-#kL5"
}
}
}
]
}
}
}
正确答案1:
GET /forum/_search
{
"query": {
"bool": {
"must_not": [
{
"match_phrase": {
"articleID": "XHDK-A-1293-#fJ3"
}
}
],
"should": [
{
"term": {
"postDate": {
"value": "2017-01-01"
}
}
},
{
"match_phrase": {
"articleID": "KDKE-B-9947-#kL5"
}
}
]
}
}
}
# 结果是KDKE-B-9947-#kL5、JODL-X-1937-#pV7
正确答案2:
GET /forum/_search
{
"query": {
"bool": {
"must_not": [
{
"term": {
"articleID.keyword": {
"value": "XHDK-A-1293-#fJ3"
}
}
}
],
"should": [
{
"term": {
"postDate": {
"value": "2017-01-01"
}
}
},
{
"term": {
"articleID.keyword":{
"value": "KDKE-B-9947-#kL5"
}
}
}
]
}
}
}
# 结果是KDKE-B-9947-#kL5、JODL-X-1937-#pV7
- bool:相当于SQL中的and,用于多值查询,一般紧跟query使用
- should:相当于SQL中的or,但是只能在bool中使用,不能紧跟query
- must_not:相当于SQL的**!=**,但是只能在bool中使用,不能紧跟query
- articleID.keyword:这是由于articleID里面有fields,fields字段可以让某一个字段具有更多的特性,具体要看fields字段对应的type
- match_phrase:match_phrase是分词后去搜的;目标文档需要包含分词后的所有词;目标文档中出现的这些词不需要保持跟这些词的相对顺序一致,取决于slop
4.terms使用
比如有2条记录:[A,B,C]、[B、C]
我输入A、C,查出来[A,B,C]、[B、C],这叫随意包含。[A,B,C]和[B,C]都有包含A,C至少一个元素。
我输入A、B,查出来[A,B,C],这叫完全包含。[A,B,C]包含A,C全部元素。
我输入B,C,查出来[B,C],这叫仅包含。[B,C]包含B,C全部元素,并且[B, C]中只有B、C两个元素。
首先先更新下数据
POST /forum/_doc/_bulk
{ "update": { "_id": "1"} }
{ "doc" : {"tag" : ["java", "js", "hadoop"]} }
{ "update": { "_id": "2"} }
{ "doc" : {"tag" : ["java", "js"]} }
{ "update": { "_id": "3"} }
{ "doc" : {"tag" : ["js", "hadoop"]} }
{ "update": { "_id": "4"} }
{ "doc" : {"tag" : ["elasticsearch"]} }
搜索articleID为KDKE-B-9947-#kL5或QQPX-R-3956-#aD8的帖子
# 方法一
GET /forum/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"articleID.keyword": {
"value": "KDKE-B-9947-#kL5"
}
}
},
{
"term": {
"articleID.keyword": {
"value": "QQPX-R-3956-#aD8"
}
}
}
]
}
}
}
# 方法二
GET /forum/_search
{
"query": {
"terms": {
"articleID.keyword": [
"KDKE-B-9947-#kL5",
"QQPX-R-3956-#aD8"
]
}
}
}
搜索tag中包含java的帖子
GET /forum/_search
{
"query": {
"term": {
"tag": {
"value": "java"
}
}
}
}
搜索tag中包含java或js的帖子
GET /forum/_search
{
"query": {
"terms": {
"tag": [
"java",
"js"
]
}
}
}
搜索tag中包含java和js的帖子
GET /forum/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"tag": {
"value": "java"
}
}
},
{
"term": {
"tag": {
"value": "js"
}
}
}
]
}
}
}
搜索tag中仅包含java和js的帖子
# 目前只知道一种解决方案,就是在添加tag数组数据的时候,同时维护一个tag_count。
POST /forum/_doc/_bulk
{ "update": { "_id": "1"} }
{ "doc" : {"tag" : ["java", "js", "hadoop"], "tag_count": 3} }
{ "update": { "_id": "2"} }
{ "doc" : {"tag" : ["java", "js"], "tag_count": 2} }
{ "update": { "_id": "3"} }
{ "doc" : {"tag" : ["js", "hadoop"], "tag_count": 2} }
{ "update": { "_id": "4"} }
{ "doc" : {"tag" : ["elasticsearch"], "tag_count": 1} }
# 然后在查询
GET /forum/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"tag": {
"value": "java"
}
}
},
{
"term": {
"tag": {
"value": "js"
}
}
},
{
"term": {
"tag_count": {
"value": "2"
}
}
}
]
}
}
}
疑问:
- 数组有2种情况:item是简单类型,item是object。es对于数组是如何建立倒排索引,如何进行分词?
es对于多值字段的处理 - 我可以把es底层的倒排索引查出来吗?
- 下面dsl中查的出来,说明tag中的倒排索引含有java。后面我用_mapping去看了tag字段是属于text类型,tag.keyword是keword类型,但是我用tag.keyword也可以查的出来,这是为什么呢?
- terms:下面代码相当于tag = ‘java’ or tag = ‘js’。因为文档[“js”, “hadoop”]会被分词成js、hadoop,只要能匹配上一个分词,文档就能匹配上。
"terms": {
"tag": [
"java",
"js"
]
}
5.基于range filter来进行范围过滤
为帖子数据增加浏览量的字段
POST /forum/_doc/_bulk
{ "update": { "_id": "1"} }
{ "doc" : {"view_count" : 30} }
{ "update": { "_id": "2"} }
{ "doc" : {"view_count" : 50} }
{ "update": { "_id": "3"} }
{ "doc" : {"view_count" : 100} }
{ "update": { "_id": "4"} }
{ "doc" : {"view_count" : 80} }
搜索浏览量在30~60之间的帖子(包含30和60)
GET /forum/_search
{
"query": {
"range": {
"view_count": {
"gte": 30,
"lte": 60
}
}
}
}
搜索发帖日期在最近10年的帖子
GET /forum/_search
{
"query": {
"range": {
"postDate": {
"gte": "now-10y"
}
}
}
}
- range,相当于sql中的between,或者>=,<=,做范围过滤。但是如果要搜索的字段是日期类型,range的value可以某些动态计算。
6.match
为帖子数据增加标题字段
POST /forum/_doc/_bulk
{ "update": { "_id": "1"} }
{ "doc" : {"title" : "this is java and elasticsearch blog"} }
{ "update": { "_id": "2"} }
{ "doc" : {"title" : "this is java blog"} }
{ "update": { "_id": "3"} }
{ "doc" : {"title" : "this is elasticsearch blog"} }
{ "update": { "_id": "4"} }
{ "doc" : {"title" : "this is elasticsearch, java, hadoop blog"} }
{ "update": { "_id": "5"} }
{ "doc" : {"title" : "this is spark blog"} }
搜索标题中包含java或elasticsearch的blog
GET /forum/_search
{
"query": {
"match": {
"title": "java elasticsearch"
}
}
}
解析:"title": "java elasticsearch"中会被分词为java和elasticsearch,所以才能命中倒排索引
搜索标题中包含java和elasticsearch的blog
# 方法一
GET /forum/_search
{
"query": {
"match": {
"title": {
"query": "java elasticsearch",
"operator": "and"
}
}
}
}
# 方法二
GET /forum/_search
{
"query": {
"match_phrase": {
"title": {
"query": "java elasticsearch",
"slop": 1000
}
}
}
}
搜索包含java,elasticsearch,spark,hadoop,4个关键字中,至少3个的blog
GET /forum/_search
{
"query": {
"match": {
"title": {
"query": "java elasticsearch spark hadoop",
"minimum_should_match": "75%"
}
}
}
}
- match可以通过and operator来控制检索关键字要全部命中
- match可以通过minimum_should_match来控制结果准确率(精确度)
7.should和must的关系
GET /forum/_search
{
"query": {
"bool": {
"must": {
"match": {
"title": "java"
}
},
"must_not": {
"match": {
"title": "spark"
}
},
"should": [
{
"match": {
"title": "hadoop"
}
},
{
"match": {
"title": "elasticsearch"
}
}
]
}
}
}
- 当有should没有must的时候,should中的条件必须至少要满足一个;当有should也有must的时候,should中的条件可以一个也不满足也能命中。
比如上面的搜索结果”this is java blog“,没有满足should的任何条件。