search(3)- elastic4s-QueryDSL
elastic4s是elasticsearch一个第三方开发的scala语言终端工具库(Elastic4s is a concise, idiomatic, reactive, type safe Scala client for Elasticsearch.)。scala用户可以用elastic4s提供的DSL用编程代码形式来构建ES服务请求。与字符型json文本直接编写请求不同的是:在编译DSL编写的ES服务请求时可以发现无论是语法上或者语意上的错误。一般来讲:elastic4s的程序流程相对直接、简单,如下:
client.execute {
indexInto("books" ).fields("title" -> "重庆火锅的十种吃法", "content" -> "在这部书里描述了火锅的各种烹饪方式")
}.await
val response = client.execute {
search("books").matchQuery("title", "火锅")
}.await
...
...
一项ES操作服务从构建请求到具体运行都是在execute(T)这个函数里进行的。值得注意的是这个T类型在上面的例子里可以是IndexRequest或者SearchRequest,如下:
def indexInto(index: Index): IndexRequest
...
def search(index: String): SearchRequest
实际上execute(T)的T代表elastic4s支持的所有ES操作类型。这种方法实现有赖于scala的typeclass模式。我们先看看execute函数定义:
// Executes the given request type T, and returns an effect of Response[U]
// where U is particular to the request type.
// For example a search request will return a Response[SearchResponse].
def execute[T, U, F[_]](t: T)(implicit
executor: Executor[F],
functor: Functor[F],
handler: Handler[T, U],
manifest: Manifest[U]): F[Response[U]] = {
val request = handler.build(t)
val f = executor.exec(client, request)
functor.map(f) { resp =>
handler.responseHandler.handle(resp) match {
case Right(u) => RequestSuccess(resp.statusCode, resp.entity.map(_.content), resp.headers, u)
case Left(error) => RequestFailure(resp.statusCode, resp.entity.map(_.content), resp.headers, error)
}
}
}
这个函数比较重要的功能之一应该是构建服务请求了。这个功能是通过handler.build(t)实现的。handler: Handler[T,U]是个隐式参数,它就是一个typeclass:
/**
* A [[Handler]] is a typeclass used by the [[ElasticClient]] in order to
* create [[ElasticRequest]] instances which are sent to the elasticsearch
* server, as well as returning a [[ResponseHandler]] which handles the
* response from the server.
*
* @tparam T the type of the request object handled by this handler
* @tparam U the type of the response object returned by this handler
*/
abstract class Handler[T, U: Manifest] extends Logging {
def responseHandler: ResponseHandler[U] = ResponseHandler.default[U]
def build(t: T): ElasticRequest
}
这个抽象类中有两个函数,其中一个就是build(t: T):ElasticRequest,也是个抽象方法,必须在构建实例时实现。在execute(T)中handler是一个隐式参数,也就是说如果在调用这个函数的可视域内能发现Handler[T,U]实例,则可获取handler,然后可调用handler.build(t)来构建请求。这个T类型是即是调用execute(T)这个T类型了,上面说过T可以是ES的任何操作类型,也就是说如果这些操作类型都继承了Handler[T,U],那么必须按照要求实现build(t:T)来构建该操作类型所需的服务请求ElasticRequest。下面就是例子里两个操作类型需要的隐式实例:
implicit object IndexHandler extends Handler[IndexRequest, IndexResponse] {
override def responseHandler: ResponseHandler[IndexResponse] = new ResponseHandler[IndexResponse] {
override def handle(response: HttpResponse): Either[ElasticError, IndexResponse] = response.statusCode match {
case | => Right(ResponseHandler.fromResponse[IndexResponse](response))
case | | | | => Left(ElasticError.parse(response))
case _ => sys.error(response.toString)
}
}
override def build(request: IndexRequest): ElasticRequest = {
val (method, endpoint) = request.id match {
case Some(id) =>
"PUT" -> s"/${URLEncoder.encode(request.index.name, StandardCharsets.UTF_8.name())}/_doc/${URLEncoder.encode(id.toString, StandardCharsets.UTF_8.name())}"
case None =>
"POST" -> s"/${URLEncoder.encode(request.index.name, StandardCharsets.UTF_8.name())}/_doc"
}
val params = scala.collection.mutable.Map.empty[String, String]
request.createOnly.foreach(
createOnly =>
if (createOnly)
params.put("op_type", "create")
)
request.routing.foreach(params.put("routing", _))
request.parent.foreach(params.put("parent", _))
request.timeout.foreach(params.put("timeout", _))
request.pipeline.foreach(params.put("pipeline", _))
request.refresh.map(RefreshPolicyHttpValue.apply).foreach(params.put("refresh", _))
request.version.map(_.toString).foreach(params.put("version", _))
request.ifPrimaryTerm.map(_.toString).foreach(params.put("if_primary_term", _))
request.ifSeqNo.map(_.toString).foreach(params.put("if_seq_no", _))
request.versionType.map(VersionTypeHttpString.apply).foreach(params.put("version_type", _))
val body = IndexContentBuilder(request)
val entity = ByteArrayEntity(body.getBytes, Some("application/json"))
logger.debug(s"Endpoint=$endpoint")
ElasticRequest(method, endpoint, params.toMap, entity)
}
}
...
implicit object SearchHandler extends Handler[SearchRequest, SearchResponse] {
override def build(request: SearchRequest): ElasticRequest = {
val endpoint =
if (request.indexes.values.isEmpty)
"/_all/_search"
else
"/" + request.indexes.values
.map(URLEncoder.encode(_, "UTF-8"))
.mkString(",") + "/_search"
val params = scala.collection.mutable.Map.empty[String, String]
request.requestCache.map(_.toString).foreach(params.put("request_cache", _))
request.searchType
.filter(_ != SearchType.DEFAULT)
.map(SearchTypeHttpParameters.convert)
.foreach(params.put("search_type", _))
request.routing.map(_.toString).foreach(params.put("routing", _))
request.pref.foreach(params.put("preference", _))
request.keepAlive.foreach(params.put("scroll", _))
request.allowPartialSearchResults.map(_.toString).foreach(params.put("allow_partial_search_results", _))
request.batchedReduceSize.map(_.toString).foreach(params.put("batched_reduce_size", _))
request.indicesOptions.foreach { opts =>
IndicesOptionsParams(opts).foreach { case (key, value) => params.put(key, value) }
}
request.typedKeys.map(_.toString).foreach(params.put("typed_keys", _))
val body = request.source.getOrElse(SearchBodyBuilderFn(request).string())
ElasticRequest("POST", endpoint, params.toMap, HttpEntity(body, "application/json"))
}
}
以上IndexHandler, SearchHandler就是针对index,search操作的Handler[T,U]隐式实例。它们的build(t:T)函数分别按传入的T类型参数构建了各自要求格式的服务请求。
我总是觉着:不一定所有类型的服务请求都适合用DSL来构建,比如多层逻辑条件的json,可能不容易用DSL来实现(我个人的顾虑)。那么应该有个接口直接json文本嵌入request-entity。elastic4s在各种操作类型的服务请求类型如IndexRequest, SearchRequest,BulkRequest等提供了source:Option[String]字段接收json文本,如下:
case class IndexRequest(index: Index,
...
source: Option[String] = None)
extends BulkCompatibleRequest {
...
def source(json: String): IndexRequest = copy(source = json.some) ...
} case class SearchRequest(indexes: Indexes,
...
source: Option[String] = None,
...
typedKeys: Option[Boolean] = None) {
...
/**
* Sets the source of the request as a json string. Note, if you use this method
* any other body-level settings will be ignored.
*
* HTTP query-parameter settings can still be used, eg limit, routing, search type etc.
*
* Unlike rawQuery, source is parsed at the "root" level
* Query must be valid json beginning with '{' and ending with '}'.
* Field names must be double quoted.
*
* NOTE: This method only works with the HTTP client.
*
* Example:
* {{{
* search in "*" limit 5 source {
* """{ "query": { "prefix": { "bands": { "prefix": "coldplay", "boost": 5.0, "rewrite": "yes" } } } }"""
* } searchType SearchType.Scan
* }}}
*/
def source(json: String): SearchRequest = copy(source = json.some) ... }
现在,我们可以直接用json文本了:
val json =
"""
|{
| "query" : {
| "match" : {"title" : "火锅"}
| }
|}
|""".stripMargin
val response = client.execute {
search("books").source(json) // .matchQuery("title", "火锅")
}.await
search(3)- elastic4s-QueryDSL的更多相关文章
- search(9)- elastic4s logback-appender
前面写了个cassandra-appender,一个基于cassandra的logback插件.正是cassandra的分布式数据库属性才合适作为akka-cluster-sharding分布式应用的 ...
- 【CF528D】Fuzzy Search(FFT)
[CF528D]Fuzzy Search(FFT) 题面 给定两个只含有\(A,T,G,C\)的\(DNA\)序列 定义一个字符\(c\)可以被匹配为:它对齐的字符,在距离\(K\)以内,存在一个字符 ...
- search(0)- 企业搜索,写在前面
计划研究一下搜索search,然后写个学习过程系列博客.开动之前先说说学习搜索的目的:不是想开发个什么搜索引擎,而是想用现成的搜索引擎在传统信息系统中引进搜索的概念和方法.对我来说,传统的管理系统le ...
- search(16)- elastic4s-内嵌文件:nested and join
从SQL领域来的用户,对于ES的文件关系维护方式会感到很不习惯.毕竟,ES是分布式数据库只能高效处理独个扁平类型文件,无法支持关系式数据库那样的文件拼接.但是,任何数据库应用都无法避免树型文件关系,因 ...
- search(6)- elastic4s-CRUD
如果我们把ES作为某种数据库来使用的话,必须熟练掌握ES的CRUD操作.在这之前先更正一下上篇中关于检查索引是否存在的方法:elastic4s的具体调用如下: //删除索引 val rspExists ...
- search(7)- elastic4s-search-filter模式
现在我们可以开始探讨ES的核心环节:搜索search了.search又分filter,query两种模式.filter模式即筛选模式:将符合筛选条件的记录作为结果找出来.query模式则分两个步骤:先 ...
- 【阅读笔记】Ranking Relevance in Yahoo Search (一)—— introduction & background
ABSTRACT: 此文在相关性方面介绍三项关键技术:ranking functions, semantic matching features, query rewriting: 此文内容基于拥有百 ...
- search(11)- elastic4s-模糊查询
很多时候搜索用户对查询语句具有模糊感觉,他们只能提供大约的描述.比如一个语句的部分,或者字句顺序颠倒等.通过模糊查询可以帮助用户更准确的找出他们希望搜索的结果. 模糊查询包括前后缀,语句(phrase ...
- search(12)- elastic4s-聚合=桶+度量
这篇我们介绍一下ES的聚合功能(aggregation).聚合是把索引数据可视化处理成可读有用数据的主要工具.聚合由bucket桶和metrics度量两部分组成. 所谓bucket就是SQL的GROU ...
- search(1)- elasticsearch结构概念
上篇提到选择了elasticsearch ES作为专业化搜索引擎的核心,这篇讨论一下ES的基本结构和应用概念.首先,从硬结构方面来讲:ES是在一个集群(cluster)环境里运行的,所以ES应该具备高 ...
随机推荐
- tfjs-node初体验:训练模型的存储
JS,一门从浏览器兴起,却不止于浏览器的脚本,个人一直认为其是最有潜力的脚本语言.不只是因为ES6优雅的语法,更重要的是其易上手,跨平台的优点. Node将JS从browser带去了client是革命 ...
- devexpress设置选中行
版本2009.3 gvTagInfo.FocusedRowHandle = k; ; //有效 gvTagInfo.FocusedRowHandle = k; //这种 ...
- Typescript - 联合类型
原文:TypeScript基本知识点整理 零.序言 联合类型表示一个变量值可以是几种类型之一,我们可以使用 “|” 来分割每个类型: 联合类型的变量在被赋值时,会根据类型推断的规则推断出一个类型: 如 ...
- 利用Load命令将本地文本里面的数据导入到MySQL数据库
摘要:在使用MySQL是我们可能会遇到要向我们的表中插入大量的数据如果都使用以下的语句在命令行输入有点不太切实际,幸好MySQL为我们提供了LOAD命令可以批量的从本地文件向MySQL表中导入数据! ...
- js 函数的防抖(debounce)与节流(throttle)
原文:函数防抖和节流: 序言: 我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求,onmousemove, resize, onscroll等等,有些时候,我们并不能或者不想频 ...
- [SDOI2008] 洞穴勘测 (LCT模板)
bzoj 2049 传送门 洛谷P2147 传送门 这个大佬的LCT详解超级棒的! Link-Cut Tree的基本思路是用splay的森林维护一条条树链. splay的森林,顾名思义,就是若干spl ...
- hexo命令
2017-09-12 by chenyan 安装 npm install hexo -g #安装npm update hexo -g #升级hexo init #初始化 简写 hexo n " ...
- SWUST OJ 青蛙的约会之二(0481)
青蛙的约会之二(0481) Time limit(ms): 1000 Memory limit(kb): 65535 Submission: 138 Accepted: 28 Descriptio ...
- HBase完全分布式集群搭建
HBase完全分布式集群搭建 hbase和hadoop一样也分为单机版,伪分布式版和完全分布式集群版,此文介绍如何搭建完全分布式集群环境搭建.hbase依赖于hadoop环境,搭建habase之前首先 ...
- 2020 倒计时 1 天,Python 工程师找工作更难了?
Python 是最神奇的编程语言. 无意引战,我说的是"神奇",不是"最好",并不想去"撼动" PHP 的地位. ...