文章目录

  • 0.前言
  • 1.根据 ID 查询
  • 2.精确匹配单个字段
  • 3.精确匹配单个字段的多个值
  • 4.全文查询
  • 5.范围查询
  • 6.判断某个字段是否存在
  • 7.bool 组合查询
    • must
    • filter
    • should
    • must_not
  • 8.分页查询
    • from+size(浅分页)
    • scroll api(深分页)
    • search after(深分页)
    • 小结
  • 9.查询文档是否存在
    • 9.1 根据 ID 判断文档是否存在
    • 9.2 查询符合条件的文档数量
  • 10.获取文档数量
  • 12.脚本查询
    • 12.1 判断数组长度
  • 13.遍历查询结果
  • 参考文献

0.前言

搜索是 ES 最为复杂精妙的地方,这里只示例项目中较为常用的查询。

ES 中的查询分为三大类,一是 Term-level queries(我翻译成字段匹配),二是 Full-text queries(全文搜索),三是不常用的 Specialized queries(专门查询)。各自可细分为如下几种:

  • Term-level queries

    • TermQuery 精确匹配单个字段
    • TermsQuery 精确匹配单个字段,但使用多值进行匹配,类似于 SQL 中的 in 操作
    • RangeQuery 范围查询
    • BoolQuery 组合查询
    • ExistsQuery 字段是否存在值
  • Full-text queries
    • MatchQuery 单字段搜索(匹配分词结果,不需要全文匹配)
  • Specialized queries
    • Script query 脚本查询

这里并未将每个大类下的全部子类列举出来,只列举了本文涉及到查询。其他可到官网了解。

1.根据 ID 查询

根据文档 ID 获取单个文档信息。

// GetByID4ES 根据ID查询单个文档
func GetByID4ES(ctx context.Context, index, id string) (string, error) {res, err := GetESClient().Get().Index(index).Id(id).Do(ctx)if err != nil {return "", err}return string(res.Source), nil
}

注意:查询不存在的 ID,会报elastic: Error 404 (Not Found)错误。

对应的 RESTful api 为:

GET /es_index_userinfo/_doc/1


如果只想返回部分字段,可以使用_source_includes_source_excludes参数来包括或过滤掉特定字段。

例如不返回创建时间(create_time) 和更新时间(update_time),支持通配符。

GET /es_index_userinfo/_doc/1?_source_includes=*&_source_excludes=*time

2.精确匹配单个字段

比如获指定用户名的用户。

// 创建 term 查询条件,用于精确查询
termQuery := elastic.NewTermQuery("username", "cat")
searchResult, err := GetESClient().Search().Index("es_index_userinfo").          // 设置索引名Query(termQuery).                       // 设置查询条件Sort("create_time", true).               // 设置排序字段,根据 create_time 字段升序排序From(0).                              // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                            // 设置分页参数 - 每页大小Do(ctx)                                 // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query": {"term": {"username": "bob"}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

注意: term 精确匹配 text 类型的字段可能匹配不到,因为 text 类型的字段会被分词.。如果分词的结果集中没有 term 指定的内容,那么将无法匹配。keyword 类型字段不会进行分词,所以可以用 term 进行精确匹配。

解决办法:给 text 类型的字段取一个别名,别名的类型为 keyword,即不进行分词。

"ancestral":{                 "type": "text",         "fields": {             "alias": {          "type": "keyword"}}
}

那么可以通过 ancestral.alias 访问字段 ancestral,其类型设为 keyword。

3.精确匹配单个字段的多个值

通过 TermsQuery 实现单个字段的多值精确匹配,类似于 SQL 的 in 查询。

比如获指定用户名的用户,只需要命中一个即可。

// 创建 terms 查询条件,用于多值精确查询
termsQuery := elastic.NewTermsQuery("username", "cat", "bob")
searchResult, err := GetESClient().Search().Index("es_index_userinfo").          // 设置索引名Query(termsQuery).                      // 设置查询条件Sort("create_time", true).               // 设置排序字段,根据 create_time 字段升序排序From(0).                              // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                            // 设置分页参数 - 每页大小Do(ctx)                                 // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query": {"terms": {"username": ["bobs","bob"]}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

4.全文查询

全文查询 Full text queries 是个 ES 的核心查询。

无论需要查询什么字段, MatchQuery 查询都应该会是首选的查询方式。它是一个高级全文查询 ,这表示它既能处理全文字段,又能处理精确字段。

