使用Python操作Elasticsearch数据索引的教程


Posted in Python onApril 08, 2015

Elasticsearch是一个分布式、Restful的搜索及分析服务器,Apache Solr一样,它也是基于Lucence的索引服务器,但我认为Elasticsearch对比Solr的优点在于:

  •     轻量级:安装启动方便,下载文件之后一条命令就可以启动;
  •     Schema free:可以向服务器提交任意结构的JSON对象,Solr中使用schema.xml指定了索引结构;
  •     多索引文件支持:使用不同的index参数就能创建另一个索引文件,Solr中需要另行配置;
  •     分布式:Solr Cloud的配置比较复杂。

环境搭建

启动Elasticsearch,访问端口在9200,通过浏览器可以查看到返回的JSON数据,Elasticsearch提交和返回的数据格式都是JSON.

>> bin/elasticsearch -f

安装官方提供的Python API,在OS X上安装后出现一些Python运行错误,是因为setuptools版本太旧引起的,删除重装后恢复正常。

>> pip install elasticsearch

索引操作

对于单条索引,可以调用create或index方法。

from datetime import datetime
from elasticsearch import Elasticsearch
es = Elasticsearch() #create a localhost server connection, or Elasticsearch("ip")
es.create(index="test-index", doc_type="test-type", id=1,
  body={"any":"data", "timestamp": datetime.now()})

Elasticsearch批量索引的命令是bulk,目前Python API的文档示例较少,花了不少时间阅读源代码才弄清楚批量索引的提交格式。

from datetime import datetime
from elasticsearch import Elasticsearch
from elasticsearch import helpers
es = Elasticsearch("10.18.13.3")
j = 0
count = int(df[0].count())
actions = []
while (j < count):
   action = {
        "_index": "tickets-index",
        "_type": "tickets",
        "_id": j + 1,
        "_source": {
              "crawaldate":df[0][j],
              "flight":df[1][j],
              "price":float(df[2][j]),
              "discount":float(df[3][j]),
              "date":df[4][j],
              "takeoff":df[5][j],
              "land":df[6][j],
              "source":df[7][j],
              "timestamp": datetime.now()}
        }
  actions.append(action)
  j += 1

  if (len(actions) == 500000):
    helpers.bulk(es, actions)
    del actions[0:len(actions)]

if (len(actions) > 0):
  helpers.bulk(es, actions)
  del actions[0:len(actions)]

在这里发现Python API序列化JSON时对数据类型支撑比较有限,原始数据使用的NumPy.Int32必须转换为int才能索引。此外,现在的bulk操作默认是每次提交500条数据,我修改为5000甚至50000进行测试,会有索引不成功的情况。

#helpers.py source code
def streaming_bulk(client, actions, chunk_size=500, raise_on_error=False,
    expand_action_callback=expand_action, **kwargs):
  actions = map(expand_action_callback, actions)

  # if raise on error is set, we need to collect errors per chunk before raising them
  errors = []

  while True:
    chunk = islice(actions, chunk_size)
    bulk_actions = []
    for action, data in chunk:
      bulk_actions.append(action)
      if data is not None:
        bulk_actions.append(data)

    if not bulk_actions:
      return

def bulk(client, actions, stats_only=False, **kwargs):
  success, failed = 0, 0

  # list of errors to be collected is not stats_only
  errors = []

  for ok, item in streaming_bulk(client, actions, **kwargs):
    # go through request-reponse pairs and detect failures
    if not ok:
      if not stats_only:
        errors.append(item)
      failed += 1
    else:
      success += 1

  return success, failed if stats_only else errors

对于索引的批量删除和更新操作,对应的文档格式如下,更新文档中的doc节点是必须的。

{
  '_op_type': 'delete',
  '_index': 'index-name',
  '_type': 'document',
  '_id': 42,
}
{
  '_op_type': 'update',
  '_index': 'index-name',
  '_type': 'document',
  '_id': 42,
  'doc': {'question': 'The life, universe and everything.'}
}

常见错误

  •     SerializationError:JSON数据序列化出错,通常是因为不支持某个节点值的数据类型
  •     RequestError:提交数据格式不正确
  •     ConflictError:索引ID冲突
  •     TransportError:连接无法建立

性能

使用Python操作Elasticsearch数据索引的教程

上面是使用MongoDB和Elasticsearch存储相同数据的对比,虽然服务器和操作方式都不完全相同,但可以看出数据库对批量写入还是比索引服务器更具备优势。

