那些年,我爬過的北科(十)——搜尋案例之ElasticSearch的使用
為什麼要用ElasticSearch?
一般來說資料庫都會自帶模糊搜尋的功能,但其實上真正使用的時候,遇到中文搜尋這種問題時,搜尋速度會非常慢,可能會需要O(n)或者O(logn)的複雜度。
在實際使用中,這是不允許的,因為使用者就搜尋一條語句。假設n非常大的話,等待時間可能會非常的久。所以肯定需要使用索引機制,加速搜尋效率。
搜尋引擎使用的是倒排索引
,建立好索引後,可以在O(c)的時間完成搜尋功能。不過這步只是一個粗略的查詢,還要對搜尋的結果進行排序,這裡可能會用到如BM25
、Query 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得分)。
結束語
到這裡,本系列教程的所有內容都結束了。網路爬蟲是一個非常實踐的應用,在真正爬取資料時,可能會遇到各種各樣的問題。從資料儲存、反反爬蟲以及演算法上可能都要踩很多坑。
本系列教程力求能夠從淺入深的講解網路爬蟲,儘可能覆蓋到爬蟲所涉及的內容的方方面。當然有些部分也會比較粗糙,只是大概提了一句。希望通過本系統教程,能讓讀者能夠對爬蟲有一個巨集觀的認識與瞭解。