2012-08-13 19 views
5

मैं एक ऐसे सर्वर पर सैकड़ों हजार JSON रिकॉर्ड पोस्ट कर रहा हूं जिसमें MAX डेटा अपलोड सीमा 1 एमबी है। मेरे रिकॉर्ड बहुत ही परिवर्तनीय आकार के हो सकते हैं, कुछ सौ बाइट्स के रूप में, कुछ सौ हजार तक।पायथन: किसी सर्वर पर पोस्ट करने के लिए जेसन स्ट्रिंग के आकार को सीमित करना

def checkSize(payload): 
    return len(payload) >= bytesPerMB 


toSend = [] 
for row in rows: 
    toSend.append(row) 
    postData = json.dumps(toSend) 
    tooBig = tooBig or checkSize() 
    if tooBig: 
      sendToServer(postData) 

जो सर्वर पर पोस्ट करता है। यह वर्तमान में काम करता है, लेकिन एक जेसनिफाइड स्ट्रिंग को भेजने के लिए निरंतर डंपिंग वास्तव में भारी और लगभग 100% बहुत अधिक लगता है, हालांकि मुझे ऐसा करने का कोई तरीका नहीं दिख रहा है। क्या मैं व्यक्तिगत नए रिकॉर्ड को स्ट्रिंग करने और एक साथ रहने के बारे में बताता हूं कि वे एक साथ होंगे?

मुझे यकीन है कि ऐसा करने का एक क्लीनर तरीका होना चाहिए, लेकिन मुझे नहीं पता।

किसी भी और सभी मदद के लिए धन्यवाद।


इस उत्तर मैं अब उपयोग कर रहा हूँ, (है मैं नीचे @rsegal के रूप में एक ही समय में यह के साथ आया था, बस स्पष्टता और पूरा करने के लिए पोस्टिंग sendToServer चीजों को दिखाने के लिए सही ढंग से काम कर रहे हैं बस एक डमी समारोह है),

import pickle 
import json 

f = open("userProfiles") 
rows = pickle.load(f) 
f.close() 

bytesPerMB = 1024 * 1024 
comma = "," 
appendSize = len(comma) 

def sendToServer(obj): 
    #send to server 
    pass 

def checkSize(numBytes): 
    return numBytes >= bytesPerMB 

def jsonDump(obj): 
    return json.dumps(obj, separators=(comma, ":")) 

leftover = [] 
numRows = len(rows) 
rowsSent = 0 

while len(rows) > 0: 
    toSend = leftover[:] 
    toSendSize = len(jsonDump(toSend)) 
    leftover = [] 
    first = len(toSend) == 0 

    while True: 
     try: 
      row = rows.pop() 
     except IndexError: 
      break 

     rowSize = len(jsonDump(row)) + (0 if first else appendSize) 
     first = False 

     if checkSize(toSendSize + rowSize): 
      leftover.append(row) 
      break 

     toSend.append(row) 
     toSendSize += rowSize 

    rowsSent += len(toSend) 
    postData = jsonDump(toSend) 
    print "assuming to send '{0}' bytes, actual size '{1}'. rows sent {2}, total {3}".format(toSendSize, len(postData), rowsSent, numRows) 
    sendToServer(postData) 

उत्तर

2

मैं निम्नलिखित की तरह कुछ करना होगा:

toSend = [] 
toSendLength = 0 
for row in rows: 
    tentativeLength = len(json.dumps(row)) 
    if tentativeLength > bytesPerMB: 
     parsingBehavior // do something about lolhuge files 
    elif toSendLength + tentativeLength > bytesPerMB: // it would be too large 
     sendToServer(json.dumps(toSend)) // don\'t exceed limit; send now 
     toSend = [row] // refresh for next round - and we know it fits! 
     toSendLength = tentativeLength 
    else: // otherwise, it wont be too long, so add it in 
     toSend.append(row) 
     toSendLength += tentative 
sentToServer(json.dumps(toSend)) // if it finishes below the limit 

मुद्दा अपने समाधान के साथ है कि यह एक बड़ी-ओ नजरिए से महान नहीं है। मेरा रैखिक समय में चलता है, आपका वर्ग वर्ग में चलता है, क्योंकि आप हर लूप संचयी लंबाई की जांच कर रहे हैं। पोस्टडेटा को रीसेट करना हर बार बहुत ही कुशल नहीं है, या तो।

+1

एचए! चारों ओर खेलते समय, मुझे काफी सटीक समाधान मिल गया। मेरे पास एक 'बचे हुए' सूची है जो कुछ भी लेती है जो सीमा पर आकार भेजती है और 'toSendLength' होना चाहिए 'len (json.dumps (toSend)) - लेन (",")' और 'tentativeLength' होना चाहिए 'लेन (json.dumps (पंक्ति)) + लेन (",") क्योंकि प्रत्येक नई पंक्ति के साथ, एक अल्पविराम और स्थान भी जोड़ा जाएगा। धन्यवाद रेसेगल! – seaders

+0

और वास्तव में इसके शीर्ष पर, मैंने "विभाजक = (',', ':')" जेसन डंप दोनों को एक और अधिक मूल्यवान डेटा सहेजने के लिए जोड़ा है! – seaders

+0

खुशी है कि आपके लिए काम किया है! JSON के साथ पाइथन के लेन-देन के विनिर्देशों के बारे में आप मुझसे अधिक स्पष्ट रूप से जानते हैं। आप फिर से प्रगति कर रहे हैं, और शायद यह भविष्य में किसी की मदद करेगा। बेहद कूल! – rsegal