使用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抓taobao图片爬虫
Oct 26 Python
在Django同1个页面中的多表单处理详解
Jan 25 Python
python取数作为临时极大值(极小值)的方法
Oct 15 Python
Python基础教程之异常详解
Jan 10 Python
python3.6根据m3u8下载mp4视频
Jun 17 Python
python使用minimax算法实现五子棋
Jul 29 Python
Django框架视图层URL映射与反向解析实例分析
Jul 29 Python
Python基于Tensor FLow的图像处理操作详解
Jan 15 Python
pytorch实现MNIST手写体识别
Feb 14 Python
keras .h5转移动端的.tflite文件实现方式
May 25 Python
python 获取谷歌浏览器保存的密码
Jan 06 Python
Python tkinter之ComboBox(下拉框)的使用简介
Feb 05 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
我的论坛源代码(一)
2006/10/09 PHP
php防注入及开发安全详细解析
2013/08/09 PHP
php结合ajax实现赞、顶、踩功能实例
2014/05/12 PHP
使用Codeigniter重写insert的方法(推荐)
2017/03/23 PHP
PHP面向对象程序设计之接口的继承定义与用法详解
2018/12/20 PHP
PHP 文件写入和读取操作实例详解【必看篇】
2019/11/04 PHP
Javascript 个人笔记(没有整理,很乱)
2007/07/07 Javascript
比较详细的关于javascript中void(0)的具体含义解释
2007/08/02 Javascript
flash javascript之间的通讯方法小结
2008/12/20 Javascript
JavaScript 关键字屏蔽实现函数
2009/08/02 Javascript
extjs之去除s.gif的影响
2010/12/25 Javascript
ajax异步刷新实现更新数据库
2012/12/03 Javascript
jquery操作复选框(checkbox)的12个小技巧总结
2014/02/04 Javascript
JS实现静止元素自动移动示例
2014/04/14 Javascript
使用Browserify配合jQuery进行编程的超级指南
2015/07/28 Javascript
基于JavaScript实现鼠标悬浮弹出跟随鼠标移动的带箭头的信息层
2016/01/18 Javascript
Node.js插件安装图文教程
2016/05/06 Javascript
深入探讨Vue.js组件和组件通信
2016/09/12 Javascript
微信小程序 页面跳转和数据传递实例详解
2017/01/19 Javascript
微信小程序云开发之云函数详解
2019/05/16 Javascript
tracking.js实现前端人脸识别功能
2020/04/16 Javascript
微信小程序自定义顶部组件customHeader的示例代码
2020/06/03 Javascript
详解Python爬虫的基本写法
2016/01/08 Python
Python3之手动创建迭代器的实例代码
2019/05/22 Python
HTML5 Canvas渐进填充与透明实现图像的Mask效果
2013/07/11 HTML / CSS
HTML5实现自带进度条和滑块滑杆效果
2018/04/17 HTML / CSS
波兰多品牌运动商店:StreetStyle24.pl
2020/09/22 全球购物
中学家长会邀请函
2014/02/03 职场文书
保护环境倡议书500字
2014/05/19 职场文书
乡镇2014法制宣传日活动总结
2014/11/01 职场文书
中班下学期幼儿评语
2014/12/30 职场文书
销售员自我评价
2015/03/11 职场文书
汽车销售员岗位职责
2015/04/11 职场文书
演讲比赛通讯稿
2015/07/18 职场文书
2019年度行政文员工作计划范本!
2019/07/04 职场文书
Mysql查询时间区间日期列表,不会由于数据表数据影响
2022/04/19 MySQL