使用 MatchQuery 对字段进行全文搜索,即匹配分词结果。如果分词出现在 MatchQuery 中指定的内容(指定的内容也会分词),如果存在相同的分词,则匹配。

假设“我爱中国”的分词结果为“我”、“爱”、“中国”,那么搜索“我是第一名”也会匹配,因为“我是第一名”的分词结果中也有“我”。

ES 查看某个字段数据的分词结果。

GET /{index}/{type}/{id}/_termvectors?fields={fields_name}

注意:
(1)如果想对输入不进行分词,请使用 term query;
(2)如果想对输入的分词结果全部匹配,请使用 match phrase query;
(3)如果想对输入的分词结果全部匹配且最后一个分词支持前缀匹配,请使用 match phrase prefix query;
(4)如果是对 keyword 字段进行 MatchQuery,因为该类型不会分词,所以是精确匹配。

比如获取指定用户名的用户。

// 创建 match 查询条件
matchQuery := elastic.NewMatchQuery("username", "bob")
searchResult, err := GetESClient().Search().Index("es_index_userinfo"). // 设置索引名Query(matchQuery).          // 设置查询条件Sort("create_time", true).  // 设置排序字段,根据 create_time 字段升序排序From(0).                    // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                   // 设置分页参数 - 每页大小Do(ctx)                     // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query": {"match": {"username": "bob"}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

5.范围查询

实现类似age >= 18 and age < 35的范围查询条件。

// 创建 range 查询条件
rangeQuery := elastic.NewRangeQuery("age").Gte(18).Lte(35)
searchResult, err := GetESClient().Search().Index("es_index_userinfo"). // 设置索引名Query(rangeQuery).          // 设置查询条件Sort("create_time", true).  // 设置排序字段,根据 create_time 字段升序排序From(0).                    // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                   // 设置分页参数 - 每页大小Do(ctx)                     // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query": {"range":{"age" : {"gte" : 18, "lte": 35}}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

6.判断某个字段是否存在

有时,我们需要查询不包含指定字段的记录,此时我们可以借助 Exists Query 来完成。其表示某个字段存在,如果表示不存在,需要借助 must_not boolean query 来完成。

注意:如果字段为 null 或者 [],虽然值为空,但是字段是存在的。

比如查询不存在 phone 字段且年龄大于 18 的用户记录,条件可以这么写:

GET /es_index_userinfo/_search
{"query": {"bool": {"must_not": {"exists": {"field": "phone"}},"filter":{"range":{"age":{"gte":18}}}}}
}

翻译成 Golang,对应的条件写为:

boolQuery := elastic.NewBoolQuery()
boolQuery.MustNot(elastic.NewExistsQuery("phone")))
boolQuery.Filter(elastic.NewRangeQuery("age").Gte(18))

7.bool 组合查询

BoolQuery 是一种组合查询,将多个条件通过类似 SQL 语句 and 和 or 组合在一起来作为查询条件。

其有四种类型的子句:

类型 描述
must 条件必须要满足,并将对分数起作用
filter 条件必须要满足,但又不同于 must 子句,在 filter context 中执行,这意味着忽略评分,并考虑使用缓存。效率会高于 must
should 条件应该满足。可以通过 minimum_should_match 参数指定应该满足的条件个数。如果 bool 查询包含 should 子句,并且没有 must 和 filter 子句,则默认值为 1,否则默认值为 0
must_not 条件必须不能满足。在 filter context 中执行,这意味着评分被忽略,并考虑使用缓存。因为评分被忽略,所以会返回所有 0 分的文档

must

类似 SQL 的 and,代表必须匹配的条件。

 // 创建 bool 查询boolQuery := elastic.NewBoolQuery()// 创建查询条件termQuery := elastic.NewTermQuery("username", "bob")rangeQuery := elastic.NewRangeQuery("age").Gte(18).Lte(35)// 设置 bool 查询的 must 条件, 组合了两个子查询// 搜索用户名为 bob 且年龄在 18~35 岁的用户boolQuery.Must(termQuery, rangeQuery)searchResult, err := GetESClient().Search().Index("es_index_userinfo"). // 设置索引名Query(boolQuery).           // 设置查询条件Sort("create_time", true).  // 设置排序字段,根据 create_time 字段升序排序From(0).                    // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                   // 设置分页参数 - 每页大小Do(ctx)                     // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query":{"bool":{"must":[{"term":{"username": "bob"}},{"range":{"age":{"gte":18, "lte":35}}}]}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

