Migracja danych z PostgresSQL do Neo4j

Często zdarza się, że podczas projektowania aplikacji nie jesteś w stanie przewidzieć jaki model danych będzie najlepszym dla Ciebie. Dopiero w późniejszym etapie wychodzą różne przypadki, które wskazują na użyteczność konkretnego modelu bazy danych. Czasem wygląda to następująco:
– zaczynasz eksperymentować z różnymi modelami danych,
– zespół wybiera jeden z nich,
– pojawia się pierwszy skomplikowany przypadek, ale nadal wierzycie, że wasz wybór jest dobry,
– aplikacja zostaje wgrana na produkcje (zostaje udostępniona dla użytkowników),
– użytkownicy zaczynają ją używać i generują dużo danych,
– zespół dochodzi do wniosku, że aplikacja zaczyna działać coraz wolniej i rozważa pewne modyfikacje,
– zmiany w kodzie nie przynoszą efektów, więc zespół rozważa zmianę bazy danych,
– pojawia się pewien problem: “Co zrobić z istniejącymi danymi i jak przenieść je do nowo wybranej bazy danych?”,

Istnieje spore prawdopodobieństwo, że w Twojej karierze wystąpi powyższy przypadek. Przeważnie migracje danych występują między tymi samymi rodzajami baz danych. Takim przypadkiem może być sytuacja gdy z monolitycznego systemu wydzielamy mikroservice, wtedy migrujemy część bazy danych, z której korzysta wydzielony kod.

Ciekawszym przypadkiem, na jaki można natrafić, jest migracja między różnymi systemami baz danych. W tym poście opiszę migrację z PostgresSQL do Neo4j. Na początku sama myśl o tym, że migracja jest konieczna bylem przerażony, ale po przeczytaniu dokumentacji znacząco zmieniłem swoje zdanie.

Wprowadzenie

Aplikacja z tłumaczeniami

Razem z kolegą zaczęliśmy pracę nad aplikacją, w której użytkownik mógł uczyć się słówek w innych językach. Mając to wymaganie w głowach, zbudowaliśmy elastyczny model bazy danych pozwalający na dodawanie słów i połączeń między nimi bez potrzeby modyfikacji schematu. To wszystko na Postgresie. Dodam, że zaplanowaliśmy możliwość uczenia się więcej niż dwóch języków (na początku było ich 5). W planie mieliśmy połączenie tych wszystkich języków między sobą, aby dodając jedno tłumaczenie, system automatycznie dodawał tłumaczenia z innych języków. Udało się, ale największym problemem było dla nas zrobienie tego poprawnie. Kod stał się bardzo zawiły i każda modyfikacja sprawiała, że czułem się bardzo sfrustrowany.

Połączenia między słowami

Krótko wspomnę o problemie, który popchnął mnie w jednym kierunku – migracja na Neo4j. Załóżmy, że w bazie danych mamy tłumaczenie z języka angielskiego na niemiecki (np. mother -> die Mutter). Teraz chciałbym dodać tłumaczenie z języka polskiego na angielski (matka -> mother). Nasza idea zakładała, że system automatycznie zrozumie, że matka po polsku to die Mutter po niemiecku. Stworzyliśmy specjalny mechanizm, który łączył za nas te dane i nawet działał. Problem zaczął się pojawiać gdy dodaliśmy dwa dodatkowe języki oraz synonimy w każdym z nich. Aplikacja działała wolniej, a w bazie danych, tworzyły się tysiące relacji.

Duża złożoność przy pobieraniu danych

Mając tak skomplikowany model danych, pobieranie informacji z bazy jest dość złożoną operacją. Nasze zapytanie o wszystkie tłumaczenia z jednego języka na drugie wymagało złączenia przynajmniej trzech tabel, z czego niektóre musiały się łączyć same ze sobą. Praktycznie zawsze tak duże zapytania z dużą ilością JOINów sprawiają późniejsze problemy.

Migracja na Neo4j – Lekarstwo na nasze problemy

