Waarom u een grafiekdatabase zou moeten gebruiken

Jeff Carpenter is een technische evangelist bij DataStax.

Er is de laatste tijd veel hype over grafische databases. Hoewel grafische databases zoals DataStax Enterprise Graph (gebaseerd op Titan DB), Neo4 en IBM Graph al enkele jaren bestaan, geven recente aankondigingen van beheerde cloudservices zoals AWS Neptune en de toevoeging van grafische mogelijkheden door Microsoft aan Azure Cosmos DB aan dat grafische databases zijn de mainstream binnengekomen. Hoe bepaal je met al deze interesse of een grafische database geschikt is voor jouw toepassing?

Wat is een grafische database?

Laten we, voordat we verder gaan, wat terminologie definiëren. Wat is een grafische database? Beschouw het in termen van het datamodel. Een grafiekgegevensmodel bestaat uit hoekpunten die de entiteiten in een domein vertegenwoordigen, en randen die de relaties tussen deze entiteiten vertegenwoordigen. Omdat zowel hoekpunten als randen extra naam-waardeparen kunnen hebben, eigenschappen genaamd , staat dit gegevensmodel formeel bekend als een eigenschappengrafiek . Bij sommige grafiedatabases moet u een schema voor uw grafiek definiëren, dwz labels of namen voor uw hoekpunten, randen en eigenschappen definiëren voordat u gegevens vult, terwijl u met andere databases kunt werken zonder een vast schema.

Zoals je misschien hebt gemerkt, bevat het grafische datamodel geen nieuwe informatie die we niet konden vastleggen in een traditioneel relationeel datamodel. Het is tenslotte eenvoudig om relaties tussen tabellen te beschrijven met behulp van externe sleutels, of we kunnen eigenschappen van een relatie met een join-tabel beschrijven. Het belangrijkste verschil tussen deze gegevensmodellen is de manier waarop gegevens worden georganiseerd en benaderd. De herkenning van randen als een "eersteklas burger" naast hoekpunten in het grafische datamodel stelt de onderliggende database-engine in staat om zeer snel in elke richting door netwerken van hoekpunten en randen te herhalen om aan toepassingsvragen te voldoen, een proces dat bekend staat als traversal .

De flexibiliteit van het grafische datamodel is een sleutelfactor voor de recente stijging van de populariteit van grafische databases. Dezelfde vereisten voor beschikbaarheid en enorme schaal die de ontwikkeling en acceptatie van verschillende NoSQL-aanbiedingen in de afgelopen 10 jaar hebben gestimuleerd, blijven vruchten afwerpen in de recente grafiektrend.

Hoe weet u of u een grafiekdatabase nodig heeft?

Zoals bij elke populaire technologie, kan er echter de neiging zijn om grafische databases op elk probleem toe te passen. Het is belangrijk om ervoor te zorgen dat u een use-case hebt die goed bij u past. Grafieken worden bijvoorbeeld vaak toegepast op probleemdomeinen zoals:

  • Sociale netwerken
  • Aanbeveling en personalisatie
  • Klant 360, inclusief entiteitsresolutie (gebruikersgegevens uit meerdere bronnen correleren)
  • Fraude detectie
  • Vermogensbeheer

