2016-06-16 13 views
8

Tôi đang sử dụng simplejson để deserialize json chuỗi để python đối tượng. Tôi có một object_hook viết tùy chỉnh mà sẽ chăm sóc deserializing các json trở lại đối tượng miền của tôi.Deserializing một chuỗi json lớn để python đối tượng

Vấn đề là, khi chuỗi json của tôi là rất lớn (tức là máy chủ đang trả về các đối tượng miền 800K dưới dạng một chuỗi json), python deserializer của tôi mất gần 10 phút để deserialize chúng.

Tôi khoan thêm một chút và có vẻ như simplejson như vậy không làm nhiều công việc hơn là ủy quyền mọi thứ cho object_hook. Tôi đã thử tối ưu hóa object_hook của mình nhưng điều đó cũng không cải thiện hiệu suất của tôi. (Tôi hầu như không có cải thiện 1 phút)

Câu hỏi của tôi là, chúng tôi có bất kỳ khung chuẩn nào khác được tối ưu hóa để xử lý tập dữ liệu khổng lồ hay không. .

Tôi thấy rằng không có object_hook, khung công tác sẽ chỉ trả về danh sách các từ điển không phải danh sách các đối tượng miền.

Mọi con trỏ ở đây sẽ hữu ích.

FYI Tôi đang sử dụng phiên bản 3.7.2 simplejson

Đây là _object_hook mẫu của tôi:

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 

Một phản ứng Sample:

{"@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"}} 

tôi có nhiều mức độ làm tổ và số hồ sơ tôi nhận được từ máy chủ hơn 800K.

+0

Có vẻ thú vị. Bất kỳ đoạn mã mẫu nào để kiểm tra nhanh, sẽ hữu ích. –

+0

Nếu bạn có thể đăng mã của hàm 'object_hook' và mẫu JSON bạn muốn phân tích cú pháp, điều đó sẽ giúp chúng tôi trả lời câu hỏi của bạn. – jstlaurent

Trả lời

6

Tôi không biết về bất kỳ khung cung cấp những gì bạn tìm kiếm ra khỏi hộp, nhưng bạn có thể áp dụng một vài tối ưu hóa cho cách thức cá thể lớp học của bạn được thiết lập.

Kể từ khi giải nén từ điển vào đối số từ khóa và áp dụng chúng vào các biến lớp học của bạn đang tiến hành phần lớn thời gian, bạn có thể xem xét thông qua các dct trực tiếp đến lớp học của bạn __init__ và thiết lập từ điển lớp cls.__dict__ với dct:

Trial 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 

Trial 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 

Sẽ không có lo lắng về việc self.__dict__ bị sửa đổi thông qua một tham chiếu khác vì tham chiếu đến dct bị mất trước khi trả lại _object_hook.

Điều này tất nhiên có nghĩa là thay đổi thiết lập của bạn __init__, với các thuộc tính của lớp học của bạn hoàn toàn tùy thuộc vào các mục trong dct. Tuỳ bạn.


Bạn cũng có thể thay thế cls != None với cls is not None (chỉ có một None đối tượng để một kiểm tra danh tính là hơn pythonic):

Trial 1

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

Trial 2

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

Và bạn có thể thay thế hai dòng với một với:

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

trở thành:

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

Trên thang điểm từ 800K miền đối tượng, những sẽ giúp bạn tiết kiệm một số thời điểm tốt để có được object_hook để tạo các đối tượng của bạn nhanh hơn.

+1

Cảm ơn bạn đã tìm đến nó. Với đề xuất của bạn tôi có thể giảm 2 phút của thời gian deserialization object_hook. Nhưng vẫn còn thời gian kết thúc cho 800K là ~ 8 phút. Tôi thấy 800K bản ghi object_hook của tôi được gọi bởi simplejson "3709170" số lần. Tôi đã tự hỏi nếu có bất kỳ khuôn khổ được tối ưu hóa để giảm các cuộc gọi này. Bất kỳ suy nghĩ nào về lambdaJSON (jsontree/jsonpickle hoặc bất kỳ khung công tác nào khác) – pragnya

+0

@pragnya Nếu nó hoạt động tốt với 'lamdaJSON', bạn có thể đăng hack của mình như một câu trả lời cho những người khác có cùng vấn đề trong tương lai. –

Các vấn đề liên quan