Kiedy już zacząłem gubić się w swoim własnym kodzie, zaczęliśmy myśleć o kompletnie innej bazie danych. Słowo połączenia, które często się pojawiało, mylnie kierowało nas w kierunku relacyjnej bazy danych. Znacznie szybszym, wygodniejszym i stworzonym do tego typu problemów rozwiązaniem jest Neo4j. W normalnym przypadku ta baza nie jest darmowa do komercyjnego użytku, ale jest to narzędzie darmowe dla startupów oraz do nauki. Mając wyjaśnioną tę sytuację, zabraliśmy się za migrację.

Relacyjna baza danych

Relacyjny model bazy danych

Powyższy schemat prezentuje część naszego modelu bazy danych (tak wiem, schemat nie jest zgodny z żadnym standardem – to rysunek poglądowy). Faktycznie baza jest dużo większa, ale na potrzeby tego posta wystarczy to, co jest na obrazku.

Phrase w tym modelu oznaczał tabelę, w której przechowujemy wszystkie słowa oraz proste zdania w różnych językach. PhraseAssociation jest miejscem, gdzie zapisujemy połączenia między wyrazami. Każde połączenie ma jeden z trzech typów TRANSLATION, SYNONYM lub ANTONYM. Tabela Sentence jest kontenerem na zdania, służące jako przykładowe użycia poszczególnych słów. PhraseSentence jest tabelą łączącą słowa z ich przykładowym użyciem.

W tym momencie wydaje się, że jest to prosty model. Problem pojawia się w momencie gdy do bazy danych dodajemy kolejne wyrazy w różnych językach, przykłady ich użycia i łączymy to wszystko ze sobą. W przypadku pięciu różnych języków aplikacja do jednego dodanego słowa tworzy przynajmniej 5 dodatkowych połączeń. Zrozumienie tych danych po pewnym czasie było nie lada wyzwaniem.

Mając taki model danych, pobieranie przykładowych tłumaczeń (w tym przypadku z polskiego na niemiecki) wymagało napisania kilku JOINów.

SELECT p1.text          as TEXT_FROM,
       l1.lang          as LANG_FROM,
       p2.id            AS ID_TO,
       l2.lang          as LANG_TO
FROM zettelchen_phrase p1
       JOIN zettelchen_language l1 ON p1.lang_id = l1.id
       JOIN zettelchen_phrase_phrase_association zppa1 on p1.id = zppa1.phrase_id
       JOIN zettelchen_phrase_association zpa ON zppa1.phrase_association_id = zpa.id
       JOIN zettelchen_association_type zat ON zat.id = zpa.association_type_id
       JOIN zettelchen_phrase_phrase_association zppa2 ON zppa2.phrase_association_id = zpa.id
       JOIN zettelchen_phrase p2 ON zppa2.phrase_id = p2.id
       JOIN zettelchen_language l2 ON p2.lang_id = l2.id
WHERE p1.id <> p2.id
  AND zat.name = 'TRANSLATION'
  AND (p1.text = '') IS NOT TRUE
  AND (p2.text = '') IS NOT TRUE
  AND (l1.lang = 'pl')
  AND (l2.lang = 'de')

Łączymy tylko 5 tabel, ale przez złożoność aplikacji zapytanie wygląda na dużo większe.

Model grafowy

Sprawdźmy teraz jak wygląda nasz model danych z użyciem grafu.

Model bazy jako graf

Nasz model bazy danych wygląda następująco. Mamy tylko węzły i 4 typy relacji między nimi. Przyznasz, że ten diagram wygląda dużo bardziej zrozumiale niż ten relacyjny? Gdy chcemy pobrać dokładnie te same tłumaczenia co wczesniej, wystarczy, że użyjemy poniższego zapytania.

MATCH (p:Phrase {lang: 'pl'})-[:TRANSLATES]->(p2:Phrase {lang: 'de'}) 
RETURN p.text, p.lang, p2.text, p2.lang

To wszystko, czego potrzebujemy, aby pobrać tłumaczenia! Zabierzmy się zatem za migrację!

Zapisz się na newsletter, aby otrzymywać informacje o nowych artykułach oraz inne dodatki.

Migracja danych krok po kroku

Zarówno nasza aplikacja jak i baza danych jest uruchomiona na dockerze, dlatego niektóre kroki zawierają komendy z dockera.

1. Przygotowanie zapytania SQL do wyciągnięcia danych z Postgresa i export ich do pliku CSV.

COPY (
  SELECT p1.id            AS ID_FROM,
         p1.text          as TEXT_FROM,
         l1.lang          as LANG_FROM,
         p2.id            AS ID_TO,
         p2.text          as TEXT_TO,
         l2.lang          as LANG_TO
  FROM zettelchen_phrase p1
         JOIN zettelchen_language l1 ON p1.lang_id = l1.id
         JOIN zettelchen_phrase_phrase_association zppa1 on p1.id = zppa1.phrase_id
         JOIN zettelchen_phrase_association zpa ON zppa1.phrase_association_id = zpa.id
         JOIN zettelchen_association_type zat ON zat.id = zpa.association_type_id
         JOIN zettelchen_phrase_phrase_association zppa2 ON zppa2.phrase_association_id = zpa.id
         JOIN zettelchen_phrase p2 ON zppa2.phrase_id = p2.id
         JOIN zettelchen_language l2 ON p2.lang_id = l2.id
  WHERE p1.id <> p2.id
    AND zat.name = 'TRANSLATION'
    AND (p1.text = '') IS NOT TRUE
    AND (p2.text = '') IS NOT TRUE
) TO '/tmp/translations.csv' WITH CSV header;

W powyższym zapytaniu ważne są użyte aliasy. Posłużą one jako nagłówki w pliku CSV.

Trzeba pamiętać, że gdy uruchomimy to zapytanie do dockerze, plik zostanie zapisany w kontenerze w podanej lokalizacji.

2. Przygotuj zapytanie CYPHER przy użyciu narzędzia LOAD CSV do importowania danych

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM 'file:/translations.csv' AS row
MERGE (from:Phrase {
  externalId: row.id_from
})
  ON CREATE SET
  from.uuid = randomUUID(),
  from.text = row.text_from,
  from.lang = row.lang_from
MERGE (to:Phrase {
  externalId: row.id_to
})
  ON CREATE SET
  to.uuid = randomUUID(),
  to.text = row.text_to,
  to.lang = row.lang_to
MERGE (from)-[r:TRANSLATES {
  code: row.lang_from + '-' + row.lang_to
}]->(to);

W powyższym skrypcie czytamy wszystkie wiersze z pliku CSV linia po linii, tworząc nowe węzły i połączenia między nimi. W tym miejscu, tworząc właściwości wierszy i relacji, używamy wcześniej przygotowanych aliasów. Plik CSV powinien być umieszczony w katalogu import. Nazwa jest dowolna, ja wybrałem import.cypher.

3. Uruchom skrypt z pierwszego kroku

Aby móc wyeksportować dane, możemy użyć narzędzia psql. Poniższa komenda ładuje podany plik i uruchamia go. Możemy do wywołać z zewnątrz kontenera dockera, ale plik i tak zostanie odłożony wewnątrz niego.

psql -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -d $POSTGRES_DB < export_csv.sql

4. Pobierz wyeksportowany plik z dockera

docker cp $POSTGRES_CONTAINER_ID:/tmp/translations.csv translations.csv

Podpowiedź: Jeśli chcesz dowiedzieć się, jaki jest Twój POSTGRES_CONTAINER_ID użyj poniższej komendy.

docker ps -aqf "name=$POSTGRES_CONTAINER_NAME"

5. Przenieś plik CSV do katalogu import w kontenerze neo4j

docker cp translations.csv $NEO4J_CONTAINER_ID:/import/translations.csv

6. Przenieś plik ze skryptem z kroku 2 do kontenera neo4j ale do katalogu /tmp

docker cp import_csv.cypher $NEO4J_CONTAINER_ID:/tmp/import_csv.cypher

7. Użyj cypher-shell do uruchomienia przygotowanego skryptu – właściwa migracja

Przygotuj skrypt shelowy i przenieś go w to samo miejsce co skrypt z kroku 2.