Of uw use case nu binnen een van die domeinen past of niet, er zijn enkele andere factoren waarmee u rekening moet houden en die kunnen helpen bepalen of een graph-database geschikt voor u is:

  • Veel-op-veel-relaties. In zijn boek "Designing Data Intensive Applications" (O'Reilly) suggereert Martin Kleppmann dat frequente veel-op-veel-relaties in uw probleemdomein een goede indicator zijn voor het gebruik van grafieken, aangezien relationele databases vaak moeite hebben om efficiënt door deze relaties te navigeren.
  • Hoge waarde van relaties. Een andere heuristiek die ik vaak heb gehoord: als de relaties tussen uw gegevenselementen net zo belangrijk of belangrijker zijn dan de elementen zelf, kunt u overwegen om graph te gebruiken.
  • Lage latentie op grote schaal. Het toevoegen van een andere database aan uw applicatie maakt uw applicatie ook complexer. Het vermogen van grafische databases om sneller door de relaties te navigeren die in grote gegevenssets worden weergegeven dan andere typen databases, rechtvaardigt deze extra complexiteit. Dit is vooral het geval in gevallen waarin een complexe relationele join-query niet langer presteert en er geen extra optimalisatiewinst kan worden behaald aan de query of de relationele structuur.

Grafiekschema en query's definiëren met Gremlin

Laten we eens kijken hoe we aan de slag kunnen gaan met het gebruik van een grafiekdatabase aan de hand van een echt voorbeeld, het aanbevelingssysteem dat we onlangs aan KillrVideo hebben toegevoegd. KillrVideo is een referentietoepassing voor het delen en bekijken van video's die we hebben ontwikkeld om ontwikkelaars te helpen leren hoe ze DataStax Enterprise moeten gebruiken, inclusief DataStax Enterprise Graph, een grafische database die is gebouwd op zeer schaalbare datatechnologieën, waaronder Apache Cassandra en Apache Spark.

De taal die wordt gebruikt voor het beschrijven van en interactie met grafieken in DataStax Enterprise Graph is Gremlin, dat deel uitmaakt van het Apache TinkerPop-project. Gremlin staat bekend als de go-to-taal voor het beschrijven van graph traversals vanwege de flexibiliteit, uitbreidbaarheid en ondersteuning voor zowel declaratieve als imperatieve zoekopdrachten. Gremlin is gebaseerd op de taal Groovy en stuurprogramma's zijn beschikbaar in meerdere talen. Het belangrijkste is dat Gremlin wordt ondersteund door de meest populaire grafische databases, waaronder DataStax Enterprise Graph, Neo4j, AWS Neptune en Azure Cosmos DB.

We hebben een aanbevelingsalgoritme ontworpen om de gegevens te identificeren die we nodig hebben als invoer. De aanpak was om aanbevelingen te genereren voor een bepaalde gebruiker op basis van video's die geliefd waren bij vergelijkbare gebruikers. Ons doel was om in realtime aanbevelingen te genereren terwijl gebruikers communiceren met de KillrVideo-applicatie, dwz als een OLTP-interactie.

Om het schema te definiëren, hebben we een subset van de gegevens geïdentificeerd die door KillrVideo worden beheerd en die we nodig hadden voor onze grafiek. Dit omvatte gebruikers, video's, beoordelingen en tags, evenals eigenschappen van deze items waarnaar we kunnen verwijzen in het algoritme of die we presenteren in aanbevelingsresultaten. We hebben vervolgens een grafiekschema gemaakt in Gremlin dat er als volgt uitzag:

// maak hoekpuntlabels

schema.vertexLabel ("gebruiker"). partitionKey ('userId').

  eigenschappen ("userId", "email", "added_date"). ifNotExists (). create ();

schema.vertexLabel ("video"). partitionKey ('videoId').

  eigenschappen ("videoId", "naam", "beschrijving", "added_date",

preview_image_location ”). ifNotExists (). create ();

schema.vertexLabel ("tag"). partitionKey ('naam').

  eigenschappen ("naam", "tagged_date"). ifNotExists (). create ();

// maak randlabels

schema.edgeLabel ("rated"). multiple (). properties ("rating").

  verbinding ("gebruiker", "video"). ifNotExists (). create ();

schema.edgeLabel ("geüpload"). single (). properties ("added_date").

  verbinding ("gebruiker", "video"). ifNotExists (). create ();

schema.edgeLabel ("taggedWith"). single ().

  verbinding ("video", "tag"). ifNotExists (). create ();

We hebben ervoor gekozen om gebruikers, video's en tags als hoekpunten te modelleren en hebben randen gebruikt om te identificeren welke gebruikers welke video's hebben geüpload, gebruikersbeoordelingen van video's en de tags die aan elke video zijn gekoppeld. We hebben eigenschappen toegewezen aan hoekpunten en randen waarnaar wordt verwezen in query's of die worden opgenomen in resultaten. Het resulterende schema ziet er als volgt uit in DataStax Studio, een ontwikkelaarstool in notebookstijl voor het ontwikkelen en uitvoeren van queries in CQL en Gremlin.

Op basis van dit schema hebben we query's gedefinieerd die gegevens in de grafiek vullen en query's die gegevens uit de grafiek ophalen. Laten we eens kijken naar een grafiekquery die aanbevelingen genereert. Hier is de basisstroom: identificeer voor een bepaalde gebruiker vergelijkbare gebruikers die van video's hielden die de betreffende gebruiker leuk vond, selecteer video's die vergelijkbare gebruikers ook leuk vonden, sluit video's uit die de betreffende gebruiker al heeft bekeken, rangschik die video's op populariteit en geef de resultaten.

def numRatingsToSample = 1000

def localUserRatingsToSample = 10

def minPositiveRating = 4

def userID = ...

gV (). has ("user", "userId", userID) .as ("^ currentUser")

    // haal alle video's op die de gebruiker heeft bekeken en sla ze op

    .map (out ('rated'). dedup (). fold ()). as ("^ watchedVideos")

    // ga terug naar de huidige gebruiker

    .select ("^ currentUser")

    // identificeer de video's die de gebruiker hoog heeft beoordeeld

    .outE ('rated'). has ('rating', gte (minPositiveRating)). inV ()

    // welke andere gebruikers beoordeelden die video's hoog?

    .inE ('rated'). has ('rating', gte (minPositiveRating))

    // beperk het aantal resultaten zodat dit werkt als een OLTP-query

    .sample (numRatingsToSample)

    // sorteer op beoordeling om gebruikers te bevoordelen die die video's het hoogst hebben beoordeeld

    .by ('rating'). outV ()

    // elimineer de huidige gebruiker

    .where (neq ("^ currentUser"))

Laten we even pauzeren om op adem te komen. Tot dusverre hebben we in dit traject vergelijkbare gebruikers geïdentificeerd. Het tweede deel van de traversal omvat die vergelijkbare gebruikers, pakt een beperkt aantal video's die vergelijkbare gebruikers leuk vonden, verwijdert video's die de gebruiker al heeft bekeken en genereert een resultatenset gesorteerd op populariteit.

    // selecteer een beperkt aantal hoog gewaardeerde video's van elke vergelijkbare gebruiker

   .local (outE ('rated'). has ('rating', gte (minPositiveRating)). limit (localUserRatingsToSample)). sack (assign) .by ('rating'). inV ()

     // sluit video's uit die de gebruiker al heeft bekeken

    .not (where (binnen ("^ watchedVideos")))

    // identificeer de meest populaire video's op basis van alle beoordelingen

    .group (). door (). door (sack (). sum ())

    // nu we een grote kaart van [video: score] hebben, bestel hem

    .order (lokaal) .by (waarden, verlagen) .limit (lokaal, 100) .select (toetsen) .unfold ()

    // output aanbevolen video's, inclusief de gebruiker die elke video heeft geüpload

    .project ('video', 'gebruiker')

        .door()

        .by (__. in ('geüpload'))

Hoewel deze traversal ingewikkeld lijkt, moet u er rekening mee houden dat het de volledige bedrijfslogica is van een aanbevelingsalgoritme. We zullen hier niet in detail op elke stap van deze reis ingaan, maar de taalreferentie is een geweldige hulpbron en er zijn hoogwaardige trainingscursussen beschikbaar.

Ik raad aan om traversals interactief te ontwikkelen over een representatieve dataset met een tool zoals DataStax Studio of de Gremlin-console van Apache TinkerPop. Hierdoor kunt u uw traversals snel herhalen en verfijnen. DataStax Studio is een webgebaseerde omgeving die meerdere manieren biedt om doorgangsresultaten te visualiseren als netwerken van knooppunten en randen, zoals weergegeven in de onderstaande afbeelding. Andere ondersteunde weergaven zijn onder meer tabellen, grafieken en grafieken, evenals prestatietracering.

DataStax

Een grafiekdatabase opnemen in uw architectuur

Zodra u uw grafiekschema en queries heeft ontworpen, is het tijd om de grafiek in uw applicatie te integreren. Hier is hoe we DataStax Enterprise Graph in KillrVideo hebben geïntegreerd. De meerlaagse architectuur van KillrVideo bestaat uit een webtoepassing die bovenop een set microservices staat die gebruikers, video's (inclusief tags) en beoordelingen beheren. Deze services maken gebruik van de DataStax Enterprise Graph-database (gebouwd op Apache Cassandra) voor gegevensopslag en toegang tot de gegevens met behulp van CQL.

We hebben onze aanbevelingsengine geïmplementeerd als onderdeel van de Suggested Videos Service, zoals hieronder weergegeven. Deze service genereert een lijst met aanbevelingen met een gebruikers-ID. Om de aanbevelingsengine te implementeren, hebben we de hierboven beschreven Gremlin-traversal vertaald naar Java-code.

DataStax

Deze architectuur benadrukt een veel voorkomende uitdaging in microservice-architecturen: de noodzaak om te communiceren met gegevens die eigendom zijn van meerdere services. Zoals hierboven is weergegeven, is de grafiek die wordt gebruikt om aanbevelingen te genereren afhankelijk van gegevens van de services Gebruikersbeheer, Videocatalogus en Beoordelingen.

We hebben het gegevenseigendom van onze bestaande services behouden door asynchrone berichten te gebruiken. De services voor gebruikersbeheer, videocatalogus en beoordelingen publiceren gebeurtenissen over gegevenswijzigingen. De dienst voor voorgestelde video's is geabonneerd op deze evenementen en brengt overeenkomstige updates van de grafiek uit. De afwegingen die we hier hebben gemaakt, zijn typerend voor applicaties die een multi-modelbenadering gebruiken, een onderwerp dat ik in mijn vorige artikel heb onderzocht.

Implementatie van Gremlin-traversals in Java

De DataStax Java Driver biedt een gebruiksvriendelijke, vloeiende API voor het implementeren van Gremlin traversals met DataStax Enterprise Graph. De API maakte het triviaal om op Groovy gebaseerde query's die we in DataStax Studio hadden gemaakt, te migreren naar Java-code.

We waren toen in staat om onze Java-code nog beter leesbaar en onderhoudbaar te maken door een Gremlin-functie te gebruiken die bekend staat als DSL's, domeinspecifieke talen. Een DSL is een uitbreiding van Gremlin naar een specifiek domein. Voor KillrVideo hebben we een DSL gemaakt om de implementatie van Gremlin traversal uit te breiden met termen die relevant zijn voor het videodomein. De KillrVideoTraversalDslklasse definieert zoekbewerkingen zoals u ser(), die het hoekpunt in de grafiek lokaliseert met een opgegeven UUID, en recommendByUserRating()die aanbevelingen genereert voor een opgegeven gebruiker op basis van parameters zoals een minimale beoordeling en een gevraagd aantal aanbevelingen.

Het gebruik van een DSL vereenvoudigde de implementatie van de Suggested Videos Service tot zoiets als het onderstaande voorbeeld, waardoor een wordt GraphStatementgecreëerd die we vervolgens uitvoeren met behulp van de DataStax Java Driver:

GraphStatement gStatement = DseGraph.statementFromTraversal (killr.users (userIdString)

       .recommendByUserRating (100, 4, 500, 10)

);

Door een DSL te gebruiken, konden we een deel van de complexiteit van onze grafiekinteracties verbergen in herbruikbare functies, die vervolgens naar behoefte kunnen worden gecombineerd om complexere traversals te vormen. Dit stelt ons in staat om aanvullende aanbevelingsengines te implementeren die beginnen bij een geselecteerde gebruikersvertex die door de user()methode wordt geleverd en waarmee de applicatie kan wisselen tussen de verschillende implementaties.

Een werkend grafiekvoorbeeld

U kunt de resultaten van onze integratie van DataStax Enterprise Graph in KillrVideo zien in het gedeelte "Aanbevolen voor u" van de onderstaande webtoepassing. Probeer het zelf uit op //www.killrvideo.com door een account aan te maken en een paar video's te beoordelen.

DataStax

Ik hoop dat dit artikel je een aantal goede ideeën geeft over hoe een graph-database zinvol kan zijn voor je toepassing en hoe je aan de slag kunt gaan met Gremlin en DataStax Enterprise Graph.

Jeff Carpenter is een technisch evangelist bij DataStax, waar hij gebruik maakt van zijn achtergrond in systeemarchitectuur, microservices en Apache Cassandra om ontwikkelaars en operations-engineers te helpen bij het bouwen van gedistribueerde systemen die schaalbaar, betrouwbaar en veilig zijn. Jeff is de auteur van Cassandra: The Definitive Guide, 2nd Edition.

-

New Tech Forum biedt een locatie om opkomende bedrijfstechnologie in ongekende diepte en breedte te verkennen en te bespreken. De selectie is subjectief, gebaseerd op onze keuze van de technologieën die wij belangrijk vinden en die het meest interessant zijn voor lezers. accepteert geen marketingmateriaal voor publicatie en behoudt zich het recht voor om alle bijgedragen inhoud te bewerken. Stuur alle vragen naar  [email protected] .