顿搜
05. ES全文检索查询——ElasticSearch搜索专栏
不同于结构化查询,全文搜索首先对查询词进行分析,然后根据查询词的分词结果构建查询。
这里所说的全文指的是文本类型数据(text类型),默认的数据形式是人类的自然语言
结构化搜索关注的是数据是否匹配,全文搜索关注的是匹配的程度;
结构化搜索一般用于精确匹配,而全文搜索用于部分匹配。
一、Match查询
match查询是全文搜索的主要代表。
对于最基本的math搜索来说,只要分词中的一个或者多个在文档中存在即可。
例如搜索“金都酒店”,查询词先被分词器切分为“金都”、“酒店”
因此,只要文档中包含这2个词中的任何一个,都会被搜索到。
1.1 DSL方式
GET /hotel/_search
{
"_source": ["title"], //只返回title字段
"query": {
"match": { //匹配title字段为“金都酒店”的文档
"title": "金都酒店"
}
}
}match搜索可以设置operator参数,该参数决定文档按照分词后的词集合进行“与”还是“或”匹配。
在默认情况下,该参数的值为“或”关系,即operator的值为or
下面的请求示例设置查询词之间的匹配结果为“与”关系:
GET /hotel/_search
{
"_source": ["title"],
"query": {
"match": {
"title":{
"query": "金都",
"operator":"and" //查询词之间的匹配结果为“与”关系
}
}
}
}这时可以采用minimum_should_match参数,该参数叫作最小匹配参数,
其值为一个数值,意义为可以匹配上的词的个数。
实际应用中更常用的做法是将其设置为一个百分数,因为我们无法控制用户查询时输入的单词数量
GET /hotel/_search
{
"_source": ["title"],
"query": {
"match": {
"title": { //match搜索条件
"query": "金都",
"operator": "or",
"minimum_should_match": "80%" //设置最小匹配度为80%
}
}
}
}以上语句执行match查询的步骤如下:
(1)检查字段类型。title字段是text类型(内容会被分词),说明此字段在存储时和查询时都会进行分词,而且在存储时会建立倒排索引。
(2)分析查询字符串。将查询的字符串"金都"传入分词器中,输出的结果是单词"金都"。因为只有一个单词,所以match查询执行的是单个底层term查询。
(3)查找匹配的文档。用term查询在倒排索引中查找"金都",然后获取一组包含该单词的文档数据。
(4)为每个文档评分。用term查询计算出每个文档的评分。
- match查询最终其实会转化为term查询
- 使用match查询时,返回结果中文档的评分是和该文档中字段的内容长度有关的,即字段内容越短,评分就越高
1.2 Java 客户端方式
在Java客户端上可以使用QueryBuilders.matchQuery()方法构建match请求,
分别给该方法传入字段名称和查询值即可进行match查询。
public void matchSearch() {
SearchRequest searchRequest = new SearchRequest(); //新建搜索请求
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("title", "金都")
.operator(Operator.AND)); //新建match查询,并设置operator值为and
searchRequest.source(searchSourceBuilder); //设置查询
printResult(searchRequest); //打印结果
}二、multi_match查询
有时用户需要在多个字段中查询关键词,除了使用布尔查询封装多个match查询之外,可替代的方案是使用multi_match。
可以在multi_match的query子句中组织数据匹配规则,并在fields子句中指定需要搜索的字段列表。
2.1 DSL方式
GET /hotel/_search
{
"_source": ["title","amenities"],
"query": {
"multi_match": {
"query": "假日", //匹配关键字为“假日”
"fields": [ //设置匹配的字段为title和amenities
"title",
"amenities"
]
}
}
}他们之间是或的关系
2.2 Java 客户端方式
public void multiMatchSearch() {
SearchRequest searchRequest = new SearchRequest(); //新建搜索请求
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//新建multi_match查询,从"title"和"amenities"字段查询"假日"
searchSourceBuilder.query(QueryBuilders.multiMatchQuery("假日", "title", "amenities"));
searchRequest.source(searchSourceBuilder); //设置查询
printResult(searchRequest); //打印结果
}三、match_phrase查询
match_phrase用于匹配短语,与match查询不同的是,match_phrase用于搜索确切的短语或邻近的词语。
假设在酒店标题中搜索“文雅酒店”,
希望酒店标题中的“文雅”与“酒店”紧邻并且“文雅”在“酒店”前面,则使用match_phrase查询
3.1 DSL方式
GET /hotel/_search
{
"query": {
"match_phrase": {
"title": "文雅酒店"
}
}
}可以设置match_phrase查询的slop参数,它用来调节匹配词之间的距离阈值。
默认slop = 0, 也就是必需紧挨着
GET /hotel/_search
{
"query": {
"match_phrase": {
"title": {
"query": "文雅酒店",
"slop": 2 //将“文雅”和“酒店”之间的最大匹配距离设置为2
}
}
}
}3.2 Java 客户端方式
在Java客户端上可以使用QueryBuilders.matchPhraseQuery()方法构建match_phrase请求,
分别给该方法传入查询字段和值即可进行match_phrase查询。
public void matchPhraseSearch() {
SearchRequest searchRequest = new SearchRequest(); //新建搜索请求
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//新建match_phrase查询,并设置slop值为2
QueryBuilder matchPhraseQueryBuilder=QueryBuilders.matchPhraseQuery("title","文雅酒店").slop(2);
searchSourceBuilder.query(matchPhraseQueryBuilder);
searchRequest.source(searchSourceBuilder); //设置查询
printResult(searchRequest); //打印结果
}四、query_string查询
4.1 DSL方式
GET /dbindex/_search
{
"query": {
"query_string": {
"query": "(dog and) AND (beautiful)",
"default_field": "title"
}
}
}五、simple_query_string查询
simple_query_string查询是一种使用简单的语法来解析要查询的字符串,并将其拆分为基于特殊运算符的查询方式。
其语法比query_string查询更受限制,但simple_query_string查询在遭遇无效语法事不会返回错误提示信息
5.1 DSL方式
GET /dbindex/_search
{
"query": {
"simple_query_string" : {
"query": "\"the dog\" + (flower | and) + beautiful",
"fields": ["title"],
"default_operator": "and"
}
}
}在以上语句中,查询索引库的title字段,必须匹配到beautiful单词,并且必须匹配dog和and其中任何一个单词的字段
六、intervals查询
intervals是时间间隔的意思,在Elasticsearch中它本质上是将多个规则按照顺序匹配。
6.1 DSL方式
GET /dbindex/_search
{
"query": {
"intervals" : {
"title" : {
"all_of" : {
"ordered" : true,
"intervals" : [
{
"match" : {
"query" : "flower", // 文档内容先匹配"flower"单词
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [ // 文档内容再匹配"beautiful"和"dog"两个单词中的其中一个
{ "match" : { "query" : "beautiful" } },
{ "match" : { "query" : "dog" } }
]
}
}
]
}
}
}
}
}七、高亮查询
7.1 DSL方式
GET /dbindex/_doc/_search
{
"query":{
"match": {
"name": "贾诩"
}
},
"highlight":{
"fields": {
"name": {}
}
}
}返回结果
{
"took" : 6,
…
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.5098253,
"hits" : [
{
"_index" : "myindex_highlight",
"_type" : "_doc",
"_id" : "UhAeYXoBiBO67Reoue-V",
"_score" : 1.5098253,
"_source" : {
"name" : "贾诩",
"address" : "魏国",
"age" : 19
},
"highlight" : { //高亮标签
"name" : [
"<em>贾</em><em>诩</em>"
]
}
}
]
}
}八、自定义高亮查询
8.1 DSL方式
GET dbindex/_doc/_search
{
"query":{
"match": {
"name": "贾诩"
}
},
"highlight":{
"pre_tags": "<p class='gaoliang'>", //自定义高亮显示效果的标签
"post_tags": "</p>",
"fields": {
"name": {}
}
}
}