USERNAME=$1
PASSWORD=$2
cat /tmp/import_csv.cypher | /var/lib/neo4j/bin/cypher-shell -u $USERNAME -p $PASSWORD

Teraz uruchom skrypt na dockerze, korzystając z opcji exec.

docker exec $NEO4J_CONTAINER_NAME /tmp/$YOUR_SHELL_SCRIPT.sh $USERNAME $PASSWORD

Operacja powinna się zakończyć z informacją o sukcesie. W przeciwnym przypadku otrzymasz klarowną informację, co poszło nie tak. Aby zobaczyć więcej szczegółów odnośnie błędów, wystarczy dodać flagę -debug -format verbose do cypher-shell.

8. Usuń tymczasowe pliki

Na koniec warto posprzątać po sobie i usunąć niepotrzebne pliki.

if [ -f translations.csv ] ; then
    rm translations.csv
fi

Podsumowanie

Jak widzisz, migracja danych jest w zasadzie kwestią przygotowania odpowiednich skryptów do wyciągnięcia danych z jednej bazy i wrzucenia na drugą. Dzięki narzędziu LOAD CSV przenoszenie danych jest bardzo proste. Jak już wspominałem w poprzednim poście, Neo4j pozwala na reprezentację prawdziwych relacji między danymi w bardzo prosty sposób. W pewnych przypadkach baza grafowa sprawdza się świetnie w porównaniu do relacyjnej bazy danych. W naszym przypadku migracja okazała się krokiem w dobrym kierunku. Teraz kod aplikacji jest czystszy i łatwiejszy w utrzymaniu. Dzięki algorytmom grafowym, szybkość pobierania danych znacznie się zwiększyła.

Uważam, że podejście grafowe jest bardzo użytecznie i przyjazne, dlatego rekomenduję każdemu przeczytanie jeszcze raz wymagań waszego systemu, ponieważ może i w waszym przypadku Neo4j będzie użyteczne.

Dziękuję za przeczytanie i zapraszam do dyskusji oraz bezpośredniego kontaktu.
Post napisany na podstawie posta z mojego innego bloga oraz własnych doświadczeń.

Neo4j – Wprowadzenie do prawdziwych relacji między danymi

Kiedy pierwszy raz usłyszałem o Neo4j, pomyślałem, że tego typu bazy danych są używane tylko do budowania silników rekomendacji. Moja percepcja zmieniła się kiedy zobaczyłem prezentację o GAAND Stack (GraphQL, Apollo, Angular, Neo4j Database). Podczas tego szkolenia zdałem sobie sprawę, że jest o wiele więcej przypadków użycia tego narzędzia. Zaraz po szkoleniu postanowiłem “zanurkować” nieco głębiej w tę technologię. Okazuje się, że Neo4j to potężne narzędzie między innymi dzięki szybkości oraz sposobowi reprezentacji danych.

Są dwa powody, dla których powstał ten artykuł. Pierwszym jest stworzenie kompletnej instrukcji tworzenia GRAND Stack (to samo co GAAND tylko z React.js zamiast Angulara). Drugim powodem jest ustrukturyzowanie wiedzy o Neo4j jako przygotowanie do profesjonalnego certyfikatu z tej technologii (* już posiadam certyfikat w momencie gdy tłumaczę artykuł z innego mojego bloga).

Co to jest grafowa baza danych?

Krótko mówiąc, grafowa baza danych to baza, która używa grafu do zapisywania danych i połączeń między nimi. Dokładnie tak samo jak w grafie takie bazy danych mają węzły (nodes) oraz krawędzie (edges), które mogą być jednostronnie (unidirectional) lub dwustronnie (bidirectional) skierowane.

Tak ustukturyzowane dane są bardzo łatwe do zrozumienia dla ludzi oraz pozwalają na szybkie wyszukiwanie dużo lepiej niż inne struktury danych.

Struktura bazy danych Neo4j

Przykładowy graf

Co to jest węzeł?

Węzeł (node) jest obiektem który reprezetuje pojedynczą encję. Węzeł może przechowywać dane w postaci właściwości (properties).

