0

Моя база данных состоит из коллекции большого номера. отелей (около 121 000).Группировка документов с тем же номером телефона

Это как моя коллекция выглядит следующим образом:

{ 
    "_id" : ObjectId("57bd5108f4733211b61217fa"), 
    "autoid" : 1, 
    "parentid" : "P01982.01982.110601173548.N2C5", 
    "companyname" : "Sheldan Holiday Home", 
    "latitude" : 34.169552, 
    "longitude" : 77.579315, 
    "state" : "JAMMU AND KASHMIR", 
    "city" : "LEH Ladakh", 
    "pincode" : 194101, 
    "phone_search" : "9419179870|253013", 
    "address" : "Sheldan Holiday Home|Changspa|Leh Ladakh-194101|LEH Ladakh|JAMMU AND KASHMIR", 
    "email" : "", 
    "website" : "", 
    "national_catidlineage_search" : "/10255012/|/10255031/|/10255037/|/10238369/|/10238380/|/10238373/", 
    "area" : "Leh Ladakh", 
    "data_city" : "Leh Ladakh" 
} 

Каждый документ может иметь 1 или несколько телефонных номеров, разделенных «|» разделитель.

Мне нужно сгруппировать документы с таким же номером телефона.

В режиме реального времени я имею в виду, когда пользователь открывает конкретный отель, чтобы увидеть его детали в веб-интерфейсе, я должен иметь возможность отображать все связанные с ним отели, сгруппированные по общим телефонным номерам.

При группировке, если один отель связывается с другим и что ссылки отелей на другие, то все 3 должны быть сгруппированы вместе.

Example : Hotel A has phone numbers 1|2, B has phone numbers 3|4 and C has phone numbers 2|3, then A, B and C should be grouped together.

from pymongo import MongoClient 
from pprint import pprint #Pretty print 
import re #for regex 
#import unicodedata 

client = MongoClient() 

cLen = 0 
cLenAll = 0 
flag = 0 
countA = 0 
countB = 0 
list = [] 
allHotels = [] 
conContact = [] 
conId = [] 
hotelTotal = [] 
splitListAll = [] 
contactChk = [] 

#We'll be passing the value later as parameter via a function call 
#hId = 37443; 

regx = re.compile("^Vivanta", re.IGNORECASE) 

#Connection 
db = client.hotel 
collection = db.hotelData 

#Finding hotels wrt search input 
for post in collection.find({"companyname":regx}): 
    list.append(post) 

#Copying all hotels in a list 
for post1 in collection.find(): 
    allHotels.append(post1) 

hotelIndex = 11 #Index of hotel selected from search result 
conIndex = hotelIndex 
x = list[hotelIndex]["companyname"] #Name of selected hotel 
y = list[hotelIndex]["phone_search"] #Phone numbers of selected hotel 

try: 
    splitList = y.split("|") #Splitting of phone numbers and storing in a list 'splitList' 
except: 
    splitList = y 


print "Contact details of",x,":" 

#Printing all contacts... 
for contact in splitList: 
    print contact 
    conContact.extend(contact) 
    cLen = cLen+1 

print "No. of contacts in",x,"=",cLen 


for i in allHotels: 
    yAll = allHotels[countA]["phone_search"] 
    try: 
     splitListAll.append(yAll.split("|")) 
     countA = countA+1 
    except: 
     splitListAll.append(yAll) 
     countA = countA + 1 
# print splitListAll 

#count = 0 

#This block has errors 
#Add code to stop when no new links occur and optimize the outer for loop 
#for j in allHotels: 
for contactAll in splitListAll: 
    if contactAll in conContact: 
     conContact.extend(contactAll) 
#  contactChk = contactAll 
#  if (set(conContact) & set(contactChk)): 
#   conContact = contactChk 
#   contactChk[:] = [] #drop contactChk list 
     conId = allHotels[countB]["autoid"] 
    countB = countB+1 

print "Printing the list of connected hotels..." 
for final in collection.find({"autoid":conId}): 
    print final 

Это один код, который я написал в Python. В этом я попытался выполнить линейный поиск в цикле for. Я получаю некоторые ошибки на данный момент, но он должен работать, если исправляться.

Мне нужна оптимизированная версия, так как поиск подкладки имеет сложную временную сложность.

Я довольно новичок в этом, поэтому любые другие предложения по улучшению кода приветствуются.

Спасибо.

+0

У меня нет много знаний о нем, но может elasticsearch мне помочь в решении этой проблемы? – Anubhav

ответ

0

Самый простой ответ на любой вопрос поиска в Python в памяти - «использовать dict». Dicts дают O (ln N) скорость доступа к ключам, списки дают O (N).

Также помните, что вы можете поместить объект Python в такое количество dicts (или списков) и столько раз в один dict или list, сколько потребуется. Они не копируются. Это просто ссылка.

Так что основы будут выглядеть

for hotel in hotels: 
    phones = hotel["phone_search"].split("|") 
    for phone in phones: 
     hotelsbyphone.setdefault(phone,[]).append(hotel) 

В конце этого цикла, hotelsbyphone["123456"] будет список гостиничных объектов, которые были «123456» в качестве одного из своих phone_search строк. Ключевая функция кодирования - это метод .setdefault(key, []), который инициализирует пустой список, если ключ еще не указан в dict, поэтому вы можете добавить к нему.

После того, как вы создали этот показатель, это будет быстро

try: 
    hotels = hotelsbyphone[x] 
    # and process a list of one or more hotels 
except KeyError: 
    # no hotels exist with that number 

В качестве альтернативы try ... except, тест if x in hotelsbyphone:

+0

Спасибо, что ответили. Как пронумеровать «телефоны» в цикле for? Пожалуйста, исправьте меня, если я ошибаюсь, но поскольку это целочисленное значение, его нельзя повторить, не так ли? – Anubhav

+0

и я использую блок catch catch, потому что в документах, содержащих только один номер телефона, я получал ошибку, так как «|» разделителя там нет. – Anubhav

+0

'hotel [" phone_search "]' является строкой, а метод .split ("|") 'возвращает список строк (список из одного элемента, если нет вертикальной полосы). Поэтому «телефон в телефонах» выполняет итерацию по каждой строке в этом списке. – nigel222