ElasticSearch入門 第九篇:實現正則表達式查詢的思路

来源:http://www.cnblogs.com/ljhdo/archive/2017/05/10/4911878.html
-Advertisement-
Play Games

ElasticSearch 2.4版本支持Java正則表達式查詢,但是,在對大段的文本(Text Block)進行挖掘之前,必須瞭解正則表達式查詢的特殊之處。由於分析器會對文本欄位進行分詞,移除停用詞,小寫轉換等操作,最終存儲在倒轉索引中的是小寫的標記流(Token Stream),預設情況下,每一... ...


這是ElasticSearch 2.4 版本系列的第九篇:

 

ElasticSearch 2.4版本支持Java正則表達式查詢,但是,在對大段的文本(Text Block)進行挖掘之前,必須瞭解正則表達式查詢的特殊之處。由於分析器會對文本欄位進行分詞,移除停用詞,小寫轉換等操作,最終存儲在倒轉索引中的是小寫的標記流(Token Stream),預設情況下,每一個標記是一個分詞(Term),這無法滿足正則表達式查詢的一般要求,這就是說,正則表達式查詢的是原始文本,需要註意的是,ElasticSearch引擎都是從原始文本的第一個字元開始執行正則表達式匹配。

在ElasticSearch 2.4版本中啟用正則表達式查詢之前,需要考慮兩個問題:分詞嗎?大小寫敏感嗎?

一,分詞還是不分詞?

通常情況下,ElasticSearch引擎對文本欄位進行分詞,移除停用詞,轉換成小寫,這是全文搜索的標準配置,在這種設置下,正則表達式只能匹配文本欄位的單個分詞,而無法對原始文本執行正則表達式查詢,為了實現正則表達式查詢,必須設置文本欄位不被分詞,也就是是設置該欄位的index屬性為not_analyzed。在實際的產品環境中,對一個欄位同時執行正則表達式查詢和全文搜索的情況是經常存在的,ElasticSearch 2.4版本提供的映射參數 fields 能夠滿足該需求。

fields 參數:多元欄位(multi-fields),用不同的處理方式,把一個相同的欄位編入索引,以實現不同的目的。多元欄位使用相同的數據派生新的欄位,例如,一個欄位field被編入索引作為分析欄位(analyzed field)以執行全文搜索,把該欄位設置為多元欄位,那麼ElasticSearch引擎派生一個新的欄位field .raw,該欄位文本作為一個詞被編入索引,只對該欄位執行排序或聚合操作。

註:多元欄位(multi-fields)不同於多值欄位(multi-values field),欄位的多值是ElasticSearch內在支持的特性,“開箱即用”,不需要做任何配置。每個欄位都能存儲多個數據值,這就是意味著,每個欄位都是數組類型,只不過在欄位中存儲的數據,其數據類型都是相同的。

1,多元欄位使用示例

在示例索引映射中,eventdescription是一個多元欄位,其index屬性是analyzed,表示該欄位是分析欄位,ElasticSearch引擎把該欄位的文本分析成分詞流,編入索引,以執行全文搜索,這就意味著,倒排索引中存儲的不是該欄位的原始文本,而是分割的單個分詞;而eventdescription.raw是多元欄位的派生欄位,其index屬性是not_analyzed,表示該派生欄位不會被分詞,整個文本欄位整體作為一個分詞被編入索引,這就意味著,倒排索引中存儲的是派生欄位原始的文本值。

 "eventdescription":{  
    "type":"string",
"index":"analyzed", "fields":{ "raw":{ "type":"string",
"index":"not_analyzed" } } }

2,對原始文本執行正則表達式查詢

ElasticSearch引擎在處理分析欄位(analyzed field)時,使用指定的分析器執行分析操作,包括分詞,移除停用詞,轉換大小寫等,如果一個欄位不是分析欄位,那麼ElasticSearch引擎不會對其執行任何分析工作。

