【问题标题】:How can I improve my method for parsing lz4 compressed json?如何改进解析 lz4 压缩 json 的方法?
【发布时间】:2018-10-11 19:03:27
【问题描述】:

我正在解析非常大的(5GB 到 2TB)压缩 json 文件,并使用以下算法将一些数据存储到 csv 文件中。它可以工作,但由于具有三个嵌套循环,因此与高效相反。

由于不熟悉python提供的json和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'}]

所以基本上,如果我们的文件中有一个名为“未知”的类别,它是一个 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 + str(str(i['key']) + ": "+str(i['value']) + "\r\n") 当字符串开始变大时,python 中的字符串连接效率非常低。是这样吗?
  • 它确实会变得很大,我应该直接附加到文件吗?

标签: python json algorithm unicode lz4


【解决方案1】:

可以肯定的是,停止使用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"))

最后将text“变异”成这样的字符串:

text = "".join(text)

或者只是

csvWriter.writerow([ip, ts, protocol, portNum, "".join(text)])

【讨论】:

  • 我相信这会有所帮助。添加条件以从列表中的每个字符串中删除某些字符怎么样?
  • 基本上是一种更快的方法: text.append(str(str(k).replace('_','-') + ": "+str(v).strip(" []").strip("\"\'") + "\r\n"))
  • 是的,附加字符串上的任何内容都不会成为问题。
猜你喜欢
  • 1970-01-01
  • 2021-10-03
  • 2016-05-01
  • 1970-01-01
  • 2016-03-31
  • 2014-02-03
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
相关资源
最近更新 更多