NoSQL – en magisk låda?

Share on FacebookShare on Google+Email this to someoneTweet about this on TwitterShare on LinkedIn

I bland när man läser marknadsmaterial och även när man hör de som säljer NoSQL kan man lätt få intrycket att det är en magisk låda, där det bara är att trycka in olika typer typer av data och plötsligt så har man öppnat en värld av möjligheter.

Allt detta utan att behöva bry sig om modellering, strukturer, ETL och så vidare.

Eller?

När jag pratar om NoSQL och hantering av data så brukar jag prata om

  • Ladda data som det är, As-Is
  • Schema agnostic, vilket kan översättas med att inte behöva ta ställning till scheman
  • Schema vid läsning, on read
  • Minskad eller ingen data modellering, nu innan du kastar dig på tangentbordet för att skriva en vass kommentar så ber jag dig att läsa färdigt min post först
  • Minskad ETL

Låt oss bryta ner det hela till vad det egentligen innebär.

Att ladda data ”som det är” handlar om att vi låter indatat vara så orört som möjligt, vi vill inte förändra strukturen om det inte verkligen behövs. Det jag menar är att vi inte skall behöva först bestämma hur vi vill lagra data innan vi läser in det, utan vi lagrar det vi får.

För att ta ett exempel. Låt oss säga att jag har ett kundregister som jag hämtar data ifrån. I detta system har vi olika typer av information om våra kunder, vi har inte all information om alla kunder. Nedan är två exempel på kunddata som vi har samlat in.

Kundnummer: 1
Förnamn: Mats
Efternamn: Stellwall
Kön: Man
Född: 1973-12-28
Gift: ja
Antal barn:2
Bor i: Stockholm
E-post: mats.stellwall@marklogic.com
Twitter: @MatsStellwall 

Kundnummer: 2
Förnamn: Kalle
Efternamn: Svensson
Kön: Man
Född: 1989-02-12
Gift: Nej
Bor i: Sundsvall
E-post: kalle.svensson@xyz.xz

Notera att vi inte har samma information för våra två kunder.

Utifrån ett ”som det är” perspektiv så läser vi in dessa som de är, vilket innebär att jag får två rader, eller dokument, i min databas som är lite olika. Nu är det så att inom NoSQL familjen så finns det olika typer av databaser och de hantera detta på olika sätt. MarkLogic, som jag jobbar med, är en dokumentdatabas med triple store, semantics, funktionalitet. Man skulle kunna kalla MarkLogic för en multidatabas.

Allt data i MarkLogic lagras som XML, JSON, text eller binärt, oavsett hur det ser ut när det levereras. I detta fall så kommer jag att använda XML som mitt lagringsformat vilket är ett sätt att beskriva data, ett relativt enkelt skulle jag vilja påstå, där vi använder taggar, eller element, som förhoppningsvis är namngiva så att vi förstår vad de innehåller, vi kan också lagra data i själva taggen men det är lite överkurs i detta fall.

Låt oss initialt förutsätta att vi just nu får data från vårt källsystem i separata filer, en för varje rad när de skapas/uppdateras.

Så när jag läser in mina två filer så kommer jag få två dokument, en för varje rad, i MarkLogic som ser ut enligt följande:

<kund>
    <kundnummer>1</kundnummer>
    <förnamn>Mats</förnamn>
    <efternamn>Stellwall</efternamn>
    <kön>Man</kön>
    <född>1973-12-28</född>
    <gift>ja</gift>
    <antalBarn>2</antalBarn>
    <borI>Stockholm</borI>
    <e-post>mats.stellwall@marklogic.com</e-post>
    <twitter>@MatsStellwall</twitter>
</kund>
<kund>
  <kundnummer>2</kundnummer>
  <förnamn>Kalle</förnamn>
  <efternamn>Svensson</efternamn>
  <kön>Man</kön>
  <född>1989-02-12</född>
   <gift>Nej</gift>
   <borI>Sundsvall</borI>
  <e-post>kalle.svensson@xyz.xz</e-post>
</kund>

Skulle jag bara få en fil med alla kunder som kanske är kommaseparerat så skulle det kunna se ut som nedan vid leverans.

kundnummer,förnamn.efternamn,kön,ålder,gift,antalBarn,borI,e-post,twitter
1,Mats,Stellwall,Man,41,ja,2,Stockholm, mats.stellwall@marklogic.com, @MatsStellwall
2,Kalle,Svensson,Man,1989-02-12,Nej,,Sundsvall,kalle.svensson@xyz.xz,

