上次分析了一下elastic4s的运算框架。本来计划接着开始实质的函数调用示范,不过看过了Elastic4s的所有使用说明文档后感觉还是走的快了一点。主要原因是elasticsearch在7.0后有了很多重点调整改变,elastic4s虽然一直在源代码方面紧跟ES的变化,但使用文件却一直未能更新,所以从说明文档中学习elastic4s的使用方法是不可能的,必须从源码中摸索。花了些时间过了一次elastic4s的源码,感觉这个工具库以后还是挺有用的:一是通过编程方式产生json请求比较灵活,而且可以通过compiler来保证json语句的正确性。二是对搜索结果的处理方面:由于返回的搜索结果是一堆又长又乱的复杂json,不敢想象自己要如何正确的解析这些json, 然后才能调用到正确的结果,但elastic4s提供了一套很完善的response类,使用起来可能会很方便。实际上elastic4s的编程模式和scala语言运用还是值得学习的。既然这样,我想可能用elastic4s做一套完整的示范,包括:索引创建、索引维护、搜索、聚合统计等,对了解和掌握elastic4s可能大有帮助。在这之前,我们还是再回顾一下elastic4s的运算原理:elastic4s的功能其实很简单:通过dsl语句组合产生json请求,然后发送给ES-rest终端, 对返回的json结果进行处理,筛选出目标答案。

上篇我们讨论过elastic4s的基本运算框架:

  client.execute(
createIndex("company")
.shards().replicas()
) ... val bookschema = putMapping("books")
.as(
KeywordField("isbn"),
textField("title"),
doubleField("price")
) client.execute(
bookschema
) ... val futAccts = client.execute(
search("bank").termQuery("city" -> "dante")
)
futAccts.onComplete{
case Success(esresp) =>
esresp.result.hits.hits.foreach(h =>println(h.sourceAsMap))
case Failure(err) => println(s"search error: ${err.getMessage}")
}

实际上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[T,U]是个typeclass, 代表对不同类型T的json构建方法。elastic4s提供了这个T类型的操作方法,如下:

trait ElasticDsl
extends ElasticApi
with Logging
with ElasticImplicits
with BulkHandlers
with CatHandlers
with CountHandlers
with ClusterHandlers
with DeleteHandlers
with ExistsHandlers
with ExplainHandlers
with GetHandlers
with IndexHandlers
with IndexAdminHandlers
with IndexAliasHandlers
with IndexStatsHandlers
with IndexTemplateHandlers
with LocksHandlers
with MappingHandlers
with NodesHandlers
with ReindexHandlers
with RoleAdminHandlers
with RoleHandlers
with RolloverHandlers
with SearchHandlers
with SearchTemplateHandlers
with SearchScrollHandlers
with SettingsHandlers
with SnapshotHandlers
with UpdateHandlers
with TaskHandlers
with TermVectorHandlers
with UserAdminHandlers
with UserHandlers
with ValidateHandlers { implicit class RichRequest[T](t: T) {
def request(implicit handler: Handler[T, _]): ElasticRequest = handler.build(t)
def show(implicit handler: Handler[T, _]): String = Show[ElasticRequest].show(handler.build(t))
}
} object ElasticDsl extends ElasticDsl

所有的操作api在这里:

trait ElasticApi
extends AliasesApi
with ElasticImplicits
with AggregationApi
with AnalyzerApi
with BulkApi
with CatsApi
with CreateIndexApi
with ClearRolesCacheApi
with ClusterApi
with CollapseApi
with CountApi
with CreateRoleApi
with CreateUserApi
with DeleteApi
with DeleteIndexApi
with DeleteRoleApi
with DeleteUserApi
with DynamicTemplateApi
with ExistsApi
with ExplainApi
with ForceMergeApi
with GetApi
with HighlightApi
with IndexApi
with IndexAdminApi
with IndexRecoveryApi
with IndexTemplateApi
with LocksApi
with MappingApi
with NodesApi
with NormalizerApi
with QueryApi
with PipelineAggregationApi
with ReindexApi
with RoleApi
with ScriptApi
with ScoreApi
with ScrollApi
with SearchApi
with SearchTemplateApi
with SettingsApi
with SnapshotApi
with SortApi
with SuggestionApi
with TaskApi
with TermVectorApi
with TokenizerApi
with TokenFilterApi
with TypesApi
with UpdateApi
with UserAdminApi
with UserApi
with ValidateApi { implicit class RichFuture[T](future: Future[T]) {
def await(implicit duration: Duration = .seconds): T = Await.result(future, duration)
}
} object ElasticApi extends ElasticApi

