之前博客有用logstash-input-jdbc同步mysql数据到ElasticSearch,但是由于同步时间最少是一分钟一次,无法满足线上业务,所以只能自己实现一个,但是时间比较紧,所以简单实现一个
思路:
网上有很多思路用什么mysql的binlog功能什么的,但是我对mysql了解实在有限,所以用一个很呆板的办法查询mysql得到数据,再插入es,因为数据量不大,而且10秒间隔同步一次,效率还可以,为了避免服务器之间的时间差和mysql更新和查询产生的时间差,所以在查询更新时间条件时是和上一次同步开始时间比较,这样不管数据多少,更新耗时多少都不会少数据,因为原则是同步不漏掉任何数据,也可以程序多开将时间差和间隔时间差异化,因为用mysql中一个id当作es中的id,也避免了重复数据
使用:
只需要按照escongif.py写配置文件,然后写sql文件,最后直接执行mstes.py就可以了,我这个也是参考logstash-input-jdbc的配置形式
MsToEs
|----esconfig.py(配置文件)
|----mstes.py(同步程序)
|----sql_manage.py(数据库管理)
|----aa.sql(需要用到sql文件)
|----bb.sql(需要用到sql文件)
sql_manage.py:
# -*-coding:utf-8 -*- __author__ = "ZJL" from sqlalchemy.pool import QueuePool from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, scoped_session import traceback import esconfig # 用于不需要回滚和提交的操作 def find(func): def wrapper(self, *args, **kwargs): try: return func(self, *args, **kwargs) except Exception as e: print(traceback.format_exc()) print(str(e)) return traceback.format_exc() finally: self.session.close() return wrapper class MysqlManager(object): def __init__(self): mysql_connection_string = esconfig.mysql.get("mysql_connection_string") self.engine = create_engine('mysql+pymysql://'+mysql_connection_string+'"htmlcode">select CONVERT(c.`id`,CHAR) as id, c.`code` as code, c.`project_name` as project_name, c.`name` as name, date_format(c.`update_time`,'%Y-%m-%dT%H:%i:%s') as update_time, from `cc` c where date_format(c.`update_time`,'%Y-%m-%dT%H:%i:%s')>='::datetime_now';bb.sql:
select CONVERT(c.`id`,CHAR) as id, CONVERT(c.`age`,CHAR) as age, c.`code` as code, c.`name` as name, c.`project_name` as project_name, date_format(c.`update_time`,'%Y-%m-%dT%H:%i:%s') as update_time, from `bb` c where date_format(c.`update_time`,'%Y-%m-%dT%H:%i:%s')>='::datetime_now';esconfig.py:
# -*- coding: utf-8 -*- #__author__="ZJL" # sql 文件名与es中的type名一致 mysql = { # mysql连接信息 "mysql_connection_string": "root:123456@127.0.0.1:3306/xxx", # sql文件信息 "statement_filespath":[ # sql对应的es索引和es类型 { "index":"a1", "sqlfile":"aa.sql", "type":"aa" }, { "index":"a1", "sqlfile":"bb.sql", "type":"bb" }, ], } # es的ip和端口 elasticsearch = { "hosts":"127.0.0.1:9200", } # 字段顺序与sql文件字段顺序一致,这是存进es中的字段名,这里用es的type名作为标识 db_field = { "aa": ("id", "code", "name", "project_name", "update_time", ), "bb": ("id", "code", "age", "project_name", "name", "update_time", ), } es_config = { # 间隔多少秒同步一次 "sleep_time":10, # 为了解决服务器之间时间差问题 "time_difference":3, # show_json 用来展示导入的json格式数据, "show_json":False, }mstes.py:
# -*- coding: utf-8 -*- #__author__="ZJL" from sql_manage import MysqlManager from esconfig import mysql,elasticsearch,db_field,es_config from elasticsearch import Elasticsearch from elasticsearch import helpers import traceback import time class TongBu(object): def __init__(self): try: # 是否展示json数据在控制台 self.show_json = es_config.get("show_json") # 间隔多少秒同步一次 self.sleep_time = es_config.get("sleep_time") # 为了解决同步时数据更新产生的误差 self.time_difference = es_config.get("time_difference") # 当前时间,留有后用 self.datetime_now = "" # es的ip和端口 es_host = elasticsearch.get("hosts") # 连接es self.es = Elasticsearch(es_host) # 连接mysql self.mm = MysqlManager() except : print(traceback.format_exc()) def tongbu_es_mm(self): try: # 同步开始时间 start_time = time.time() print("start..............",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))) # 这个list用于批量插入es actions = [] # 获得所有sql文件list statement_filespath = mysql.get("statement_filespath",[]) if self.datetime_now: # 当前时间加上时间差(间隔时间加上执行同步用掉的时间,等于上一次同步开始时间)再字符串格式化 # sql中格式化时间时年月日和时分秒之间不能空格,不然导入es时报解析错误,所以这里的时间格式化也统一中间加一个T self.datetime_now = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(time.time()-(self.sleep_time+self.time_difference))) else: self.datetime_now = "1999-01-01T00:00:00" if statement_filespath: for filepath in statement_filespath: # sql文件 sqlfile = filepath.get("sqlfile") # es的索引 es_index = filepath.get("index") # es的type es_type = filepath.get("type") # 读取sql文件内容 with open(sqlfile,"r") as opf: sqldatas = opf.read() # ::datetime_now是一个自定义的特殊字符串用于增量更新 if "::datetime_now" in sqldatas: sqldatas = sqldatas.replace("::datetime_now",self.datetime_now) else: sqldatas = sqldatas # es和sql字段的映射 dict_set = db_field.get(es_type) # 访问mysql,得到一个list,元素都是字典,键是字段名,值是数据 db_data_list = self.mm.select_all_dict(sqldatas, dict_set) if db_data_list: # 将数据拼装成es的格式 for db_data in db_data_list: action = { "_index": es_index, "_type": es_type, "@timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(time.time())), "_source": db_data } # 如果没有id字段就自动生成 es_id = db_data.get("id", "") if es_id: action["_id"] = es_id # 是否显示json再终端 if self.show_json: print(action) # 将拼装好的数据放进list中 actions.append(action) # list不为空就批量插入数据到es中 if len(actions) > 0 : helpers.bulk(self.es, actions) except Exception as e: print(traceback.format_exc()) else: end_time = time.time() print("end...................",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))) self.time_difference = end_time-start_time finally: # 报错就关闭数据库 self.mm.close() def main(): tb = TongBu() # 间隔多少秒同步一次 sleep_time = tb.sleep_time # 死循环执行导入数据,加上时间间隔 while True: tb.tongbu_es_mm() time.sleep(sleep_time) if __name__ == '__main__': main()以上这篇用python简单实现mysql数据同步到ElasticSearch的教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]