Elasticsearch,為了搜尋

Macken發表於2016-09-06

Elasticsearch是一個基於Apache Lucene(TM)的開源搜尋引擎。無論在開源還是專有領域,Lucene可以被認為是迄今為止最先進、效能最好的、功能最全的搜尋引擎庫。

但是,Lucene只是一個庫。想要使用它,你必須使用Java來作為開發語言並將其直接整合到你的應用中,更糟糕的是,Lucene非常複雜,你需要深入瞭解檢索的相關知識來理解它是如何工作的。

Elasticsearch也使用Java開發並使用Lucene作為其核心來實現所有索引和搜尋的功能,但是它的目的是通過簡單的RESTful API來隱藏Lucene的複雜性,從而讓全文搜尋變得簡單。

如果沒有搜尋引擎,單單憑藉Mysql提供的簡單搜尋功能,無論在效能還是效果上都不盡如人意,繼承程式猿的折騰屬性,決定將自己的部落格插上Elasticsearch的翅膀。

安裝 Oracle JDK

sudo apt-get update
sudo apt-get install openjdk-8-jdk

安裝 Elasticsearch

  • 下載

    wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-2.3.4.deb    
    sudo dpkg -i elasticsearch-2.3.4.deb

    目前ElasticSearch的中文分詞外掛IK最高版本為1.9.4,相容Elasticsearch的2.3.4版本。

  • 安裝
    sudo dpkg -i elasticsearch-2.3.4.deb
  • 開機自啟動
    sudo update-rc.d elasticsearch defaults 95 10
    sudo service elasticsearch start
  • 測試
    curl http://localhost:9200

你如果你看到以下資訊,說明你的ElasticSearch已安裝成功。

{
    "name" : "Peter Petruski",
    "cluster_name" : "elasticsearch",
    "version" : {
        "number" : "2.3.4",
        "build_hash" : "...(隱藏)",
        "build_timestamp" : "2016-06-30T11:24:31Z",
        "build_snapshot" : false,
        "lucene_version" : "5.5.0"
    },
      "tagline" : "You Know, for Search"
}

預設情況下 Elasticsearch 的 RESTful 服務只有本機才能訪問,也就是說無法從主機訪問虛擬機器中的服務。為了方便除錯,可以修改 /etc/elasticsearch/config/elasticsearch.yml檔案,加入以下兩行:

network.bind_host: “0.0.0.0"
network.publish_host: \_non_loopback:ipv4_

安裝中文分詞外掛 IK

Elasticsearch原裝分詞器會簡單地拆分每個漢字,沒有根據詞庫來分詞,這樣的後果就是搜尋結果很可能不是你想要的。這裡推薦使用elasticsearch-analysis-ik,支援自定義詞庫。

  • 下載
    wget https://github.com/medcl/elasticsearch-analysis-ik/archive/v1.9.4.tar.gz
  • 解壓
    tar -xvf elasticsearch-analysis-ik.tar.gz
  • 使用maven打包該java專案
    cd elasticsearch-analysis-ik-1.9.4
    mvn package
  • 在plugins目錄下建立ik目錄,並將打包好的IK外掛解壓到其中
    mkdir /usr/share/elasticsearch/plugins/ik
    unzip target/releases/elasticsearch-analysis-ik-1.9.4.zip -d /usr/share/elasticsearch/plugins/ik/

    elasticsearch-analysis-ik 的配置檔案在 ~/{es_root}/plugins/ik/config/ik/ 目錄,很多都是詞表,直接用文字編輯器開啟就可以修改,改完記得儲存為 utf-8 格式。

現在再啟動 Elasticsearch 服務,如果看到類似下面這樣的資訊,說明 IK Analysis 外掛已經裝好了

plugins [analysis-ik]

使用 Elasticsearch

在使用之前,先大概瞭解下ES的特點:

網上通常會將Elasticsearch和傳統關係型資料庫Mysql做一下類比:

MySQL Elasticsearch
Database(資料庫) Index (索引)
Table(表) Type (型別)
Row (行) Document (文件)
Column (列) Field (欄位)
Schema (方案) Mapping (對映)
Index (索引) Everything Indexed by default (所有欄位都被索引)
SQL (結構化查詢語言) Query DSL (查詢專用語言)

Elasticsearch不僅僅是全文搜尋:

  • 分散式的實時檔案儲存,每個欄位都被索引並可被搜尋
  • 分散式的實時分析搜尋引擎
  • 可以擴充套件到上百臺伺服器,處理PB級結構化或非結構化資料

