ES-基本原理及架構


一、全文檢索與ES

(一)全文檢索

  數據可以分為結構化數據和非結構化數據,比如說我們常用的sql語句就都是操作結構化數據,郵件等信息都是非結構化數據;

    對於結構化數據的查詢可以使用sql語句進行查詢,速度較快;

    對於非結構化數據的查詢可以把非結構化數據變成結構化數據:先根據空格進行字符串拆分,得到一個基礎的單詞列表。需要去掉標點符號、轉換大小寫、去除停用詞、重復的單詞只記錄一次,就得到了一個最終的單詞列表。然后基於單詞列表創建一個索引。查詢時直接查詢索引,找到關鍵詞后根據關鍵詞和文檔的對應關系,找到文檔列表。這個過程就是全文檢索的過程。

  全文檢索的場景有:搜索引擎、站內搜索、系統文件搜索

  全文檢索技術有:

    Lucene:使用該技術需要對Lucene的API和底層架構非常了解,而且需要編寫大量的JAVA代碼

    Solr:使用JAVA實現一個web應用,可以使用rest方式的http請求,進程遠程API調用

    ElasticSearch(ES):可以使用rest方式的http請求,進行遠程API調用

  全文檢索可以分為兩大步驟:創建索引和搜索索引

    

    1、創建索引:

      1)獲得原始文檔

        原始文檔就是待搜索的文檔。
          搜索引擎:原始文檔就是整個互聯網的網頁
          電商搜索:數據庫中的商品數據
          站內搜索:微博搜索,微博的數據。
        如何獲得原始文檔:
          搜索引擎:使用爬蟲程序
          電商搜索:使用jdbc查詢數據庫
          站內搜索:數據庫中的數據
      2)需要對應每個原始文檔創建一個Document對象
        Document對象是對原始文檔的封裝,需要使用Field對象保存原始文檔的屬性。例如:描述一個文件,需要有文件名稱、文件的內容、文件的路徑、文件的大小……
        Field:叫做字段或者域。field由兩部分組成:名稱和內容
        一個Document中可以有多個Field,不同的Document中可以有不同的Field。
      3)分析文檔
        field中包含文件的相關屬性,其中有些field是需要分詞的。
        對需要分詞的field的內容進行分詞處理:
          1)字符串拆分
          2)去除標點符號
          3)轉換大小寫
          4)去除停用詞
        最終得到一個單詞列表。單詞列表中每個單詞需要封裝成一個Term對象。
          term中包含兩部分內容:term所在的field的名稱關鍵詞本身
        基於Term創建索引。

        注意:不是所有的field都需要分詞
      4)創建索引
        基於上一步得到的單詞列表創建索引,然后把索引和文檔以及關鍵詞和文檔的對應關系保存到磁盤。
        索引庫中包含的內容:索引、文檔和索引與文檔的對應關系

    2、搜索索引:

      1)用戶交互接口:接收到用戶輸入的查詢內容。

      2)把查詢內容封裝:封裝成一個Query對象,其中包含要查詢的內容以及要查詢的field。
      3)根據關鍵詞到索引上查詢:迅速的定位到一個關鍵詞,根據關鍵詞和文檔對應關系找到文檔列表。
      4)根據文檔的id列表取文檔對象:得到一個文檔列表,把文檔列表展示給用戶。

  索引庫結構:索引庫分為索引域和文檔域,索引域里面存儲的是term字典和文檔的倒排索引,文檔域存儲的就是document。

          

(二)ElasticSearch

  ElasticSearch是一款開源的高擴展分布式全文檢索引擎。其是使用JAVA開發並使用Lucene作為核心來實現所有索引和搜索功能的。

    ES與Lucene對比:ES通過簡單的Restful API來隱藏Lucene的復雜性,從而讓全文檢索變得簡單。

    ES與Solr對比:Solr是通過ZK進行分布式管理的,而ES自身帶的有分布式協調管理功能;Solr支持更多格式的數據,ES只支持Json格式的數據;Solr在傳統搜索應用中表現好於ES,但是在處理實時搜索應用時效率明顯低於ES,因為Solr創建索引時,會產生IO阻塞。

二、ES概念與架構

