Elasticsearch Query DSL之全文检索(Full text queries)

本节将详细介绍DSL全文搜索。
全文查询包括如下几种模式:

  1. match query
    标准的全文检索模式,包含模糊匹配、前缀或近似匹配等。
  2. match_phrase query
    与match query类似,但只是用来精确匹配的短语。
  3. match_phrase_prefix query
    与match_phrase查询类似,但是在最后一个单词上执行通配符搜索。
  4. multi_match query
    支持多字段的match query。
  5. common terms query
    相比match query,消除停用词与高频词对相关度的影响。
  6. query_string query
    查询字符串方式
  7. simple_query_string query
    简单查询字符串方式

1、match query详解

1.1 match query使用示例与基本工作原理

全文索引查询,这意外着首先会对待查字符串(查询条件)进行分词,然后再去匹配,返回结果中会待上本次匹配的关联度分数。
例如存在这样一条数据:

"_source":{
             "post_date":"2009-11-16T14:12:12",
              "message":"trying out Elasticsearch",
               "user":"dingw2"
      }

使用如下查询条件:

"query": {
             "match" : {
                "message" : "this out Elasticsearch"
            }
        }

其JAVA代码对应:

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("message", "this out elasticsearch"));

其大体步骤如下:
首先对this out Elasticsearch分词,最终返回结果为 this、out、Elasticsearch,然后分别去库中进行匹配,默认只要一个匹配,就认为匹配,但会加入一个匹配程度(关联度),用scoce分数表示。

1.2 match query常用参数详解

  • operator(操作类型)
    可选值为:Operator.OR 和 Operator.AND。表示对查询字符串分词后,返回的词根列表,OR只需一个满足及认为匹配,而AND则需要全部词根都能匹配,默认值为:Operator.OR。
  • minimum_should_match 最少需要匹配个数。
    在操作类型为Operator.OR时生效,指明分词后的词根,至少minimum_should_match 个词根匹配,则命中。
"match" : {
            "message" : "this out Elasticsearch",
            “minimum_should_match ”:“3”
}

此时由于this词根并不在原始数据"trying out Elasticsearch"中,又要求必须匹配的词根个数为3,故本次查询,无法命中。minimum_should_match 可选值如下:

Type Example Description
Integer 3 直接数字,不考虑查询字符串分词后的个数。如果分词的个数小于3个,则无法匹配到任何条目。
Negative integer -2 负数表示最多不允许不匹配的个数。也就是需要匹配的个数为(total-2)。
Negative percentage -25% 百分比,表示需要匹配的词根占总数的百分比。
Percentage 75% 允许不匹配的个数占总数的百分比。
Combination 3<90% 如果查询字符串分词的个数小于等于3(前面的整数),则只要全部匹配则返回,如果分词的个数大于3个,则只要90%的匹配即可。
Multiple combinations 2<-25% 9<-3 支持多条件表达式,中间用空格分开。该表达式的意义如下:1、如果分词的个数小于等于2,则必须全部匹配;如果大于2小于9,则除了25%(注意负号)之外都需要满足。2、如果大于9个,则只允许其中3个不满足。
  • analyzer
    设置分词器,默认使用字段映射中定义的分词器或elasticsearch默认的分词器。
  • lenient
    是否忽略由于数据类型不匹配引起的异常,默认为false。例如尝试用文本查询字符串查询数值字段,默认会抛出错误。
  • fuzziness
    模糊匹配。
  • zero_terms_query
    默认情况下,如果分词器会过滤查询字句中的停用词,可能会造成查询字符串分词后变成空字符串,此时默认的行为是无法匹配到任何文档,如果想改变该默认情况,可以设置zero_terms_query=all,类似于match_all,默认值为none。
  • cutoff_frequency
    match查询支持cutoff_frequency,允许指定绝对或相对的文档频率:
    • OR:高频单词被放入“或许有”的类别,仅在至少有一个低频(低于cutoff_frequency)单词满足条
      件时才积分;
    • AND:高频单词被放入“或许有”的类别,仅在所有低频(低于cutoff_frequency)单词满足条件时才积分。该查询允许在运行时动态处理停用词而不需要使用停用词文件。它阻止了对高频短语(停用词)的评分/迭代,并且只在更重要/更低频率的短语与文档匹配时才会考虑这些文档。然而,如果所有查询条件都高于给定的cutoff_frequency,则查询将自动转换为纯连接(and)查询,以确保快速执行。
      cutoff_frequency取值是相对于文档的总数的小数[0..1),也可以是绝对值[1, +∞)。
  • Synonyms(同义词)
    可在分词器中定义同义词,具体同义词将在后续章节中会单独介绍。

