上篇章,介绍了 ES 基本的增删改查。本篇章,将介绍 ES 的全文搜索(full text query),term query 会放到下一章节介绍。
被搜索的关键字,要按照指定的顺序出现在文档中,该文档才能被检索。
例如。
PUT /test/_doc/1
{
"name": "do you like search? yes. i am. i like java"
}
GET /test/_search
{
"query": {
"intervals": {
"name": {
"all_of": {
"ordered": true,
"intervals": [
{ "match": { "query": "am" }},
{ "match": { "query": "i" }},
{ "match": { "query": "java" }}
]
}
}
}
}
}
该查询的意思为,文档中需要有对应的term, am i java
,且必须按照 am > i > java
的顺序出现。
先对搜索词进行分词,然后再搜索。
例如
PUT /test/_doc/2
{
"name": "PHP is the best language in the world"
}
PUT /test/_doc/3
{
"name": "hello world! elasticsearch!"
}
GET /test/_search
{
"query": {
"match": {
"name": "php"
}
}
}
心细如你的一定可以发现,输入的 PHP 是大写。但小写也可搜索到。这部分内容和分词有关系,后续会补充,这里先忽略。
前缀匹配。将搜索词分词,最后一个词,被用作前缀匹配。
GET /test/_search
{
"query": {
"match_bool_prefix": {
"name": {
"query": "search wor",
"operator": "or"
}
}
}
}
search wor
,被分词为 search
, wor
。
要求文档中出现 search
或者
有关键字是以 wor
开头。
operator
还有 and
选项。即文档中必须有 search
关键字, 且有关键字以 wor
开头。
短语搜索。将搜索词分词,而后根据 slop
定义的词与词的间距,判断词与词之间最多能出现多少单词
GET /test/_search
{
"query": {
"match_phrase": {
"name": {
"query": "hello elasticsearch",
"slop": 2
}
}
}
}
hello elasticsearch
被分词为 hello
, elasticsearch
。
slop=2
表示匹配的文档, hello
, elasticsearch
之间至多只能间隔 2 个词。
短语搜索和前缀搜索的结合体。
GET /test/_search
{
"query": {
"match_phrase_prefix": {
"name": {
"query": "you sear",
"slop": 2
}
}
}
}
you sear
被分词为 you
, sear
。
slop=2
表示匹配的文档, you
, sear
之间至多只能间隔 2 个词。并且只要以 sear
开头即满足条件。
组合查询。需要注意的是,被搜索的字段,需要有相同的分词器。
PUT /test2/_doc/1
{
"name": "elasticsearch i love it",
"title": "java is very good"
}
PUT /test2/_doc/2
{
"name": "php i love it",
"title": "mysql is very good"
}
PUT /test2/_doc/3
{
"name": "redis i love it",
"title": "rocketMQ is very good"
}
GET /test2/_search
{
"query": {
"combined_fields" : {
"query": "java redis",
"fields": [ "name", "title"],
"operator": "or"
}
}
}
将 java redis
分词为 java、redis, 并在 name、title 中查找。name 或者 title 中有出现,文档就算匹配。
多字段查询。
GET /test2/_search
{
"query": {
"multi_match": {
"query": "mysql java",
"fields": ["name", "title"]
}
}
}
将 mysql java
分词为 mysql, java。分别在 name, title 中查询,如果 name 或者 title 中有匹配,文档就算匹配。
评分公式为:max(field_scores) * boost
type 会影响查询的行为和结果
默认 type 为 best_fields。
假设:
字段 | 文档 ID | mysql 得分 | java 得分 | 最终得分 |
---|---|---|---|---|
name | 1 | 0 | 3 | 0 + 3 |
title | 1 | 7 | 0 | 7 + 0 |
文档 1 最终得分 max(3, 7) = 7 |
GET /test2/_search
{
"query": {
"multi_match": {
"query": "mysql java",
"fields": ["name", "title"],
"type": "most_fields"
}
}
}
与 best_fields 的区别为:算分公式为,sum(field_scores * boost)
字段 | 文档 ID | mysql 得分 | java 得分 | 最终得分 |
---|---|---|---|---|
name | 1 | 0 | 10 | 0 + 10 |
title | 1 | 10 | 0 | 10 + 0 |
文档 1 最终得分 10 + 10 |
GET /test2/_search
{
"query": {
"multi_match": {
"query": "php java",
"fields": ["name", "title"],
"type": "cross_fields"
}
}
}
算分公式为, sum(max( term_in_field_scores * boost))
。即 每个分词(term) 在不同 field 中得分最大值之和,即为该文档的得分。
与 most_fields, best_fields 主要区别在于,cross_fields 算分是以 term(分词) 为纬度,后两者是以字段为维度。
分词(term) | 文档 ID | name 中的得分 | title 中的得分 | 最终得分 |
---|---|---|---|---|
php | 1 | 12 | 10 | 12(取最大的) |
java | 1 | 3 | 10 | 10(取最大的) |
文档 1 最终得分 (12) + (10) |
与 Match boolean prefix query、Match phrase query 类似。只不过是在多个字段中搜索,不过多介绍
tie_breaker
是一个 0-1 的值。默认为 0.
当设置了 tie_breaker 后,算分公式会变为。
final_score = max_score + tie_breaker * sum_of_other_scores
即,tie_breaker 值越大,其他字段的得分对总得分影响越大。
我们以 cross_fields 举例说明。
GET /test2/_search
{
"query": {
"multi_match": {
"query": "php java",
"fields": ["name", "title"],
"type": "cross_fields"
}
}
}
分词(term) | 文档 ID | name 中的得分 | title 中的得分 | 最终得分 | tie_breaker = 0.3 时的得分 |
---|---|---|---|---|---|
php | 1 | 12 | 10 | 12(取最大的) | 12 + 10 * 0.3 |
java | 1 | 3 | 10 | 10(取最大的) | 10 + 3 * 0.3 |
文档 1 最终得分 (12 + 10 * 0.3) + (10 + 3 * 0.3) |
默认为 or
。
例如
GET /test2/_search
{
"query": {
"multi_match": {
"query": "mysql java",
"fields": ["name", "title"],
"operator": "or"
}
}
}
表示,(mysql, java) in name
or (mysql, java) in title
。
即只要有 1个 term 存在于 field 就算匹配。
还有另外一个值 and
。
例如
GET /test2/_search
{
"query": {
"multi_match": {
"query": "mysql java",
"fields": ["name", "title"],
"operator": "and"
}
}
}
表示,((mysql) in name and (java) in name)
OR ((mysql) in title and (java) in title)
。
即 terms 必须同时出现在 field 才算匹配。
我们可以为每个字段单独设置权重。
例如
GET /test2/_search
{
"query": {
"multi_match": {
"query": "mysql java",
"fields": ["name^2", "title^3"],
"operator": "and"
}
}
}
name^2
, 表示,在对 name 字段进行算法时,需要将得分 * 2。
{
"query": {
"intervals": {
"name": {
"all_of": {
"ordered": true,
"intervals": [
{ "match": { "query": "am" }},
{ "match": { "query": "i" }},
{ "match": { "query": "java" }}
]
}
}
}
}
}