映射參數index:決定ElasticSearch引擎是否對文本欄位執行分析操作,也就是說分析操作將分割文本,把分詞編入索引,並使分詞能夠被搜索到

  • 當參數值為analyzed時,該欄位是分析欄位,ElasticSearch引擎對該欄位執行分析操作,把文本分割成分詞流,存儲在倒排索引中,使其支持全文搜索;
  • 當參數值為not_analyzed時,該欄位不會被分析,ElasticSearch引擎把原始文本作為單個分詞存儲在倒排索引中,不支持全文搜索,但是支持詞條級別的搜索;也就是說,欄位的原始文本不經過分析而存儲在倒排索引中,使用原始文本編入索引,在搜索的過程中,查詢條件必須全部匹配整個原始文本;
  • 當參數值為no時,該欄位不會被存儲到倒排索引中,也不會被搜索到;

 這也就意味著,要對原始文本執行正則表達式查詢,必須設置index屬性為not_analyzed,這也就意味著,保留文本的原始形式,例如大小寫,空格等。

3,單個分詞的最大長度

如果設置欄位的index屬性為not_analyzed,原始文本將作為單個分詞,其最大長度跟UTF8 編碼有關,預設的最大長度是32766Bytes,如果欄位的文本超過該限制,那麼ElasticSearch將跳過(Skip)該文檔,併在Response中拋出異常消息:

operation[607]: index returned 400 _index: ebrite _type: events _id: 76860 _version: 0 error: Type: illegal_argument_exception Reason: "Document contains at least one immense term in field="event_raw" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[112, 114,... 115]...', original message: bytes can be at most 32766 in length; got 35100" CausedBy:Type: max_bytes_length_exceeded_exception Reason: "bytes can be at most 32766 in length; got 35100"

可以在欄位中設置ignore_above屬性,該屬性值指的是字元數量,而不是位元組數量;由於一個UTF8字元最多占用3個位元組,因此,可以設置

“ignore_above”:10000

這樣,超過30000位元組之後的字元將會被分析器忽略,單個分詞(Term)的最大長度是30000Bytes。

The value for ignore_above is the character count, but Lucene counts bytes. If you use UTF-8 text with many non-ASCII characters, you may want to set the limit to 32766 / 3 = 10922 since UTF-8 characters may occupy at most 3 bytes.

二,大小寫敏感?

正則表達式查詢一般是區分大小寫的,有時,我們可能會希望,正則表達式查詢忽略大小寫,在這種情況下,多元欄位(fields)就無法滿足需求了,多元欄位不能執行文本大小寫轉換。為瞭解決這個問題,我們可以新建一個欄位,在更新索引時,把原始文本導入到分析欄位,把相同的數據轉換成小寫形式導入到另一個欄位中,這樣做以後,分析欄位及其派生欄位,用於支持全文搜索和大小寫敏感的正則表達式查詢,另外一個欄位用於忽略大小寫的正則表達式搜索。

 "eventdescription":{  
    "type":"string",
"index":"analyzed", "fields":{ "raw":{ "type":"string",
"index":"not_analyzed" } } }, "eventdescription_lowcase":{ "type":"string",
"index":"not_analyzed" } }

三,存儲控制

為了實現正則表達式查詢,上例為一個數據創建三個欄位,eventdescription、eventdescription.raw和 eventdescription_lowcase,這三個欄位都需要存儲在倒排索引中,ElasticSearch引擎是否使用3倍的容量來存儲這個數據?

預設情況下,一旦欄位值被編入索引,該欄位能夠被搜索,但是,欄位的原始值沒有存儲到倒排索引中,這就意味著,該欄位能夠被搜索,卻不能從倒排索引中獲取該欄位的原始值。通常情況下,這樣設計能夠節省硬碟存儲空間,不會對應用程式有什麼影響,實際上,ElasticSearch引擎把該欄位的原始值存儲在_source元欄位中,預設情況下,_source元欄位是存儲的。

1,存儲屬性(store)

欄位的原始值是否被存儲到倒排索引,是由映射參數store決定的,預設值是false,也就是,原始值不存儲到倒排索引中。在特定的情況下,存儲欄位的原始值是有意義的。例如,為了存儲一篇博客,文檔必須有title,date和一個非常大的正文欄位(content),如果僅僅是獲取title和date,而不用獲取正文欄位,那麼你可以存儲title和date,並把content欄位的store屬性設置為false。