1.3 match query示例

public static void testMatchQuery() {
        RestHighLevelClient client = EsClient.getClient();
        try {
            SearchRequest searchRequest = new SearchRequest();
            searchRequest.indices("twitter");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(
                    QueryBuilders.matchQuery("message", "is out Elasticsearch")
                        .zeroTermsQuery(ZeroTermsQuery.ALL)
                        .operator(Operator.OR)
                        .minimumShouldMatch("4<90%")
                    ).sort(new FieldSortBuilder("post_date").order(SortOrder.DESC))
                     .docValueField("post_date", "epoch_millis");
            searchRequest.source(sourceBuilder);
            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
            System.out.println(result);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            EsClient.close(client);
        }
    }

2、match_phrase query

与match query类似,但只是用来精确匹配的短语。
其主要工作流程:首先,Elasearch(lucene)会使用分词器对全文本进行分词(返回一个一个的词根(顺序排列)),然后同样使用分词器对查询字符串进行分析,返回一个一个的词根(顺序性)。如果能在全字段中能够精确找到与查询字符串通用的词根序列,则认为匹配,否则认为不匹配。

举例如下:
如果原文字段message:"quick brown fox test we will like to you",则使用标准分词器(analyzer=standard)返回的结果如下:

curl -X GET "192.168.1.10:9200/_analyze" -H 'Content-Type: application/json' -d'
{
  "tokenizer" : "standard",
  "text" : "quick brown fox test we will like to you",
  "attributes" : ["keyword"] 
}'

得出如下结果:

{
    "tokens":[
        {
            "token":"quick",
            "start_offset":0,
            "end_offset":5,
            "type":"<ALPHANUM>",
            "position":0
        },
        {
            "token":"brown",
            "start_offset":6,
            "end_offset":11,
            "type":"<ALPHANUM>",
            "position":1
        },
        {
            "token":"fox",
            "start_offset":12,
            "end_offset":15,
            "type":"<ALPHANUM>",
            "position":2
        },
        {
            "token":"test",
            "start_offset":16,
            "end_offset":20,
            "type":"<ALPHANUM>",
            "position":3
        },
        {
            "token":"we",
            "start_offset":21,
            "end_offset":23,
            "type":"<ALPHANUM>",
            "position":4
        },
        {
            "token":"will",
            "start_offset":24,
            "end_offset":28,
            "type":"<ALPHANUM>",
            "position":5
        },
        {
            "token":"like",
            "start_offset":29,
            "end_offset":33,
            "type":"<ALPHANUM>",
            "position":6
        },
        {
            "token":"to",
            "start_offset":34,
            "end_offset":36,
            "type":"<ALPHANUM>",
            "position":7
        },
        {
            "token":"you",
            "start_offset":37,
            "end_offset":40,
            "type":"<ALPHANUM>",
            "position":8
        }
    ]
}

其词根具有顺序性(词根序列)为quick、brown、fox、test 、we 、will、 like、 to 、you,

如果查询字符串为 quick brown,分词后的词根序列为 quick brown,则是原词根序列的子集,则匹配。

如果查询字符串为 quick fox,分词后的词根序列为 quick fox,与原词根序列不匹配。如果指定slop属性,设置为1,则匹配,其表示每一个词根直接跳过一个词根形成新的序列,与搜索词根进行比较,是否匹配。

如果查询字符串为quick fox test,其特点是quick与原序列跳过一个词brown,但fox后面不跳过任何次,与test紧挨着,如果指定slop=1,同样能匹配到文档,但查询字符串quick fox test will,却匹配不到文档,说明slop表示整个搜索词根中为了匹配流,能跳过的最大次数。

