如何改进解析 lz4 压缩 json 的方法?
How can I improve my method for parsing lz4 compressed json?
我正在解析非常大(5GB 到 2TB)压缩的 json 文件,并使用以下算法将一些数据存储到 csv 文件中。它有效,但由于具有三个嵌套循环而与效率相反。
由于我不熟悉 json 和 python 提供的 yaml 库,我也不确定几行代码的成本:
k = yaml.load(json.dumps(v))
如果你没注意到,我已经调用了一个 yaml.load()
函数
在该行上方:
header = yaml.load(json.dumps(header))
看来我不得不调用该函数两次,因为 header
中键的内部叶子(值)被解释为字符串。
当我简单地在这一行打印出 v 的值时:for k, v in header.iteritems():
,输出通常类似于以下行之一:
[{'value': ['4-55251088-0 0NNN RT(1535855435726 0) q(0 -1 -1 -1) r(0 -1)'], 'key': 'x_iinfo'}]
[{'value': ['timeout=60'], 'key': 'keep_alive'}, {'value': ['Sun, 02 Sep 2018 02:30:35 GMT'], 'key': 'date'}]
[{'value': ['W/"12765-1490784752000"'], 'key': 'etag'}, {'value': ['Sun, 02 Sep 2018 02:27:16 GMT'], 'key': 'date'}]
[{'value': ['Sun, 02 Sep 2018 02:30:32 GMT'], 'key': 'date'}]
所以基本上,如果在我们的文件中有一个名为 'unknown' 的类别,它是一个 json 树,包括没有特定类别的所有内容。
是否有更好的方法来获得所有这些值,而不通过添加两个循环来减慢算法速度?
完整方法来源:
def convertJsonHeadersToCSV(jsonFilePath, CSVFilePath,portNum, protocol):
try:
bodyPattern = re.compile('<(html|!DOCTYPE).*$', re.IGNORECASE | re.MULTILINE)
csvFile = open(CSVFilePath, 'w')
print("Converting " + protocol + " file to csv, please wait...")
spinner.start()
csvWriter = unicodecsv.writer(csvFile)
csvWriter.writerow(['ip', 'date', 'protocol', 'port', 'data'])
chunk_size = 128 * 1024 * 1024
with lz4.frame.open(jsonFilePath, 'r') as f:
for line in f:
try:
text = ""
jsonData = json.loads(line)
ts = jsonData['timestamp'][:10]
ip = jsonData['ip']
data = jsonData['data']['http']
if 'response' in data:
if 'headers' in data['response']:
header = jsonData['data']['http']['response']['headers']
header = yaml.load(json.dumps(header))
for k, v in header.iteritems():
if 'unknown' in k:
#print(v)
k = yaml.load(json.dumps(v))
for i in k:
#print(str(i['key']) + ": "+str(i['value']) + "\r\n")
text = text + str(str(i['key']) + ": "+str(i['value']) + "\r\n")
else:
text = text + str(str(k) + ": "+str(v) + "\r\n")
#csvWriter.writerow([ip, ts, protocol, portNum, text])
except:#sometimes will run into a unicode error, still working on handling this exception.
pass
csvFile.close()
spinner.stop()
print("Completed conversion of " + protocol + " file.")
except Exception as ex:
spinner.stop()
traceback.print_exc()
print("An error occurred while converting the file, moving on to the next task...")
可以肯定会大大加快速度的是停止使用 text
作为字符串,因为这些行:
text = text + str(str(i['key']) + ": "+str(i['value']) + "\r\n")
else:
text = text + str(str(k) + ": "+str(v) + "\r\n")
正在执行字符串连接。由于字符串是不可变的,因此每次都必须进行新的复制(即使使用 text +=
而不是 text = text +
,所以这没有任何帮助),并且要复制的字符串越大,越慢(二次复杂度)。
最好是:
- 定义
text
为空列表
- 附加到列表
- 最后用
"".join
所以
for line in f:
try:
text = [] # define an empty list at start
jsonData = json.loads(line)
然后(使用 str?format
在这里也会有所改善,但那是次要的)
text.append(str(str(i['key']) + ": "+str(i['value']) + "\r\n"))
else:
text.append(str(str(k) + ": "+str(v) + "\r\n"))
最后"mutate" text
变成这样的字符串:
text = "".join(text)
或者只是
csvWriter.writerow([ip, ts, protocol, portNum, "".join(text)])
我正在解析非常大(5GB 到 2TB)压缩的 json 文件,并使用以下算法将一些数据存储到 csv 文件中。它有效,但由于具有三个嵌套循环而与效率相反。
由于我不熟悉 json 和 python 提供的 yaml 库,我也不确定几行代码的成本:
k = yaml.load(json.dumps(v))
如果你没注意到,我已经调用了一个 yaml.load()
函数
在该行上方:
header = yaml.load(json.dumps(header))
看来我不得不调用该函数两次,因为 header
中键的内部叶子(值)被解释为字符串。
当我简单地在这一行打印出 v 的值时:for k, v in header.iteritems():
,输出通常类似于以下行之一:
[{'value': ['4-55251088-0 0NNN RT(1535855435726 0) q(0 -1 -1 -1) r(0 -1)'], 'key': 'x_iinfo'}]
[{'value': ['timeout=60'], 'key': 'keep_alive'}, {'value': ['Sun, 02 Sep 2018 02:30:35 GMT'], 'key': 'date'}]
[{'value': ['W/"12765-1490784752000"'], 'key': 'etag'}, {'value': ['Sun, 02 Sep 2018 02:27:16 GMT'], 'key': 'date'}]
[{'value': ['Sun, 02 Sep 2018 02:30:32 GMT'], 'key': 'date'}]
所以基本上,如果在我们的文件中有一个名为 'unknown' 的类别,它是一个 json 树,包括没有特定类别的所有内容。
是否有更好的方法来获得所有这些值,而不通过添加两个循环来减慢算法速度?
完整方法来源:
def convertJsonHeadersToCSV(jsonFilePath, CSVFilePath,portNum, protocol):
try:
bodyPattern = re.compile('<(html|!DOCTYPE).*$', re.IGNORECASE | re.MULTILINE)
csvFile = open(CSVFilePath, 'w')
print("Converting " + protocol + " file to csv, please wait...")
spinner.start()
csvWriter = unicodecsv.writer(csvFile)
csvWriter.writerow(['ip', 'date', 'protocol', 'port', 'data'])
chunk_size = 128 * 1024 * 1024
with lz4.frame.open(jsonFilePath, 'r') as f:
for line in f:
try:
text = ""
jsonData = json.loads(line)
ts = jsonData['timestamp'][:10]
ip = jsonData['ip']
data = jsonData['data']['http']
if 'response' in data:
if 'headers' in data['response']:
header = jsonData['data']['http']['response']['headers']
header = yaml.load(json.dumps(header))
for k, v in header.iteritems():
if 'unknown' in k:
#print(v)
k = yaml.load(json.dumps(v))
for i in k:
#print(str(i['key']) + ": "+str(i['value']) + "\r\n")
text = text + str(str(i['key']) + ": "+str(i['value']) + "\r\n")
else:
text = text + str(str(k) + ": "+str(v) + "\r\n")
#csvWriter.writerow([ip, ts, protocol, portNum, text])
except:#sometimes will run into a unicode error, still working on handling this exception.
pass
csvFile.close()
spinner.stop()
print("Completed conversion of " + protocol + " file.")
except Exception as ex:
spinner.stop()
traceback.print_exc()
print("An error occurred while converting the file, moving on to the next task...")
可以肯定会大大加快速度的是停止使用 text
作为字符串,因为这些行:
text = text + str(str(i['key']) + ": "+str(i['value']) + "\r\n")
else:
text = text + str(str(k) + ": "+str(v) + "\r\n")
正在执行字符串连接。由于字符串是不可变的,因此每次都必须进行新的复制(即使使用 text +=
而不是 text = text +
,所以这没有任何帮助),并且要复制的字符串越大,越慢(二次复杂度)。
最好是:
- 定义
text
为空列表 - 附加到列表
- 最后用
"".join
所以
for line in f:
try:
text = [] # define an empty list at start
jsonData = json.loads(line)
然后(使用 str?format
在这里也会有所改善,但那是次要的)
text.append(str(str(i['key']) + ": "+str(i['value']) + "\r\n"))
else:
text.append(str(str(k) + ": "+str(v) + "\r\n"))
最后"mutate" text
变成这样的字符串:
text = "".join(text)
或者只是
csvWriter.writerow([ip, ts, protocol, portNum, "".join(text)])