filter

类似 SQL 的 and,代表必须匹配的条件。不计算匹配分值,且子句被考虑用于缓存。

使用 filter 替代 must 条件,查询用户名为 bob 且年龄在 18~35 岁的用户

 // 创建 bool 查询boolQuery := elastic.NewBoolQuery()// 创建查询条件termQuery := elastic.NewTermQuery("username", "bob")rangeQuery := elastic.NewRangeQuery("age").Gte(18).Lte(35)// 设置 bool 查询的 filter 条件, 组合了两个子查询// 搜索用户名为 bob 且年龄在 18~35 岁的用户boolQuery.Filter(termQuery, rangeQuery)searchResult, err := GetESClient().Search().Index("es_index_userinfo"). // 设置索引名Query(boolQuery).          // 设置查询条件Sort("create_time", true).  // 设置排序字段,根据 create_time 字段升序排序From(0).                    // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                   // 设置分页参数 - 每页大小Do(ctx)                     // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query":{"bool":{"filter":[{"term":{"username": "bob"}},{"range":{"age":{"gte":18, "lte":35}}}]}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

should

类似 SQL 中的 or, 可以通过 minimum_should_match 参数指定应该满足的条件个数。如果 bool 查询包含 should 子句,并且没有 must 和 filter 子句,则默认值为 1,否则默认值为 0。

比如查询用户名为 bob 且年龄为18 或 35 岁的用户。

// 创建 bool 查询
boolQuery := elastic.NewBoolQuery()// 创建查询条件
termQuery := elastic.NewTermQuery("username", "bob")
termQuery1 := elastic.NewTermQuery("age", 18)
termQuery2 := elastic.NewTermQuery("age", 35)// 设置 bool 查询的 filter 条件, 组合了两个子查询
// 搜索用户名为 bob 且年龄为 18 或 35 岁的用户
boolQuery.Filter(termQuery, termQuery)
boolQuery.Should(termQuery, termQuery1, termQuery2)
boolQuery.MinimumNumberShouldMatch(1) // 至少满足 should 中的一个条件searchResult, err := GetESClient().Search().Index("es_index_userinfo"). // 设置索引名Query(boolQuery).           // 设置查询条件Sort("create_time", true).  // 设置排序字段,根据 create_time 字段升序排序From(0).                    // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                   // 设置分页参数 - 每页大小Do(ctx)                     // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query":{"bool":{"filter": {"term":{"username": "bob"}},"should":[{"term":{"age":18}},{"term":{"age":35}}],"minimum_should_match" : 1}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

must_not

跟 must 作用相反,表示条件必须不能满足。

比如搜索用户名为 bob 且年龄不为 18 或 35 岁的用户。

 // 创建 bool 查询boolQuery := elastic.NewBoolQuery()// 创建查询条件termQuery := elastic.NewTermQuery("username", "bob")termQuery1 := elastic.NewTermQuery("age", 18)termQuery2 := elastic.NewTermQuery("age", 35)// 设置 bool 查询的 filter 条件, 组合了两个子查询// 搜索用户名为 bob 且年龄不为 18 和 35 岁的用户boolQuery.Filter(termQuery)boolQuery.MustNot(termQuery1, termQuery2)searchResult, err := GetESClient().Search().Index("es_index_userinfo"). // 设置索引名Query(boolQuery).           // 设置查询条件Sort("create_time", true).  // 设置排序字段,根据 create_time 字段升序排序From(0).                    // 设置分页参数 - 起始偏移量,从第 0 行记录开始Size(10).                   // 设置分页参数 - 每页大小Do(ctx)                     // 执行请求

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query":{"bool":{"filter": {"term":{"username": "bob"}},"must_not":[{"term":{"age":18}},{"term":{"age":35}}]}},"sort": [{"create_time": "asc"}],"from": 0,"size":10
}

8.分页查询

我们也可以根据条件分页查询。

ES 分页搜索一般有三种方案,from + size、search after、scroll api,这三种方案分别有自己的优缺点。

from+size(浅分页)

这是 ES 分页中最常用的一种方式,与 MySQL 类似,from 指定起始位置,size 指定返回的文档数。