按照match_phrase的定义,与match query的区别一个在与精确匹配,一个在于词组term(理解为词根序列),故match_phrase与match相比,不会有如下参数:fuzziness、cutoff_frequency、operator、minimum_should_match 这些参数。

3、match phrase prefix query

与match phrase基本相同,只是该查询模式会对最后一个词根进行前缀匹配。

GET /_search
{
    "query": {
        "match_phrase_prefix" : {
            "message" : {
                "query" : "quick brown f",
                "max_expansions" : 10
            }
        }
    }
}

其工作流程如下:首先先对除最后一个词进行分词,得到词根序列 quick brown,然后遍历整个elasticsearch倒排索引,查找以f开头的词根,依次组成多个词根流,例如(quick brown fox) (quick brown foot),默认查找50组,受参数max_expansions控制,在使用时请设置合理的max_expansions,该值越大,查询速度将会变的更慢。该技术主要完成及时搜索,指用户在输入过程中,就根据前缀返回查询结果,随着用户输入的字符越多,查询的结果越接近用户的需求。

4、multi match query

multi_match查询建立在match查询之上,允许多字段查询。

GET /_search
{
  "query": {
    "multi_match" : {
      "query":    "this is a test", 
      "fields": [ "subject", "message" ]   // @1
    }
  }
}

@1执行作用(查询)的字段,有如下几种用法:

  1. [ "subject", "message" ] ,表示针对查询自动对subject,message字段进行查询匹配。
  2. [ "title", "*_name" ],支持通配符,表示对title,以_name结尾的字段进行查询匹配。
  3. [ "subject^3", "message" ],表示subject字段是message的重要性的3倍,类似于字段权重。

4.1 multi_query重要参数详解

4.1.1 type 属性

指定multi_query内部的执行方式,取值如下:best_fields、most_fields、cross_fields、phrase、phrase_prefix。

4.1.1.1 best_fields

type默认值,只要其中一个字段匹配则匹配文档(match query)。但是使用最佳匹配的字段的score来表示文档的分数,会影响文档的排序。

例如有如下两个文档,id,title,context字段值分别如下:
doc1 : 1 "Quick brown rabbits" "Brown rabbits are commonly seen brown."
doc2:2 "Keeping pets healthy", "My quick brown as fox eats rabbits on a regular basis."

如果查询字段“brown fox”字符串,两个文档的匹配度谁高呢?初步分析如下:查询字符串"brown fox"会被分词为brown、fox两个词根,首先brown在doc1的title、context中都能匹配brown,而且次数为3次,在doc2中,只有在context字段中匹配到brown fox各一次,那哪个相关度(评分score)。

best_fields类型,认为在同一个字段能匹配到更多的查询字符串词根,则认为该字段更佳。由于doc2的context字段能匹配到两个查询词根,故doc2的匹配度更高,doc2会优先返回,对应测试代码:

    public static void testMultiQueue_best_fields() {
        RestHighLevelClient client = EsClient.getClient();
        try {
            SearchRequest searchRequest = new SearchRequest();
            searchRequest.indices("esdemo");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(
                    QueryBuilders.multiMatchQuery("brown fox", "title","context")
                        .type(Type.BEST_FIELDS)
                    );
            searchRequest.source(sourceBuilder);
            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
            System.out.println(result);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            EsClient.close(client);
        }
    }

执行的查询结果如下:

{
    "took":4,
    "timed_out":false,
    "_shards":{
        "total":5,
        "successful":5,
        "skipped":0,
        "failed":0
    },
    "hits":{
        "total":2,
        "max_score":0.5753642,
        "hits":[
            {
                "_index":"esdemo",
                "_type":"matchquerydemo",
                "_id":"2",
                "_score":0.5753642,
                "_source":{
                    "context":"My quick brown as fox eats rabbits on a regular basis.",
                    "title":"Keeping pets healthy"
                }
            },
            {
                "_index":"esdemo",
                "_type":"matchquerydemo",
                "_id":"1",
                "_score":0.2876821,
                "_source":{
                    "context":"Brown rabbits are commonly seen.",
                    "title":"Quick brown rabbits"
                }
            }
        ]
    }
}

best_fields类型内部会转换为(dis_max):