Enda skillnaden är att det andra dokumentet får några tomma element efter inläsning. Detta kan åtgärdas vid eller efter inläsning men det ligger utanför denna post.

<kund>
  <kundnummer>2</kundnummer>
  <förnamn>Kalle</förnamn>
  <efternamn>Svensson</efternamn>
  <kön>Man</kön>
  <född>1989-02-12</född>
   <gift>Nej</gift>
   <antalBarn></antalBarn>
   <borI>Sundsvall</borI>
   <e-post>kalle.svensson@xyz.xz</e-post>
   <twitter></twitter>
</kund>

Och om jag skall vara riktigt ärligt så är mina exempel hittills baserade att jag sätter root elementet, <kund>, vid inläsning. Standard så blir det <root>, men hur kul är det?

Om vi nu skulle börja fånga upp telefonnummer på våra kunder, vi har det inte på alla gamla men alla nya. Hur hanteras det från ett ”som det är” laddningsperspektiv?

Vi får en ny fil där alla kunder som har ett telefonnummer är med, en gammal och en ny.

kundnummer,förnamn.efternamn,kön,ålder,gift,antalBarn,borI,e-post,twitter,telefon
2,Kalle,Svensson,Man,1989-02-12,Nej,,Sundsvall,kalle.svensson@xyz.xz,,1234-1234567
3,Lisa,Larsson,Kvinna,1971-08-23,Ja,,Malmö,ll@abcd.ac,@llMalmoe,234-432345

Dokumentet med kundnummer = 1 kommer inte uppdateras, dokument är som det tidigare var.

Kundnummer 2 dokumentet uppdateras, per automatik, med det nya fältet:

<kund>
  <kundnummer>2</kundnummer>
  <förnamn>Kalle</förnamn>
  <efternamn>Svensson</efternamn>
  <kön>Man</kön>
  <född>1989-02-12</född>
   <gift>Nej</gift>
   <antalBarn></antalBarn>
   <borI>Sundsvall</borI>
   <e-post>kalle.svensson@xyz.xz</e-post>
   <twitter></twitter>
  <telefon>1234-1234567</telefon>
</kund>

Och vi har nu också ett tredje dokument kundnummer 3:

<kund>
  <kundnummer>3</kundnummer>
  <förnamn>Lisa</förnamn>
  <efternamn>Larsson</efternamn>
  <kön>Kvinna</kön>
  <född>1971-08-23</född>
   <gift>Ja</gift>
   <antalBarn></antalBarn>
   <borI>Malmö</borI>
   <e-post> ll@abcd.ac</e-post>
   <twitter>@llMalmoe </twitter>
  <telefon>234-432345</telefon>
</kund>

Ovan exempel illustrerar ganska väl hur MarkLogic hanterar ”som det är”, as-is, inläsning och uppdatering. I och med att jag inte behöver i förväg bestämma mitt schema/struktur så får jag en mer flexibel hantering av data. Jag behöver inte lägga en massa tid på att designa indatatabeller eller hur jag skall hantera förändringar så som nya kolumner.

Det är också det som blir schema agnostic, att inte behöva ta ställning till schema, i och med att varje dokument är sitt eget schema. Det innebär också att jag kan lagra olika typer av data i samma dokument, förutom text och värden också geo spatial eller tripplar, semantics, för att nämna några andra typer av data.

MarkLogic indexerar alla dessa dokument när jag läser in dem, vilket gör det möjligt för mig att snabbt kan börja söka bland dem. Om jag vill veta vilka kunder som är män så söker jag efter alla vars Kön = Man och får tillbaka två dokument., jag skriver mer om sökning i denna post. Detta fungerar även om jag skulle ha olika namn på mina root noder, som i detta exempel heter Kund.

Men om jag nu skulle börja ta in ytterligare data, till exempel försäljning också, hur fungerar det då?

Ett ytterst enkelt exempel på försäljningsdata skulle kunna vara enligt nedan.

kundnummer,orderNr,orderRad,produkt,pris
1,1,1,Svarta Strumpor,125kr
1,1,2,Blå Skjorta;545Kr
3,2,1,Beige Strumpbyxor,99Kr

Dessa rader skulle generera följande dokument i vår databas om vi vill ha ”som det är”.

<orderRad>
  <kundnummer>1</kundnummer>
  <orderNr>1</orderNr>
  <orderRad>1</orderRad>
  <produkt>Svarta Strumpor</produkt>
  <pris>125Kr</pris>
</orderRad>

