Elasticsearch(四)elasticsearch复杂检索
来源:互联网 发布:程序员未来的发展方向 编辑:程序博客网 时间:2024/06/05 09:44
Query-string 搜索通过命令非常方便地进行临时性的即席搜索 ,但它有自身的局限性(参见 轻量 搜索 )。Elasticsearch 提供一个丰富灵活的查询语言叫做 查询表达式 , 它支持构建更加复杂和健壮的查询。
领域特定语言 (DSL), 指定了使用一个 JSON 请求。我们可以像这样重写之前的查询所有 Smith 的搜索 :
GET /megacorp/employee/_search
{
“query” : {
“match” : {
“last_name” : “Smith”
}
}
}
View in Sense
返回结果与之前的查询一样,但还是可以看到有一些变化。其中之一是,不再使用 query-string 参数,而是一个请求体替代。这个请求使用 JSON 构造,并使用了一个 match 查询(属于查询类型之一,后续将会了解)。
更复杂的搜索
现在尝试下更复杂的搜索。 同样搜索姓氏为 Smith 的雇员,但这次我们只需要年龄大于 30 的。查询需要稍作调整,使用过滤器 filter ,它支持高效地执行一个结构化查询。
GET /megacorp/employee/_search{ "query" : { "bool": { "must": { "match" : { "last_name" : "smith" } }, "filter": { "range" : { "age" : { "gt" : 30 } } } } }}
这部分与我们之前使用的 match 查询 一样。
这部分是一个 range 过滤器 , 它能找到年龄大于 30 的文档,其中 gt 表示_大于(_great than)。
目前无需太多担心语法问题,后续会更详细地介绍。只需明确我们添加了一个 过滤器 用于执行一个范围查询,并复用之前的 match 查询。现在结果只返回了一个雇员,叫 Jane Smith,32 岁。
{ ... "hits": { "total": 1, "max_score": 0.30685282, "hits": [ { ... "_source": { "first_name": "Jane", "last_name": "Smith", "age": 32, "about": "I like to collect rock albums", "interests": [ "music" ] } } ] }}
bool简单介绍
首先,简单介绍下bool,它是一种复合查询方式,
(参考:https://www.elastic.co/guide/en/elasticsearch/reference/6.0/query-dsl-bool-query.html)
与匹配其他查询的布尔组合的文档相匹配的查询。bool查询映射到Lucene BooleanQuery。它是使用一个或多个布尔子句构建的,每个子句都有一个类型化的事件。发生的类型是:
发生 描述
must 该条款(查询)必须出现在匹配的文件,并将有助于得分。
filter 子句(查询)必须出现在匹配的文档中。然而不像 must查询的分数将被忽略。Filter子句在过滤器上下文中执行,这意味着评分被忽略,子句被考虑用于高速缓存。
should 子句(查询)应该出现在匹配的文档中。如果 bool查询位于查询上下文中并且具有mustorfilter子句,那么bool即使没有 should查询匹配,文档也将匹配查询。在这种情况下,这些条款仅用于影响分数。如果bool查询是过滤器上下文 或者两者都不存在,must或者filter至少有一个should查询必须与文档相匹配才能与bool查询匹配。这种行为可以通过设置minimum_should_match参数来显式控制 。
must_not 子句(查询)不能出现在匹配的文档中。子句在过滤器上下文中执行,意味着评分被忽略,子句被考虑用于高速缓存。因为计分被忽略,0所有文件的分数被返回。
即,must:必须匹配,filter:匹配的结果过滤,should:至少有一个 must_not:不能匹配
Client程序演示bool查询
term
增加一个方法:
/* * 简单运用一个bool查询,查询姓Smith且年龄大于的员工 * 查询姓Smith的员工 * 过滤为大于30岁的 */ private static void findEmployeeByAgeAndName(Client client) { SearchRequestBuilder request = client.prepareSearch("megacorp1") .setTypes("employee1") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.boolQuery().must(termQuery("last_name","Smith")).filter(rangeQuery("age").gt(30)));// SearchResponse response = request.get(); printResponseHits(request.get()); }
封装查看结果方法:
//查看结果 private static void printResponseHits(SearchResponse response) { SearchHits searchHits = response.getHits(); Iterator<SearchHit> iterator = searchHits.iterator(); while(iterator.hasNext()) { SearchHit hit = iterator.next(); String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); System.out.println("index="+index+" type="+type+" id="+id+" score="+score+" source-->"+hit.getSourceAsString()); } }
Main方法中增加调用
// 5.查询姓smith的雇员,过滤过滤器查询示例 bool查询findEmployeeByAgeAndName(client);
结果显示:
index=megacorp1 type=employee1 id=2 score=1.2809339 source–>{“first_name”:”Jane”,”last_name”:”Smith”,”age”:”32”,”about”:”I like to collect rock albums”,”interests”:[“music”]}
有兴趣的可以自己debug到request查看bool的请求
Head插件示例
match
我们可以现在用match来写下:
将刚才的例子改为如下
SearchRequestBuilder request = client.prepareSearch("megacorp1") .setTypes("employee1") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.boolQuery().must(matchQuery("last_name","Smith")).filter(rangeQuery("age").gt(30)));// SearchResponse response = request.get(); printResponseHits(request.get());
再次调用此方法返回结果为:
index=megacorp1 type=employee1 id=2 score=1.3862944 source–>{“first_name”:”Jane”,”last_name”:”Smith”,”age”:”32”,”about”:”I like to collect rock albums”,”interests”:[“music”]}
head插件示例
我们的结果没有区别,因为这里我们的索引不会进行分词解析。
我们去可以之前可以分词解析的索引megacorp中实验以下:
term:rock climbing
Match:rock climbing
可以看出档案的结果根据相关性评分排序。整个都匹配的在第一个,匹配其中一个的在后面。
Elasticsearch 默认按照相关性得分排序,即每个文档跟查询的匹配程度。第一个最高得分的结果很明显:John Smith 的 about 属性清楚地写着 “rock climbing” 。
但为什么 Jane Smith 也作为结果返回了呢?原因是她的 about 属性里提到了 “rock” 。因为只有 “rock” 而没有 “climbing” ,所以她的相关性得分低于 John 的。
这是一个很好的案例,阐明了 Elasticsearch 如何 在 全文属性上搜索并返回相关性最强的结果。Elasticsearch中的 相关性 概念非常重要,也是完全区别于传统关系型数据库的一个概念,数据库中的一条记录要么匹配要么不匹配。
至于之前的last_name为何查不出,还是一个疑问。
尝试将lastname增加这个没有下划线的字段,term依旧没有查出来。
尝试将内容改为Smith Smith中间空格形式也查不出来term
欢迎解惑。
短语搜索
找出一个属性中的独立单词是没有问题的,但有时候想要精确匹配一系列单词或者短语 。 比如, 我们想执行这样一个查询,仅匹配同时包含 “rock” 和 “climbing” ,并且 二者以短语 “rock climbing” 的形式紧挨着的雇员记录。
为此对 match 查询稍作调整,使用一个叫做 match_phrase 的查询:
GET /megacorp/employee/_search{ "query" : { "match_phrase" : { "about" : "rock climbing" } }}
毫无悬念,返回结果仅有 John Smith 的文档。
{ ... "hits": { "total": 1, "max_score": 0.23013961, "hits": [ { ... "_score": 0.23013961, "_source": { "first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ] } } ] }}
Client程序演示
增加一个方法
/** * match phrase查询 * 仅匹配同时包含 “rock” 和 “climbing” ,并且 二者以短语 “rock climbing” 的形式紧挨着的雇员记录。 * @param client 客户端 * @param field 字段 * @param phrase 词语 */ private static void findEmployeesWithOneUniqueMatchPhrase(Client client, String field, String phrase) { SearchRequestBuilder request = client.prepareSearch("megacorp") .setTypes("employee") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.boolQuery().must(matchPhraseQuery(field, phrase))); printResponseHits(request.get()); }
Main方法中调用
// 6.match_phrase查询 仅匹配同时包含 “rock” 和 “climbing” ,并且 二者以短语 “rock climbing” 的形式紧挨着的雇员记录。 findEmployeesWithOneUniqueMatchPhrase(client,"about","rock climbing");
我增加了一些数据:
结果显示:
index=megacorp type=employee id=5 score=0.6449836 source–>{“first_name”:”John”,”last_name”:”Smith1”,”age”:25,”about”:”I love to go rock climbing”,”interests”:[“sports”,”music”]}
index=megacorp type=employee id=8 score=0.6449836 source–>{“first_name”:”John”,”last_name”:”蜂蜜柚子”,”age”:25,”about”:”I love to go rock climbing”,”interests”:[“sports”,”music”]}
index=megacorp type=employee id=9 score=0.6449836 source–>{“first_name”:”John”,”last_name”:”蜂蜜”,”age”:25,”about”:”I love to go rock climbing”,”interests”:[“sports”,”music”]}
index=megacorp type=employee id=10 score=0.6449836 source–>{“first_name”:”John”,”last_name”:”Smith Smith”,”age”:25,”about”:”I love to go rock climbing”,”interests”:[“sports”,”music”]}
index=megacorp type=employee id=6 score=0.6449836 source–>{“first_name”:”John”,”last_name”:”Smith 1”,”age”:26,”about”:”I love to go rock climbing”,”interests”:[“sports”,”art”]}
index=megacorp type=employee id=1 score=0.6449836 source–>{“first_name”:”John”,”last_name”:”Smith”,”age”:25,”about”:”I love to go rock climbing”,”interests”:[“sports”,”music”]}
index=megacorp type=employee id=7 score=0.6449836 source–>{“first_name”:”John”,”last_name”:”蜂蜜柚子蜂蜜”,”age”:25,”about”:”I love to go rock climbing”,”interests”:[“sports”,”music”]}
可以看出结果完全符合。
Head插件示例
{“query”:{“match_phrase”:{“about”:”rock climbing”}}}
抱歉图发不出!!!
- Elasticsearch(四)elasticsearch复杂检索
- Elasticsearch(三)elasticsearch轻量检索
- ElasticSearch源码解析(四):检索(Search)
- Elasticsearch学习(四)
- ElasticSearch(四):查询
- ElasticSearch(四)
- Elasticsearch(7)实践三-简单检索
- Elasticsearch:检索篇
- ElasticSearch 分页检索
- elasticsearch--php检索
- Elasticsearch全文检索
- elasticsearch-多文档检索
- ElasticSearch基础知识--检索文档
- 用Elasticsearch做检索
- elasticSearch 全文检索工具
- Elasticsearch检索文档。
- elasticsearch分布式检索
- (四)ElasticSearch索引创建
- Tornado 文档学习:模板与 UI
- PDF转Word时提示有密码两种常用解密技巧分享
- ACM中涉及到的数学知识
- 微信蓝牙硬件设备接入(1)
- hdoj 1002 A + B Problem II(大数加法)
- Elasticsearch(四)elasticsearch复杂检索
- iOS单选和多选的实现
- noip2017 爆炸记GG记
- ajax动态加载页面,对页面的按钮绑定点击事件
- 深搜
- spring中无法读取properties文件中属性的解决方法
- CSS3 透明属性 RGBA 和 opacity
- 修正jdbc调用mysql的时区不一致问题
- PAT:B1011 A+B 和C