GET /_search
        {
            "query": {
                    "dis_max": {
                        "queries": [
                            { "match": { "subject": "brown fox" }},
                            { "match": { "message": "brown fox" }}
                        ],
                        "tie_breaker": 0.3
                    }
            }
        }

通常best_fields类型使用单个最佳匹配字段的分数,但如果指定了tie_breaker,则其计算结果如下:最佳匹配字段的分数加上 tie_breaker * _score(其他匹配字段分数)。该查询模式支持match query相关的参数,例如analyzer, boost, operator, minimum_should_match, fuzziness, lenient, prefix_length, max_expansions, rewrite, zero_terms_query, cutoff_frequency, auto_generate_synonyms_phrase_query 、fuzzy_transpositions等参数。

best_fields和大多数字段类型都是以字段为中心的——它们为每个字段生成匹配查询。这意味着运算符和minimum_should_match参数将分别应用于每个字段。

4.1.1.2 most_fields

查找匹配任何字段并结合每个字段的_score的文档,Elasticsearch会为每个字段生成一个match查询,然后将它们包含在一个bool查询中。其算法的核心是各个字段的评分相加作为文档的最终得分参与排序。其建议场景是不同字段对同一关键字的存储维度不一样,例如字段一可能包含同义词、词干、变音符等;字段二可能包含原始词根,这种情况下综合各个字段的评分就会显的更加具有相关性。
该查询模式支持match query相关的参数,例如analyzer, boost, operator, minimum_should_match, fuzziness, lenient, prefix_length, max_expansions, rewrite, zero_terms_query, cutoff_frequency, auto_generate_synonyms_phrase_query 、fuzzy_transpositions等参数。

4.1.1.3 phrase、phrase_prefix

这两种类型score的计算采用best_fields方法,但是其查询方式分别为match_phrase、match_phrase_prefix。

4.1.1.4 cross_fields

交叉字段,对于需要匹配多个字段的结构化文档,cross_fields类型特别有用。例如,在查询“Will Smith”的first_name和last_name字段时,在一个字段中可能会有“Will”,而在另一个字段中可能会有“Smith”。这听起来很象most_fields,cross_fields与most_fields的两个明显区别如下:

对于opreator、minimum_should_match的作用域不一样,most_fields是针对字段的,(遍历每个字段,然后遍历查询词根列表,进行逐一匹配),而cross_fields是针对词根的,即遍历词根列表,搜索范围是所有字段。

相关性的考量不相同,cross_fields重在这个交叉匹配,对于一组查询词根,一部分出现在其中一个字段,另外一部分出现在另外一个字段中,其相关性计算评分将更高。
举例说明:例如有如下查询语句:

{
        "query": {
                "multi_match" : {
                    "query":      "Will Smith",
                    "type":       "cross_fields",
                    "fields":     [ "first_name", "last_name" ],
                    "operator":   "and"
                }
        }
    }

其执行操作时,首先对查询字符串分析得出will、smith两个词根,然后遍历这两个词根,一次对 first_name,last_name 进行匹配,也就是说 opreator、minimum_should_match 这些参数作用2次,而 most_fields 方式,是一个嵌套循环,先遍历字段,然后对每一个词根在该字段上进行匹配,在该示例中,opreator、minimum_should_match 这些参数作用4次。

4.1.2 tie_breaker属性

默认情况下,每个词汇混合查询将使用组中任何字段返回的最佳分数,然后将这些分数相加,以给出最终分数。tie_breaker参数可以改变每项混合查询的默认行为。tie_breaker可选值如下:

  • 0.0 : 默认行为,使用最佳字段的score。
  • 1.0 :所有匹配字段socre的和。
  • 0.0 ~ 1.0 : 使用最佳匹配字段的score + (其他匹配字段score) * tie_breaker。

4.1.3 multi_query支持其他match query参数

其他诸如analyzer, boost, operator, minimum_should_match, fuzziness, lenient, prefix_length, max_expansions, rewrite, zero_terms_query, cutoff_frequency, auto_generate_synonyms_phrase_query 、fuzzy_transpositions等参数,multi_query同样支持。

5、common terms query

定位:排除停用词或高频词对文档的匹配影响。提高文档匹配的精确度,同时不对性能产生影响。

