现在我们可以开始探讨ES的核心环节:搜索search了。search又分filter,query两种模式。filter模式即筛选模式:将符合筛选条件的记录作为结果找出来。query模式则分两个步骤:先筛选,然后对每条符合条件记录进行相似度计算。就是多了个评分过程。如果我们首先要实现传统数据库的查询功能的话,那么用filter模式就足够了。filter模式同样可以利用搜索引擎的分词功能产生高质量的查询结果,而且filter是可以进缓存的,执行起来效率更高。这些功能数据库管理系统是无法达到的。ES的filter模式是在bool查询框架下实现的,如下:

GET /_search
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}

下面是一个最简单的示范:

  val filterTerm = search("bank")
.query(
boolQuery().filter(termQuery("city.keyword","Brogan")))

产生的请求json如下:

POST /bank/_search
{
"query":{
"bool":{
"filter":[
{
"term":{"city.keyword":{"value":"Brogan"}}
}
]
}
}
}

先说明一下这个查询请求:这是一个词条查询termQuery,要求条件完全匹配,包括大小写,肯定无法用经过分词器分析过的字段,所以用city.keyword。

返回查询结果json:

{
"took" : ,
"timed_out" : false,
"_shards" : {
"total" : ,
"successful" : ,
"skipped" : ,
"failed" :
},
"hits" : {
"total" : {
"value" : ,
"relation" : "eq"
},
"max_score" : 0.0,
"hits" : [
{
"_index" : "bank",
"_type" : "_doc",
"_id" : "",
"_score" : 0.0,
"_source" : {
"account_number" : ,
"balance" : ,
"firstname" : "Amber",
"lastname" : "Duke",
"age" : ,
"gender" : "M",
"address" : "880 Holmes Lane",
"employer" : "Pyrami",
"email" : "amberduke@pyrami.com",
"city" : "Brogan",
"state" : "IL"
}
}
]
}
}

我们来看看elasitic4s是怎样表达上面json结果的:首先,返回的类型是 Reponse[SearchResponse]。Response类定义如下:

sealed trait Response[+U] {
def status: Int // the http status code of the response
def body: Option[String] // the http response body if the response included one
def headers: Map[String, String] // any http headers included in the response
def result: U // returns the marshalled response U or throws an exception
def error: ElasticError // returns the error or throw an exception
def isError: Boolean // returns true if this is an error response
final def isSuccess: Boolean = !isError // returns true if this is a success def map[V](f: U => V): Response[V]
def flatMap[V](f: U => Response[V]): Response[V] final def fold[V](ifError: => V)(f: U => V): V = if (isError) ifError else f(result)
final def fold[V](onError: RequestFailure => V, onSuccess: U => V): V = this match {
case failure: RequestFailure => onError(failure)
case RequestSuccess(_, _, _, result) => onSuccess(result)
}
final def foreach[V](f: U => V): Unit = if (!isError) f(result) final def toOption: Option[U] = if (isError) None else Some(result)
}

Response[+U]是个高阶类,如果把U替换成SearchResponse, 那么返回的结果值可以用def result: SearchResponse来获取。status代表标准HTTP返回状态,isError,isSuccess代表执行情况,error是确切的异常消息。返回结果的头部信息在headers内。我们再看看这个SearchResponse类的定义:

case class SearchResponse(took: Long,
@JsonProperty("timed_out") isTimedOut: Boolean,
@JsonProperty("terminated_early") isTerminatedEarly: Boolean,
private val suggest: Map[String, Seq[SuggestionResult]],
@JsonProperty("_shards") private val _shards: Shards,
@JsonProperty("_scroll_id") scrollId: Option[String],
@JsonProperty("aggregations") private val _aggregationsAsMap: Map[String, Any],
hits: SearchHits) {...} case class SearchHits(total: Total,
@JsonProperty("max_score") maxScore: Double,
hits: Array[SearchHit]) {
def size: Long = hits.length
def isEmpty: Boolean = hits.isEmpty
def nonEmpty: Boolean = hits.nonEmpty
} case class SearchHit(@JsonProperty("_id") id: String,
@JsonProperty("_index") index: String,
@JsonProperty("_type") `type`: String,
@JsonProperty("_version") version: Long,
@JsonProperty("_seq_no") seqNo: Long,
@JsonProperty("_primary_term") primaryTerm: Long,
@JsonProperty("_score") score: Float,
@JsonProperty("_parent") parent: Option[String],
@JsonProperty("_shard") shard: Option[String],
@JsonProperty("_node") node: Option[String],
@JsonProperty("_routing") routing: Option[String],
@JsonProperty("_explanation") explanation: Option[Explanation],
@JsonProperty("sort") sort: Option[Seq[AnyRef]],
private val _source: Map[String, AnyRef],
fields: Map[String, AnyRef],
@JsonProperty("highlight") private val _highlight: Option[Map[String, Seq[String]]],
private val inner_hits: Map[String, Map[String, Any]],
@JsonProperty("matched_queries") matchedQueries: Option[Set[String]])
extends Hit {...}