(一)概念

  ES不僅僅是存儲,還會索引整個文檔的內容讓其可以進行搜索,在ES中,可以對文檔進行索引、搜索、排序、過濾等操作。

  ES的概念有索引index、類型type、文檔document、字段field和映射mapping

  1、索引index

    索引可以看作是MySQL中的數據庫,一套數據可以使用一套索引。

    一個索引由一個名字來標識,名字必須全部是小寫字母,當我們對這個索引中文檔進行索引、搜索、更新和刪除的時候,都需要使用這個名字。

  2、類型type

    類型類似與MySQL中的表,在一個索引中可以創建多個type。這個在es7及以后已經被廢棄,只有_doc。

  3、文檔document

    文檔類似MySQL中的一條數據,存儲的是具體的數據,存儲格式為Json

  4、字段field

    相當於MySQL中的字段。

  5、映射mapping

    mapping對處理數據方式和規則做的一些限制,如某個字段的數據類型、默認值、分析器、是否被索引等

(二)架構

    

   ES的架構總體如上圖所示,從下到上分為網關、搜索引擎、四大組件、自動發現、通信和Restful API

  1、Gateway網關

    其作用是用來對數據進行持久化以及ES重啟后重新恢復數據。

    es支持多種類型的gateway,有本地文件系統、分布式文件系統、Hadoop的HDFS等。

    其存儲的信息包括索引信息、集群信息、mapping等

  2、districted lucene directory搜索引擎

    Gateway上層就是Lucene的分布式檢索框架。

    ES是分布式的搜索引擎,雖然底層用的是Lucene,但是需要在每個節點上都運行Lucene進行相應的索引、查詢、更新等操作,所以需要做成一個分布式的運行框架來滿足業務需要。

  3、四大組件模塊

    districted lucene directory之上就是ES的四大模塊。

    Index Model:索引模塊,對數據建立索引(通常是建立倒排索引)

    Seacher Model:搜索模塊,就是對數據進行查詢搜索

    Mapping Model:是數據映射與解析模塊,數據的每個字段可以根據建立的表結構通過mapping進行映射解析;如果沒有建立表結構,那么ES會根據數據類型來推測數據結構,並自動生成一個mapping,然后根據mapping進行解析

    River Model:在es2.0之后被取消了,表示可以使用插件處理。例如可以通過一些自定義腳本將傳統數據庫的數據實時同步到es中。

  4、自動發現Discovery Script

    es集群中各個節點通過discovery相互發現的,默認使用的是Zen。es是一個基於p2p的系統,他先通過廣播尋找存在的節點,再通過多播協議來進行節點之間的通信,同時也支持點對點的交互。

    es還可以支持多種script腳本語言,例如mvel、js、python等。

  5、通信(Transport)

    代表es內部節點或集群與客戶的交互方式,默認內部使用tcp協議進行交互,同時其還支持http協議,thrift、servlet、memcached、zeroMQ等通信協議。

    節點間通信端口默認9300-9400

  6、Restful接口

    最上層就是ES暴漏給我們的訪問接口。 

三、Restful訪問ES

  使用Restful訪問ES的方式:curl X<VERB> <PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>d <BOD

  其中VERB是請求方式(post、get....),PROTOCOL是協議(http、https......),HOST和PORT是es的ip和端口,PATH是API的終端路徑,QUERY_STRING表示任何可選的查詢字符串參數(例如@pertty將格式化的輸出JSON格式),BODY是一個Json格式的請求體。

  1、創建索引和mapping映射(PUT  ip:9200/test)

{
    "settings":{
        "index":{
            "number_of_shards":"5",
            "number_of_replicas":"1"
        }
    },
    "mappings":{
        "_doc":{
            "properties":{
                "orderId":{
                    "type":"long",
                    "store":true,
                    "index":true
                },
                "orderName":{
                    "type":"text",
                    "store":true,
                    "index":true,
                    "analyzer":"standard"
                },
                "content":{
                    "type":"text",
                    "store":true,
                    "index":true,
                    "analyzer":"standard"
                }
            }
        }
    }
}

    也可以先設置索引,然后再設置mapping,設置mapping的路徑:post  ip:9200/test/_doc/_mapping,參數與上面設置mapping的參數一樣

