全文搜索引擎 ElasticSearch

ElasticSearch是一個基於Lucene的分佈式多用戶全文搜索引擎,使用Json索引,提供RESTful API,有着極高的實時搜索性能。html

基礎知識

ES主要功能git

  • 全文搜索引擎(倒排索引:根據詞找到 位置&頻次)
  • 數據分析系統(尤爲是時間序列數據的聚合分析)
  • 分佈式實時存儲系統

優勢github

  • 高效的分詞搜索
  • 強大的聚合運算

ES特性算法

  • 集羣由主節點(負責管理集羣全部變動)和普通節點組成
  • 索引被切割爲分片調配到集羣節點上(分片上並存着原始文檔),主分片數在索引建立時即已肯定
  • 副本分片用於實現故障切換,負載均衡(分片的備份套數隨時可變)

索引結構sql

  • 分片、副本等配置
  • Type Mapping配置,包含:
    • 元數據配置
    • 字段域的類型、索引及搜索方式

健康狀態docker

  • 綠色:全部主副分片均正常
  • 黃色:副本分片存在不正常
  • 紅色:主分片有存在不正常

Mysql概念對比

Mysql : ES 關係對比數據庫

  • 數據庫 : 索引 index
  • 表 : 類型 type
  • 行 : 文檔 document
  • 列 : 字段 field
  • Schema : 映射 mapping
  • SQL : DSL

Index VS Type

在具體存儲空間選型時須要考慮一下幾點:json

  • Index由一系列分片組成, 每一個分片即一個Lucene索引實例並存在磁盤,內存,文件句柄的開銷
  • 查詢結果時,ES須要合併全部相關Index下的全部分片的結果集
  • 同Index下的不一樣Type有資源爭用問題
  • 相關性得分在Index範圍內計算, 不一樣類型Type會相互影響判分

存儲空間選型建議:
通常一種文檔數據即佔用一個INDEX空間,除非知足如下條件可考慮TYPE空間數組

  • 兩種文檔有明顯父子關係
  • 兩種文檔有相似的mapping結構
  • 每一個Type下的文檔量級不是特別大

基於Docker安裝

DockerFile:緩存

FROM elasticsearch:2.3.5

# head插件
RUN /usr/share/elasticsearch/bin/plugin install mobz/elasticsearch-head

# IK分詞安裝
RUN mkdir /usr/share/elasticsearch/plugins/analysis-ik \
	&& cd /usr/share/elasticsearch/plugins/analysis-ik \
	&& wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v1.9.5/elasticsearch-analysis-ik-1.9.5.zip \
	&& unzip elasticsearch-analysis-ik-1.9.5.zip \
	&& rm -fr elasticsearch-analysis-ik-1.9.5.zip

鏡像構建與啓動:

  • API服務端口:9200
  • 集羣節點通訊端口:9300
docker build -t test/elasticsearch .
docker run -d -p 9200:9200 -p 9300:9300 --name=es test/elasticsearch

# 檢查插件(應該會羅列head、 analysis-ik兩個插件)
docker exec es bin/elasticsearch-plugin list

訪問:

  • API接口:http://localhost:9200
  • head插件:http://192.168.137.4:9200/_plugin/head

中文分詞

analyzer分析器由如下組成:

  • char_filter字符過濾器
  • tokenizer分詞器
  • filter詞條過濾器

IK分詞:

  • 支持自定義本地詞庫
    • plugins/analysis-ik/config/custom/mydict.dic文件中追加自定義詞條
    • 重啓ES服務
    • 重建相關數據的索引
  • 支持熱更新遠程詞庫
    • plugins/analysis-ik/config/IKAnalyzer.cfg.xml中配置utf-8遠程詞庫remote_ext_dict地址
    • 詞庫地址http頭部需返回Last-Modified、ETag,任一值變更都會觸發IK插件進行詞庫熱更新
    • 常規WebServerclient請求文件的內容發生變動時 會自動更新Last-Modified、ETag兩個頭部信息
  • 可用分詞器
    • ik_smart: 會作最粗粒度的拆分
    • ik_max_word: 會將文本作最細粒度的拆分

測試分詞器

curl -XGET 'http://localhost:9200/索引/_analyze?analyzer=ik&pretty=true&text=xxx'

索引管理

  • 初始化Index curl -XPUT http://localhost:9200/索引
  • 建立Type Mapping
curl -XPUT http://localhost:9200/索引/_mapping/類型 -d'
        {
           "properties": {
              "字段": {
                   "type": "text", #byte、integer、float、string、date、boolean、geo_point、geo_shape、nested(用於嵌套的對象數組)、object(用於對象,對象會被扁平化處理)
                   "index": "analyzed", #analyzed(全文搜索)、not_analyzed(精確值搜索)、no(不可搜索);
                   "analyzer": "ik_max_word",

                    "include_in_all": true, #該字段是否要包含在_all字段中進行搜索
                    "fields": {
                        "子字段1": {
                            "type": "string"
                        }
                    }
               }
           }
        }

        #子字段查詢標識
        字段.子字段1

        # 默認索引模式
        - string類型默認`analyzed`
        - 其餘簡單類型默認`not_analyzed`
  • Index文檔
    • 指定id curl -XPUT http://localhost:9200/索引/類型/id -d'xxx'
    • 自動id curl -XPOST http://localhost:9200/索引/類型 -d'xxx'
  • Index更新 curl -XPUT http://localhost:9200/索引/類型/id -d'xxx'
  • Index刪除 curl -XDELETE http://localhost:9200/索引
  • 檢索文檔 curl -XGET http://localhost:9200/索引/類型/id