分散式實時每個欄位PB級,有點不明覺厲~ 不要慌,剛認識不熟悉很正常,慢慢接觸,自然就熟絡了,stop getting off track(迴歸正題),想要詳細認識ES,請移步Elasticsearch權威指南,接下來就是一步步將ES整合進專案當中:

1. 使用package

可以直接使用官方提供的package,由於不想花時間重複造輪子,我直接使用進一步封裝的第三方package。在github上有好幾個可用的,我選了Elasticquent,部分是因為名字和laravel的Eloquent比較搭(笑...)。Elasticquent提供了簡潔好用的trait,直接整合進你的Model裡,例如Article:

...
use Elasticquent\ElasticquentTrait;

class Article extends Model
{
    use ElasticquentTrait;
        ...
}

然後就可以優雅的使用Elasticsearch了,具體如何安裝使用,請參考Elasticquent的說明文件。

2. 配置Mapping

關於Mapping(對映),我找到了一篇專門介紹它的文章(傳送們),通俗易懂。

文章中提到,mapping不僅告訴ES一個field中是什麼型別的值, 它還告訴ES如何索引資料以及資料是否能被搜尋到。

Got it! 也就是說,如果我們不配置mapping,那ES就不會知道我們是想讓它按照IK的分詞方式來進行索引咯~

到這裡,不得不說這是一個坑,目前網上的很多資料因為使用的是老版本的ES和IK,所以index和mapping的配置一般都放在es的配置檔案yml當中。但我按照那種配置方法,並沒有達到預期的分詞效果,ES還是簡單粗暴的將漢字一個個的切開,屢敗屢戰折騰兩天之後,終於想到試著使用Elasticquent說明文件裡在Model中配置mapping的方式,果然,豁然開朗:

curl -XGET 'http://localhost:9200/_analyze?analyzer=ik&pretty=true&text=%e4%bd%a0%e5%a5%bd%e9%ba%a6%e8%82%af%e5%85%88%e7%94%9f'
{   
    "tokens" : [ {
        "token" : "你好",
           "start_offset" : 0,
        "end_offset" : 2,
        "type" : "CN_WORD",
        "position" : 0
    },
    {
        "token" : "麥",
        "start_offset" : 2,
        "end_offset" : 3,
        "type" : "CN_WORD",
        "position" : 1
    }, {
        "token" : "肯",
        "start_offset" : 3,
        "end_offset" : 4,
        "type" : "CN_WORD",
    "position" : 2
    }, {
        "token" : "先生",
        "start_offset" : 4,
        "end_offset" : 6,
        "type" : "CN_WORD",
        "position" : 3
    }]
}

附上我的mapping配置程式碼

protected $mappingProperties = array(
   'title' => array(
        'type' => 'string',
        'analyzer' => 'ik_max_word'
    ),
   'content' => array(
        'type' => 'string',
        'analyzer' => 'ik_max_word'
    )
);

可以看出,我告訴ES,我的title和content欄位是string型別而且請按照ik的分詞方式幫我檢索。

3. 建立索引

直接使用Elasticquent提供的createIndex方法建立,如果想把現有文件全部索引,可以使用addAllToIndex方法,簡單愉快。

Article::createIndex($shards = null, $replicas = null);
Article::addAllToIndex();

4. 增刪改查

在你的控制器裡的增刪改查方法中,將Elasticquent提供的相應操作索引的方法依次加上即可,完成之後,那麼你對文件的操作就會同步ES的索引了。具體程式碼請直接移步Elasticquent開源專案中trait裡的程式碼就好,這裡不再貼出。

寫在最後

在此之前,瞭解過sphinx,使用過配置好的xunsearch,但真正自己從零開始研究全文搜尋引擎還是頭一次,中間遇到了許多坑,雖然被坑鬱悶,但也感謝這些坑,畢竟越過去就會有快感。寫這篇文章一來作為紀念和起點,二來希望能多少對別人有點幫助,因為我也是看過好多相關的文章才一點點將ES搭建完成,在這裡感謝那些樂於分享的前輩。

當然,Elasticsearch功能很強大,各種外掛各種配置,這篇文章需要完善的地方還有很多,後期會不斷更新,如果文中有錯誤或者不嚴謹的地方,歡迎留言交流。

PS. 最後貼出我專案中的Dockerfile,方便感興趣的同學使用。

原文連結:https://macken.me/article/elasticsearch-for-search

參考資料

相關文章