文章目录
[一、Restful API](#一、Restful API)
Elasticsearch语法与案例介绍
一、Restful API
Elasticsearch采用REST API,所有的操作都可通过REST API完成,例如增删改查、别名配置等。
Elasticsearch官方参考文档
单文档API:
多文档API:
二、查询语法
1、ES分词器
对于存入ES索引(Index)中的各个字段(Term),ES内部都会有一个分词器对其进行分词,然后将这个分词结果存储起来,方便未来的查询使用,这个分词器用户也可以直接很方便的调用,只要访问其_analyze即可:
在学习查询语法之前需要了解一下ES的分词器。因为这是ES搜索引一个很大的特点,它查询速度之所以这么快也和这个有很大关系。但更重要的是,如果不了解ES会对存储的索引文本或者查询query进行分词,后面的语法将很难理解。
cpp
GET _analyze
{
"analyzer": "standard",
"text": "This is a test doc"
}
这里需要指定一个分词器,ES默认的分词器是standard,不过只支持英文分词,如果用它来对中文进行分词的话会直接按字拆分,有一些中文分词器可以下载使用,像ik或者jieba之类的。
**注意:**阿里云ES内置了ik分词器,直接指定analyzer为ik_smart即可使用。
用上述的分词请求返回的结果如下
可以看到句子被分词器这样做好了分词,还有偏移量之类的信息。这里只是看一下ES是如何做到分词的,用户平时查询的话自己是用不到分词的,这些分词都是在保存索引时ES自动分好存储起来的。
总结:
- Elasticsearch调用分词器的命令是GET _analyze
- Elasticsearch默认的分词器是standard
2、ES查询
下面介绍一下ES常用的几种查询,详细的可以参考官网
Query DSL | Elasticsearch Guide [8.5] | Elastic
2.1、match
ES的查询有一个很大的特点就是分词。所以用户在使用ES的过程中脑子要始终有这么一个意识,要查找的text是通过分词器分过词的,所以去匹配的实际上是一个个被分词的片段。 而搜索的query也有可能会被分词,match就是一种会将用户搜索的query进行分词的查询方法。结合例子来看, 比如要查询的索引结构如下:
- _index代表索引名称
- _id代表该条数据唯一id
- _source代表该条数据具体的结构
案例
cpp
-- 创建索引
PUT /textbook
{
"settings": {
"number_of_shards": 5,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"bookName": {
"type": "text",
"analyzer": "standard"
},
"author":{
"type":"text"
},
"num": {
"type": "integer"
}
}
}
}
cpp
-- 插入数据
POST /textbook/_doc/kIwXeYQB8iTYJNkI986Y
{
"bookName": "this is a test doc",
"author": "老坛",
"num": 20
}
输入query语句如下:
cpp
GET /textbook/_search
{
"query": {
"match": {
"bookName":"test"
}
}
}
该条语句代表用match方式搜索索引为textbook中bookName可以匹配到test的语句。因为"bookName": "this is a test doc"原文被分词器分词后包含test这个词语,所以可以正常被匹配出来。
上面例子比较简单,看个复杂一点的例子
cpp
GET /textbook/_search
{
"query": {
"match": {
"bookName":"my test"
}
}
}
这个能否被匹配出来呢?原文中根本就没有my这个词语,那怎么被匹配出来?
但实际上是可以匹配出来的。原因是match查询里,会对查询的query也进行分词,也就是会将"my test"进行分词,得到my与test两个词语,然后用这两个词语分别去匹配文本,发现虽然my匹配不到,但是test可以匹配到,所以依然可以查出来。这个和传统的搜索方式确实存在差异,用户要注意。
那这种搜索方式存在的价值是什么呢?
其实还有蛮大用处的。比如ES库存储的是很多的英文好词好句,然后用户想提高自己的英文写作,因此想搜索出一些比较好的表达加在自己的文章中,那这个时候对于用户来讲,严格的匹配方式大概率什么都搜不到,但是像match这样的搜索方式便非常合适。
例如有个好句是这样的:If at first you don't succeed, try again
然后用户用下面的方式搜索:If you don't success
用match就可以很好的匹配出来。
总结:
Elasticsearch中math查询的特点是会对query进行分词,拿到分好的词去进行匹配文本,而不是将query进行整体匹配。
2.2、match_phrase
既然match的限制比较小,那如果需要限制更强一点用什么方式呢?match_phrase便是一个比较不错的选择。match_phrase和match一样也是会对搜索query进行分词,但是,不同的是它不是匹配到某一处分词的结果就算是匹配成功了,而是需要query中所有的词都匹配到,而且相对顺序还要一致,而且默认还是连续的,如此一来,限制就更多了。还是举个例子,对于刚刚的索引数据,如果还用刚刚的方式搜索:
cpp
GET /textbook/_search
{
"query": {
"match_phrase": {
"bookName":"my test"
}
}
}
这次是匹配不到结果的。那么怎样才能匹配到结果呢?
只能是搜索原文中的连续字串:
cpp
GET /textbook/_search
{
"query": {
"match_phrase": {
"bookName":"is a test"
}
}
}
这样是可以匹配到结果的。但是如此一来限制可能太大了一点,所以官方还给了一个核心参数可以调整搜索的严格程度,这个参数叫slop。
举个例子
cpp
GET /textbook/_search
{
"query": {
"match_phrase": {
"bookName":{
"query":"is test",
"slop":1
}
}
}
}
比如将slop置为1,然后搜索"is test",虽然is test中间省略了一个词语"a",但是在slop为1的情况下是可以容忍中间省略一个词语,也可以搜索出来结果。以此类推,slop为2就可以省略两个词语了。用户可以根据自己的实际情况进行调整。
2.3、multi_match
有了前面的基础,multi_match比较好理解。实际上就是可以从多个字段中去寻找要查找的query:
cpp
GET /textbook/_search
{
"query": {
"multi_match": {
"query" : "老坛",
"fields" : ["bookName", "author"]
}
}
}
比如这里是从bookName和author两个字段里去寻找老坛,虽然bookName没有,但是author可以匹配到,那也可以找到数据。所以本质上就是对bookName和author分别做了一次match。
总结:
- Elasticsearch中match_phrase查询的特点是它不是匹配到某一处分词的结果就算是匹配成功了,而是需要query中所有的词都匹配到,而且相对顺序还要一致,而且默认还是连续的。
- Elasticsearch中multi_match查询的特点是从多个字段中去寻找要查找的query。
2.4、term
term查询也是比较常用的一种查询方式,它和match的唯一区别就是match需要对query进行分词,而term是不会进行分词的,它会直接拿query整体和原文进行匹配。所以不理解的小伙伴使用起来可能会非常奇怪:
cpp
GET /textbook/_search
{
"query": {
"term": {
"bookName": "this is a test doc"
}
}
}
当用这种方式进行搜索时,明明要搜索的和被搜索的文本一模一样,但就是搜不出来。这就是因为去搜的实际上并不是原文本身,而是被分词的原文,在原文被分好的每一个词语里,没有一个词语是:"this is a test doc",那自然是什么都搜不到了。所以在这种情况下就只能用某一个词进行搜索才可以搜到:
cpp
GET /textbook/_search
{
"query": {
"term": {
"bookName": "this"
}
}
}
2.5、terms
terms查询事实上就是多个term查询取一个交集,也就是要满足多个term查询条件匹配出来的结果才可以查到,所以是比单纯的term条件更为严格了:
cpp
GET /textbook/_search
{
"query": {
"terms": {
"bookName": ["this", "is"]
}
}
}
比如这个例子,是要求原文中既有this这个词,又有is这个词才可以被查到,那按照这个规则是可以匹配到数据的。但是如果改成了一个不存在的词便匹配不到了。
cpp
GET /textbook/_search
{
"query": {
"terms": {
"bookName": ["this", "my"]
}
}
}
总结:
- Elasticsearch中term查询的特点是term是不会进行分词的,它会直接拿query整体和分词后的原文进行匹配。
- Elasticsearch中terms查询的特点是查询事实上就是多个term查询取一个交集,也就是要满足多个term查询条件匹配出来的结果,只要有一个匹配成功就返回。
2.6、fuzzy
fuzzy是ES里面的模糊搜索,它可以借助term查询来进行理解。fuzzy和term一样,也不会将query进行分词,但不同的是它在进行匹配时可以容忍词语拼写错误,至于容忍度如何,是根据参数fuzziness决定的。fuzziness默认是2,也就是在默认情况下,fuzzy查询容忍有两个字符及以下的拼写错误。即如果要匹配的词语为test,但是query是text,那也可以匹配到。这里无论是错写多写还是少写都是计算在内的。
同样还是举例说明,对于之前索引数据,如果查询语句为:
cpp
GET /textbook/_search
{
"query": {
"fuzzy": {
"bookName":"text"
}
}
这时肯定是用text来匹配原文中的每一个词,发现text和test最为接近,但是有一个字符的差异,在默认fuzziness为2的情况下,依然可以匹配出来。
当然这个fuzziness是可以调的,比如:
cpp
GET /textbook/_search
{
"query": {
"fuzzy": {
"bookName":{
"value":"texts",
"fuzziness":1
}
}
}
}
在容忍度为1的情况下,如果想查texts就查不到结果了。
2.7、range
range查询时对于某一个数值字段的大小范围查询,range的语法设计到了一些关键字:
- gte:大于等于
- gt:大于
- lt:小于
- lte:小于等于
cpp
GET /textbook/_search
{
"query": {
"range": {
"num": {
"gte":20,
"lt":30
}
}
}
}
比如这样的条件就是去查找字段num大于等于20小于30的数据,那数据便可以被查询到。
2.8、bool
bool查询是上面查询的一个综合,它可以用多个上面的查询去组合出一个大的查询语句,它也有一些关键字:
- must:代表且的关系,也就是必须要满足该条件
- should:代表或的关系,代表符合该条件就可以被查出来(满足其中部分条件)
- must_not:代表非的关系,也就是要求不能是符合该条件的数据才能被查出来
cpp
GET /textbook/_search
{
"query":{
"bool":{
"must":{
"match":{
"author":"老坛"
}},
"should":[
{
"term":{
"bookName":"老坛"
}},
{
"range":{
"num":{
"gt":10
} }}
]
, "minimum_should_match" : 1
}}}
这里就要求must里面的match是必须要符合的,但是should里面的条件符合一条即可。
注意:minimum_should_match 参数指定should返回的文档必须匹配的子句的数量或百分比。如果bool查询包含至少一个should子句,而没有must或filter子句,则默认值为1。否则,默认值为0。
总结:
- Elasticsearch中fuzzy查询的特点是fuzzy是ES里面的模糊搜索,允许词语发生一定的拼写错误。
- Elasticsearch中range查询的特点是范围查询:gte、gt、lt、lte。
- Elasticsearch中bool查询的特点是查询逻辑组合,可以用使用一些小查询去组合出一个大的查询语句。
- 📢博客主页:https://lansonli.blog.csdn.net
- 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
- 📢本文由 Lansonli 原创,首发于 CSDN博客🙉
- 📢停下休息的时候不要忘了别人还在奔跑,希望大家抓紧时间学习,全力奔赴更美好的生活✨