这种分页方式,在分布式的环境下的深度分页是有性能问题的,一般不建议用这种方式做深度分页,可以用下面将要介绍的两种方式。

理解为什么深度分页是有问题的,假设取的页数较大时(深分页),如请求第20页,Elasticsearch 不得不取出所有分片上的第 1 页到第 20 页的所有文档,并做排序,最终再取出 from 后的 size 条结果作爲最终的返回值。

所以,当索引记录非常非常多(千万或亿),是无法使用 from + size 做深分页的,分页越深则越容易 OOM。即便不 OOM,也很消耗 CPU 和内存资源。

所以 ES 为了避免深分页,不允许使用 from + size 的方式查询 1 万条以后的数据,即 from + size 大于 10000 会报错,不过可以通过 index.max_result_window 参数进行修改。

// GetByQueryPage4ES 分页查询
// param: index 索引; query 查询条件; page 起始页(从 1 开始); size 页大小
func GetByQueryPage4ES(ctx context.Context, index string, query elastic.Query, page, size int) ([]string, error) {start := (page - 1) * sizeres, err := GetESClient().Search(index).Query(query).From(start).Size(size).Do(ctx)if err != nil {return nil, err}sl := make([]string, 0, res.TotalHits())for _, hit := range res.Hits.Hits {sl = append(sl, string(hit.Source))}return sl, nil
}// GetByQueryPageSort4ES 根据条件分页查询 & 指定字段排序
// param: index 索引; query 查询条件; page 起始页(从 1 开始); size 页大小; field 排序字段; ascending 升序
func GetByQueryPageSort4ES(ctx context.Context, index string, query elastic.Query, page, size int, field string,ascending bool) ([]string, error) {from := (page - 1) * sizeres, err := GetESClient().Search(index).Query(query).Sort(field, ascending).From(from).Size(size).Do(ctx)if err != nil {return nil, err}sl := make([]string, 0, res.TotalHits())for _, hit := range res.Hits.Hits {sl = append(sl, string(hit.Source))}return sl, nil
}

比如分页查询年龄 >=18 且按照创建时间降序排序:

query := elastic.NewBoolQuery()
query.Filter(elastic.NewRangeQuery("age").Gte(18))
sl, err := GetByQueryPageSort4ES(context.Background(), index, query, 1, 500, "create_time", false)

对应的 RESTful api 为:

GET /es_index_userinfo/_search
{"query": {"bool": {"filter":[{"range" : {"age" : {"gte" : 18}}}]}},"from": 0, "size" : 500,"sort" : [{"create_time":"desc"}]
}

注意:如果想控制返回哪些字段,可以使用 _source 来指定。比如只返回用户名(username)和年龄(age)。

GET /es_index_userinfo/_search
{"query": {"bool": {"filter":[{"range" : {"age" : {"gte" : 18}}}]}},"from": 0, "size" : 500,"sort" : [{"create_time":"desc"}],"_source": ["username", "age"]
}

Go 代码带上_source的方式。

fsc := elastic.NewFetchSourceContext(true).Include("username", "age")
res, err := GetESClient().Search(index).Query(query).FetchSourceContext(fsc).Sort(field, ascending).From(from).Size(size).Do(ctx)

scroll api(深分页)

创建一个快照,有新的数据写入以后,无法被查到。每次查询后,输入上一次的 scroll_id。目前官方已经不推荐使用这个 API 了,建议使用search after。

Go 代码示例:

// GetByQueryPageSortScroll4ES 获取第一页数据 & 获取游标ID
// ret: 文档切片, 游标ID, error
func GetByQueryPageSortScroll4ES(ctx context.Context, index string, query elastic.Query, size int, field string,
ascending bool) ([]string, string, error) {res, err := GetESClient().Scroll(index).Query(query).Sort(field, ascending).Size(size).Do(ctx)if err != nil {return nil, "", err}sl := make([]string, 0, res.TotalHits())for _, hit := range res.Hits.Hits {sl = append(sl, string(hit.Source))}return sl, res.ScrollId, nil
}// GetByQScrollID4ES 根据游标 ID 获取下一页
func GetByQScrollID4ES(ctx context.Context, scrollID string) ([]string, error) {res, err := GetESClient().Scroll().ScrollId(scrollID).Do(ctx)if err != nil {return nil, err}sl := make([]string, 0, res.TotalHits())for _, hit := range res.Hits.Hits {sl = append(sl, string(hit.Source))}return sl, nil
}

