2016-06-16 11 views
8

私はsimplejsonを使用してjson文字列をPythonオブジェクトに逆直列化しています。私はjsonを自分のドメインオブジェクトにデシリアライズすることを担当するカスタムの書かれたobject_hookを持っています。Pythonオブジェクトに大きなjson文字列をデシリアライズ

私のjson文字列が巨大な場合(つまり、サーバーが約800Kのドメインオブジェクトをjson文字列の形で返している)、私のpythonデシリアライザはそれらを逆シリアル化するのに約10分かかります。

もう少し詳しく掘り下げてみましたが、それは単なるjsonsonのように見えますが、それはすべてをobject_hookに委任しています。私はobject_hookを最適化しようとしましたが、それも私のパフォーマンスを改善していません。 (私はほとんど1分の改善を得た)

私の質問は、巨大なデータセットを扱うために最適化された他の標準フレームワークを持っているのか、object_hookレベルですべてを行うのではなくフレームワークの能力を利用できる方法です。

私は、object_hookがなければ、フレームワークはドメインオブジェクトのリストではなく辞書のリストを返すことが分かります。

ここにはすべてのポインタが便利です。 FYI私はここのsimplejsonバージョン3.7.2

を使用しています

は私のサンプル_object_hookです:

def _object_hook(dct): 
    if '@CLASS' in dct: # server sends domain objects with this @CLASS 
     clsname = dct['@CLASS'] 
     # This is like Class.forName (This imports the module and gives the class) 
     cls = get_class(clsname) 
     # As my server is in java, I convert the attributes to python as per python naming convention. 
     dct = dict((convert_java_name_to_python(k), dct[k]) for k in dct.keys()) 
     if cls != None: 
      obj_key = None 
      if "@uuid"in dct 
       obj_key = dct["@uuid"] 
       del(dct["@uuid"]) 
      else: 
       info("Class missing uuid: " + clsname) 
      dct.pop("@CLASS", None) 

      obj = cls(**dct) #This I found to be the most time consuming process. In my domian object, in the __init__ method I have the logic to set all attributes based on the kwargs passed 
      if obj_key is not None: 
       shared_objs[obj_key] = obj #I keep all uuids along with the objects in shared_objs dictionary. This shared_objs will be used later to replace references. 
     else: 
      warning("class not found: " + clsname) 
      obj = dct 

     return obj 
    else: 
     return dct 

サンプル応答:

{"@CLASS":"sample.counter","@UUID":"86f26a0a-1a58-4429-a762- 9b1778a99c82","val1":"ABC","val2":1131,"val3":1754095,"value4": {"@CLASS":"sample.nestedClass","@UUID":"f7bb298c-fd0b-4d87-bed8- 74d5eb1d6517","id":1754095,"name":"XYZ","abbreviation":"ABC"}} 

私は多くの入れ子のレベルと数を持っていますサーバーから受け取ったレコードの数は800K以上です。

+0

興味深いですね。それを素早くチェックするためのサンプルスニペットが便利です。 –

+0

'object_hook'関数のコードと解析したいJSONのサンプルを投稿できれば、あなたの質問に答えるのに役立ちます。 – jstlaurent

答えて

6

あなたが探し求めているものを提供するフレームワークについてはわかりませんが、クラスインスタンスの設定方法にいくつかの最適化を適用することができます。

キーワード引数に辞書を開梱し、時間の大半を取っているあなたのクラス変数に適用しているので、あなたはdctとあなたのクラス__init__に直接dctを渡すと、クラスの辞書cls.__dict__の設定を検討可能性があります

試験1

In [1]: data = {"name": "yolanda", "age": 4} 

In [2]: class Person: 
    ...:  def __init__(self, name, age): 
    ...:   self.name = name 
    ...:   self.age = age 
    ...: 
In [3]: %%timeit 
    ...: Person(**data) 
    ...: 
1000000 loops, best of 3: 926 ns per loop 

試験2

In [4]: data = {"name": "yolanda", "age": 4} 

In [5]: class Person2: 
    ....:  def __init__(self, data): 
    ....:   self.__dict__ = data 
    ....: 
In [6]: %%timeit 
    ....: Person2(data) 
    ....: 
1000000 loops, best of 3: 541 ns per loop 

dctへの参照が失われてから_object_hookが返されるため、self.__dict__が別の参照によって変更される心配はありません。

これはもちろん__init__の設定を変更することを意味し、クラスの属性は厳密にはdctの項目に依存します。それはあなた次第です。


また(IDチェックがより多くのニシキヘビがあるので、一つだけNoneオブジェクトが存在する)cls is not Nonecls != None置き換えることがあります。

試用版を1

In [38]: cls = 5 
In [39]: %%timeit 
    ....: cls != None 
    ....: 
10000000 loops, best of 3: 85.8 ns per loop 

試験2

In [40]: %%timeit 
    ....: cls is not None 
    ....: 
10000000 loops, best of 3: 57.8 ns per loop 

そして、あなたが持つものと2つの行を置き換えることができますになってきて

obj_key = dct["@uuid"] 
del(dct["@uuid"]) 

obj_key = dct.pop('@uuid') # Not an optimization as this is same with the above 

800K ドメインオブジェクトのスケールでは、これらはあなたにいくつかを救いますobject_hookにオブジェクトをより迅速に作成するのには良い時間です。

+1

それを見ていただきありがとうございます。あなたの提案では、object_hookの逆シリアル化時間を2分短縮できました。しかし、800Kの終わりの時間は〜8分です。私はobject_hookがsimplejson "3709170"回数で呼び出された800Kレコードを見る。私は、この呼び出しを減らすために最適化されたフレームワークがあるかどうか疑問に思っていました。 lambdaJSON(jsontree/jsonpickleやその他のフレームワーク)についての考え方 – pragnya

+0

@pragnya 'lamdaJSON'でうまくいけば、将来同じ問題を抱えるかもしれない人のための解答としてあなたのハックを投稿することができます。 –

関連する問題