2016-06-17 5 views
0

Я пишу скрипт python, который выполняет следующие действия.Python MongoDB запрашивает данные сегмента в куски

запрос по MongoDB базы данных анализа и совокупные результаты загрузки данных в таблицу ServiceNow через REST API

Скрипт работает, однако, набор данных слишком велик, а время ОСТАЛЬНЫЕ транзакций через 60 секунд (соединение закрывается сервером ServiceNow в пункте назначения).

Мне нужно будет сегментировать данные в куски и отправлять отдельные транзакции REST для каждого блока данных, чтобы гарантировать, что полный набор данных отправляется через POST без превышения предела таймаута.

Как я могу достичь этой цели, изменив сценарий ниже?

#!/usr/bin/env python 

from config import * 

import os, sys 

mypath = os.path.dirname(os.path.realpath(__file__)) 
sys.path.append(os.path.join(mypath, "api-python-client")) 

from apiclient.mongo import * 

from pymongo import MongoClient 

import json 

import requests 

from bson.json_util import dumps 

client = MongoClient(mongo_uri) 

#Create ServiceNow URL 
svcnow_url = create_svcnow_url('u_imp_cmps') 

#BITSDB Nmap Collection 
db = client[mongo_db] 

#Aggregate - RDBMS equivalent to Alias select x as y 
#Rename fields to match ServiceNow field names 
computers = db['computer'].aggregate([ 
     {"$unwind": "$hostnames"}, 
     {"$project" : { 
       "_id":0, 
       "u_hostname": "$hostnames.name", 
       "u_ipv4": "$addresses.ipv4", 
       "u_status": "$status.state", 
       "u_updated_timestamp": "$last_seen" 
     }} 

]) 

j = dumps({"records":computers}) 
#print(j) 


#Set proper headers 
headers = {"Content-Type":"application/json","Accept":"application/json"} 

#Build HTTP Request 
response = requests.post(url=svcnow_url, auth=(svcnow_user, svcnow_pwd), headers=headers ,data=j) 

#Check for HTTP codes other than 200 
if response.status_code != 200: 
     print('Status:', response.status_code, 'Headers:', response.headers, 'Response Text', response.text, 'Error Response:',response.json()) 
     exit() 

#Decode the JSON response into a dictionary and use the data 
print('Status:',response.status_code,'Headers:',response.headers,'Response:',response.json()) 

ОБНОВЛЕНИЕ: У меня есть план, но я не уверен, как его реализовать.

  • Установите курсор на фиксированный размер партии 1000 записывает каждое
  • Когда партия полна, создать выход JSON и отправить данные через запросы
  • В цикле: продолжать захватывая новую партию и отправку каждая партия к месту назначения до полного набора данных достигается

https://docs.mongodb.com/v3.0/reference/method/cursor.batchSize/

в принципе я думаю, что я могу решить эту проблему путем создания партий и loopin g через партии, с новым вызовом API каждый раз. Пожалуйста, дайте мне знать, есть ли у кого-нибудь идеи, если это хороший план и как реализовать решение. Благодарю.

+0

Кто-нибудь есть какие-либо предложения, по крайней мере там, где начать? Я застрял. Спасибо. – pengz

ответ

1

j = dumps({"records":computers}) вернет список, поэтому вы можете легко указать один элемент данных, вызвав j[x], или итерацию через цикл for. Каждая из этих записей должна быть приемлемой для ServiceNow.

# Set proper headers (these are always the same, so this 
# can be assigned outside of the for loop) 
headers = {"Content-Type":"application/json","Accept":"application/json"} 

for data_point in j: 

    #Build HTTP Request (Note we are using data_point instead of j) 
    response = requests.post(url=svcnow_url, auth=(svcnow_user, svcnow_pwd), headers=headers ,data=data_point) 

    #Check for HTTP codes other than 200 
    if response.status_code != 200: 
     print('Status:', response.status_code, 'Headers:', response.headers, 'Response Text', response.text, 'Error Response:',response.json()) 
    else: 
     # This is a response of success for a single record 
     print('Status:',response.status_code,'Headers:',response.headers,'Response:',response.json()) 

exit() 

Если у вас есть 100 новых записей в MongoDB, это вызовет 100 POST-вызовов ServiceNow. Ваш экземпляр ServiceNow должен иметь возможность обрабатывать нагрузку, и вы можете очень легко идентифицировать записи, которые не удалось загрузить.

Однако, если вам нужно уплотнить количество вызовов по какой-либо причине, я хотел бы предложить, разделив свой список в «подсписки», как one-liner featured in this answer:

# Set proper headers (these are always the same, so this 
# can be assigned outside of the for loop) 
headers = {"Content-Type":"application/json","Accept":"application/json"} 

# Each POST will send up to 10 records of data 
split_size = 10 

# Note the two places where our split_size variable is used 
for data_point in [j[x:x+split_size] for x in xrange(0, len(j), split_size)]: 

    #Build HTTP Request (Note we are using data_point instead of j) 
    response = requests.post(url=svcnow_url, auth=(svcnow_user, svcnow_pwd), headers=headers ,data=data_point) 

    #Check for HTTP codes other than 200 
    if response.status_code != 200: 
     print('Status:', response.status_code, 'Headers:', response.headers, 'Response Text', response.text, 'Error Response:',response.json()) 
    else: 
     # This is a response of success for a single record 
     print('Status:',response.status_code,'Headers:',response.headers,'Response:',response.json()) 

exit() 
+0

Привет, Стив благодарен за ответ. У меня возникает проблема, когда цикл циклически переплетается по символам данных (а не по записи). Другими словами, если я делаю «для data_point в j: print (data_point)», который будет возвращать каждый отдельный символ один за другим, а не каждую запись. Любая идея о том, как я могу смягчить эту проблему? Благодаря! – pengz

+0

А я думаю, я знаю, почему это так. Тип данных переменной «j» - это строка, не являющаяся списком. "print (type (j))" . – pengz

+0

Я смог исправить это, преобразовывая данные курсора в список и итерируя список. Большое спасибо за вашу помощь. – pengz

Смежные вопросы