Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >search(3)- elastic4s-QueryDSL

search(3)- elastic4s-QueryDSL

作者头像
用户1150956
发布于 2020-03-24 09:35:02
发布于 2020-03-24 09:35:02
50600
代码可运行
举报
运行总次数:0
代码可运行

elastic4s是elasticsearch一个第三方开发的scala语言终端工具库(Elastic4s is a concise, idiomatic, reactive, type safe Scala client for Elasticsearch.)。scala用户可以用elastic4s提供的DSL用编程代码形式来构建ES服务请求。与字符型json文本直接编写请求不同的是:在编译DSL编写的ES服务请求时可以发现无论是语法上或者语意上的错误。一般来讲:elastic4s的程序流程相对直接、简单,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  client.execute {
    indexInto("books" ).fields("title" -> "重庆火锅的十种吃法", "content" -> "在这部书里描述了火锅的各种烹饪方式")
  }.await

  val response = client.execute {
    search("books").matchQuery("title", "火锅")
  }.await

...

...

一项ES操作服务从构建请求到具体运行都是在execute(T)这个函数里进行的。值得注意的是这个T类型在上面的例子里可以是IndexRequest或者SearchRequest,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   def indexInto(index: Index): IndexRequest
...
   def search(index: String): SearchRequest

实际上execute(T)的T代表elastic4s支持的所有ES操作类型。这种方法实现有赖于scala的typeclass模式。我们先看看execute函数定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // 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:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
  * 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。下面就是例子里两个操作类型需要的隐式实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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 201 | 200                   => Right(ResponseHandler.fromResponse[IndexResponse](response))
        case 400 | 401 | 403 | 409 | 500 => 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文本,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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文本了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  val json =
    """
      |{
      |  "query" : {
      |    "match" : {"title" : "火锅"}
      |  }
      |}
      |""".stripMargin
  val response = client.execute {
    search("books").source(json)   //      .matchQuery("title", "火锅")
  }.await
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
search(4)- elastic4s-ElasticDsl
上次分析了一下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结果进行处理,筛选出目标答案。
用户1150956
2020/04/23
6270
search(2)- elasticsearch scala终端:elastic4s
上篇谈到:elasticsearch本身是一个完整的后台系统,对其的操作使用是通过终端api进行的。elasticsearch本身提供了多种编程语言的api,包括java的esjava。而elastic4s是一套基于esjava之上的scala api。
用户1150956
2020/03/24
8900
search(7)- elastic4s-search-filter模式
现在我们可以开始探讨ES的核心环节:搜索search了。search又分filter,query两种模式。filter模式即筛选模式:将符合筛选条件的记录作为结果找出来。query模式则分两个步骤:先筛选,然后对每条符合条件记录进行相似度计算。就是多了个评分过程。如果我们首先要实现传统数据库的查询功能的话,那么用filter模式就足够了。filter模式同样可以利用搜索引擎的分词功能产生高质量的查询结果,而且filter是可以进缓存的,执行起来效率更高。这些功能数据库管理系统是无法达到的。ES的filter模式是在bool查询框架下实现的,如下:
用户1150956
2020/05/04
4410
【详解】ElasticSearchJava操作ES实例
Elasticsearch 是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景。本文将介绍如何在 Java 应用中使用 Elasticsearch 客户端来连接和操作 Elasticsearch 集群。
大盘鸡拌面
2025/01/19
1430
彻底搞懂 Elasticsearch Java API
在明确了ES的基本概念和使用方法后,我们来学习如何使用ES的Java API. 本文假设你已经对ES的基本概念已经有了一个比较全面的认识。
小勇DW3
2019/07/08
10K0
ES实战系列01:基于SpringBoot和RestHighLevelClient 快速搭建博客搜索系统
通过4个博客检索场景,巩固之前所学的全文搜索 Full Text Queries 和 基于词项的 Term lever Queries,同时通过组合查询的Bool query 完成复杂检索,并应用相关度知识对相关性评分进行控制。
方才编程_公众号同名
2020/11/13
1.6K0
ES实战系列01:基于SpringBoot和RestHighLevelClient 快速搭建博客搜索系统
ES系列(六):search处理过程实现1框架
上一篇文章中,我们看了get在es的实现过程,虽只是一个简单的单条查询,但看起来实现却非常之复杂。纠其原因,是我们围绕了太多外围的东西讲了,而其核心则无外乎三点:1. 定义id对应的机器节点;2. 查找真正的docId;3. 查找docId对应的field信息;
烂猪皮
2021/07/16
3.5K0
ES系列(六):search处理过程实现1框架
Springboot接入ES
详细见https://cloud.tencent.com/developer/article/2312482
翰墨飘香
2023/08/16
4950
SpringBoot整合elasticsearch集群
原文首发于CSDN:https://maoli.blog.csdn.net/article/details/104332506
润森
2020/02/25
2.1K0
SpringBoot整合elasticsearch集群
search(5)- elastic4s-构建索引
按照计划,这篇开始尝试用elastic4s来做一系列索引管理和搜索操作示范。前面提过,elastic4s的主要功能之一是通过组合Dsl语句形成json请求。那么我们先试试组合一些Dsl语句,再想办法产生出json请求文本,然后在kibana控制台中验证它的正确性。
用户1150956
2020/04/23
4970
java elasticsearch-rest-high-level-client 根据歌名搜索,创建索引,根据索引ID搜索
oktokeep
2024/10/09
970
【Elasticsearch系列五】Java API
Logstash 的工作是从 MySQL 中读取数据,向 ES 中创建索引,这里需要提前创建 mapping 的模板文件以便 logstash 使用。
kwan的解忧杂货铺
2024/09/16
2990
search(6)- elastic4s-CRUD
如果我们把ES作为某种数据库来使用的话,必须熟练掌握ES的CRUD操作。在这之前先更正一下上篇中关于检查索引是否存在的方法:elastic4s的具体调用如下:
用户1150956
2020/04/23
5000
search(15)- elastic4s-sorting buckets
聚合结果buckets默认以doc_count 排序方式呈现,即: _count asc 表达。其它还有 _term, _key 为排序控制元素。_key适用于histogram,date_histogram,如下:
用户1150956
2020/05/18
7670
Elasticsearch 中文分词、全文搜索、分布式集群搭建和java客户端操作
分词就是指将一个文本转化成一系列单词的过程,也叫文本分析,在Elasticsearch中称之为Analysis。 举例:我是中国人 --> 我/是/中国人
不愿意做鱼的小鲸鱼
2022/09/24
2.2K0
Elasticsearch 中文分词、全文搜索、分布式集群搭建和java客户端操作
Elasticsearch Search API之搜索模板(search Template)
首先在学习Search Template之前,我们需要先掌握mustache模板语法,因为在ES中默认使用mustache语言来定义模板。
丁威
2019/06/10
3.6K0
Elasticsearch Search API之搜索模板(search Template)
search(12)- elastic4s-聚合=桶+度量
这篇我们介绍一下ES的聚合功能(aggregation)。聚合是把索引数据可视化处理成可读有用数据的主要工具。聚合由bucket桶和metrics度量两部分组成。
用户1150956
2020/05/18
3860
SpringBoot集成ElasticSearch,实现模糊查询,批量CRUD,排序,分页,高亮...
非常重要:检查依赖版本是否与你当前所用的版本是否一致,如果不一致,会连接失败!!!!!!!!
Java技术精选
2024/03/27
4790
Spring Boot整合分布式搜索引擎ElasticSearch 实现相关基本操作
Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,打分,再将返回结果呈现给用户。
百思不得小赵
2022/12/20
6200
Spring Boot整合分布式搜索引擎ElasticSearch 实现相关基本操作
02_ElasticSearch索引操作总结归纳
只要name中包含手机、手、机都会被查询出来.会对手机进行分词,多个词语之间的关系默认为or。如果要精准查询,需要将操作改为and关系.
全栈程序员站长
2021/07/13
1.3K0
相关推荐
search(4)- elastic4s-ElasticDsl
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验