Elasticsearch的索引文件是自动分块,达到千万级数据对写入速度也没有影响。但在达到磁盘空间上限时,Elasticsearch出现了文件合并错误,并且大量丢失数据(共丢了100多万条),停止客户端写入后,服务器也无法自动恢复,必须手动停止。在生产环境中这点比较致命,尤其是使用非Java客户端,似乎无法在客户端获取到服务端的Java异常,这使得程序员必须很小心地处理服务端的返回信息。

Python 相关文章推荐
深入浅析Python中join 和 split详解(推荐)
Jun 30 Python
python实现下载文件的三种方法
Feb 09 Python
python调用系统ffmpeg实现视频截图、http发送
Mar 06 Python
使用Python通过win32 COM实现Word文档的写入与保存方法
May 08 Python
python3实现163邮箱SMTP发送邮件
May 22 Python
使用Py2Exe for Python3创建自己的exe程序示例
Oct 31 Python
python微信好友数据分析详解
Nov 19 Python
利用nohup来开启python文件的方法
Jan 14 Python
Python面向对象程序设计之类的定义与继承简单示例
Mar 18 Python
python实现从尾到头打印单链表操作示例
Feb 22 Python
python多进程 主进程和子进程间共享和不共享全局变量实例
Apr 25 Python
Selenium python时间控件输入问题解决方案
Jul 22 Python
用Python实现协同过滤的教程
Apr 08 #Python
在Python中调用ggplot的三种方法
Apr 08 #Python
Python字符串和文件操作常用函数分析
Apr 08 #Python
Python遍历zip文件输出名称时出现乱码问题的解决方法
Apr 08 #Python
python smtplib模块发送SSL/TLS安全邮件实例
Apr 08 #Python
python复制与引用用法分析
Apr 08 #Python
Python导入txt数据到mysql的方法
Apr 08 #Python
You might like
先进的自动咖啡技术,真的可以取代咖啡师吗?
2021/03/06 冲泡冲煮
浅谈apache和nginx的rewrite的区别
2013/02/22 PHP
PHP将XML转数组过程详解
2013/11/13 PHP
php读取mysql的简单实例
2014/01/15 PHP
php中使用gd库实现远程图片下载实例
2015/05/12 PHP
测试你的JS的掌握程度的代码
2009/12/09 Javascript
javascript 基础篇1 什么是js 建立第一个js程序
2012/03/14 Javascript
表头固定(利用jquery实现原理介绍)
2012/11/08 Javascript
使用JQUERY进行后台页面布局控制DIV实现左右式
2014/01/07 Javascript
iframe窗口高度自适应的又一个巧妙实现思路
2014/04/04 Javascript
谈一谈bootstrap响应式布局
2016/05/23 Javascript
js 博客内容进度插件详解
2017/02/19 Javascript
Js实现中国公民身份证号码有效性验证实例代码
2017/05/03 Javascript
VueJS 取得 URL 参数值的方法
2019/07/19 Javascript
使用webpack搭建vue环境的教程详解
2019/12/31 Javascript
vue 路由守卫(导航守卫)及其具体使用
2020/02/25 Javascript
javascript设计模式 ? 享元模式原理与用法实例分析
2020/04/15 Javascript
JavaScript随机数的组合问题案例分析
2020/05/16 Javascript
Element Backtop回到顶部的具体使用
2020/07/27 Javascript
Vue插槽_特殊特性slot,slot-scope与指令v-slot说明
2020/09/04 Javascript
javascript实现电商放大镜效果
2020/11/23 Javascript
小程序实现列表倒计时功能
2021/01/29 Javascript
python与C互相调用的方法详解
2017/07/14 Python
浅谈Python_Openpyxl使用(最全总结)
2019/09/05 Python
python之yield和Generator深入解析
2019/09/18 Python
pytorch1.0中torch.nn.Conv2d用法详解
2020/01/10 Python
tensorflow 变长序列存储实例
2020/01/20 Python
Python小白不正确的使用类变量实例
2020/05/29 Python
一款纯css3实现的竖形二级导航的实例教程
2014/12/11 HTML / CSS
怎样声明接口
2014/09/19 面试题
介绍一下如何利用路径遍历进行攻击及如何防范
2014/01/19 面试题
师范应届生语文教师求职信
2013/10/29 职场文书
多媒体编辑专业毕业生推荐信
2013/11/05 职场文书
公积金单位接收函
2014/01/11 职场文书
2014年中班下学期工作总结
2014/12/11 职场文书
酒店前台岗位职责
2015/04/16 职场文书