【Elasticsearch】使用Python + MySQL在Elasticsearch中进行高速化【MySQL】
首先
我平常主要学习机器学习方面的知识,但在空闲时间也会接触一些与Web技术相关的内容。
这次我打算在实验室内开发一个电子图书搜索引擎,但是我对从数据库读取数据速度慢这一点感到担忧。
我本来想快速完成,所以用Python编写了一个从MySQL读取数据的服务器脚本,但是一旦数据量稍微大一些,绘图就变得很慢。
因此,我考虑引入elasticsearch以加快加载速度并解决成为瓶颈的部分。
只是简单提一下,不详细说明。
环境
-
- OSX
-
- python ver3.6.0
-
- elasticsearch ver2.3.4
-
- elasticsearch-jdbc ver2.3.4.1
- msyql
引入
假设您已经能够在 Python 中进行 MySQL 数据交互。
关于elasticsearch的介绍。
首先是elasticsearch的安装,有两种方式。
一种方法是使用brew进行操作。
使用brew安装elasticsearch
可以通过安装来实现。
另一个方法是通过官方网站https://www.elastic.co/downloads/past-releases进行下载。
本次使用公式网站下载的方法。我觉得版本可以随您的喜好选择,但如果以后需要jdbc,我认为以上环境的组合很不错。
启动
启动elasticsearch非常简单,只需要下载并解压缩文件夹,然后在bin/elasticsearch运行即可。
我建议将bin添加到路径中。
但是,只有这样很难了解elasticsearch中有什么数据,所以我们要安装一个名为elasticsearch-head的工具。
plugin install mobz/elasticsearch-head
在启动elasticsearch的情况下,可以通过http://localhost:9200/_plugin/head在浏览器中查看elasticsearch内的数据。
上面的图片中的search_degital_library是我创建的索引(类似于关系型数据库中的数据表)。
现在可以开始使用elsticsearch了。
MySQL的整合
在这个elasticsearch中进行mysql数据的映射,有几种方法可供选择。
让程序处理
这一次的数据量并不是很大,所以我们就这样做了。
具体方法是使用Python从MySQL数据库中读取数据,并通过Elasticsearch的库将其插入。
使用jdbc
下载并使用用于Elasticsearch的JDBC插件,通过专门的脚本将数据导入。由于导入后索引名称会变为jdbc,且无法有效处理,因此我们放弃了这种方法。
使用logstash
如果你有兴趣,请自行调查一下。看起来使用起来很方便。
数据传输
根据这个想法,我们将把 MySQL 数据导入 Elasticsearch。
在Python中,我使用了一个名为dataset的ORM来加载MySQL数据。
pip install dataset
pip install mysqlclient
我认为多数情况下,你通过这个方法应该能够使用了。
顺便一提,我简单说明一下连接相关的内容。
import dataset
DBMS = 'mysql'
USER = '__user_name'
PASS = '__pass_word'
HOST = '__db_host'
DB = 'search_degital_library'
db = dataset.connect('{0}://{1}:{2}@{3}/{4}?charset=utf8'.format(DBMS, USER, PASS, HOST, DB))
请将charset部分转换为适当的字符编码。
以下为批量脚本的内容。
该脚本会读取mysql数据库中的books表中的电子书id、名称、创建时间和修改时间,并通过elasticsearch库进行批量导入。
pip install elasticsearch
~~
from elasticsearch import Elasticsearch
es = Elasticsearch("localhost:9200")
# db['接続したいテーブル名']
table_books = db['books']
for data in table_books.find():
es.index(index="search_degital_library", doc_type="books", id=data['id'], body={"name":data['name'], "created":data['created'], "modified":data['modified']})
您可以使用index方法将数据插入到Elasticsearch中。
参数是指索引名称的 index 和在 RDB 中对应表的 doc_type,在 elasticsearch 中也会创建一个名为 books 的索引。即使在 elasticsearch 中事先没有定义 index 或 doc_type,只需指定即可创建。
在 body 中使用字典类型指定列和数据。顺便提一下,在 RDB 中的列在 elasticsearch 中称为字段。
将上述内容应用于每个表中,然后流入完成。
如果数据量较大,可能最好使用工具。
使用elasticsearch-head查看时,
您可以通过浏览器选项卡查看输入的数据。
接下来,我们将总结一下从Python调用Elasticsearch数据的要点。这只是最基本的用法。
使用Python访问Elasticsearch数据。
数据获取
from elasticsearch import Elasticsearch
es = Elasticsearch("localhost:9200")
单一记录
我们决定将上述图片中的一行称为记录(可能有所不同)。当要读取Elasticsearch内的一条记录时,使用get命令。
# categoriesのidが42のデータを読み込む
es.get(index="search_degital_library", doc_type="categories", id=42)
{
'_source':
{
'created': '2017-11-21T16:50:58',
'name': 'スクレイピング',
'modified': '2017-11-21T16:50:58'
},
'_version': 1,
'_index': 'search_degital_library',
'_type': 'categories',
'found': True,
'_id': '42'
}
用 JSON 格式返回。使用 “get_source” 只会返回源数据部分。
获取多条记录
当需要读取多条记录时,可以使用search函数。
# categoriesのデータを全て読み込む
es.search(index="search_degital_library", doc_type="categories", body={"query": {"match_all": {}}})
{
'_shards':
{
'failed': 0,
'total': 5,
'successful': 5
},
'took': 4,
'hits':
{
'max_score': 1.0,
'total': 28,
'hits':
[{
'_type': 'categories',
'_source':
{
'created': '2017-11-20T15:40:10',
'name': 'データ分析',
'modified': '2017-11-20T15:40:10'
},
'_score': 1.0,
'_index': 'search_degital_library',
'_id': '14'
},
・・・・,
{
'_source':
{
'created': '2017-11-20T15:40:10',
'name': '強化学習',
'modified': '2017-11-20T15:40:10'
},
'_type': 'categories',
'_score': 1.0,
'_index': 'search_degital_library',
'_id': '10'
}]
},
'timed_out': False
}
我原以为可以一次性加载所有内容,但默认情况下只加载了10个项目。因为search参数中有一个size选项,所以只要在那里指定,就可以获取更多的内容。
es.search(index="search_degital_library", doc_type="categories", body={"query": {"match_all": {}}, "size": 200})
因为是最大值,所以可能要设置得相对较大,或者通过某种方式获取数量并进行指定。
获得前提
指定字段并获取多个。
# nameが最適化のcategoriesのデータを読み込む
es.search(index="search_degital_library", doc_type="categories", body={"query": {"match": {"name":"最適化"}}}, "size"=100)
添加数据
我之前已经提到过,
es.index(index=インデックス名, doc_type=タイプ名, id=id_, body={"name":name_, ~})
删除数据
获取要删除记录的id。
es.delete(index=インデックス名, doc_type=タイプ名, id=id_)
如果能掌握这个,我认为基本操作就能上手了。
总结起来
当将其应用在瓶颈(特别是数据的全量提取)的部分时,原本需要5秒的绘制时间现在可以在1秒以内完成!太好了!
由于在许多地方听到过 Elasticsearch 的名字并对其产生了兴趣,所以这次有机会接触到它感到很好。
如果可以的话,请参考一下。