基本查詢

curl -XGET http://localhost:9200/索引/類型/_search?查詢字符串

查詢字符串:

  • q匹配參數q=xxx:yyy
    • 若是q參數沒有指定字段,則查詢 _all 字段(全部字段值拼接成的大字符串)
    • +追加匹配條件,-追加不匹配條件
  • sort排序參數 sort=字段:desc|asc
    • sort可指定屢次

複合查詢

DSL請求體形式 curl -XPOST http://localhost:9200/_search -d'DSL請求體' (注意請求類型是post)

DSL請求體

  • 空查詢 {}
  • DSL查詢表達式 {query:查詢表達式, sort:排序, from:起始數, size:每頁文檔數}

查詢模式

  • filters過濾模式:高效 不評分查詢(結果緩存)
  • queries搜索模式:低效 評分查詢(結果不緩存) 通常query前先filter來縮減查詢規模

查詢表達式

  • 單一查詢語句
    • 不指定字段 {查詢方法: 值}
    • 指定了字段 {查詢方法: {字段:值}}
  • bool合併查詢語句
{
	    bool:{
		    合併關係: 查詢語句 或 [查詢語句],
		    ...
	    }
	}

查詢語句合併關係
每一個子查詢有本身的評分,在bool時合併評分,如下每一個合併關係每一個bool的直接下級中只能調用一次

  • filter 必須匹配(不評分模式的過濾)
  • must 必須匹配(評分模式的搜索)
  • must_not 必須不匹配
  • should 但願匹配(匹配其一則加分,用於修正相關性)
  • minimum_should_match 指定should方式的最小匹配次數
    bool查詢若只有filter則可替換爲constant_score查詢,從而使評分爲常量值

常見查詢語句

  • match_all 匹配全部文檔(默認查詢方法){match_all: {}}
  • match 標準查詢(字段配置決定全文或精確查詢){match: {字段: 值}}
  • multi_match 多字段匹配 {multi_match: {query:值, fields:[字段1, ...]}}
  • range 區間查詢 {range: {字段:{gte:最小值,lt:最大值}}}
  • term 精確值查詢 {term: {字段:值}}
  • terms 多值精確查詢(等於其一就行){terms: {字段:[值1,...]}}
  • exists、missing 字段有值判斷 {exists: {field:字段}}
  • nested 嵌套查詢 {nested: {path:上級字段, query:查詢表達式}}

注意

  • term 和 terms 是 包含(contains) 操做,而非 等值(equals),即 { "term" : { "tags" : "search" } } 能夠匹配字段 { "tags" : ["search", "open_source"] }
  • 參考 https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/finding_multiple_exact_values.html#%E5%8C%85%E5%90%AB_%E8%80%8C%E4%B8%8D%E6%98%AF%E7%9B%B8%E7%AD%89

查詢調試

  • 校驗語法:curl -XGET http://localhost:9200/索引/類型/_validate/query -d{}
  • 解釋校驗:curl -XGET http://localhost:9200/索引/類型/_validate/query?explain -d{}
  • 解釋評分
    • 面向常規查詢:curl -XGET http://localhost:9200/_search?explain&format=yaml -d{}
    • 面向指定文檔:curl -XGET http://localhost:9200/索引/類型/ID/_explain -d{}

查詢排序

默認相關性得分降序排列 curl -XGET http://localhost:9200/索引/類型/_search -d'{query:查詢表達式, sort:排序, from:起始數, size:每頁文檔數}'

查詢結果集排序:

  • 單字段排序
    • 排序字段單值 {字段: {order:desc|asc}}
    • 排序字段多值 {字段: {order:desc|asc, mode:歸一模式}}
      • 歸一模式:min、max、avg、sum、
    • index:analyzedString會被ES處理成多值字段
  • 多字段排序 [{字段1: {order:desc|asc}}, ...]

注意:

  • 儘可能在index:not_analyzed字段上進行排序
  • 然而在index:analyzed字段上排序極耗內存

查詢高亮

請求結構 curl -XGET http://localhost:9200/索引/類型/_search -d'{query:查詢表達式, highlight:高亮表達式}'

高亮表達式:

{
    pre_tags : [<tag1>],
    post_tags : [</tag1>],
    fields : {
        _all: {
            pre_tags : [<tag1>],
            post_tags : [</tag1>],
            fragment_size: 100,  #匹配片斷長度
            number_of_fragments: 5,  #匹配片斷數
            no_match_size: 0,  #無匹配狀況下文本長度
        }
        field1 : {}
    }
}

聚合查詢

請求體

curl -XGET http://localhost:9200/索引/類型/_search -d
{
	size:0, #設置查詢結果集數目爲0提升聚合查詢速度
	query:查詢表達式,
	aggs:聚合表達式,
}

