Python如何把Spark数据写入ElasticSearch


Posted in Python onApril 18, 2020

这里以将Apache的日志写入到ElasticSearch为例,来演示一下如何使用Python将Spark数据导入到ES中。

实际工作中,由于数据与使用框架或技术的复杂性,数据的写入变得比较复杂,在这里我们简单演示一下。

如果使用Scala或Java的话,Spark提供自带了支持写入ES的支持库,但Python不支持。所以首先你需要去这里下载依赖的ES官方开发的依赖包包。

下载完成后,放在本地目录,以下面命令方式启动pyspark:

pyspark --jars elasticsearch-hadoop-6.4.1.jar

如果你想pyspark使用Python3,请设置环境变量:

export PYSPARK_PYTHON=/usr/bin/python3
理解如何写入ES的关键是要明白,ES是一个JSON格式的数据库,它有一个必须的要求。数据格式必须采用以下格式

{ "id: { the rest of your json}}

往下会展示如何转换成这种格式。

解析Apache日志文件
我们将Apache的日志文件读入,构建Spark RDD。然后我们写一个parse()函数用正则表达式处理每条日志,提取我们需要的字

rdd = sc.textFile("/home/ubuntu/walker/apache_logs")
regex='^(\S+) (\S+) (\S+) \[([\w:/]+\s[+\-]\d{4})\] "(\S+)\s?(\S+)?\s?(\S+)?" (\d{3}|-) (\d+|-)\s?"?([^"]*)"?\s?"?([^"]*)?"?$'

p=re.compile(regex)
def parse(str):
  s=p.match(str)
  d = {}
  d['ip']=s.group(1)
  d['date']=s.group(4)
  d['operation']=s.group(5)
  d['uri']=s.group(6)
  return d

换句话说,我们刚开始从日志文件读入RDD的数据类似如下:

['83.149.9.216 - - [17/May/2015:10:05:03 +0000] "GET /presentations/logstash-monitorama-2013/images/kibana-search.png HTTP/1.1" 200 203023 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"']

然后我们使用map函数转换每条记录:

rdd2 = rdd.map(parse)

rdd2.take(1)

[{'date': '17/May/2015:10:05:03 +0000', 'ip': '83.149.9.216', 'operation': 'GET', 'uri': '/presentations/logstash-monitorama-2013/images/kibana-search.png'}]

现在看起来像JSON,但并不是JSON字符串,我们需要使用json.dumps将dict对象转换。

我们同时增加一个doc_id字段作为整个JSON的ID。在配置ES中我们增加如下配置“es.mapping.id”: “doc_id”告诉ES我们将这个字段作为ID。

这里我们使用SHA算法,将这个JSON字符串作为参数,得到一个唯一ID。
计算结果类似如下,可以看到ID是一个很长的SHA数值。

rdd3.take(1)

[('a5b086b04e1cc45fb4a19e2a641bf99ea3a378599ef62ba12563b75c', '{"date": "17/May/2015:10:05:03 +0000", "ip": "83.149.9.216", "operation": "GET", "doc_id": "a5b086b04e1cc45fb4a19e2a641bf99ea3a378599ef62ba12563b75c", "uri": "/presentations/logstash-monitorama-2013/images/kibana-search.png"}')]

现在我们需要制定ES配置,比较重要的两项是:

  • “es.resource” : ‘walker/apache': "walker"是索引,apache是类型,两者一般合称索引
  • “es.mapping.id”: “doc_id”: 告诉ES那个字段作为整个文档的ID,也就是查询结果中的_id

其他的配置自己去探索。

然后我们使用saveAsNewAPIHadoopFile()将RDD写入到ES。这部分代码对于所有的ES都是一样的,比较固定,不需要理解每一个细节

es_write_conf = {
    "es.nodes" : "localhost",
    "es.port" : "9200",
    "es.resource" : 'walker/apache',
    "es.input.json": "yes",
    "es.mapping.id": "doc_id"
  }
    
rdd3.saveAsNewAPIHadoopFile(
    path='-',
   outputFormatClass="org.elasticsearch.hadoop.mr.EsOutputFormat",    keyClass="org.apache.hadoop.io.NullWritable",
    valueClass="org.elasticsearch.hadoop.mr.LinkedMapWritable",
    conf=es_write_conf)

rdd3 = rdd2.map(addID)

def addId(data):
  j=json.dumps(data).encode('ascii', 'ignore')
  data['doc_id'] = hashlib.sha224(j).hexdigest()
  return (data['doc_id'], json.dumps(data))

最后我们可以使用curl进行查询

curl http://localhost:9200s/walker/apache/_search?pretty=true&?q=*
{
    "_index" : "walker",
    "_type" : "apache",
    "_id" : "227e977849bfd5f8d1fca69b04f7a766560745c6cb3712c106d590c2",
    "_score" : 1.0,
    "_source" : {
     "date" : "17/May/2015:10:05:32 +0000",
     "ip" : "91.177.205.119",
     "operation" : "GET",
     "doc_id" : "227e977849bfd5f8d1fca69b04f7a766560745c6cb3712c106d590c2",
     "uri" : "/favicon.ico"
    }

如下是所有代码:

import json
import hashlib
import re

def addId(data):
  j=json.dumps(data).encode('ascii', 'ignore')
  data['doc_id'] = hashlib.sha224(j).hexdigest()
  return (data['doc_id'], json.dumps(data))

def parse(str):
  s=p.match(str)
  d = {}
  d['ip']=s.group(1)
  d['date']=s.group(4)
  d['operation']=s.group(5)
  d['uri']=s.group(6)
  return d  

regex='^(\S+) (\S+) (\S+) \[([\w:/]+\s[+\-]\d{4})\] "(\S+)\s?(\S+)?\s?(\S+)?" (\d{3}|-) (\d+|-)\s?"?([^"]*)"?\s?"?([^"]*)?"?$'

p=re.compile(regex)

rdd = sc.textFile("/home/ubuntu/walker/apache_logs")

rdd2 = rdd.map(parse)

rdd3 = rdd2.map(addID)

es_write_conf = {
    "es.nodes" : "localhost",
    "es.port" : "9200",
    "es.resource" : 'walker/apache',
    "es.input.json": "yes",
    "es.mapping.id": "doc_id"
  }
   
rdd3.saveAsNewAPIHadoopFile(
    path='-',
   outputFormatClass="org.elasticsearch.hadoop.mr.EsOutputFormat",    keyClass="org.apache.hadoop.io.NullWritable",
    valueClass="org.elasticsearch.hadoop.mr.LinkedMapWritable",
    conf=es_write_conf)

也可以这么封装,其实原理是一样的

import hashlib
import json
from pyspark import Sparkcontext

def make_md5(line):
  md5_obj=hashlib.md5()
  md5_obj.encode(line)
  return md5_obj.hexdigest()

def parse(line):
  dic={}
  l = line.split('\t')
  doc_id=make_md5(line)
  dic['name']=l[1]
  dic['age'] =l[2]
  dic['doc_id']=doc_id
  return dic  #记得这边返回的是字典类型的,在写入es之前要记得dumps

def saveData2es(pdd, es_host, port,index, index_type, key):
  """
  把saprk的运行结果写入es
  :param pdd: 一个rdd类型的数据
  :param es_host: 要写es的ip
  :param index: 要写入数据的索引
  :param index_type: 索引的类型
  :param key: 指定文档的id,就是要以文档的那个字段作为_id
  :return:
  """
  #实例es客户端记得单例模式
  if es.exist.index(index):
    es.index.create(index, 'spo')
  es_write_conf = {
    "es.nodes": es_host,
    "es.port": port,
    "es.resource": index/index_type,
    "es.input.json": "yes",
    "es.mapping.id": key
  }

  (pdd.map(lambda _dic: ('', json.dumps(_dic))))  #这百年是为把这个数据构造成元组格式,如果传进来的_dic是字典则需要jdumps,如果传进来之前就已经dumps,这便就不需要dumps了
  .saveAsNewAPIHadoopFile(
    path='-',
    outputFormatClass="org.elasticsearch.hadoop.mr.EsOutputFormat", keyClass="org.apache.hadoop.io.NullWritable",
    valueClass="org.elasticsearch.hadoop.mr.LinkedMapWritable",
    conf=es_write_conf)
  )
if __name__ == '__main__':
  #实例化sp对象
  sc=Sparkcontext()
  #文件中的呢内容一行一行用sc的读取出来
  json_text=sc.textFile('./1.txt')
  #进行转换
  json_data=json_text.map(lambda line:parse(line))

  saveData2es(json_data,'127.0.01','9200','index_test','index_type','doc_id')

  sc.stop()

看到了把,面那个例子在写入es之前加了一个id,返回一个元组格式的,现在这个封装指定_id就会比较灵活了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
闭包在python中的应用之translate和maketrans用法详解
Aug 27 Python
Python编程二分法实现冒泡算法+快速排序代码示例
Jan 15 Python
对dataframe进行列相加,行相加的实例
Jun 08 Python
用Python实现筛选文件脚本的方法
Oct 27 Python
Python实现定期检查源目录与备份目录的差异并进行备份功能示例
Feb 27 Python
Django打印出在数据库中执行的语句问题
Jul 25 Python
python获取指定日期范围内的每一天,每个月,每季度的方法
Aug 08 Python
Python函数的迭代器与生成器的示例代码
Jun 18 Python
Python实现对word文档添加密码去除密码的示例代码
Dec 29 Python
Pytorch之扩充tensor的操作
Mar 04 Python
从np.random.normal()到正态分布的拟合操作
Jun 02 Python
python playwright之元素定位示例详解
Jul 23 Python
Python virtualenv虚拟环境实现过程解析
Apr 18 #Python
python实现贪吃蛇双人大战
Apr 18 #Python
Python的in,is和id函数代码实例
Apr 18 #Python
Python json读写方式和字典相互转化
Apr 18 #Python
Python figure参数及subplot子图绘制代码
Apr 18 #Python
Python数组拼接np.concatenate实现过程
Apr 18 #Python
Python稀疏矩阵及参数保存代码实现
Apr 18 #Python
You might like
php一句话cmdshell新型 (非一句话木马)
2009/04/18 PHP
PHP 数据结构队列(SplQueue)和优先队列(SplPriorityQueue)简单使用实例
2015/05/12 PHP
php 修改上传文件大小限制实例详解
2016/10/23 PHP
Laravel框架Auth用户认证操作实例分析
2019/09/29 PHP
PHP哈希表实现算法原理解析
2020/12/11 PHP
键盘控制事件应用教程大全
2006/11/24 Javascript
JQuery替换DOM节点的方法
2015/06/11 Javascript
jquery插件ajaxupload实现文件上传操作
2015/12/09 Javascript
jquery实现倒计时效果
2015/12/14 Javascript
Bootstrap组件(一)之菜单
2016/05/11 Javascript
解决微信浏览器Javascript无法使用window.location.reload()刷新页面
2016/06/21 Javascript
vue.js 上传图片实例代码
2017/06/22 Javascript
js实现canvas图片与img图片的相互转换的示例
2017/08/31 Javascript
微信小程序利用canvas 绘制幸运大转盘功能
2018/07/06 Javascript
解决vue-router 二级导航默认选中某一选项的问题
2019/11/01 Javascript
vue 路由meta 设置导航隐藏与显示功能的示例代码
2020/09/04 Javascript
[48:41]VP vs VG Supermajor小组赛 B组胜者组决赛 BO3 第二场 6.2
2018/06/03 DOTA
python爬取网站数据保存使用的方法
2013/11/20 Python
使用IPython下的Net-SNMP来管理类UNIX系统的教程
2015/04/15 Python
详解详解Python中writelines()方法的使用
2015/05/25 Python
Python闭包思想与用法浅析
2018/12/27 Python
python+pyqt5编写md5生成器
2019/03/18 Python
python中比较两个列表的实例方法
2019/07/04 Python
python3 使用Opencv打开USB摄像头,配置1080P分辨率的操作
2019/12/11 Python
python中图像通道分离与合并实例
2020/01/17 Python
实例教程 HTML5 Canvas 超炫酷烟花绽放动画实现代码
2014/11/05 HTML / CSS
香港百佳网上超级市场:PARKNSHOP.com
2020/06/10 全球购物
大一期末自我鉴定
2013/12/13 职场文书
求职自荐信
2013/12/14 职场文书
城建学院毕业生自荐信
2014/01/31 职场文书
出国留学担保书
2014/05/20 职场文书
建筑管理专业求职信
2014/07/28 职场文书
文明单位创建材料
2014/12/24 职场文书
关于远足的感想
2015/08/10 职场文书
html css3不拉伸图片显示效果
2021/06/07 HTML / CSS
5个pandas调用函数的方法让数据处理更加灵活自如
2022/04/24 Python