Optymalizacja wstawiania partii o dużej objętości do Neo4j za pomocą REST
Muszę wstawić ogromną liczbę węzłów z relacjami między nimi do Neo4j poprzez punkt końcowy wsadowy API REST, około 5k rekordów / s (wciąż rośnie).
Będzie to ciągłe wstawianie 24x7. Każdy rekord może wymagać utworzenia tylko jednego węzła, ale inny może wymagać dwóch węzłów i utworzenia jednej relacji.
Czy mogę poprawić wydajność wkładek, zmieniając procedurę lub modyfikując ustawienia Neo4j?
Moje dotychczasowe postępy:
1. Testowałem z Neo4j przez chwilę, ale nie mogłem uzyskać wydajności, której potrzebowałem
Pole serwera testowego: 24 rdzenie + 32 GB pamięci RAM
Neo4j 2.0.0-M06 zainstalowany jako samodzielna usługa.
Uruchamianie mojej aplikacji Java na tym samym serwerze (aplikacja Neo4j i Java będą musiały w przyszłości działać na własnym serwerze, więc nie można używać trybu osadzonego)
REST API Endpoint: / db / data / batch (target: / cypher)
Używając indeksu schematu, ograniczenia, MERGE, CREATE UNIQUE.
2. Mój schemat:
neo4j-sh (0)$ schema
==> Indexes
==> ON :REPLY(created_at) ONLINE
==> ON :REPLY(ids) ONLINE (for uniqueness constraint)
==> ON :REPOST(created_at) ONLINE
==> ON :REPOST(ids) ONLINE (for uniqueness constraint)
==> ON :Post(userId) ONLINE
==> ON :Post(postId) ONLINE (for uniqueness constraint)
==>
==> Constraints
==> ON (post:Post) ASSERT post.postId IS UNIQUE
==> ON (repost:REPOST) ASSERT repost.ids IS UNIQUE
==> ON (reply:REPLY) ASSERT reply.ids IS UNIQUE
3. Moje szyfrowane zapytania i żądania JSON
3.1. Gdy jeden rekord wymaga utworzenia pojedynczego węzła, opis zadania wygląda jak poniżej
{"method" : "POST","to" : "/cypher","body" : {"query" : "MERGE (child:Post {postId:1001, userId:901})"}}
3.2. Gdy jeden rekord wymaga dwóch węzłów z jedną relacją do utworzenia, opis zadania wygląda jak poniżej
{"method" : "POST","to" : "/cypher","body" : {"query" : "MERGE (parent:Post {postId:1002, userId:902}) MERGE (child:Post {postId:1003, userId:903}) CREATE UNIQUE parent-[relationship:REPOST {ids:'1002_1003', created_at:'Wed Nov 06 14:06:56 AST 2013' }]->child"}}
3.3. Zwykle wysyłam 100 opisów zadań (mieszanych 3.1 i 3.2) na partię, co zajmuje około 150 ~ 250ms, aby to zrobić.
4. Problemy z wydajnością
4.1. Konkurencja:
/ db / data / batch (target: / cypher) wydaje się nie być bezpieczny dla wątków, testowany z dwoma lub więcej współbieżnymi wątkami, które sprowadziły serwer Neo4j w ciągu sekund (s) ~ minut (y).
4.2. MERGE z ograniczeniami nie zawsze działa.
Podczas tworzenia dwóch węzłów i jednej relacji z pojedynczym zapytaniem (wspomnianym powyżej w 3.2.), Czasami działa jak urok; ale czasami zawiedzie z wyjątkiem CypherExecutionException i powiedzenie, że jeden z Node xxxx już istnieje z etykietą aaaa i właściwością „bbbbb” = [ccccc]; Z mojego zrozumienia wynika, że MERGE nie zakłada powrotu żadnego wyjątku, ale zwraca węzeł, jeśli już istnieje.
W wyniku wyjątku cała partia zakończy się niepowodzeniem i wycofaniem, co wpływa na moją szybkość wstawiania.
W tym wydaniu otworzyłem problem w GitHub,https://github.com/neo4j/neo4j/issues/1428
4.3. TWORZENIE UNIKATU z ograniczeniami nie zawsze działa w przypadku tworzenia relacji.
Jest to również wspomniane w tym samym wydaniu github.
4.4. Wydajność:
Właściwie, zanim użyję partii z szyfrowaniem, wypróbowałem starsze indeksowanie za pomocą get_or_create (/ db / data / index / node / Post? Uniqueness = get_or_create & / db / data / index / relationship / XXXXX? Uniqueness = get_or_create)
Ze względu na charakter tych starszych punktów końcowych indeksu (zwracają lokalizację danych w indeksie zamiast lokalizacji danych w rzeczywistym przechowywaniu danych), więc nie mogłem ich użyć w partii (potrzebna była funkcja węzła odsyłającego utworzona wcześniej w tej samej partii) )
Wiem, że mogę włączyć funkcję auto_indexing i zajmować się przechowywaniem danych bezpośrednio zamiast indeksu starszego, ale wspomnieli o wersji 2.0.0, indeks schematu jest zalecany w stosunku do starszego indeksu, więc decyduję się na przejście do metody indeksowania + szyfrowania + schematu.
JEDNAK, w przypadku batch + cypher, mogę uzyskać tylko około 200 opisów zadań na sekundę szybkości wstawiania, byłoby to znacznie wyższe, gdyby MERGE z ograniczeniami zawsze działało, powiedzmy około 600 ~ 800 / s, ale nadal jest znacznie niższe niż 5 kB / s. Wypróbowałem także indeks schematu bez żadnych ograniczeń, ale osiągnięto jeszcze niższą wydajność pod względem szybkości wstawiania.