为什么要用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得分)。
结束语
到这里,本系列教程的所有内容都结束了。网络爬虫是一个非常实践的应用,在真正爬取数据时,可能会遇到各种各样的问题。从数据存储、反反爬虫以及算法上可能都要踩很多坑。
本系列教程力求能够从浅入深的讲解网络爬虫,尽可能覆盖到爬虫所涉及的内容的方方面。当然有些部分也会比较粗糙,只是大概提了一句。希望通过本系统教程,能让读者能够对爬虫有一个宏观的认识与了解。