原文轉(zhuǎn)載自「劉悅的技術(shù)博客」https://v3u.cn/a_id_166
基于文檔式的全文檢索引擎大家都不陌生,之前一篇文章:使用Redisearch實(shí)現(xiàn)的全文檢索功能服務(wù),曾經(jīng)使用Rediseach來小試牛刀了一把,文中戲謔的稱Rediseach已經(jīng)替代了Elasticsearch,其實(shí)不然,Elasticsearch作為老牌的全文檢索引擎還并沒有退出歷史舞臺,依舊占據(jù)主流市場,桃花依舊笑春風(fēng),阿里也在其ecs服務(wù)中推出了云端Elasticsearch引擎,所以本次我們在Win10系統(tǒng)中依托Docker來感受一下Elasticsearch的魅力。
首先安裝Docker,具體流程請參照:win10系統(tǒng)下把玩折騰DockerToolBox以及更換國內(nèi)鏡像源(各種神坑),這里不再贅述。
拉取Elasticsearch鏡像,這里我們使用7.0以上的版本,該版本從性能和效率上都得到了優(yōu)化。
docker pull elasticsearch:7.2.0
隨后運(yùn)行Elasticsearch鏡像
docker run --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.2.0
容器別名我們就用縮寫es來替代,通過 9200 端口并使用 Elasticsearch 的原生 傳輸 協(xié)議和集群交互。集群中的節(jié)點(diǎn)通過端口 9300 彼此通信。如果這個端口沒有打開,節(jié)點(diǎn)將無法形成一個集群,運(yùn)行模式先走單節(jié)點(diǎn)模式。
啟動容器成功后,可以訪問一下瀏覽器: http://localhost:9200

OK,沒有任何問題,Elasticsearch 采用 YAML 文件對系統(tǒng)進(jìn)行配置,原理很簡單,就像Django的settings或者Flask的Config,只要通知Elasticsearch服務(wù)在運(yùn)行過程中一些你想要的功能,而Elasticsearch會找到elasticsearch.yml,之后按你指定的參數(shù)運(yùn)行服務(wù)。
此時,我們需要將容器內(nèi)部Elasticsearch的配置文件拷貝出來,這樣以后啟動容器就可以按照我們自己指定的配置來修改了。
docker cp 容器id:/usr/share/elasticsearch/config/elasticsearch.yml ./elasticsearch.yml
老規(guī)矩,前面的是容器內(nèi)地址,后面的是宿主機(jī)地址,這里我就拷貝到當(dāng)前目錄下,當(dāng)然了,你也可以指定絕對路徑。
打開elasticsearch.yml,可以自己加一些配置,比如允許跨域訪問,這樣你這臺Elasticsearch就可以被別的服務(wù)器訪問了,這是微服務(wù)全文檢索系統(tǒng)架構(gòu)的第一步。
cluster.name: "docker-cluster"
network.host: 0.0.0.0
http.cors.enabled: true
http.cors.allow-origin: "*"
然后停止正在運(yùn)行的Elasticsearch容器,并且刪除它。
docker stop 容器id
docker rm $(docker ps -a -q)
再次啟動Elasticsearch容器,這一次不同的是,我們需要通過-v掛載命令把我們剛剛修改好的elasticsearch.yml掛載到容器內(nèi)部去,這樣容器就根據(jù)我們自己修改的配置文件來運(yùn)行Elasticsearch服務(wù)。
docker run --name es -v /es/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.2.0
這里需要注意一點(diǎn),就是在Win10宿主機(jī)里需要單獨(dú)設(shè)置一下共享文件夾,這里我設(shè)置的共享文件夾叫做es,如果是Centos或者M(jìn)ac os就直接寫真實(shí)物理路徑即可。
這里再簡單介紹一下Win10如何設(shè)置共享文件夾用來配合Docker的掛載,打開virtualBox設(shè)置,新建一個共享文件夾es

隨后,重啟Docker,輸入命令進(jìn)入默認(rèn)容器:docker-machine ssh default
在容器根目錄能夠看到剛剛設(shè)置的共享文件夾,就說明設(shè)置成功了。