"title":{  
    "type":"string",
    "store":true,
    "index":"analyzed"
},
 "date":{  
    "type":"date",
    "store":true,
    "index":"not_analyzed"
},
 "content":{  
    "type":"string",
    "store":false,
    "index":"analyzed"
}
View Code

映射參數index和store的區別在於:

  • store用於獲取(Retrieve)欄位的原始值,不支持查詢,可以使用投影參數fields,對stroe屬性為true的欄位進行過濾,只獲取(Retrieve)特定的欄位,減少網路負載;
  • index用於查詢(Search)欄位,當index為analyzed時,對欄位的分詞執行全文查詢;當index為not_analyzed時,欄位的原始值作為一個分詞,只能對欄位的原始文本執行詞條查詢;

2,源欄位(_source)

當把原始的JSON文檔傳遞到ElasticSearch引擎時,ElasticSearch引擎使用_source欄位存儲最原始的JSON文檔。_source欄位本身不會被索引,也不會被搜索,但是,該欄位會存儲在倒排索引中,用於返回查詢的結果。

_source欄位會導致索引存儲空間的增加,因此,可以禁用_source欄位,但是,在禁用_source欄位之前,請認真閱讀官方文檔《_source field》。

"mappings": {
    "tweet": {
      "_source": {
        "enabled": false
      }
    }
  }

一般情況下,不要禁用_source欄位,當需要考慮占用的Disk空間時,請有限考慮壓縮存儲,提高壓縮等級。在配置文檔 中,壓縮選項是 index.codec,預設值是LZ4壓縮,設置best_compression 能夠提供更高的壓縮率,代價是降低數據存儲的性能。

四,一個欄位包含所有文本?

為了實現正則表達式查詢,上例為一個數據創建三個欄位,eventdescription、eventdescription.raw和 eventdescription_lowcase,這三個欄位都需要存儲在倒排索引中,通常做法是,同時對這三個欄位執行正則表達式查詢,但是在ElasticSearch中,在編碼上,可以更簡單。元欄位 _all是一個特殊的“包羅萬象”(catch-all)的欄位,把其他欄位的值拼接成一個大的字元串,欄位值之間使用空格分隔。ElasticSearch引擎先分析_all欄位,然後編入索引,但是,預設情況下,不會存儲欄位的原始值,這就意味著,_all欄位能夠被搜索,但是不會返回原始值。_all 欄位把所有欄位的原始值,都視為字元類型,並把欄位的原始值通過分隔符空格拼接在一起。

註意,添加到_all欄位的是原始值,而不是欄位分析之後的詞條(term)。欄位的原始值是否包含到_all欄位,是由該欄位的屬性 include_in_all控制的,預設值是true。啟用_all欄位是需要付出代價的,_all欄位會消耗額外的CPU時鐘周期和更多的硬碟空間,如果不是必需,推薦把_all欄位禁用掉。

"content": { 
     "type": "string""include_in_all": false
},

當把_all欄位禁用之後,用戶可以創建自定義的"_all"欄位:新建一個數據類型為string的欄位,併在需要拼接的欄位中設置屬性“copy_to”。

在ElasticSearch中,每個索引只有一個_all欄位,通過欄位的屬性copy_to能夠創建自定義的"_all"欄位。例如,欄位 first_name和 last_name能夠通過分隔符空格被拼接到一起,作為full_name欄位的值。

{
  "mappings": {
    "mytype": {
      "properties": {
        "first_name": {
          "type":    "string",
          "copy_to": "full_name" 
        },
        "last_name": {
          "type":    "string",
          "copy_to": "full_name" 
        },
        "full_name": {
          "type":    "string"
        }
      }
    }
  }
}
PUT myindex/mytype/1
{
  "first_name": "John",
  "last_name": "Smith"
}

GET myindex/_search
{
  "query": {
    "match": {
      "full_name": "John Smith"
    }
  }
}
View Code

預設情況下,_all欄位不會存儲_source欄位的值,也不會存儲原始值,這是因為_all欄位是其他欄位結合在一起組成的,存儲_all欄位會占用大量的硬碟存儲空間,如果設置_all欄位的屬性store為true,那麼ElasticSearch引擎將會存儲_all欄位的原始值,其原始值也能夠被獲取到。 

五,示例

綜上所述,為了實現正則表達式查詢,為了實現正則表達式的查詢,有兩個設計思路