通过 import ElasticDsl._  ,所有类型的api,handler操作方法都有了。下面是例子里的api方法:

trait CreateIndexApi {

  def createIndex(name: String): CreateIndexRequest = CreateIndexRequest(name)
...
} trait MappingApi {
...
def putMapping(indexes: Indexes): PutMappingRequest = PutMappingRequest(IndexesAndType(indexes))
} trait SearchApi {
def search(index: String): SearchRequest = search(Indexes(index))
...
}

CreateIndexRequest, PutMappingRequest,SearchRequest这几个类型都提供了handler隐式实例:

trait IndexAdminHandlers {
...
implicit object CreateIndexHandler extends Handler[CreateIndexRequest, CreateIndexResponse] { override def responseHandler: ResponseHandler[CreateIndexResponse] = new ResponseHandler[CreateIndexResponse] {
override def handle(response: HttpResponse): Either[ElasticError, CreateIndexResponse] =
response.statusCode match {
case | => Right(ResponseHandler.fromResponse[CreateIndexResponse](response))
case | => Left(ElasticError.parse(response))
case _ => sys.error(response.toString)
}
} override def build(request: CreateIndexRequest): ElasticRequest = { val endpoint = "/" + URLEncoder.encode(request.name, "UTF-8") val params = scala.collection.mutable.Map.empty[String, Any]
request.waitForActiveShards.foreach(params.put("wait_for_active_shards", _))
request.includeTypeName.foreach(params.put("include_type_name", _)) val body = CreateIndexContentBuilder(request).string()
val entity = HttpEntity(body, "application/json") ElasticRequest("PUT", endpoint, params.toMap, entity)
}
} } ... trait MappingHandlers {
...
implicit object PutMappingHandler extends Handler[PutMappingRequest, PutMappingResponse] { override def build(request: PutMappingRequest): ElasticRequest = { val endpoint = s"/${request.indexesAndType.indexes.mkString(",")}/_mapping${request.indexesAndType.`type`.map("/" + _).getOrElse("")}" val params = scala.collection.mutable.Map.empty[String, Any]
request.updateAllTypes.foreach(params.put("update_all_types", _))
request.ignoreUnavailable.foreach(params.put("ignore_unavailable", _))
request.allowNoIndices.foreach(params.put("allow_no_indices", _))
request.expandWildcards.foreach(params.put("expand_wildcards", _))
request.includeTypeName.foreach(params.put("include_type_name", _)) val body = PutMappingBuilderFn(request).string()
val entity = HttpEntity(body, "application/json") ElasticRequest("PUT", endpoint, params.toMap, entity)
}
} }
...
trait SearchHandlers {
...
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"))
}
} }