首先需要获取第一页数据并获取游标ID,然后便可以根据游标 ID 继续获取下一页数据,如果下一页如果为空的话会报 EOF 错误,此时便可知拉取结束了。

比如我们还是要分页获取籍贯为安徽的用户,且按照创建时间降序。

GET es_index_userinfo/_search?scroll=1m
{"size": 1,"query": {"match": {"ancestral": "安徽"}},"sort": [{"create_time": "desc"}]
}

在返回的数据中,有一个 _scroll_id 字段,下次搜索的时候带上这个数据,并且使用下面的查询语句。

POST _search/scroll
{"scroll" : "1m","scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFFRpdno4bm9CU3A1TEhvY3ktQjZzAAAAAAKolSoWbm04UWQ5SHlRdDJRRjZaeGFBdjFEQQ=="
}

上面的 scroll 指定搜索上下文保留的时间,1m 代表 1 分钟,还有其他时间可以选择,有 d、h、m、s 等,分别代表天、时、分钟、秒。

搜索上下文有过期自动删除,但如果自己知道什么时候该删,可以自己手动删除,减少资源占用。

DELETE /_search/scroll
{"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAA6UWWVJRTk9TUXFTLUdnU28xVFN6bEM4QQ=="
}

search after(深分页)

search after 利用实时游标来帮我们解决实时滚动的问题。

第一次搜索时需要指定 sort,并且保证值是唯一的,可以通过加入 _id 保证唯一性。

比如获取籍贯为安徽的用户,且按照创建时间降序。

matchQuery := elastic.NewMatchQuery("ancestral", "安徽")// 查询第一页(无需指定 SearchAfter)
searchResult, err := GetESClient().Search().Index("es_index_userinfo"). // 设置索引名Query(matchQuery).          // 设置查询条件Sort("create_time", false). // 按照创建时间降序Sort("_id", false).      // 加入 ID 排序保证 after id 唯一Size(1000).                 // 设置分页参数Do(ctx)// 查询第 n 页(n > 1,需要指定 SearchAfter)
searchResult, err := GetESClient().Search().Index("es_index_userinfo").          // 设置索引名Query(matchQuery).                  // 设置查询条件Sort("create_time", false).          // 按照创建时间降序Sort("_id", false).                // 加入 ID 排序保证 after id 唯一SearchAfter(lastCreateTime, id).   // 上页最后一条的创建时间和 IDSize(1000).                       // 设置分页参数Do(ctx)

对应 RESTful api 的示例。

GET es_index_userinfo/_search
{"size": 1,"query": {"match": {"ancestral": "安徽"}},"sort": [{"create_time": "desc"},{"_id": "desc"}]
}

在返回的结果中,最后一个文档有类似下面的数据,由于我们排序用的是两个字段,返回的是两个值。

"sort" : [1627522828,"2"
]

第二次搜索,带上这个 sort 信息即可,如下:

GET es_index_userinfo/_search
{"size": 1,"query": {"match": {"ancestral": "安徽"}},"sort": [{"create_time": "desc"},{"_id": "desc"}],"search_after": [1627522828,"2"]
}

小结

from + size 的优点是简单,缺点是在深度分页的场景下系统开销比较大。

search after 可以实时高效的进行分页查询,但是它只能做下一页这样的查询场景,不能随机的指定页数查询。

scroll api 方案也很高效,但是它基于快照,不能用在实时性高的业务场景,且官方已不建议使用。

9.查询文档是否存在

借助 ExistsService 使用 HEAD 检查文档是否存在判断。

如果文档存在, Elasticsearch 将返回一个 200 ok 的状态码,若文档不存在, Elasticsearch 将返回一个 404 Not Found 的状态码。

9.1 根据 ID 判断文档是否存在

// IsDocExists 某条记录是否存在
func IsDocExists(ctx context.Context, id, index string) (bool, error) {return GetESClient().Exists().Index(index).Id(id).Do(ctx)
}

RESTful api 示例:

head es_index_userinfo/_doc/1

返回:

200 - OK

9.2 查询符合条件的文档数量

可以借助 CountService 查询符合条件的文档数量,进而判断文档是否存在。

比如查询年龄>=18的用户数量。

 // 创建 range 查询条件rangeQuery := elastic.NewRangeQuery("age").Gte(18)cnt, err := GetESClient().Count("es_index_userinfo").Query(rangeQuery).Do(ctx)