Węzeł z Neo4j

Co to jest relacja?

Relacja to niekoniecznie trafne tłumaczenie angielskiego słowa relation, ale chodzi o połączenie między węzłami. W grafie będzie to po prostu krawędź. Jak sama nazwa mówi, jest ona elementem bazy danych reprezentującą związek, jaki zachodzi między dwoma węzłami. Relacja, podobnie jak węzeł, może mieć właściwości oraz musi mieć dokładnie jeden typ.

Relacje w Neo4j

Co to jest typ relacji?

Typ relacji definiuje jaką rolę jeden węzeł pełni względem innego i wyjaśnia, dlaczego dwa węzły są ze sobą połączone.

Typ relacji w Neo4j

Co to jest etykieta?

Etykieta (label) jest używana do przypisywania węzłów do różnych grup. Węzeł może mieć dowolną ilość etykiet.

O etykietach możemy myśleć jak o nazwach tabel z relacyjnej bazy danych takiej jak np. MySQL. Etykiety definiują rodzaje węzłów. W poniższym przypadku mamy dostępne dwa typy: Person oraz Movie.

Etykiety w Neo4j

Co to jest właściwość?

Właściwości są właściwie zwykłymi danymi, które mogą być przechowywane przez węzły lub relacje.

Właściwości w Neo4j

Co to jest traversal?

Używam angielskiej nazwy, bo jej polski odpowiednik – przejście – brzmi trochę śmiesznie. Grafowe bazy danych korzystają z path traversal, aby wykonać zapytanie, o których dane potrzebujemy. Traversing (przechodzenie) grafu oznacza odwiedzanie poszczególnych węzłów, podążając zdefiniowanymi krawędziami. Algorytm przechodzi po krawędziach zgodnie z regułami ustawionymi w zapytaniu.

Co to jest index?

Index – podobnie jak w innych bazach danych – pozwala nam zwiększyć wydajność pobierania danych. Baza danych tworzy kopię danych i zapisuje je w możliwie najbardziej efektywny sposób. Powoduje to większe zużycie pamięci i nieco wolniejsze zapisy danych.

Co to jest constraint?

W bazach danych programiści mogą tworzyć pewne ograniczenia zabezpieczające system przed wprowadzaniem niepoprawnych danych. O to właśnie dbają konstrukcje zwane constraintami. Programista definiuje reguły a baza danych przed zatwierdzeniem danych, sprawdza ich poprawność.

Język zapytań w Neo4j – Cypher

Cypher jest językiem zapytań używanym w Neo4j. Dla osób, które miały okazję korzystać z SQL ten język będzie wyglądał znajomo. Cypher nieco przypomina mi streamy w Javie, ponieważ pisząc zapytania, przypominają one coś w rodzaju strumienia. Czytanie zapytania od lewej do prawej przypomina czytanie zdania w języku naturalnym.

Ten język zapytań używa ASCII-Art do tworzenia wzorców, które czynią Cypher bardziej czytelnym. Po spojrzeniu na kod, od razu wiemy, co jest węzłem, co relacją oraz jak zamierzamy użyć tych informacji.

Podstawowe zapytania

Pobieranie danych

MATCH (actor { name: 'Charlie Sheen' })-[:ACTED_IN]->(movie)<-[:DIRECTED]-(director)
RETURN movie.title, director.name

Powyższy kod “mówi” bazie danych, aby zwróciła tytuły filmów oraz imiona reżyserów, w których jednym z aktorów był Charlie Sheen.

Zauważ, że używamy relacji jednokierunkowej poprzez wpisanie strzałki (-[:RELATION_TYPE]->). Ta strzałka precyzyjnie wyjaśnia związek między węzłami.

Tworzenie węzła

CREATE (a:Artist { Name : "Strapping Young Lad" })

Możemy również tworzyć wiele węzłów naraz – używając jednej komendy – oddzielając je przecinkami

CREATE (a:Album { Name: "Killers"}), (b:Album { Name: "Fear of the Dark"}) 
RETURN a,b

