search(7)- elastic4s-search-filter模式

来源:https://www.cnblogs.com/tiger-xc/archive/2020/04/26/12782333.html
-Advertisement-
Play Games

現在我們可以開始探討ES的核心環節:搜索search了。search又分filter,query兩種模式。filter模式即篩選模式:將符合篩選條件的記錄作為結果找出來。query模式則分兩個步驟:先篩選,然後對每條符合條件記錄進行相似度計算。就是多了個評分過程。如果我們首先要實現傳統資料庫的查詢功 ...


 現在我們可以開始探討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" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "bank",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.0,
        "_source" : {
          "account_number" : 1,
          "balance" : 39225,
          "firstname" : "Amber",
          "lastname" : "Duke",
          "age" : 32,
          "gender" : "M",
          "address" : "880 Holmes Lane",
          "employer" : "Pyrami",
          "email" : "[email protected]",
          "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 -> 880 Holmes Lane, city -> Brogan, state -> IL)
Map(address -> 810 Nostrand Avenue, city -> Brooktrails, state -> GA)
Map(address -> 295 Whitty Lane, city -> Broadlands, state -> VT)
Map(address -> 511 Heath Place, city -> Brookfield, state -> OK)
Map(address -> 918 Bridge Street, city -> Brownlee, state -> HI)
Map(address -> 806 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 -> 384 Bainbridge Street, city -> Elizaville, state -> MS)
Map(address -> 721 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 -> 384 Bainbridge Street, city -> Elizaville, state -> MS, lastname -> Lane)

score: 0.0 ,說明filter不會進行評分。可能執行效率會有所提高吧。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 參考https://www.cnblogs.com/xenny/p/9739600.html 樹狀數組與線段樹的區別 1. 兩者在複雜度上同級, 但是樹狀數組的常數明顯優於線段樹, 其編程複雜度也遠小於線段樹. 2. 樹狀數組的作用被線段樹完全涵蓋, , 但是線段樹能夠解決的問題樹狀數組未必能夠解決 ...
  • 什麼是while迴圈: while語句也稱條件判斷語句,它的迴圈方式是利用一個條件來控制是否要繼續反覆執行這個語句。 他的語法是 while( 條件表達式){ 執行 語句 } 他的特點是:先判斷,後執行迴圈操作。 概念:一直重覆做有開始有結束的事情。 特征為: 條件:開始結束的條件。 操作:一直重覆 ...
  • npm run dev 報錯,這個錯誤好像還遇到挺多次的,這次特地記錄一下,反正錯誤翻譯過來就是模塊生成失敗:錯誤:找不到模塊“node sass” 需要堆棧:....這大概意思就是下載node sass失敗唄 我這裡是這麼做法就成功了 首先執行:npm install g cnpm registr ...
  • 1 簡介 是不安全的,我們需要給它套上 ,讓它變成 。本文章將用實例介紹 整合 。 2 密碼學基礎 要談 就要談 ,自然就要談安全;談及安全,就必然涉及密碼學的一些知識。 2.1 密碼體制 要建立一個密碼體制,需要由五個空間組成,分別是: 明文M:加密前或解密後的信息; 密文C:明文加密後的信息; ...
  • 為什麼要使用switch 迴圈結構: 因為多重if選擇結構從代碼上看的話,顯得結構複雜,容易出錯,代碼多,冗餘且有多次的等值判斷。為瞭解決上述問題,我們開發出switch選擇結構。 if選擇結構主要用於區間的判斷上如 boolean類型,switch選擇結構用於等值的判斷。 switch語法結構: ...
  • 46. 全排列 題目來源: "https://leetcode cn.com/problems/permutations/" 題目 給定一個 沒有重覆 數字的序列,返回其所有可能的全排列。 示例: 解題思路 思路:深度優化搜索 先看題目,以所給數組 [1, 2, 3] 的全排列為例: 以 1 開始, ...
  • ```python import sqlite3 import os class DBOperate: def __init__(self,dbPath=os.path.join(os.getcwd(),"db")): self.dbPath=dbPath self.connect=sqlite3.... ...
  • 要想在終端後臺常駐進程,首先想到的是在命令後加 & 符號,來達到隱藏程式在後臺的目的,儘管看起來進程已經在後臺運行了,實際上終端會話關閉時進程還是會被 kill 掉,這種問題一般是採用搭配 nohup 命令來解決的,nohup 作用是忽略 SIGHUP 信號,而會話關閉時正好發送了該信號給會話內所有 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...