现在我们可以开始探讨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. ClickHouse学习系列之一【安装说明】

    背景 最近花了些时间看了下ClickHouse文档,发现它在OLAP方面表现很优异,而且相对也比较轻量和简单,所以准备入门了解下该数据库系统.按照习惯第一步先安装,本文对其用户权限管理方面进行梳理说明 ...

  2. html-css:浮动_清除浮动

    1.浮动 清除浮动之前我们首先需要了解为什么要清除浮动 1. 假设我们有一个父盒子,不设置高度,其高度有内部子盒子的大小自动撑开,这样是完全可行的,因为有时候我们并不想直接固定死父盒子的大小,而是根据 ...

  3. jsonp跨域的原理及实现

    1,什么是跨域? 跨域跨域,跨过域名,笼统来说就是一个域名区请求另外一个域名的数据,但实际上,不同端口.不同域名.不同协议上请求数据都会出现跨域问题.浏览器出于安全考虑会报出异常,拒绝访问. 2,js ...

  4. python—异常处理try

    写代码的时候会遇到各种各样的异常,那么代码就不会继续往下走了.比如说10除以0是错误的,因为除数不能为零学会捕捉异常,在异常出现的时候我们要做什么操作. 捕捉异常 d={} #例如定义字典 try: ...

  5. linux硬件资源问题排查:cpu负载、内存使用情况、磁盘空间、磁盘IO

    在使用过程中之前正常的功能,突然无法使用,性能变慢,通常都是资源消耗问题,资源消耗可以从以下几个方面去排查.对于已经安装硬件资源监控软件(zabbix)的环境,直接使用硬件资源监控软件(zabbix) ...

  6. Redis 笔记(二)—— STRING 常用命令

    字符串中不仅仅可以存储字符串,它可以存储以下 3 中类型的值 : 字符串 整数 浮点数 Redis 可以对字符串进行截取等相关操作,对整数.浮点数进行增减操作. 自增自减命令 命令 用例和描述 INC ...

  7. python--模块、列表生成式、集合元祖列表

    一.导入模块的两种方式 1.直接使用import import 模块名 #调用 模块名.方法名() 2.使用from…import… from 模块名 import 方法名1,方法名2(from 模块 ...

  8. Linux下修改efi启动项

    Linux下有一个efibootmgr工具可以编辑efi启动项,十分方便,简单介绍如下 直接运行efibootmgr会显示出当前所有efi启动项,每个启动项前都有相应编号, 可以使用efibootmg ...

  9. Golang源码分析之目录详解

    开源项目「go home」聚焦Go语言技术栈与面试题,以协助Gopher登上更大的舞台,欢迎go home~ 导读 学习Go语言源码的第一步就是了解先了解它的目录结构,你对它的源码目录了解多少呢? 目 ...

  10. golang trace 分析 简例

    今天,通过一个例子,一方面熟悉trace在自定义范围内的分析,另一方面golang 在协程调度策略上的浅析. Show Code // trace_example.go package main im ...