{
    "_doc":{
        "properties":{
            "orderId":{
                "type":"long",
                "store":true
            },
            "orderName":{
                "type":"text",
                "store":true,
                "index":true,
                "analyzer":"standard"
            },
            "content":{
                "type":"text",
                "store":true,
                "index":true,
                "analyzer":"standard"
            }
        }
    }
}

    這里需要特殊說明一下,如果是es5及以前的版本,type可以隨意定義,如果是es6,一個索引庫中只能有一個type,如果是es7,一個索引庫只能有一個type,且必須為“_doc”,其實Lucene是沒有type這個概念的。

    對field屬性:

      type:數據類型,如果是text,就一定會分詞,如果是keyword,就不會分詞

      store:是否存儲原始數據,取決於是否要展示給用戶看,但是不影響分詞和索引

      index:是否要把當前field的內容添加到索引中,如果分詞,就一定要索引,不分詞也可以索引(例如身份證號或訂單號)

      analyzer:具體的分詞器,如果不寫,則使用默認分詞器

  2、刪除索引

    直接使用:delete  ip:9200/test

  3、document處理

    對於文檔的操作,都是:ip:9200/test/_doc/123(其中test為index,_doc為type,123為document的id),post請求表示增改操作,delete請求表示刪除操作,get請求表示查詢操作。其中只有post請求需要傳遞參數,也就是設置document的參數。

{"orderId":123,"orderName":"123的測試訂單號","content":"修改隨便寫一個進行測試"}

四、查詢表達式(Query DSL)

  1、查詢全部

    請求地址:post  ip:9200/_search  查詢可以添加索引或type進行查詢:ip:9200/test/_doc/123

    請求參數:{"query":{"match_all":{}}}

  2、term查詢    

    請求地址:post  ip:9200/test/_doc/_search

    請求參數:{"query":{"term":{"orderName":"123"}}}

      

  3、queryString查詢

    請求地址:post  ip:9200/test/article/_search

    請求參數:{"query":{"query_string":{"default_field":"orderName","query":"123"}}}

  4、multi_match查詢

    請求地址與上面一樣,參數可以設置多個field進行查詢:{"query":{"multi_match":{"query":"123","fields":["orderId", "orderName"]}}}

  5、bool查詢

    布爾過濾器,其是一個符合過濾器,可以結果多個其他過濾器作為參數,並將這些過濾器組合成各式各樣的布爾組合。

{
    "bool":{
        "must":[],
        "should":[],
        "must_not":[],
        "filter":[]
    }
}

    如上所示,一個布爾查詢由must、should、must_not、filter四部分組成。

      must:必須為真,才會被匹配到

      should:查詢列表中,只要有一個為真,就會被匹配到

      must_not:所有必須都不為真,才會被匹配到

      filter:對數據進行過濾,filter可以是多個

    以下是示例:

{
    "query":{
        "bool":{
            "must":{
                "query_string":{
                    "query":"李四",
                    "default_field":"name"
                }
            },
            "should":{
                "term":{
                    "address":"上海"
                }
            },
            "filter":{
                "query_string":{
                    "query":"",
                    "default_field":"sex"
                }
            }
        }
    }
}

五、IK分詞器和ElasticScher集成使用

(一)使用標准分詞器存在的問題  

  在查詢數據時,在orderName中使用123就可以查詢成功,但是使用”測試“去查詢,就查詢不到數據。這是因為在創建索引的時候,使用了標准分詞器導致。

          

   可以使用:post  ip:9200/_analyze查看分詞結果,如下圖所示,可以看到,中文都被分成了一個一個漢字。

        

 (二)使用IK分詞器

  安裝IK分詞器,安裝地址:https://github.com/medcl/elasticsearch-analysis-ik/releases,這里需要注意一樣,ES的版本要和IK分詞器的版本對應,如果不對應,ES啟動不起來。

./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.4/elasticsearch-analysis-ik-6.2.4.zip

  版本不一致啟動出現的異常信息

      

  訪問IK分詞器查看分詞效果:post  ip:9200/_analyze,里面只需要傳入analyzer和text,其中text為測試分詞的文本,analyzer在IK分詞器中有ik_smart和ik_max_word兩種,分別是最少切分和最細力度切分。

       

 

   然后使用IK分詞器創建索引:"analyzer":"ik_max_word",然后用中文詞組搜索,就可以搜索到了。

      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM