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

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Elasticsearch Query DSL之全文检索(Full text queries)下篇

本文将继续介绍Elasticsearch Query DSL之全文检索(Full text queries)方式的后3种。


  • common terms query
  • query_string query
  • simple_query_string 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)"
        }
    }
}

qquery_string的顶层参数如下:uery_string的顶层参数如下:


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时区
  • quote_field_suffix
  • 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 搜索字符串权重提升


使用提高运算符^可以设置一个词根相比其他词根更加重要(相关性更高)。例如针对查询字符串"quick^2 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);
        }
    }

全文索引查询就介绍到这里了,下节开始将介绍Elasticsearch DSL term query(词根匹配)。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
11天前
|
存储 人工智能 API
(Elasticsearch)使用阿里云 infererence API 及 semantic text 进行向量搜索
本文展示了如何使用阿里云 infererence API 及 semantic text 进行向量搜索。
|
3月前
|
JSON 自然语言处理 算法
ElasticSearch基础2——DSL查询文档,黑马旅游项目查询功能
DSL查询文档、RestClient查询文档、全文检索查询、精准查询、复合查询、地理坐标查询、分页、排序、高亮、黑马旅游案例
|
4月前
|
JSON 自然语言处理 Java
ElasticSearch 实现分词全文检索 - 搜素关键字自动补全(Completion Suggest)
ElasticSearch 实现分词全文检索 - 搜素关键字自动补全(Completion Suggest)
130 1
|
4月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
161 1
|
4月前
|
自然语言处理 Java 索引
ElasticSearch 实现分词全文检索 - delete-by-query
ElasticSearch 实现分词全文检索 - delete-by-query
45 1
|
4月前
|
自然语言处理 索引
ElasticSearch 实现分词全文检索 - 测试数据准备
ElasticSearch 实现分词全文检索 - 测试数据准备
60 1
|
4月前
|
自然语言处理 索引
ElasticSearch 实现分词全文检索 - Restful基本操作
ElasticSearch 实现分词全文检索 - Restful基本操作
40 0
ElasticSearch 实现分词全文检索 - Restful基本操作
|
4月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - SpringBoot 完整实现 Demo 附源码【完结篇】
ElasticSearch 实现分词全文检索 - SpringBoot 完整实现 Demo 附源码【完结篇】
74 0
|
4月前
|
存储 自然语言处理 Java
ElasticSearch 实现分词全文检索 - 经纬度定位商家距离查询
ElasticSearch 实现分词全文检索 - 经纬度定位商家距离查询
69 0
|
4月前
|
自然语言处理 Java
ElasticSearch 实现分词全文检索 - 高亮查询
ElasticSearch 实现分词全文检索 - 高亮查询
78 0