另外還有一個需要注意的點(diǎn),就是Elasticsearch存儲數(shù)據(jù)也可以通過-v命令掛載出來,如果不對數(shù)據(jù)進(jìn)行掛載,當(dāng)容器被停止或者刪除,數(shù)據(jù)也會不復(fù)存在,所以掛載后存儲在宿主機(jī)會比較好一點(diǎn),命令是:
docker run --name es -v /es/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /es/data:/usr/share/elasticsearch/data -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.2.0
再次啟動容器成功之后,我們就可以利用Python3來和全文檢索引擎Elasticsearch進(jìn)行交互了,安裝依賴的庫。
pip3 install elasticsearch
新建es_test.py測試腳本
建立Elasticsearch的檢索實(shí)例
from elasticsearch import Elasticsearch
es = Elasticsearch(hosts=[{"host":'Docker容器所在的ip', "port": 9200}])
這里的host指容器ip,因?yàn)榭梢詳U(kuò)展集群,所以是一個list,需要注意一點(diǎn),如果是Win10就是系統(tǒng)分配的那個ip,Centos或者M(jìn)ac os直接寫127.0.0.1即可。
建立索引(Index),這里我們創(chuàng)建一個名為 article 的索引
result = es.indices.create(index='article', ignore=400)
print(result)
{'acknowledged': True, 'shards_acknowledged': True, 'index': 'article'}
其中的 acknowledged 字段表示創(chuàng)建操作執(zhí)行成功。
刪除索引也是類似的,代碼如下:
result = es.indices.delete(index='article', ignore=[400, 404])
print(result)
{'acknowledged':True}
插入數(shù)據(jù),Elasticsearch 就像 MongoDB 一樣,在插入數(shù)據(jù)的時候可以直接插入結(jié)構(gòu)化字典數(shù)據(jù),插入數(shù)據(jù)可以調(diào)用 index() 方法,這里索引和數(shù)據(jù)是強(qiáng)關(guān)聯(lián)的,所以插入時需要指定之前建立好的索引。
data = {'title': '我在北京學(xué)習(xí)人工智能', 'url': 'http://123.com','content':"在北京學(xué)習(xí)"}
result = es.index(index='article',body=data)
print(result)
{'_index': 'article', '_type': '_doc', '_id': 'GyJgb3MBuQaE6wYOApTh', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 5, '_primary_term': 1}
可以看到index()方法會自動生成一個唯一id,當(dāng)然我們也可以使用create()方法創(chuàng)建數(shù)據(jù),不同的是create()需要手動指定一個id。
修改數(shù)據(jù)也非常簡單,我們同樣需要指定數(shù)據(jù)的 id 和內(nèi)容,調(diào)用 index() 方法即可,代碼如下:
data = {'content':"在北京學(xué)習(xí)python"}
#修改
result = es.index(index='article',body=data, id='GyJgb3MBuQaE6wYOApTh')
{'_index': 'article', '_type': '_doc', '_id': 'GyJgb3MBuQaE6wYOApTh', '_version': 2, 'result': 'updated', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 6, '_primary_term': 1}
刪除數(shù)據(jù),可以調(diào)用 delete() 方法,指定需要刪除的數(shù)據(jù) id 即可
#刪除
result = es.delete(index='article',id='GyJgb3MBuQaE6wYOApTh')
print(result)
{'_index': 'article', '_type': '_doc', '_id': 'GyJgb3MBuQaE6wYOApTh', '_version': 3, 'result': 'deleted', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 7, '_primary_term': 1}
查詢數(shù)據(jù),這里可以簡單的查詢?nèi)繑?shù)據(jù):
#查詢
result = es.search(index='article')
print(result)
{'took': 1079, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 5, 'relation': 'eq'}, 'max_score': 1.0, 'hits': [{'_index': 'article', '_type': 'blog', '_id': '1', '_score': 1.0, '_source': {'title': '我在北京學(xué)習(xí)人工智能', 'url': 'http://123.com', 'content': '在北京學(xué)習(xí)'}}, {'_index': 'article', '_type': 'blog', '_id': 'FyIdb3MBuQaE6wYO8JQR', '_score': 1.0, '_source': {'title': '你好', 'content': '你好123'}}, {'_index': 'article', '_type': 'blog', '_id': 'GCIeb3MBuQaE6wYOnpSv', '_score': 1.0, '_source': {'title': '你好', 'url': 'http://123.com', 'content': '你好123'}}, {'_index': 'article', '_type': 'blog', '_id': 'GSJfb3MBuQaE6wYOu5RD', '_score': 1.0, '_source': {'title': '你好', 'url': 'http://123.com', 'content': '你好123'}}, {'_index': 'article', '_type': 'blog', '_id': 'GiJfb3MBuQaE6wYO5pR4', '_score': 1.0, '_source': {'title': '你好', 'url': 'http://123.com', 'content': '你好123'}}]}}
還可以進(jìn)行全文檢索,這才是體現(xiàn) Elasticsearch 搜索引擎特性的地方。
mapping = {
'query': {
'match': {
'content': '學(xué)習(xí) 北京'
}
}
}
result = es.search(index='article',body=mapping)
print(result)
{'took': 4, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'max_score': 4.075481, 'hits': [{'_index': 'article', '_type': 'blog', '_id': '1', '_score': 4.075481, '_source': {'title': '我在北京學(xué)習(xí)人工智能', 'url': 'http://123.com', 'content': '在北京學(xué)習(xí)'}}]}}
可以看出,檢索時會對對應(yīng)的字段全文檢索,結(jié)果還會按照檢索關(guān)鍵詞的相關(guān)性進(jìn)行排序,這就是一個基本的搜索引擎雛形。
除了這些最基本的操作,Elasticsearch還支持很多復(fù)雜的查詢,可以參照最新的7.2版本文檔:https://www.elastic.co/guide/en/elasticsearch/reference/7.2/query-dsl.html
結(jié)語:體驗(yàn)了之后,有人說,Elasticsearch這玩意還真不錯,能不能把Mysql或者M(jìn)ongo全都扔了,就拿它當(dāng)數(shù)據(jù)庫不就完事了嗎?答案當(dāng)然是不可能的,因?yàn)镋lasticsearch沒有事務(wù),而且是查詢是近實(shí)時,寫入速度很慢,只是讀取數(shù)據(jù)快,成本也比數(shù)據(jù)庫高,幾乎就在靠吃內(nèi)存提高性能,它目前只是作為搜索引擎的存在,如果你的業(yè)務(wù)涉及全文檢索,那么它就是你的首選方案之一。
原文轉(zhuǎn)載自「劉悅的技術(shù)博客」 https://v3u.cn/a_id_166