在我之前的文章系列里,我详细描述了 query_string 的一些功能:
- Elasticsearch: query_string 查询
- Elasticsearch:以更简单的方式编写具有逻辑条件的 Elasticsearch 查询 - query_string
- Elasticsearch:理解 query_string 和 simple_query_string 查询
在今天的文章中,我们来聊聊 query_string 中的一下特殊查询。
使用 query_string 查询的短语查询
如果您想知道是否支持使用 query_string 进行短语搜索,确实有。 我们唯一需要注意的是短语必须用引号引起来。 也就是说,对应于该短语的引号必须被转义; 例如,"query": ""Design Patterns""。 下一个清单中的查询搜索一个短语。
1. PUT books/_doc/1
2. {
3. "synopsis": "I am making the code better"
4. }
6. GET books/_search
7. {
8. "query": {
9. "query_string": {
10. "query": "\"making the code better\"",
11. "default_field": "synopsis"
12. }
13. }
14. }
上面讲返回如下的结果:
1. {
2. "took": 0,
3. "timed_out": false,
4. "_shards": {
5. "total": 1,
6. "successful": 1,
7. "skipped": 0,
8. "failed": 0
9. },
10. "hits": {
11. "total": {
12. "value": 1,
13. "relation": "eq"
14. },
15. "max_score": 1.1507283,
16. "hits": [
17. {
18. "_index": "books",
19. "_id": "1",
20. "_score": 1.1507283,
21. "_source": {
22. "synopsis": "I am making the code better"
23. }
24. }
25. ]
26. }
27. }
如果我们做如下的搜索:
1. GET books/_search
2. {
3. "query": {
4. "query_string": {
5. "query": "\"making the better code\"",
6. "default_field": "synopsis"
7. }
8. }
9. }
在上面,我们把 code 及 better 调换过来,我们发现就没有搜索到结果。很显然这是一个 phrase 查询。
顺其自然,如果短语中缺少一两个单词,我们可以使用 slop 参数。
例如,以下清单中的代码演示了 phrase_slop 参数如何允许短语中缺少单词(the 从短语中删除)并且仍然获得成功的结果。
1. GET books/_search
2. {
3. "query": {
4. "query_string": {
5. "query": "\"making code better\"",
6. "default_field": "synopsis",
7. "phrase_slop": 1
8. }
9. }
10. }
上面的搜索可以搜索到我们之前写入的文档。查询遗漏了一个词,但是 phrased_slop 设置原谅了遗漏,因此,我们得到了想要的结果。
同样地,我们可以针对如下的搜索来进行:
1. GET books/_search
2. {
3. "query": {
4. "query_string": {
5. "query": "\"making the code better\"",
6. "default_field": "synopsis",
7. "phrase_slop": 2
8. }
9. }
10. }
在上面,尽管 code 和 better 是倒置的,我们需要设置 phrase_stop 为 2 才可以搜索到。有关 slop 的定义,请详细阅读文章 “开始使用 Elasticsearch (2)” 中的 “匹配短语” 章节。
使用 query_string 查询的模糊查询
我们还可以通过使用带有 query_string queries 的模糊查询来要求 Elasticsearch 原谅拼写错误。 我们需要做的就是在查询条件后面加上波浪号 (~) 运算符。
下面的清单演示了一个示例,可以最好地理解这一点。
1. PUT books/_doc/2
2. {
3. "title": "I like these patterns"
4. }
6. GET books/_search
7. {
8. "query": {
9. "query_string": {
10. "query": "Pattenrs~",
11. "default_field": "title"
12. }
13. }
14. }
上面搜索的结果为:
1. {
2. "took": 853,
3. "timed_out": false,
4. "_shards": {
5. "total": 1,
6. "successful": 1,
7. "skipped": 0,
8. "failed": 0
9. },
10. "hits": {
11. "total": {
12. "value": 1,
13. "relation": "eq"
14. },
15. "max_score": 0.25172183,
16. "hits": [
17. {
18. "_index": "books",
19. "_id": "2",
20. "_score": 0.25172183,
21. "_source": {
22. "title": "I like these patterns"
23. }
24. }
25. ]
26. }
27. }
通过使用 ~ 运算符设置后缀,我们请求引擎将查询视为模糊查询。 默认情况下,使用模糊查询时使用的编辑距离为 2。
编辑距离是将一个字符串转换为另一个字符串所需的突变数。 例如,“CAT” 需要编辑距离为 1 才能将其转换为“CAP”。有关这个编辑距离的更多知识,请参阅文章 “Elasticsearch:fuzzy 搜索 (模糊搜索)”。
查询使用 Levenshtein 距离算法来支持模糊查询。 然而,还有另一种类型的编辑距离算法,称为 Damerau–Levenshtein 距离算法。 事实上,Damerau–Levenshtein 距离用于支持模糊查询。 它支持最多两个字符的插入、删除或替换,以及相邻字符的调换。
Levenshtein 距离算法定义了将一个字符串转换为另一个字符串所需的最少突变数。 这些突变包括插入、删除和替换。 Damerau–Levenshtein 距离算法更进了一步。 除了具有 Levenshtein 定义的所有突变之外,Damerau-Levenshtein 算法还考虑了相邻字符的转置(例如,TB-> BT -> BAT)。
默认情况下,query_stringquery 中的编辑距离为 2,但如果需要,我们可以通过在波浪号后设置 1 来减少它,如下所示:“Patterns~1”。比如:
1. GET books/_search
2. {
3. "query": {
4. "query_string": {
5. "query": "Pattenrs~1",
6. "default_field": "title"
7. }
8. }
9. }
上述搜索结果将返回我们之前输入的文档。