返回结果的重要部分如 _score, _source,fields都在SearchHit里。完整的返回结果处理示范如下:

 val filterTerm  = client.execute(search("bank")
.query(
boolQuery().filter(termQuery("city.keyword","Brogan")))).await if (filterTerm.isSuccess) {
if (filterTerm.result.nonEmpty)
filterTerm.result.hits.hits.foreach {hit => println(hit.sourceAsMap)}
} else println(s"Error: ${filterTerm.error.reason}")

传统查询方式中前缀查询用的比较多:

POST /bank/_search
{
"query":{
"bool":{
"filter":[
{
"prefix":{"city.keyword":{"value":"Bro"}}
}
]
}
}
} val filterPrifix = client.execute(search("bank")
.query(
boolQuery().filter(prefixQuery("city.keyword","Bro")))
.sourceInclude("address","city","state")
).await
if (filterPrifix.isSuccess) {
if (filterPrifix.result.nonEmpty)
filterPrifix.result.hits.hits.foreach {hit => println(hit.sourceAsMap)}
} else println(s"Error: ${filterPrifix.error.reason}") .... Map(address -> Holmes Lane, city -> Brogan, state -> IL)
Map(address -> Nostrand Avenue, city -> Brooktrails, state -> GA)
Map(address -> Whitty Lane, city -> Broadlands, state -> VT)
Map(address -> Heath Place, city -> Brookfield, state -> OK)
Map(address -> Bridge Street, city -> Brownlee, state -> HI)
Map(address -> Pierrepont Place, city -> Brownsville, state -> MI)

正则表达式查询也有:

POST /bank/_search
{
"query":{
"bool":{
"filter":[
{
"regexp":{"address.keyword":{"value":".*bridge.*"}}
}
]
}
}
} val filterRegex = client.execute(search("bank")
.query(
boolQuery().filter(regexQuery("address.keyword",".*bridge.*")))
.sourceInclude("address","city","state")
).await
if (filterRegex.isSuccess) {
if (filterRegex.result.nonEmpty)
filterRegex.result.hits.hits.foreach {hit => println(hit.sourceAsMap)}
} else println(s"Error: ${filterRegex.error.reason}") ....
Map(address -> Bainbridge Street, city -> Elizaville, state -> MS)
Map(address -> Cambridge Place, city -> Efland, state -> ID)

当然,ES用bool查询来实现复合式查询,我们可以把一个bool查询放进filter框架,如下:

POST /bank/_search
{
"query":{
"bool":{
"filter":[
{
"regexp":{"address.keyword":{"value":".*bridge.*"}}
},
{
"bool": {
"must": [
{ "match" : {"lastname" : "lane"}}
]
}
}
]
}
}
}

elastic4s QueryDSL 语句和返回结果如下:

  val filterBool  = client.execute(search("bank")
.query(
boolQuery().filter(regexQuery("address.keyword",".*bridge.*"),
boolQuery().must(matchQuery("lastname","lane"))))
.sourceInclude("lastname","address","city","state")
).await
if (filterBool.isSuccess) {
if (filterBool.result.nonEmpty)
filterBool.result.hits.hits.foreach {hit => println(s"score: ${hit.score}, ${hit.sourceAsMap}")}
} else println(s"Error: ${filterBool.error.reason}") ... score: 0.0, Map(address -> Bainbridge Street, city -> Elizaville, state -> MS, lastname -> Lane)

score: 0.0 ,说明filter不会进行评分。可能执行效率会有所提高吧。

