最近我设置了一个flask post端点,通过impyla模块将数据写入impala db。
env:centos上的python3.6.5。
impala版本:impalad版本2.6.0-cdh5.8.0
api.py版本:
from flask import Flask, request, abort, Response
from flask_cors import CORS
import json
from impala.dbapi import connect
import sys
import re
from datetime import datetime
app = application = Flask(__name__)
CORS(app)
conn = connect(host='datanode2', port=21050,
user='user', database='testdb')
@app.route("/api/endpoint", methods=['POST'])
def post_data():
# if not request.json:
# abort(400)
params = request.get_json(force=True) # getting request data
print(">>>>>> ", params, flush=True)
params['log_time'] = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
# params['page_url'] = re.sub(
# '[^a-zA-Z0-9-_*.]', '', re.sub(':', '_', params['page_url']))
try:
cursor = conn.cursor()
sql = "INSERT INTO table ( page_title, page_url, log_time, machine, clicks, id ) VALUES (%s, %s, %s, %s, %s, %s)"
values = (params['page_title'], params['page_url'], params['log_time'],
params['machine'], params['clicks'], params['id'])
print(">>>>>> " + sql % values, file=sys.stderr, flush=True)
cursor.execute(sql, values)
print(
f">>>>>> Data Written Successfully", file=sys.stderr, flush=True)
return Response(json.dumps({'success': True}), 201, mimetype="application/json")
except Exception as e:
print(e, file=sys.stderr, flush=True)
return Response(json.dumps({'success': False}), 400, mimetype="application/json")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5008, debug=True)
需求类型:
import requests as r
url = "http://123.234.345.456:30001/"
# url = "https://stackoverflow.com/questions/ask"
res = r.post('http://localhost:5008/api/endpoint',
json={
"page_title": "Home",
"page_url": url,
"machine": "Mac OS",
"clicks": 16,
"id": "60cd1d79-eda7-44c2-a4ec-ffdd5d6ac3db"
}
)
if res.ok:
print(res.json())
else:
print('Error!')
我查了一下 flask 的api python api.py
然后用 python req.py
.
flask服务器出现以下错误:
>>>>>> {'page_title': 'Home', 'page_url': 'http://123.234.345.456:30001/', 'machine': 'Mac OS', 'clicks': 16, 'id': '60cd1d79-eda7-44c2-a4ec-ffdd5d6ac3db'}
>>>>>> INSERT INTO table ( page_title, page_url, log_time, machine, clicks, id ) VALUES (Home, http://123.234.345.456:30001/, 2018-12-12 16-14-04, Mac OS, 16, 60cd1d79-eda7-44c2-a4ec-ffdd5d6ac3db)
AnalysisException: Syntax error in line 1:
..., 'http://123.234.345.456'2018-12-12 16-14-04'0001/', ...
^
Encountered: INTEGER LITERAL
Expected: AND, AS, ASC, BETWEEN, CROSS, DESC, DIV, ELSE, END, FOLLOWING, FROM, FULL, GROUP, HAVING, ILIKE, IN, INNER, IREGEXP, IS, JOIN, LEFT, LIKE, LIMIT, NOT, NULLS, OFFSET, OR, ORDER, PRECEDING, RANGE, REGEXP, RIGHT, RLIKE, ROWS, THEN, UNION, WHEN, WHERE, COMMA, IDENTIFIER
CAUSED BY: Exception: Syntax error
这个错误有点烦人:
我试着直接在impala shell中插入sql命令,结果它成功了。
当pageurl是唯一的参数时,它也可以正常工作。
所以这是一些条件字符转义的问题?我设法绕过这个问题,用一些正则表达式调整url(取消注解第27-28行)。但这真的很烦人,我不想因为这个清理我的数据。
当我检查其他人的试验时,人们认为在每个插入值中添加一对引号会起作用。但是,在使用字符串格式时,我该如何做到这一点,而且必须在 cursor.execute(sql, values)
?
2条答案
按热度按时间dffbzjpn1#
经过一些努力,以及@scratch'n'purr和@msafiullah在参数替换问题上的巨大帮助,我成功地使它工作了。这有点复杂,所以我将发布完整的文档代码:
错误原因:冒号通过impyla api转义的问题。
解决方案:使用定制的转义函数来处理数据,并采用sql注入(python的字符串格式化方式来替换参数)而不是标准的pythondbapi。
cursor.execute(sql, values)
.api.py版本:
req.py与问题相同。
table
架构:flask的服务器输出:
在 Impala 壳里面,
select * from table
将提供:基本上,只有数字(例如。
INT
类型)不需要通过parameterize()
清洁/逃生过程。其他类型,如VARCHAR
,CHAR
,STRING
,TIMESTAMP
(因为冒号)应预先逃逸,以便安全地通过impyla api插入。umuewwlo2#
impyla或其他基于impala的python库不支持参数化查询,就像传统的sqldb那样。我遇到的唯一解决方案是,如果插入值定义为string/timestamp,则用引号将其括起来。
您提到在执行查询之前使用字符串格式时如何做到这一点?很简单,只需应用字符串格式,然后插入格式化的值。
在您的示例中,假设您的表具有以下类型定义:
那么您的insert语句将是:
现在自从
log_time
是时间戳类型,您必须格式化datetime.now()
到yyyy-MM-dd HH:mm:ss
格式。如果你定义了
log_time
作为字符串而不是时间戳%Y-%m-%d %H-%M-%S
会有用的。最后,执行:
请注意,此方法仅在处理基本数据类型(如数字或字符串)时有效。任何复杂的东西,比如数组或结构,都是行不通的。