search(4)- elastic4s-ElasticDsl的更多相关文章

  1. search(9)- elastic4s logback-appender

    前面写了个cassandra-appender,一个基于cassandra的logback插件.正是cassandra的分布式数据库属性才合适作为akka-cluster-sharding分布式应用的 ...

  2. 【CF528D】Fuzzy Search(FFT)

    [CF528D]Fuzzy Search(FFT) 题面 给定两个只含有\(A,T,G,C\)的\(DNA\)序列 定义一个字符\(c\)可以被匹配为:它对齐的字符,在距离\(K\)以内,存在一个字符 ...

  3. search(2)- elasticsearch scala终端:elastic4s

    上篇谈到:elasticsearch本身是一个完整的后台系统,对其的操作使用是通过终端api进行的.elasticsearch本身提供了多种编程语言的api,包括java的esjava.而elasti ...

  4. search(0)- 企业搜索,写在前面

    计划研究一下搜索search,然后写个学习过程系列博客.开动之前先说说学习搜索的目的:不是想开发个什么搜索引擎,而是想用现成的搜索引擎在传统信息系统中引进搜索的概念和方法.对我来说,传统的管理系统le ...

  5. search(6)- elastic4s-CRUD

    如果我们把ES作为某种数据库来使用的话,必须熟练掌握ES的CRUD操作.在这之前先更正一下上篇中关于检查索引是否存在的方法:elastic4s的具体调用如下: //删除索引 val rspExists ...

  6. search(16)- elastic4s-内嵌文件:nested and join

    从SQL领域来的用户,对于ES的文件关系维护方式会感到很不习惯.毕竟,ES是分布式数据库只能高效处理独个扁平类型文件,无法支持关系式数据库那样的文件拼接.但是,任何数据库应用都无法避免树型文件关系,因 ...

  7. 【阅读笔记】Ranking Relevance in Yahoo Search (一)—— introduction & background

    ABSTRACT: 此文在相关性方面介绍三项关键技术:ranking functions, semantic matching features, query rewriting: 此文内容基于拥有百 ...

  8. search(11)- elastic4s-模糊查询

    很多时候搜索用户对查询语句具有模糊感觉,他们只能提供大约的描述.比如一个语句的部分,或者字句顺序颠倒等.通过模糊查询可以帮助用户更准确的找出他们希望搜索的结果. 模糊查询包括前后缀,语句(phrase ...

  9. search(12)- elastic4s-聚合=桶+度量

    这篇我们介绍一下ES的聚合功能(aggregation).聚合是把索引数据可视化处理成可读有用数据的主要工具.聚合由bucket桶和metrics度量两部分组成. 所谓bucket就是SQL的GROU ...

  10. search(1)- elasticsearch结构概念

    上篇提到选择了elasticsearch ES作为专业化搜索引擎的核心,这篇讨论一下ES的基本结构和应用概念.首先,从硬结构方面来讲:ES是在一个集群(cluster)环境里运行的,所以ES应该具备高 ...

随机推荐

  1. The Game Of Life – 数据结构与算法的敲门砖

    The Game Of Life(生命游戏,又称为细胞自动机)几乎是所有数据结构与算法导论教程前言的一个很经典的程序了.这是一个零玩家游戏,发生在一个平面网格里.每个格子的细胞都有死亡和存活两种状态, ...

  2. AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth

    title: "AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth" date: 2020-03-24T23:27:45+08:00 ...

  3. Netty Hello World 入门源码分析

    第一节简单提了什么是网络编程,Netty 做了什么,Netty 都有哪些功能组件.这一节就具体进入 Netty 的世界,我们从用 Netty 的功能实现基本的网络通信开始分析 各个组件的使用. 1. ...

  4. Dubbo反序列化漏洞(CVE-2019-17564) 重现

    1. 下载官方 demo 代码(暴出的漏洞是 http 协议的,故使用 http 的 demo 来重现)https://github.com/apache/dubbo-samples/tree/mas ...

  5. python爬虫之beautifulsoup的使用

    一.Beautiful Soup的简介 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据.官方解释:Beautiful Soup提供一些简单的.python式 ...

  6. POJ 1182食物链(分集合以及加权两种解法) 种类并查集的经典

    题目链接:http://icpc.njust.edu.cn/Problem/Pku/1182/ 题意:给出动物之间的关系,有几种询问方式,问是真话还是假话. 定义三种偏移关系: x->y 偏移量 ...

  7. apache 自带的ab.exe 测试网站的并发量(网站压力测试)

    AB(ApacheBench) 是 Apache 自带的超文本传输协议 (HTTP) 性能测试工具. 其设计意图是描绘当前所安装的 Apache 的执行性能, 主要是显示 Apache 每秒可以处理多 ...

  8. POJ-3134-Power Calculus(迭代加深)

    题意:输入一个n,问x从1次方开始,到n次方 ,可以乘或除已经计算出来的数 ,最少需要执行多少步? 思路:迭代加深 ,深度从0开始 ,直到返回值为真. 在深搜过程中剪枝(深度的判断 ,当前最大值尽全力 ...

  9. Python python 函数参数:参数组合

    '''在Python中定义函数,可以用必选参数.默认参数.可变参数和关键字参数, 这4种参数都可以一起使用,或者只用其中某些 参数定义的顺序必须是:必选参数.默认参数.可变参数和关键字参数 ''' d ...

  10. js 中的yield

    yield是什么 yield是ES6的新关键字,使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者.它可以被认为是一个基于生成器的版本的return关键字. yield关键字实 ...