search(7)- elastic4s-search-filter模式的更多相关文章

  1. 1.3 正则表达式和Python语言-1.3.5使用 search()在一个字符串中查找模式(搜索与匹配 的对比)

    1.3.5 使用 search()在一个字符串中查找模式(搜索与匹配的对比) 其实,想要搜索的模式出现在一个字符串中间部分的概率,远大于出现在字符串起始部分的概率.这也就是 search()派上用场的 ...

  2. Comparing randomized search and grid search for hyperparameter estimation

    Comparing randomized search and grid search for hyperparameter estimation Compare randomized search ...

  3. 【起航计划 032】2015 起航计划 Android APIDemo的魔鬼步伐 31 App->Search->Invoke Search 搜索功能 Search Dialog SearchView SearchRecentSuggestions

    Search (搜索)是Android平台的一个核心功能之一,用户可以在手机搜索在线的或是本地的信息.Android平台为所有需要提供搜索或是查询功能的应用提 供了一个统一的Search Framew ...

  4. search(8)- elastic4s-search-query模式

    上篇提过query模式除对记录的筛选之外还对符合条件的记录进行了评分,即与条件的相似匹配程度.我们把评分放在后面的博文中讨论,这篇我们只介绍query查询. 查询可以分为绝对值查询和全文查询:绝对值查 ...

  5. [Math] Beating the binary search algorithm – interpolation search, galloping search

    From: http://blog.jobbole.com/73517/ 二分检索是查找有序数组最简单然而最有效的算法之一.现在的问题是,更复杂的算法能不能做的更好?我们先看一下其他方法. 有些情况下 ...

  6. LeetCode:Search Insert Position,Search for a Range (二分查找,lower_bound,upper_bound)

    Search Insert Position Given a sorted array and a target value, return the index if the target is fo ...

  7. leetcode 704. Binary Search 、35. Search Insert Position 、278. First Bad Version

    704. Binary Search 1.使用start+1 < end,这样保证最后剩两个数 2.mid = start + (end - start)/2,这样避免接近max-int导致的溢 ...

  8. Depth-first search and Breadth-first search 深度优先搜索和广度优先搜索

    Depth-first search Depth-first search (DFS) is an algorithm for traversing or searching tree or grap ...

  9. [Algorithm] Beating the Binary Search algorithm – Interpolation Search, Galloping Search

    From: http://blog.jobbole.com/73517/ 二分检索是查找有序数组最简单然而最有效的算法之一.现在的问题是,更复杂的算法能不能做的更好?我们先看一下其他方法. 有些情况下 ...

随机推荐

  1. ES6语法:函数新特性(一)

    ES6 函数 引言: 函数在任何语言中偶读很重要,java里面的函数通常叫做方法,其实是一个东西,使用函数可以简化更多的代码,代码结构看着更加清晰.今天我们来学学ES6语法中,函数有什么变化. 虽然现 ...

  2. coding++:解决Not allowed to load local resource错误-SpringBoot配置虚拟路径

    1.在SpringBoot里上传图片后返回了绝对路径,发现本地读取的环节上面出现了错误(Not allowed to load local resource),一开始用的是直接本地路径. 但是在页面上 ...

  3. js 的位运算

    api 用途 待更...

  4. 微信阻止ios下拉回弹,橡皮筋效果

    直接阻止touchmove事件就好了(需设置passive: false): document.addEventListener("touchmove", function(evt ...

  5. input radio点击选中再点击取消

    这里主要说一下这个jquery中的data()方法,个人感觉这个方法平时挺少用到的,所以说一说,按照官方的解释就是 向元素附加数据,然后取回该数据; 嗯,是的,就是这么简单. 那这里说一下这个方法的使 ...

  6. 部署并测试动态WSGI站点

                                                            部署并测试动态WSGI站点 5.1问题 本例要求为站点webapp0.example.c ...

  7. WIFI:802.11无线LAN

    IEEE 802.11 无线LAN(也称WiFi) IEEE是什么 电气和电子工程师协会(IEEE,全称是Institute of Electrical and Electronics Enginee ...

  8. django类视图的装饰器验证

    django类视图的装饰器验证 django类视图的get和post方法是由View内部调用dispatch方法来分发,最后调用as_view来完成一个视图的流程. 函数视图可以直接使用对应的装饰器 ...

  9. Java第三天,如何从键盘输入?匿名对象的使用方法

    在学习完Java的基础语法之后,我们还需要学会如何使用API文档,这几乎是程序员所必备的能力.对于API我们不必须去记住每一个类的功能乃至用法,只需会查就行了.但是话说回来,一些经常使用的类我们还是必 ...

  10. Flask 入门(三)

    官方的文档虽然正规,但是有点太过书面语,有时候,明明很简单的一个程序,如果非要看它的说明,反而会让人疑惑不解,倒不如看一下别人写的简单的一个demo,jinjia2模板看官方的文档看了5回,愣是不明白 ...