示例1,原始文本和小寫文本各使用一個欄位

通過bool查詢的should子句,對多個欄位執行正則表達式查詢,當欄位較多,或者欄位的文本特別大時,使用該方式,節省硬碟空間,但是要編寫更多的查詢代碼:

"eventdescription":{  
    "type":"string",
    "index":"analyzed",
    "fields":{  
        "raw":{  
            "type":"string",
            "index":"not_analyzed",
            "ignore_above":10000
        }
    }
},
"eventdescription_lowcase":{  
    "type":"string",
    "index":"not_analyzed",
    "ignore_above":10000
    }
}

示例2,添加冗餘欄位

在冗餘欄位上執行正則表達式查詢,當在多個欄位上執行相同的正則表達式時,使用該方式,便於編程,但是要註意,拼接欄位的大小不能超過限制(32766Bytes):

"eventdescription":{  
    "type":"string",
    "index":"analyzed",
    "copy_to":"eventdescription_regexp"
},
"eventdescription_lowcase":{  
    "type":"string",
    "index":"not_analyzed",
    "copy_to":"eventdescription_regexp"
},
"eventdescription_regexp":{
    "type":"string",
    "index":"not_analyzed"
}
View Code

 

 

參考文檔:

Elasticsearch Reference [2.4] » Mapping » Meta-Fields

Elasticsearch Reference [2.4] » Mapping » Mapping parameters

Elasticsearch Reference [2.4] » Query DSL » Term level queries » Regexp Query

Elasticsearch: The Definitive Guide [2.x] » Search in Depth » Partial Matching » wildcard and regexp Queries


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

-Advertisement-
Play Games
更多相關文章
  • Redis分散式緩存安裝(單節點) Redis官網:http://redis.io 獨立緩存伺服器:IP:xxx.xxx.xxx.xxx 安裝環境:CentOS 6.6 Redis 版本:redis-3.0 (因為 Redis3.0 在集群和性能提升方面的特性,rc 版為正式版的候選版,請在安裝時去 ...
  • 這篇文章是我在網上找到的,感覺不錯就粘過來了,感謝原作者的辛勤總結。 原文鏈接:http://database.51cto.com/art/201407/445934.html 1.對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避 ...
  • R CMD BATCH 和 Rscript 使用前都要先添加環境變數 把 C:\Program Files\R\R-3.3.0\bin; 加到"系統變數"的Path 值的最開始 可以用 R CMD BATCH *.r 也可以用 Rscript *.r args0 args1 這個可以跟一定的參數 當 ...
  • 1、 官網下載mysql5.5 下載地址: http://dev.mysql.com/downloads/mysql/5.5.html#downloads 2、 安裝mysql5.5 註意,安裝之前,請關閉殺毒軟體。 (1) 打開下載的mysql-5.5.53-winx64.msi (2) 點擊下一 ...
  • " 1、靜態數據字典 " "1.1、實用靜態數據字典" "1.2、運用靜態數據字典" " 2、動態數據字典 " "2.1、實用動態性能視圖" "2.2、運用動態性能視圖" " 3、死鎖 " "3.1、定位死鎖" "3.2、解鎖方法" "3.3、強制刪除已連接用戶" " 4、總結 " 數據字典是 Or ...
  • PXC三節點安裝: node1:10.157.26.132 node2:10.157.26.133 node3:10.157.26.134 配置伺服器ssh登錄無密碼驗證 ssh-keygen實現三台主機之間相互免密鑰登錄,保證三台主機之間能ping通 1)在所有的主機上執行: # ssh-keyg ...
  • 背景簡介: 本文為針對一次windows平臺RAC資料庫遷移至Linux平臺RAC的筆記,基本步驟為: 1.搭建windows RAC到Linux 單實例資料庫的DataGuard 2.做switchover,將備庫IP修改為原RAC資料庫的scanip 3.搭建單實例到Linux RAC的Data ...
  • ZooKeeper是一個分散式開源框架,提供了協調分散式應用的基本服務,它向外部應用暴露一組通用服務——分散式同步(Distributed Synchronization).命名服務(Naming Service).集群維護(Group Maintenance)等,簡化分散式應用協調及其管理的難度, ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...