我们来看一个停用词(高频词)对文档过滤帅选带来的影响:

查询字符串中的每个词根都有搜索成本。搜索“the brown fox”需要三个词根查询,分别为“The”、“brown”和“fox”,所有这些查询都是针对索引中的所有文档执行的。

对于“The”的查询可能匹配许多文档,因此对相关性的影响要比其他两个术语小得多。
一种解决这个问题的方法是忽略高频项。通过将“the”视为stopword(停用词),我们可以减少索引大小并减少需要执行的词汇查询的数量。这种方法的问题在于,尽管停止语对相关性的影响很小,但它们仍然很重要。

如果我们去掉stopwords,我们就会失去精确性(比如我们无法区分“快乐”和“不快乐”),我们就会失去回忆(比如像“The The The”或“to be or not to be”这样的文本就不会存在于索引中)。

本文将介绍另外一种方式来解决上述问题:
common terms query 将查询词根分为两组:更重要的(即低频词根)和不那么重要的(即高频词根,以前应该是停止词)。

首先,它搜索与更重要的词根(低频词)匹配的文档。这些术语出现在较少的文档中,对相关性的影响更大,性能更好。

然后,它对不太重要的词根(高频词)执行第二个查询。但是它并不会计算所有匹配(匹配高频词的所有文档)文档的相关得分,而是只计算第一个查询已经匹配的文档的_score。通过这种方式,高频项可以在不付出性能差的代价的情况下改进关联计算(低频词、高频次相互关联)。

如果查询只包含高频术语,那么一个查询将作为AND(连接)查询执行,换句话说,所有的词根都必须满足。尽管每个单独的词根将匹配许多文档,但术语组合将结果集缩小到最相关的部分,当然单个查询也可以作为或以特定的minimum_should_match执行。
词根根据cutoff_frequency被分配给高频或低频组,可以指定为绝对频率(>=1)或相对频率(0.0)。1.0)。

5.1 示例详解

5.1.1 简单使用说明

GET /_search
{
    "query": {
        "common": {
            "body": {
                "query": "this is bonsai cool",
                "cutoff_frequency": 0.001
            }
        }
    }
}

会对查询词根 this、is、bonsai、cool4个词根分词,词根频率小于0.001的bonsail、cool会被当成低频次,而this、is会被设置为高频词组。由于common term query将词根分成了低频组与高频组,故针对match query的operator、minimum_should_match分别由如下四个参数代替:low_freq_operator、high_freq_operator、minimum_should_match:{low_freq、hign_freq}。

java rest api使用示例如下:

public static void testCommonQuery() {
        RestHighLevelClient client = EsClient.getClient();
        try {
            SearchRequest searchRequest = new SearchRequest();
            searchRequest.indices("esdemo");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(
                    QueryBuilders.commonTermsQuery("context", "this is brown fox")
                        .cutoffFrequency(0.001f)
                        .highFreqOperator(Operator.OR)
                        .highFreqMinimumShouldMatch("3")
                        .lowFreqOperator(Operator.OR)
                        .lowFreqMinimumShouldMatch("2")
                    );
            searchRequest.source(sourceBuilder);
            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
            System.out.println(result);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            EsClient.close(client);
        }
    }

6、query_string query

查询字符串方式。query_string查询解析器支持对查询字符串按照操作符进行切割,每个部分独立分析,例如:

GET /_search
{
    "query": {
        "query_string" : {
            "default_field" : "content",
            "query" : "(new york city) OR (big apple)"
        }
    }
}

query_string的顶层参数如下:

参数名 描述
query 查询字符串。
default_field 默认匹配字段,如果未设置,则为"*",表示所有的字段,也可通过index.query.default_field来统一配置默认字段。
default_operator 设置默认操作类型,可选值:Operator.OR 和 Operator.AND,默认为Operator.OR。
analyzer 设置分词器。
quote_analyzer 用于分析查询字符串中引用的短语的分析器的名称。对于这些部分,它覆盖了使用analyzer参数或search_quote_analyzer设置设置的其他分析器。
allow_leading_wildcard 是否允许第一个字符为通配符(*或?),默认为允许。
enable_position_increments 是否允许以在结果查询中启用位置增量。默认值为true。
fuzzy_max_expansions 控制模糊匹配的词根的扩展个数,在match phrase prefix的max_expansions已详解,默认为50。
fuzziness 设置为模糊匹配。
fuzzy_prefix_length 模糊查询设置前缀长度。默认值为0。
fuzzy_transpositions 是否开启模糊互换(ab -> ba)。默认为true。
phrase_slop match_phrase查询的slop。
boost 设置查询的boost值。默认为1.0。
auto_generate_phrase_queries 是否自动生成短语查询(match_phrase),默认为false。
analyze_wildcard 默认情况下,查询字符串中的通配符项不会被分析。通过将该值设置为true,还将尽力分析这些值。
max_determinized_states 设置可以创建自动状态机(正则表达式),默认为 10000。
minimum_should_match 具体参考match_query的minimum_should_match。
lenient 是否忽略由于数据类型不匹配引起的异常,默认为false
time_zone 时区应用于与日期相关的任何范围查询。参见JODA时区。
auto_generate_synonyms_phrase_query 在使用match_phrase_query查询时开启同义词匹配,默认为true.
all_fields 6.4.0版本后已废弃,使用default_field。

6.1 多字段支持(multi field)

query_string支持多字段查询,可通过fields属性指定,例如:

GET /_search
{
    "query": {
        "query_string" : {
            "fields" : ["content", "name"],
            "query" : "this AND that"
        }
    }
}

其含义类似于:"query": "(content:this OR name:this) AND (content:that OR name:that)"。

同时query_string(查询字符串)模式同样支持match_query等查询对应的参数,其工作机制一样,示例如下:

GET /_search
{
    "query": {
        "query_string" : {
            "fields" : ["content", "name^5"],
//          "fields" : ["city.*"],
            "query" : "this AND that OR thus",
            "tie_breaker" : 0,
             "type": "best_fields",
  "auto_generate_synonyms_phrase_query" : false    (同义词synonym机制)
        }
    }
}

6.2 支持通配符

查询字符串中支持使用通配符?与,其中?表示的单个字符,而表示0个或多个字符。查询字符串使用通配符,可能会消耗更多的内存,查询性能较低下。为了提高通配符效率,如果只是一个的话,命令就会被重写为存在查询(是否存在文档),例如fields:[""]。在关系型数据库中前置通配符(" ab"),这种查询是不支持索引查询的,在es中同样如此,需要遍历索引中所有词根,可以通过allow_leading_wildcard=false来禁用这种查询。通过将analyze_wildcard设置为true,将分析以结尾的查询,并从不同的令牌构建布尔查询,方法是确保第一个N-1令牌上的精确匹配,以及最后一个令牌上的前缀匹配。

6.3 支持正则表达式

正则表达式可以嵌入到查询字符串中,方法是将它们包装成斜杠("/")。注意allow_leading_wildcard无法控制正则表达式的行为。

6.4 邻近查询(可前可后)

虽然短语查询match_phrase(如“john smith”)要求所有的术语都按照完全相同的顺序进行查询,但是接近查询允许指定的单词进一步分开或以不同的顺序进行查询,并且也提供诸如match_query的slop属性。例如:"fox quick"~5。

6.5 范围查询

可以为日期、数字或字符串字段指定范围查询。包含范围用方括号[min到max]指定,排他范围用花括号{min到max}指定。例如如下:

  • 日期在2012年之内。
    date:[2012-01-01 TO 2012-12-31]
  • 大于等1,小于等5
    count:[1 TO 5]
  • Tags在 alpha 和omega之间,但不包括alpha和omega
    tag:{alpha TO omega}
  • 大于等于10
    count:[10 TO *]
  • 日期小于2012年
    date:{* TO 2012-01-01}

6.6 搜索字符串权重提升

使用提高运算符可以设置一个词根相比其他词根更加重要(相关性更高)。例如针对查询字符串"quick2 fox",表明quick这个词根的重要性比fox重要2倍。该操作符也可以针对短语或组,一个组用()表示,示例如下:"john smith"^2 (foo bar)^4。

6.7 boolean运算

