0

非常に大きな(5GBから2TB)圧縮されたjsonファイルを解析し、以下のアルゴリズムでいくつかのデータをcsvファイルに保存しています。機能しますが、3 つのネストされたループがあるため、効率的ではありません。

また、Python が提供する json および yaml ライブラリに慣れていないため、数行のコードのコストもわかりません。

k = yaml.load(json.dumps(v))

気付かなかった場合は、yaml.load()その行の上の関数を次のように呼び出しています。

header = yaml.load(json.dumps(header))

からのキーの内側の葉(値)がheader文字列として解釈されたため、関数を2回呼び出す必要があったようです。

この行の 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 ツリーです。

さらに 2 つのループを追加して、アルゴリズムの速度を落とさずにこれらの値をすべて取得するより良い方法はありますか?

完全なメソッド ソース:

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...")
4

1 に答える 1

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 +、これは役に立ちません)、コピーする文字列が大きいほど遅くなります (2 次複雑度)。

次のことをお勧めします。

  • 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)])
于 2018-10-11T19:17:15.083 に答える