此问题可能是由于我对ELK,Python和Unicode不满意。
我有一个索引,其中包含经过logstash消化的日志,包括一个包含主机名的字段“ host_req”。使用Elasticsearch- py,我将该主机名从记录中拉出,并使用它来搜索另一个索引。但是,如果主机名包含多字节字符,它将失败并显示UnicodeDecodeError。当我在命令行中使用“ curl -XGET”输入相同的查询时,它确实可以正常工作。unicode字符是带有小写字母(两个点)的小写字母“ a”。UTF-8值为C3 A4,而Unicode代码点似乎是00E4(语言是瑞典语)。
这些curl命令可以从命令行正常运行:
curl -XGET 'http://localhost:9200/logstash-2015.01.30/logs/_search?pretty=1' -d ' { "query" : {"match" :{"req_host" : "www.utkl\u00E4dningskl\u00E4derna.se" }}}' curl -XGET 'http://localhost:9200/logstash-2015.01.30/logs/_search?pretty=1' -d ' { "query" : {"match" :{"req_host" : "www.utklädningskläderna.se" }}}'
他们找到并返回记录
(第二行显示了主机名在我从中提取的日志中的显示方式,在两个位置显示了带有小写字母的小写字母“ a”)
我编写了一个非常简短的Python脚本来显示问题:它使用硬连线查询,打印它们及其类型,然后尝试在搜索中使用它们。
#!/usr/bin/python # -*- coding: utf-8 -*- import json import elasticsearch es = elasticsearch.Elasticsearch() if __name__=="__main__": #uq = u'{ "query": { "match": { "req_host": "www.utklädningskläderna.se" }}}' # raw utf-8 characters. does not work #uq = u'{ "query": { "match": { "req_host": "www.utkl\u00E4dningskl\u00E4derna.se" }}}' # quoted unicode characters. does not work #uq = u'{ "query": { "match": { "req_host": "www.utkl\uC3A4dningskl\uC3A4derna.se" }}}' # quoted utf-8 characters. does not work uq = u'{ "query": { "match": { "req_host": "www.facebook.com" }}}' # non-unicode. works fine print "uq", type(uq), uq result = es.search(index="logstash-2015.01.30",doc_type="logs",timeout=1000,body=uq); if result["hits"]["total"] == 0: print "nothing found" else: print "found some"
如果我如图所示运行它,并使用“ facebook”查询,那就很好了-输出为:
$python testutf8b.py uq <type 'unicode'> { "query": { "match": { "req_host": "www.facebook.com" }}} found some
请注意,查询字符串’uq’是unicode。
但是,如果我使用其他三个字符串(包括Unicode字符),它就会炸毁。例如,在第二行中,我得到:
$python testutf8b.py uq <type 'unicode'> { "query": { "match": { "req_host": "www.utklädningskläderna.se" }}} Traceback (most recent call last): File "testutf8b.py", line 15, in <module> result = es.search(index="logstash-2015.01.30",doc_type="logs",timeout=1000,body=uq); File "build/bdist.linux-x86_64/egg/elasticsearch/client/utils.py", line 68, in _wrapped File "build/bdist.linux-x86_64/egg/elasticsearch/client/__init__.py", line 497, in search File "build/bdist.linux-x86_64/egg/elasticsearch/transport.py", line 307, in perform_request File "build/bdist.linux-x86_64/egg/elasticsearch/connection/http_urllib3.py", line 82, in perform_request elasticsearch.exceptions.ConnectionError: ConnectionError('ascii' codec can't decode byte 0xc3 in position 45: ordinal not in range(128)) caused by: UnicodeDecodeError('ascii' codec can't decode byte 0xc3 in position 45: ordinal not in range(128)) $
再次注意,查询字符串是一个unicode字符串(是的,源代码行是带有\u00E4字符的字符串)。
\u00E4
我真的很想解决这个问题。我尝试了uq = uq.encode("utf=8")和的各种组合uq = uq.decode("utf=8"),但似乎无济于事。我开始怀疑elasticsearch-py图书馆是否存在问题。
uq = uq.encode("utf=8")
uq = uq.decode("utf=8")
elasticsearch-py
谢谢!
pt
PS:这是在Centos 7下,使用ES 1.5.0。使用logstash-1.4.2将日志摘要消化到稍旧版本的ES中
基本上,您不需要body作为字符串传递。使用本地python数据结构。或即时转换它们。试试看,请:
body
>>> import elasticsearch >>> es = elasticsearch.Elasticsearch() >>> es.index(index='unicode-index', body={'host': u'www.utklädningskläderna.se'}, doc_type='log') {u'_id': u'AUyGJuFMy0qdfghJ6KwJ', u'_index': u'unicode-index', u'_type': u'log', u'_version': 1, u'created': True} >>> es.search(index='unicode-index', body={}, doc_type='log') {u'_shards': {u'failed': 0, u'successful': 5, u'total': 5}, u'hits': {u'hits': [{u'_id': u'AUyBTz5CsiBSSvubLioQ', u'_index': u'unicode-index', u'_score': 1.0, u'_source': {u'host': u'www.utkl\xe4dningskl\xe4derna.se'}, u'_type': u'log'}], u'max_score': 1.0, u'total': 1}, u'timed_out': False, u'took': 5} >>> es.search(index='unicode-index', body={'query': {'match': {'host': u'www.utklädningskläderna.se'}}}, doc_type='log') {u'_shards': {u'failed': 0, u'successful': 5, u'total': 5}, u'hits': {u'hits': [{u'_id': u'AUyBTz5CsiBSSvubLioQ', u'_index': u'unicode-index', u'_score': 0.30685282, u'_source': {u'host': u'www.utkl\xe4dningskl\xe4derna.se'}, u'_type': u'log'}], u'max_score': 0.30685282, u'total': 1}, u'timed_out': False, u'took': 122} >>> import json >>> body={'query': {'match': {'host': u'www.utklädningskläderna.se'}}} >>> es.search(index='unicode-index', body=body, doc_type='log') {u'_shards': {u'failed': 0, u'successful': 5, u'total': 5}, u'hits': {u'hits': [{u'_id': u'AUyBTz5CsiBSSvubLioQ', u'_index': u'unicode-index', u'_score': 0.30685282, u'_source': {u'host': u'www.utkl\xe4dningskl\xe4derna.se'}, u'_type': u'log'}], u'max_score': 0.30685282, u'total': 1}, u'timed_out': False, u'took': 4} >>> es.search(index='unicode-index', body=json.dumps(body), doc_type='log') {u'_shards': {u'failed': 0, u'successful': 5, u'total': 5}, u'hits': {u'hits': [{u'_id': u'AUyBTz5CsiBSSvubLioQ', u'_index': u'unicode-index', u'_score': 0.30685282, u'_source': {u'host': u'www.utkl\xe4dningskl\xe4derna.se'}, u'_type': u'log'}], u'max_score': 0.30685282, u'total': 1}, u'timed_out': False, u'took': 5} >>> json.dumps(body) '{"query": {"match": {"host": "www.utkl\\u00e4dningskl\\u00e4derna.se"}}}'