lub przez użycie oddzielnych instrukcji CREATE

CREATE (a:Album { Name: "Piece of Mind"}) 
CREATE (b:Album { Name: "Somewhere in Time"}) 
RETURN a,b

Tworzenie relacji

MATCH (a:Actor),(b:Movie)
WHERE a.Name = "John Tree" AND b.Name = "The neo4j movie"
CREATE (a)-[r:ACTED_IN]->(b)
RETURN r

Jak widać powyżej, do tworzenia związków między węzłami używane jest to samo słowo kluczowe. Jedyne co trzeba dodać to informacje o węzłach, które mają być ze sobą powiązane.

Rożnica w porównaniu do SQL

Jeśli znasz SQL, prawdopodobnie zobaczysz wiele podobieństw między tymi językami zapytań. Klauzule takie jak WHERE, UNION, ORDER BY oraz CREATE istnieją w obydwu językach. Główną różnicą jest brak instrukcji JOIN dzięki temu, że Neo4j jest zbudowana w zupełnie inny sposób niż klasyczne relacyjne bazy danych.

Transakcje w Neo4j

Neo4j wspiera ACID, aby w pełni wspierać integralność danych oraz zapewnić dobre zachowanie transakcji.

Wszystkie operacje na danych takie jak dostęp do grafu, indexów czy schematu powinniśmy wykonywać w transakcji.

Ważne do zapamiętania:

  • Dane pobrane podczas przeglądania grafu nie są z żaden sposób chronione przed modyfikacją przez inną transakcję,
  • Mogę wystąpić niepowtarzalne odczyty (non-repeatable) – podczas transakcji zakładane są tylko blokady zapisu,
  • Istnieje możliwość manualnego założenia blokad na węzły oraz relacje, aby osiągnąć wyższy poziom izolacji,
  • Wykrywanie zakleszczeń (deadlock) jest mechanizmem wbudowanym w systemie zarządzania transakcjami.

Aby przeczytać więcej o transakcjach w Neo4j, odwiedź tę stronę.

Poziom Izolacji

Transakcje w Neo4j używają poziomu READ_COMMITED. To oznacza, że transakcje nie widzą żadnych niezatwierdzonych zmian z innych transakcji. Dodatkowo Java API udostępnia możliwość doprecyzowania blokad na węzłach oraz relacjach. Blokady dają możliwość symulowania wyższych poziomów izolacji poprzez zakładanie i zdejmowanie blokad.

Zapisz się na newsletter, aby otrzymywać informacje o nowych artykułach oraz inne dodatki.

Badanie zapytań w Neo4j

EXPLAIN

Komenda EXPLAIN umożliwia nam sprawdzenie planu wykonania zapytanie bez potrzeby uruchamiania kodu. Aby wykonać plan zapytania, wystarczy poprzedzić nasze zapytanie słowem kluczowym EXPLAIN. Taka konstrukcja zwróci nam pusty wynik i nie spowoduje wprowadzenia żadnych zmian na bazie danych.

Poniżej umieściłem wynik następujacego zapytania

EXPLAIN MATCH p=()-[r:ACTED_IN]->() RETURN p LIMIT 25
Plan zapytania
Plan zapytania w Neo4j

PROFILE

Aby sprawdzić, co w naszym zapytaniu wykonuje większość pracy, możemy użyć komendy PROFILE na początku zapytania. Ta komenda uruchamia zapytanie i śledzi ile wierszy wyników przeszło rzez poszczególne operatory. Dodatkowo sprawdzany jest czas, jaki operator potrzebował na interakcję z bazą danych, aby otrzymać dane.

Przykład:

PROFILE MATCH p=()-[r:ACTED_IN]->() RETURN p LIMIT 25
Plan Profilu

Nazewnictwo w Neo4j

Etykieta węzła

Do nazywania etykiet węzłów używamy CamelCase

Poprawna nazwaNiepoprawna nazwa
VehicleOwnervehicle_owner
NetworkNodenetworkNode

Nazwa relacji/związku

Do nazywania relacji używamy wielkich liter, gdzie słowa oddzielone są od siebie znakiem “podłogi” (underscore)