RESTful api 示例:

GET es_index_userinfo/_count
{"query": {"range": {"age": {"gte" : 18}}}
}

10.获取文档数量

上一节已经说了可以借助 CountService 查询符合条件的文档数量,如果想查询 index 下的所有文档呢?

很简单,不指定条件即可。

// GetIndexDocNum 获取索引文档总数
func GetIndexDocNum(ctx context.Context, index string) (int64, error) {return GetESClient().Count(index).Do(ctx)
}

RESTful API 示例:

GET es_index_userinfo/_count# 示例结果
{"count" : 337,"_shards" : {"total" : 20,"successful" : 20,"skipped" : 0,"failed" : 0}
}

12.脚本查询

有时候,我们需要通过脚本来设置复杂的查询条件。

注意

  • 脚本查询属于慢查询,在对性能要求严格的场景下谨慎使用;
  • 如果 search.allow_expensive_queries 被设置为 false(缺省为 true),则无法进行脚本查询。

12.1 判断数组长度

ES 中每一个字段都是数组,我们无需对字段做额外的设置,便可以将其当作数组来使用。

有时我们需要根据某个字段的元素个数,即数组长度来查询,此时便需要借助于脚本来完成。比如查询 phone 字段的长度为 1 个且等于某个值。

POST /es_index_userinfo/_search
{"query": {"bool":{"filter": [{"term":{"phone":18819064334}},{"script": {"script": "doc['phone'].length == 1"}}]}}
}

对应的 Golang 条件设置如下:

boolQuery := elastic.NewBoolQuery().Filter(elastic.NewTermQuery("phone", 18819064334)).Filter(elastic.NewScriptQuery(elastic.NewScript("doc['phone'].length == 1")))

如果需要向脚本传参,我们在脚本中设置相关的参数即可。

POST /es_index_userinfo/_search
{"query": {"bool":{"filter": [{"term":{"phone":18819064334}},{"script": {"script": {"source": "doc['phone'].length == params.length","params": {"length": 1}}}}]}}
}

对应 Golang 条件设置如下:

boolQuery := elastic.NewBoolQuery().Filter(elastic.NewTermQuery("phone", 18819064334)).Filter(elastic.NewScriptQuery(elastic.NewScript("doc['phone'].length == 1").Params(map[string]interface{}{"length": 1,},)))

13.遍历查询结果

获取到查询结果后,我们可以借助 olivere/elastic 提供的工具函数 func (*SearchResult) Each 完成对查询结果的遍历。下面是一个示例。

假设 ES 中的文档对应的 Go struct 如下。

type UserInfo struct {Id         uint64 `json:"id,omitempty"`Age        int32  `json:"age,omitempty"`Username   string `json:"username,omitempty"`Nickname   string `json:"nickname,omitempty"`Identity   string `json:"identity,omitempty"`Phone      uint64 `json:"phone,omitempty"`Ancestral  string `json:"ancestral,omitempty"`UpdateTime int64  `json:"update_time,omitempty"`CreateTime int64  `json:"create_time,omitempty"`
}

遍历取出查询到的文档。

for _, v := range res.Each(reflect.TypeOf(UserInfo{})) {u := v.(UserInfo)...
}

参考文献

github/elastic/elasticsearch
github/olivere/elastic/v7
pkg.go.dev/github.com/olivere/elastic/v7
掘金.Elasticsearch 分页查询
golang elasticsearch 查询教程
CSDN.ES中如何对text字段进行精确匹配
知乎.一文搞懂match、match_phrase与match_phrase_prefix的检索过程
elastic type CountService
elastic type ExistsService
Elasticsearch Guide [7.15] » Query DSL » Full text queries » Match query
Elasticsearch Guide [7.15] » Query DSL » Full text queries » Match phrase query
Elasticsearch Guide [7.15] » Query DSL » Full text queries » Match phrase prefix query
Elasticsearch Guide [7.15] » REST APIs » Search APIs » Count API
Elasticsearch Guide [8.1] » Query DSL » Term-level queries
Elasticsearch Guide [8.1] » Query DSL » Full text queries
Elasticsearch Guide [8.1] » Query DSL » Specialized queries » Script query

