1. 程式人生 > >那些年,我爬過的北科(十)——搜尋案例之ElasticSearch的使用

那些年,我爬過的北科(十)——搜尋案例之ElasticSearch的使用

為什麼要用ElasticSearch?

一般來說資料庫都會自帶模糊搜尋的功能,但其實上真正使用的時候,遇到中文搜尋這種問題時,搜尋速度會非常慢,可能會需要O(n)或者O(logn)的複雜度。

在實際使用中,這是不允許的,因為使用者就搜尋一條語句。假設n非常大的話,等待時間可能會非常的久。所以肯定需要使用索引機制,加速搜尋效率。

搜尋引擎使用的是倒排索引,建立好索引後,可以在O(c)的時間完成搜尋功能。不過這步只是一個粗略的查詢,還要對搜尋的結果進行排序,這裡可能會用到如BM25Query Likelihood Model等給文件打分的方法,通過打分對搜尋結果進行排序。

如果我們自己去實現這些功能的話,首先可能要學學什麼是倒排索引,還有文件的打分的各種方法,再加上程式碼,要用起來不知道要到哪年哪月了。而ElasticSearch將這些操作變得非常簡單。它是一個基於Lucene的搜尋伺服器,它提供了一個分散式多使用者能力的全文搜尋引擎,基於RESTful web介面。

下面我們將要講解如何使用ElasticSearch構建我們的帖子搜尋。

ElasticSearch安裝

“工欲善其事,必先利其器”,我們這裡先講解一些ElasticSearch的安裝步驟,下面的操作是在mac系統上進行的。因為ElasticSearch是基於Java開發的,Java本身是跨平臺的,所以其他系統上面其實操作都是基本一樣的。

ElasticSearch安裝

這裡首先安裝JDK,然後下載安裝ElasticSearch-6.0.0版本。

下載解壓後,我們可以看到這裡有一個bin資料夾。

bin資料夾裡都是ElasticSearch相關操作的指令碼。我們把ElasticSearch的bin

目錄新增到PATH中,之後在終端中就不需要輸入絕對路徑了。

export PATH=$HOME/ProgramFiles/elasticsearch-6.0.0/bin:${PATH}
複製程式碼

ik分詞工具的安裝

因為我們做的是中文搜尋,而ElasticSearch自帶的中文分詞做的不好,所以這裡需要使用到ik的一個外掛。使用以下命令安裝即可。

elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.0.0/elasticsearch-analysis-ik-6.0.0.zip
複製程式碼

Python庫的安裝

最後,我們因為要使用python操作ElasticSearch,通過pip命令安裝ElasticSearch的API庫。

pip install elasticsearch
複製程式碼

服務啟動

在建立索引之前,我們要先開啟ElasticSearch服務。在終端輸入elasticsearch命令即可。

啟動後可以看到ElasticSearch服務監聽了本地的9300埠。

索引構建

接下來,我們來看看如何建立索引。

建立Mappings

首先像資料庫一樣,我們先建立一個索引。這裡我們管它叫:tiezi_index。在建立索引的過程中,要配置對映一個Mappings(對映)。

我們先來看下程式碼:

from elasticsearch import Elasticsearch

es = Elasticsearch()

# 初始化索引的Mappings設定,只有一個欄位: 標題。
index_mappings = {
  "mappings": {
    "tiezi": {
      "properties": {
        "title": {
            "type": "text",
            "analyzer": "ik_max_word",
            "search_analyzer": "ik_max_word"
        },
      }
    },
  }
}

if es.indices.exists(index='tieba_index') is not True:
    print("create tieba_index")
    es.indices.create(index='tieba_index', body=index_mappings)
複製程式碼

這裡主要看一下index_mappings這個變數,在Mappings下面是一個Type(型別),這裡Type的名稱我起名為:tiezi。Type其實就類似於mongodb中集合的概念,是對文件分割槽的。

對於tiezi這個型別,還要配置一下它所包含的屬性。由於我們的帖子只爬取了標題,所以只有一個title就好了。

可以看到在title欄位裡面還有東西,這裡指定了title是文字型別,並且使用ik分詞工具進行分析索引。

索引資料

完成對映後,我們開始把所有資料進行索引。這裡只需要遍歷一遍我們爬的帖子資料,然後索引到ElasticSearch裡就好了。

def init_collection():
    client = pymongo.MongoClient(host="localhost", port=27017)
    db = client['tieba']
    return db["beike"]

coll = init_collection()

for tiezi in coll.find():
    _id = str(tiezi["_id"])
    doc = {
        "id": _id,
        "title": tiezi["title"]
    }
    print(doc)
    res = es.index(index="tieba_index", doc_type="tiezi", id=_id, body=doc)
    print(res)
複製程式碼

這裡索引需要花一定的時間,耐心等待即可。

搜尋測試

最後,我們進行一下搜尋測試。搜尋直接可以呼叫search即可。搜尋的返回結果是字典型別。

from elasticsearch import Elasticsearch


def search(query):
    query_contains = {
        'query': {
            'match': {
                'title': query,
            }
        }
    }
    es = Elasticsearch()
    searched = es.search("tieba_index", doc_type="tiezi", body=query_contains, size=20)

    return searched


for res in search("假期都做什麼呢")["hits"]["hits"]:
    print(res["_source"]["title"], res["_score"])
複製程式碼

我們這裡可以列印一下,搜尋出來的標題和搜尋的得分(預設是BM25得分)。

結束語

到這裡,本系列教程的所有內容都結束了。網路爬蟲是一個非常實踐的應用,在真正爬取資料時,可能會遇到各種各樣的問題。從資料儲存、反反爬蟲以及演算法上可能都要踩很多坑。

本系列教程力求能夠從淺入深的講解網路爬蟲,儘可能覆蓋到爬蟲所涉及的內容的方方面。當然有些部分也會比較粗糙,只是大概提了一句。希望通過本系統教程,能讓讀者能夠對爬蟲有一個巨集觀的認識與瞭解。