Poprawna nazwaNiepoprawna nazwa
ACTED_INacted_in
OWNED_BYownedBy

Nazwa właściwości

Do nazywania właściwości używamy loweCamelCase.

Poprawna nazwaNiepoprawna nazwa
firstNamefirst_name
amountOfStudentsAMOUNT_OF_STUDENTS

Porównanie do relacyjnej bazy danych

Zakładając hipotetyczną sytuację, że chcemy przemigrować dane z bazy relacyjnej do Neo4j, musielibyśmy myśleć o poszczególnych wierszach jak o węzłach. Mając tę analogię, nazwa tabeli byłaby etykietą węzła. Właściwości w węźle byłby po prostu danymi z poszczególnych wierszy. Nazwa każdej kolumny z kluczem obcym może być wzięta pod uwagę podczas budowania związków między węzłami.

Protokół komunikacyjny w Neo4j – Bolt

Bolt jest nieustandaryzowanym protokołem open-source stworzonym na potrzeby baz danych. Protokół ten jest zorientowany na komunikaty (znów dziwne tłumaczenieni z statement-oriented). Mówiąc prościej, oznacza to, że klient może wysłać komunikaty zawierające ciągi znaków wraz ze zbiorem parametrów. Serwer będzie odpowiadał wiadomościami oraz opcjonalnym strumieniem danych. Neo4j używa tego protokołu a domyślny port to 7687.

Neo4j Bloom

Bloom jest aplikacją dostępną w Graph Platform, która umożliwia użytkownikowi nawiązać wizualną interakcję z danymi w postaci grafu. W prostych słowach jest to aplikacja internetowa, która wizualnie przedstawia graf, z którym pracujemy.

Bloom

Aby zobaczyć więcej o Neo4j Bloom, zachęcam do obejrzenia poniższego wideo.

Licencja

Są dwa typy licencji. Community jest w pełni działającą bazą danych, która może być używana do projektów open-source, projektów wewnątrz organizacji lub do aplikacji uruchamianych na prywatnych urządzeniach. Enterprise udostępnia większą dostępność oraz skalowalność do komercyjnego użycia.

Baza Neo4j wspiera startupy. Aby otrzymać licencję Enterprise dla startupu, wystarczy dołączyć do programu dla startupów oraz spełnić opisane tam wymagania. Zobaz więcej tutaj.

Podsumowanie

Z mojej perspektywy grafowe bazy danych są idealnym wyborem gdy musimy zamodelować prawdziwe zależności lub jakiekolwiek bardziej złożone związki między obiektami. Wyszukiwanie w grafach jest niesamowicie szybkie, co jest obecnie wielką zaletą. Struktura danych w grafie jest o wiele łatwiejsza do wyobrażenia niż w jakiejkolwiek dokumentowej czy tabelarycznej bazie danych.

W Neo4j bardzo lubię sposób operowania na danych. Cypher jest intuicyjnym językiem, który dokładnie pokazuje, co chcemy zrobić. Cypher swoją czytelność zawdzięcza użyciu ASCII-Art. Ten język jest czysty, a napisany w nim kod możemy czytać jak zwykłe zdanie. Dodatkowo zachwycony jestem narzędziem Bloom. Dzięki idealnej wizualizacji grafów oraz dobremu interfejsowi praca z nim jest intuicyjna i przyjemna.

Neo4j nie jest najtańszym narzędziem, ale w przypadku gdy szybkość pobierania danych ma znaczenie, może okazać się idealnym wyborem. Dzięki temu, że bazy grafowe są elastyczne i łatwe w utrzymaniu, dają nieproporcjonalnie dużo zalet w niektórych typach projektów.

Aby podsumować, chciałbym wszystkim polecić Neo4j jako bazę danych do wszystkich projektów, które mogłyby skorzystać z dobrodziejstwa path traversal i innych algorytmów grafowych, jak również z elastycznych relacji i modelowania danych.

Artykuł napisany na podstawie mojego bloga EagerToIt oraz własnych doświadczeń. Zapraszam do kontaktu i dyskusji.