Go Elasticsearch 查询快速入门相关推荐

  1. Go Elasticsearch 删除快速入门

    文章目录 1.根据 ID 删除 2.根据条件删除 3.批量删除 4.FAQ 4.1 elastic: Error 409 (Conflict) 参考文献 本文借助第三方库 olivere/elasti ...

  2. Elasticsearch【快速入门】

    前言:毕设项目还要求加了这个做大数据搜索,正好自己也比较感兴趣,就一起来学习学习吧! Elasticsearch 简介 Elasticsearch 是一个分布式.RESTful 风格的搜索和数据分析引 ...

  3. Go Elasticsearch 更新快速入门

    文章目录 1.根据 ID 修改 2.根据 ID 修改(不存在则插入) 3.根据条件更新 4.批量更新 5.脚本更新 5.1 删除数组中的某个元素 5.2 删除数组中的多个元素 参考文献 本文借助第三方 ...

  4. Go Elasticsearch 增加快速入门

    文章目录 1.创建单个文档 1.1 Go 1.2 RESTful API 2.批量创建文档 2.1 Go 2.1 RESTful API 参考文献 创建完 ES 的 index,便可以向 index ...

  5. Go Elasticsearch 快速入门

    文章目录 1.入门简介 2.基本概念 3.客户端库 4.创建客户端 5.index 增删改查 6.增加 7.删除 8.修改 9.查询 10.小结 参考文献 1.入门简介 Elasticsearch 简 ...

  6. 【Elastic Stack上】Elastic Search快速入门,让你对ELK日志架构不再困惑

    课程介绍 Elastic Stack简介 Elasticsearch的介绍与安装 Elasticsearch的快速入门 Elasticsearch的核心讲解中文分词 全文搜索 Elasticsearc ...

  7. Elasticsearch快速入门2 - 高级查询功能

    我们在Elasticsearch快速入门1中详细介绍了ES的安装.基本概念和一些基本的REST Api请求,在这篇入门(2)中,我们继续介绍ES的高级查询功能. 为了说明ES强大的搜索功能,我们还以上 ...

  8. 尚硅谷-SpringBoot高级-检索-Elasticsearch快速入门

    前面我们安装好了ElasticSearch,我以后就简称他为ES,而一些人还不知道基本的使用,那我们接下来做一个快速入门,了解一下他的使用方法,以及一些基本概念,方便我们后来整合,那么要学习ES最好的 ...

  9. ElasticSearch快速入门

    官网地址(https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html)而且是中文的 Elastic的快速入门 1.基础 ...

最新文章

  1. 京东发布农民丰收节交易会大数据 互联网谋定现代农业
  2. JavaScript强化教程——正则表达式回溯
  3. 7添加静态路由 hat red_win7系统使用dos命令添加静态路由的操作方法
  4. Shell学习之结合正则表达式与通配符的使用(五)
  5. python itertools卡死_Python使用itertools模块来解决算法问题,python
  6. Centos7下yum安装MySQL 5.7
  7. 【420天】跃迁之路——程序员高效学习方法论探索系列(实验阶段177-2018.04.01)...
  8. ThinkPHP胜出Laravel 近4倍,主流框架性能测试
  9. 服务器配置文档模板,服务器配置模板
  10. hypervisor详解
  11. FortiGate防火墙配置SSL用户分流
  12. 服务器和网站APP为什么会被反复入侵
  13. 使用vscode 编辑运行processing代码
  14. 四种常用的100G QSFP28光模块的详细介绍
  15. 基于AT89C52的超声波测距仪
  16. Tyvj 1047 乘积最大
  17. My Life(1)
  18. 从K站看出谷歌与百度的差异
  19. 位置分布图怎么画,如何用电脑绘制电子地图
  20. 华为交换机链路聚合Eth-trunk实例

热门文章

  1. Python连接Oracle-常见问题
  2. 一个极简版本的 VUE SSR demo
  3. spring boot 2.0.3+spring cloud (Finchley)6、配置中心Spring Cloud Config
  4. RCNN,fast R-CNN,faster R-CNN
  5. live555学习之基本类介绍及计划任务深度探讨
  6. 美封锁对华半导体出口:14nm制造可以 X86设计不行
  7. DNS配置,主从,子域,转发
  8. 编程之美 3.1 字符串移位包含问 复杂度(O(N*K)
  9. 学习spring必须java基础知识-动态代理
  10. 《Web Load Testing For Dummie》读书笔记