聚合表達式

{
	聚合名1:{
		聚合方法:{field:字段}
		
		global:{}, #聲明在全局桶下聚合(聚合運算基於所有文檔)
		aggs:嵌套聚合表達式(僅桶類聚合下面能夠增長嵌套聚合)
	},

	...
}

聚合構成
一個聚合的每一個 層級 均可以有多個度量或桶

  • Buckets桶 - 足特定條件的文檔的集合
  • Metrics指標 - 桶內的文檔進行統計計算

聚合方法

  • Buckets桶類(輸出桶集,桶內包含統計量)
    • terms 惟一詞項分桶(俗稱facet特性,高效統計指定層面下各種目約束下的統計量)
    • histogram 數值序列分桶
      • interval: 間隔數值
    • date_histogram 時間序列分桶
      • interval: year|quarter|month|day ...
      • format: yyyy-MM-dd
  • Metrics指標類(輸出度量值)
    • min 最小字段值
    • max 最大字段值
    • avg 平均字段值
    • sum 求和字段值
    • stats 字段統計值彙總(包括count、min、max、avg、sum)
    • extended_stats 拓展的字段統計值彙總(stats基礎上追加 sum_of_squares平方和、variance方差、std_deviation標準差)

分桶聚合通用參數

  • min_doc_count 指定爲0則強制空桶也被返回
  • extended_bounds 擴展分桶的上下限

GEO查詢

距離算法distance_type

  • arc 最慢但最精確(球體地球角度)
  • plane 精度性能居中(平坦地球角度)
  • sloppy_arc 最快但最偏差(比arc快四五倍,精度99.9%)

圈過濾

{
    geo_distance:{
        distance:1km,
        distance_type:距離算法,
        location位置字段:{
            lon:對比經度
            lat:對比緯度
        }
    }
}

環過濾

{
    geo_distance_range:{
        gte:1km,內徑
        lte:1km,外徑
        distance_type:距離算法,
        location位置字段:{
            lon:對比經度
            lat:對比緯度
        }
    }
}

排序

{
    _geo_distance:{
        location位置字段:{
            lat:對比緯度,
            lon:對比經度
        },
        nested_path:可選的nest路徑,
        order:desc|asc,
        unit:km,
        distance_type:距離算法
    }
}

返回結果中,每一個條目的sort字段首個值即爲相對距離/m

完整示例

{
    index: my_index,
    body: {
        query: {
            bool: {
                must: [ #評分模式的搜搜匹配
                    {match: {字段: 值}},
                    ...
                    {nested: {
                        path:上級字段,
                        query: {
                            bool: {
                                must: [
                                    {match: {上級字段.該級字段: 值}},
                                    ...
                                ]
                            }
                        }
                    }}
                ],
                filter: [ #不評分模式的過濾
                    {term: {字段:值}},
                    {range: {字段:{gte:最小值,lt:最大值}}},
                    ...
                    {
                        geo_distance:{
                            distance:1km,
                            distance_type:距離算法,
                            location位置字段:{
                                lon:對比經度
                                lat:對比緯度
                            }
                        }
                    }
                ],
            }
        },
        
        from: 100,
        
        size: 50,

        sort: [
            {排序字段: {order: desc}},
            ...
            {_geo_distance:{
                location位置字段{
                    lon:對比經度
                    lat:對比緯度
                },
                order:asc,
                unit:km,
                distance_type:距離算法
              }
            }
        ],
        
          highlight: {
            {
                fields : {
                    myField: {
                        pre_tags : [<tag1>],
                        post_tags : [</tag1>],
                        fragment_size: 100,  #匹配片斷長度
                        number_of_fragments: 5,  #匹配片斷數
                        no_match_size: 0,  #無匹配狀況下文本長度
                    }
                }
            }
          },

        aggs: {
            聚合名: {
                term: {field: 字段名},
                ...
                aggs: {
                    mySum: {sum: {field:字段名}}
                }
            },
            ...
        },
    }
}

數據建模

關聯關係設計

  • 應用層關聯 mapping:獨立 優缺點:相似於關係型數據庫的標準設計,查詢性能較差 查詢:人工組織關聯查詢
  • 非規範化文檔(適用單個子對象) mapping:共用(子對象:object類型字段,也是字段默認自動映射類型) 文檔結構:冗餘文檔結構,被扁平化爲鍵值結構 優缺點:查詢效率較高,可是文檔索引過大 查詢:使用點語法查詢子對象字段
  • 嵌套對象文檔(適用多個子對象) mapping:共用(子對象:nested類型字段) 文檔結構:冗餘文檔結構,每個嵌套對象都會被索引爲一個隱藏的獨立文檔 優缺點:查詢效率較高,可是文檔索引過大 查詢:使用nested語法查詢子對象字段
  • 父子關係文檔 mapping:獨立 文檔結構:父對象和子對象都是徹底獨立的文檔 優缺點:索引效率較高,可是查詢效率較低 查詢:使用has_child、has_parent語法查詢父子對象字段

擴容設計

  • 待定
相關文章
相關標籤/搜索