<orderRad>
  <kundnummer>1</kundnummer>
  <orderNr>1</orderNr>
  <orderRad>2</orderRad>
  <produkt>Blå Skjorta</produkt>
  <pris>545Kr</pris>
</orderRad>

<orderRad>
  <kundnummer>3</kundnummer>
  <orderNr>2</orderNr>
  <orderRad>1</orderRad>
  <produkt> Beige Strumpbyxor </produkt>
  <pris>99Kr</pris>
</orderRad>

Om jag söker efter kundnummer = 1 så kommer jag få tillbaka tre dokument, ett kunddokument och två orderradsdokument. Detta på grund av den indexering som sker vid inläsning, jag behöver inte tala om för MarkLogic att kundnummer i orderrad är samma som kundnummer i kund.

Men om nu kundnummer från mitt ordersystem heter kundNr istället, vad händer då?

Efter inläsning så ser våra dokument då ut enligt följande:

<orderRad>
  <kundNr>1</kundNr>
  <orderNr>1</orderNr>
  <orderRad>1</orderRad>
  <produkt>Svarta Strumpor</produkt>
  <pris>125Kr</pris>
</orderRad>

<orderRad>
  <kundNr>1</kundNr>
  <orderNr>1</orderNr>
  <orderRad>2</orderRad>
  <produkt>Blå Skjorta</produkt>
  <pris>545Kr</pris>
</orderRad>

<orderRad>
  <kundNr>3</kundNr>
  <orderNr>2</orderNr>
  <orderRad>1</orderRad>
  <produkt> Beige Strumpbyxor </produkt>
  <pris>99Kr</pris>
</orderRad>

Om jag nu söker på kundnummer = 1 så kommer jag endast få tillbaka ett dokument, nämligen kunden. Detta eftersom kundnummer fältet i försäljningsdokumenten heter kundNr. Däremot om jag söker bara efter 1 så kommer jag få träff på alla tre dokumenten, och alla andra som har 1 i något fält.

Nu har jag tre val

  1. Att ändra namnet vid inläsning så att fältet heter kundnummer
  2. Att i MarkLogic skapa något som heter fält där jag talar om att kundNr och Kundnummer är samma sak
  3. Hantera det vid sökning genom att alltid söka på båda fälten med en OR/ELLER fråga

Och det är nu vi behöver börja ta dessa beslut, ”som det är”, As-is, inläsning av data ger oss möjligheten att snabbt komma igång och det skapar en flexibilitet i hantering av förändringar av data men det gör inte att vi slipper behöva tänka på strukturen. Vi måste vid varje ny källa fundera på och besluta hur vi skall hantera olikheter och likheter, hur vi skall söka och fråga på data samt hur vi vill visa det.

Detta leder oss till det vi brukar kalla för ”schema on read”, schema vid läsning, vilket innebär att när vi hämtar och presenterar data så behöver vi bestämma hur den strukturen skall vara. Detta är en ganska vital skillnad mot att använda en relationsdatabas, där vi måste bestämma struktur innan vi läser in data och ofta även en ytterligare struktur för när vi presenterar data.

Om fortsätter med exemplet vi har använt hittills och om jag nu istället för att söka på kundnummer vill kunna välja en produkt och sedan se alla kunder som köpt den så kommer jag behöva tala om hur kund och produkt information skall kopplas ihop. Detta kan göras i samband med att jag skapar min fråga eller genom att skapa nya dokument där jag slår ihop produkt och kundinformation i förväg, lite som att skapa aggregerad data i relationsvärlden, helt beroende på hur statisk resultatet skall vara.

För att summera det hela så skulle jag vilja påstå att kanske så är inte NoSQL, och MarkLogic i synnerhet, en magisk låda. Men sättet som data hanteras gör att man får många fördelar jämfört med en relationsdatabas som ger möjlighet att fokusera mer på slutresultatet.

Hur påverkar detta modellerande och ETL?

Det tar som sagt inte bort behovet av modellering, men det minskar det ganska mycket. Fokus blir mer på vilka informations objekt, kund, produkt och så vidare, som skall finnas och inte hur vi skall lagra det.

Vår ETL blir också enklare, vi behöver forfarande hantera datakvalité och verifiera att vi har rätt värden i fälten men inte så mycket runt att transformera data.

Så jag skulle säga att det kanske är så nära en magisk låda man kan komma.

Låter detta spännande?

Kontakta mig gärna så berättar jag mer.

/Mats Stellwall

P.S Kontaktuppgifter finns under About D.S

 

Share on FacebookShare on Google+Email this to someoneTweet about this on TwitterShare on LinkedIn