默认情况下,所有词根都是可选的,只要一个词根匹配即可(Opreator.OR),从上面得知通过修改default_operator可以改变其默认行为。ES还支持对查询字符串进行boolean运算。例如查询字符串“quick brown +fox -news”表示的含义是:

  1. fox词根必须存在。
  2. news词根必须不存在。
  3. quick brown 可选。
    也支持常见的布尔运算符AND, OR和NOT(也写为&&,||和!),但要注意,它们不遵守通常的优先规则,因此当多个运算符一起使用时,应该使用括号。例如,前面的查询可以改写为:((quick AND fox) OR (brown AND fox) OR fox) AND NOT news。

6.8 分组(grouping)

多个词根或子句可以用括号组合在一起,形成子查询,例如(quick OR brown) AND fox。

6.9 转义字符

在ES中,如下字符需要使用转义符合\,保留字符是:+ - = && || > < !(){ }[]”^ ~ * ?:\ /。

6.10 空查询

如果查询字符串为空或仅包含空白,则查询将生成空结果集。

6.11 query_string示例

public static void testQueryStringQuery_Query() {
        RestHighLevelClient client = EsClient.getClient();
        try {
            SearchRequest searchRequest = new SearchRequest();
            searchRequest.indices("esdemo");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(
//                  QueryBuilders.queryStringQuery("brown -fox")
//                  QueryBuilders.queryStringQuery("brown^8 fox^2")
                    QueryBuilders.queryStringQuery("(quick OR brown) AND fox")
                        .allowLeadingWildcard(false)
                        .field("context")
                        .field("title")
//                      .minimumShouldMatch("1")
                    );
            searchRequest.source(sourceBuilder);
            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
            System.out.println(result);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            EsClient.close(client);
        }
    }

测试情况如下:
目前范围查询暂不知如何编写查询字符串,但ES专门通过QueryBuilders.rangeQuery(String name)返回RangeQueryBuilder,邻近查询未能编写Demo。

7、simple_query_string query

简单字符串查询模式。使用SimpleQueryParser解析上下文的查询。与常规的query_string查询不同,simple_query_string查询永远不会抛出异常,并丢弃查询的无效部分。下面是一个例子:

GET /_search
{
  "query": {
    "simple_query_string" : {
        "query": "\"fried eggs\" +(eggplant | potato) -frittata",
        "fields": ["title^5", "body"],
        "default_operator": "and"
    }
  }
}

查询字符串的写法非常符合(query_string)中定义的,例如查询字符串中支持boolean运算等。simple_query_string中的顶级参数都定义在org.elasticsearch.index.query.SimpleQueryStringBuilder中,其含义与query_string中类似,在这里就不重复介绍了。
simple_query_string支持如下写法。

  • +signifies 表示必须包含。
  • | signifies 相当于OR。
  • negates 相当于非
  • " 包装一些标记以表示搜索的短语
    • 例如a*,表示前缀匹配
  • ( and ) 括号可表示优先级
  • ~N after a word 表示模糊匹配举例,类似于match_phrase slop。
  • ~N after a phrase(短语),表示溢出量。

上述这些写法与在query_string机制一样。接下来主要再讲述query_string不同点。

7.1 flags

simple_query_string支持多个标记来指定应该启用哪些解析特性。它被指定为一个|分隔的字符串,例如:

GET /_search
{
    "query": {
        "simple_query_string" : {
            "query" : "foo | bar + baz*",
            "flags" : "OR|AND|PREFIX"
        }
    }
}

可用的flag的列表如下:ALL, NONE, AND, OR, NOT, PREFIX, PHRASE, PRECEDENCE, ESCAPE, WHITESPACE, FUZZY, NEAR, and SLOP。

7.2 使用示例

public static void testSimpleQueryString_Query() {
        RestHighLevelClient client = EsClient.getClient();
        try {
            SearchRequest searchRequest = new SearchRequest();
            searchRequest.indices("esdemo");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(
                    QueryBuilders.simpleQueryStringQuery("brown -fox")
                    );
            searchRequest.source(sourceBuilder);
            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
            System.out.println(result);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            EsClient.close(client);
        }
    }

关于es 的全文检索就介绍到这里了。


更多文章建议关注我的个人公众号:


中间件兴趣圈
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容