Codziennie otrzymuję zapas dokumentów (aktualizacja). Chcę wstawić każdy element, który jeszcze nie istnieje.
- Chcę również śledzić, kiedy wstawiłem je po raz pierwszy i kiedy ostatnio widziałem je w aktualizacji.
- Nie chcę mieć zduplikowanych dokumentów.
- Nie chcę usuwać dokumentu, który został wcześniej zapisany, ale nie ma go w mojej aktualizacji.
- 95% (szacunkowo) zapisów jest niezmienionych z dnia na dzień.
Używam sterownika Python (pymongo).
To, co obecnie robię, to (pseudokod):
for each document in update:
existing_document = collection.find_one(document)
if not existing_document:
document['insertion_date'] = now
else:
document = existing_document
document['last_update_date'] = now
my_collection.save(document)
Mój problem polega na tym, że jest bardzo wolny (40 minut dla mniej niż 100 000 rekordów, a mam ich miliony w aktualizacji). Jestem prawie pewien, że jest coś wbudowanego, aby to zrobić, ale dokument do update () jest mmmhhh .... trochę lakoniczny .... ( http://www.mongodb.org/display/DOCS/Updating )
Czy ktoś może doradzić, jak to zrobić szybciej?
Od MongoDB 2.4 możesz używać $ setOnInsert ( http://docs.mongodb.org/manual/reference/operator/setOnInsert/ )
Ustaw „insertion_date” za pomocą $ setOnInsert i „last_update_date” używając $ set w poleceniu upsert.
Aby zamienić swój pseudokod w działający przykład:
źródło
Zawsze możesz utworzyć unikalny indeks, co spowoduje, że MongoDB odrzuci konflikt zapisu. Rozważ następujące czynności wykonane przy użyciu powłoki mongodb:
źródło
Możesz użyć Upsert z operatorem $ setOnInsert.
źródło
1. Użyj aktualizacji.
Czerpiąc z powyższej odpowiedzi Van Nguyena, użyj aktualizacji zamiast zapisywania. Daje to dostęp do opcji upsert.
UWAGA : Ta metoda zastępuje cały dokument po znalezieniu ( z dokumentów )
1.a. Użyj $ set
Jeśli chcesz zaktualizować wybór dokumentu, ale nie całość, możesz użyć metody $ set z update. (znowu z dokumentów ) ... Więc jeśli chcesz ustawić ...
Wyślij to jako ...
Zapobiega to przypadkowemu zastąpieniu wszystkich dokumentów formatem
{ name: 'jason borne' }
.źródło
Podsumowanie
Uwaga, zakładam, że PyMongo, zmień, aby dopasować do wybranego języka.
Instrukcje:
Utwórz kolekcję z indeksem z unique = true, aby nie uzyskać zduplikowanych rekordów.
Powtarzaj swoje rekordy wejściowe, tworząc partie 15 000 rekordów. Dla każdego rekordu w partii utwórz dyktę składającą się z danych, które chcesz wstawić, zakładając, że każdy z nich będzie nowym rekordem. Dodaj do nich „utworzone” i „zaktualizowane” sygnatury czasowe. Wydaj to jako polecenie wstawiania wsadowego z flagą „ContinueOnError” = true, więc wstawianie wszystkiego innego ma miejsce, nawet jeśli jest tam zduplikowany klucz (co wydaje się, że będzie). TO SIĘ STANIE BARDZO SZYBKO. Duże wstawki rocka, osiągnąłem poziom wydajności 15k / sekundę. Więcej informacji na temat ContinueOnError można znaleźć pod adresem http://docs.mongodb.org/manual/core/write-operations/
Wstawianie płyt odbywa się BARDZO szybko, więc w mgnieniu oka skończysz z tymi wstawkami. Teraz nadszedł czas, aby zaktualizować odpowiednie rekordy. Zrób to przy pobieraniu partii, znacznie szybciej niż pojedynczo.
Ponownie wykonaj iterację wszystkich swoich rekordów wejściowych, tworząc partie po 15 KB. Wyjmij klucze (najlepiej, jeśli jest jeden klucz, ale nie można pomóc, jeśli go nie ma). Pobierz tę grupę rekordów z Mongo za pomocą zapytania db.collectionNameBlah.find ({field: {$ in: [1, 2,3 ...}). Dla każdego z tych rekordów określ, czy istnieje aktualizacja, a jeśli tak, przeprowadź aktualizację, w tym aktualizację „zaktualizowanej” sygnatury czasowej.
Niestety, powinniśmy zauważyć, że MongoDB 2.4 i starsze NIE obejmują operacji zbiorczej aktualizacji. Pracują nad tym.
Kluczowe punkty optymalizacji:
źródło
Nie sądzę, że mongodb obsługuje tego typu selektywne podwyższanie. Mam ten sam problem co LeMiz, a używanie aktualizacji (kryteria, noweObj, upsert, multi) nie działa poprawnie, gdy mamy do czynienia zarówno z „utworzonym”, jak i „zaktualizowanym” znacznikiem czasu. Biorąc pod uwagę następujące oświadczenie upsert:
Scenariusz nr 1 - dokument o „nazwie” „abc” nie istnieje: nowy dokument jest tworzony z „name” = „abc”, „created” = 2010-07-14 11:11:11 i „updated” = 2010-07-14 11:11:11.
Scenariusz nr 2 - dokument o „nazwie” „abc” już istnieje z następującymi: „name” = „abc”, „created” = 2010-07-12 09:09:09 i „updated” = 2010-07 -13 10:10:10. Po poprawie dokument byłby teraz taki sam, jak wynik w scenariuszu nr 1. Nie ma sposobu, aby określić w upsert, które pola mają być ustawione podczas wstawiania, a które pola mają pozostać bez zmian w przypadku aktualizacji.
Moje rozwiązanie polegało na utworzeniu unikalnego indeksu dla pól krytycznych , wykonaniu wstawienia i natychmiast po wykonaniu aktualizacji tylko w polu „zaktualizowanym”.
źródło
Ogólnie rzecz biorąc, użycie aktualizacji jest lepsze w MongoDB, ponieważ po prostu utworzy dokument, jeśli jeszcze nie istnieje, chociaż nie jestem pewien, jak to zrobić z adapterem Pythona.
Po drugie, jeśli chcesz tylko wiedzieć, czy ten dokument istnieje, czy nie, funkcja count (), która zwraca tylko liczbę, będzie lepszą opcją niż find_one, która rzekomo przenosi cały dokument z bazy danych MongoDB, powodując niepotrzebny ruch.
źródło