通常來講數據庫都會自帶模糊搜索的功能,但其實上真正使用的時候,遇到中文搜索這種問題時,搜索速度會很是慢,可能會須要O(n)或者O(logn)的複雜度。html
在實際使用中,這是不容許的,由於用戶就搜索一條語句。假設n很是大的話,等待時間可能會很是的久。因此確定須要使用索引機制,加速搜索效率。java
搜索引擎使用的是倒排索引
,創建好索引後,能夠在O(c)的時間完成搜索功能。不過這步只是一個粗略的查詢,還要對搜索的結果進行排序,這裏可能會用到如BM25
、Query Likelihood Model
等給文檔打分的方法,經過打分對搜索結果進行排序。python
若是咱們本身去實現這些功能的話,首先可能要學學什麼是倒排索引,還有文檔的打分的各類方法,再加上代碼,要用起來不知道要到哪年哪月了。而ElasticSearch將這些操做變得很是簡單。它是一個基於Lucene的搜索服務器,它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。git
下面咱們將要講解如何使用ElasticSearch構建咱們的帖子搜索。github
「工欲善其事,必先利其器」,咱們這裏先講解一些ElasticSearch的安裝步驟,下面的操做是在mac系統上進行的。由於ElasticSearch是基於Java開發的,Java自己是跨平臺的,因此其餘系統上面其實操做都是基本同樣的。web
這裏首先安裝JDK,而後下載安裝ElasticSearch-6.0.0版本。算法
下載解壓後,咱們能夠看到這裏有一個bin
文件夾。mongodb
bin
文件夾裏都是ElasticSearch相關操做的腳本。咱們把ElasticSearch的bin
目錄添加到PATH
中,以後在終端中就不須要輸入絕對路徑了。數據庫
export PATH=$HOME/ProgramFiles/elasticsearch-6.0.0/bin:${PATH}
複製代碼
由於咱們作的是中文搜索,而ElasticSearch自帶的中文分詞作的很差,因此這裏須要使用到ik的一個插件。使用如下命令安裝便可。bash
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.0.0/elasticsearch-analysis-ik-6.0.0.zip
複製代碼
最後,咱們由於要使用python操做ElasticSearch,經過pip命令安裝ElasticSearch的API庫。
pip install elasticsearch
複製代碼
在創建索引以前,咱們要先打開ElasticSearch服務。在終端輸入elasticsearch
命令便可。
啓動後能夠看到ElasticSearch服務監聽了本地的9300端口。
接下來,咱們來看看如何創建索引。
首先像數據庫同樣,咱們先創建一個索引。這裏咱們管它叫: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得分)。
到這裏,本系列教程的全部內容都結束了。網絡爬蟲是一個很是實踐的應用,在真正爬取數據時,可能會遇到各類各樣的問題。從數據存儲、反反爬蟲以及算法上可能都要踩不少坑。
本系列教程力求可以從淺入深的講解網絡爬蟲,儘量覆蓋到爬蟲所涉及的內容的方方面。固然有些部分也會比較粗糙,只是大概提了一句。但願經過本系統教程,能讓讀者可以對爬蟲有一個宏觀的認識與瞭解。