ElasticSearch练习一:搜索语法学习(term,filter,bool,terms,range)

版本: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
    }
  }
}
  1. query:搜索
  2. constant_score:常量分数,指定查询出的结果所得的分数
  3. filter:过滤
  4. 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
  1. bool:相当于SQL中的and,用于多值查询,一般紧跟query使用
  2. should:相当于SQL中的or,但是只能在bool中使用,不能紧跟query
  3. must_not:相当于SQL的**!=**,但是只能在bool中使用,不能紧跟query
  4. articleID.keyword:这是由于articleID里面有fields,fields字段可以让某一个字段具有更多的特性,具体要看fields字段对应的type
  5. 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也可以查的出来,这是为什么呢?
  1. 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"
      }
    }
  }
}
  1. 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%"
      }
    }
  }
}
  1. match可以通过and operator来控制检索关键字要全部命中
  2. 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"
          }
        }
      ]
    }
  }
}
  1. 当有should没有must的时候,should中的条件必须至少要满足一个;当有should也有must的时候,should中的条件可以一个也不满足也能命中。
    比如上面的搜索结果”this is java blog“,没有满足should的任何条件。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫985

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值