Bitmap-indekser i Go: søg med vild hastighed

Bitmap-indekser i Go: søg med vild hastighed

introduktion

Jeg gav denne rapport på engelsk ved GopherCon Russia 2019-konferencen i Moskva og på russisk ved et møde i Nizhny Novgorod. Vi taler om et bitmapindeks - mindre almindeligt end B-træ, men ikke mindre interessant. Deling optage taler på konferencen på engelsk og tekstudskrifter på russisk.

Vi vil se på, hvordan et bitmapindeks fungerer, hvornår det er bedre, hvornår det er dårligere end andre indekser, og i hvilke tilfælde er det væsentligt hurtigere end dem; Lad os se, hvilke populære DBMS'er, der allerede har bitmap-indekser; Lad os prøve at skrive vores egen i Go. Og "til dessert" vil vi bruge færdige biblioteker til at skabe vores egen superhurtige specialiserede database.

Jeg håber virkelig, at mine værker vil være nyttige og interessante for dig. Gå!

Indledning


http://bit.ly/bitmapindexes
https://github.com/mkevac/gopherconrussia2019

Hej alle! Klokken er seks om aftenen, og vi er alle super trætte. God tid til at tale om kedelig databaseindeksteori, ikke? Bare rolig, jeg har et par linjer kildekode her og der. 🙂

Bortset fra alle vittigheder er rapporten propfyldt med information, og vi har ikke meget tid. Så lad os komme i gang.
Bitmap-indekser i Go: søg med vild hastighed
I dag vil jeg tale om følgende:

  • hvad er indekser;
  • hvad er et bitmapindeks;
  • hvor det bruges og hvor det IKKE bruges og hvorfor;
  • simpel implementering i Go og lidt kamp med compileren;
  • lidt mindre enkel, men meget mere produktiv implementering i Go assembler;
  • "problemer" med bitmap-indekser;
  • eksisterende implementeringer.

Så hvad er indekser?

Bitmap-indekser i Go: søg med vild hastighed

Indekset er en separat datastruktur, som vi vedligeholder og opdaterer ud over hoveddataene. Det bruges til at fremskynde søgningen. Uden indekser ville søgning kræve at gennemgå dataene fuldstændigt (en proces kaldet fuld scanning), og denne proces har lineær algoritmisk kompleksitet. Men databaser indeholder normalt enorme mængder data, og den lineære kompleksitet er for langsom. Ideelt set ville vi få en logaritmisk eller konstant.

Dette er et enormt komplekst emne, fyldt med finesser og afvejninger, men efter at have set på årtiers databaseudvikling og forskning, er jeg villig til at sige, at der kun er nogle få udbredte tilgange til at skabe databaseindekser.

Bitmap-indekser i Go: søg med vild hastighed

Den første tilgang er at hierarkisk reducere søgerummet, opdele søgerummet i mindre dele.

Det gør vi normalt ved hjælp af forskellige typer træer. Et eksempel kunne være en stor kasse med materialer i dit skab, der indeholder mindre kasser med materialer opdelt i forskellige emner. Hvis du har brug for materialer, vil du sandsynligvis lede efter dem i en boks, hvor der står "Materials" i stedet for en, hvor der står "Cookies", ikke?

Bitmap-indekser i Go: søg med vild hastighed

Den anden tilgang er straks at vælge det ønskede element eller gruppe af elementer. Vi gør dette i hash-kort eller omvendte indekser. Brug af hash-kort ligner meget det forrige eksempel, men i stedet for en kasse med kasser, har du en masse små kasser med sidste ting i dit skab.

Bitmap-indekser i Go: søg med vild hastighed

Den tredje tilgang er at eliminere behovet for søgning. Det gør vi ved hjælp af Bloom-filtre eller gøgefiltre. De første giver et svar med det samme, så du slipper for at skulle søge.

Bitmap-indekser i Go: søg med vild hastighed

Den sidste tilgang er at udnytte al den kraft, som moderne hardware giver os. Det er præcis, hvad vi gør i bitmap-indekser. Ja, når vi bruger dem, skal vi nogle gange gennemgå hele indekset, men vi gør det super effektivt.

Som jeg sagde, er emnet for databaseindekser stort og fyldt med kompromiser. Det betyder, at vi nogle gange kan bruge flere tilgange på samme tid: hvis vi skal fremskynde søgningen endnu mere, eller hvis vi skal dække alle mulige søgetyper.

I dag vil jeg tale om den mindst kendte tilgang til disse - bitmap-indekser.

Hvem er jeg til at tale om dette emne?

Bitmap-indekser i Go: søg med vild hastighed

Jeg arbejder som teamleder hos Badoo (måske du er mere bekendt med vores andet produkt, Bumble). Vi har allerede mere end 400 millioner brugere rundt om i verden og mange funktioner, der vælger det bedste match til dem. Vi gør dette ved hjælp af tilpassede tjenester, herunder bitmap-indekser.

Så hvad er et bitmapindeks?

Bitmap-indekser i Go: søg med vild hastighed
Bitmapindekser, som navnet antyder, bruger bitmaps eller bitsæt til at implementere et søgeindeks. Fra et fugleperspektiv består dette indeks af et eller flere sådanne bitmaps, der repræsenterer enhver entitet (såsom mennesker) og deres egenskaber eller parametre (alder, øjenfarve osv.), og en algoritme, der bruger bitoperationer (AND, OR, NOT ) for at besvare søgeforespørgslen.
Bitmap-indekser i Go: søg med vild hastighed
Vi får at vide, at bitmap-indekser er bedst egnede og meget effektive til tilfælde, hvor der er søgninger, der kombinerer forespørgsler på tværs af mange kolonner med lav kardinalitet (tænk "øjenfarve" eller "civilstand" versus noget som "afstand fra bymidte"). Men jeg viser senere, at de også fungerer fint til kolonner med høj kardinalitet.

Lad os se på det enkleste eksempel på et bitmapindeks.
Bitmap-indekser i Go: søg med vild hastighed
Forestil dig, at vi har en liste over restauranter i Moskva med binære egenskaber som disse:

  • nær metro;
  • der er privat parkering;
  • der er en veranda (har terrasse);
  • du kan reservere et bord (accepterer reservationer);
  • velegnet til vegetarer (vegansk venlig);
  • dyrt (dyrt).

Bitmap-indekser i Go: søg med vild hastighed
Lad os give hver restaurant et sekvensnummer startende fra 0 og allokere hukommelse til 6 bitmaps (en for hver karakteristik). Vi vil derefter udfylde disse bitmaps afhængigt af, om restauranten har denne egenskab eller ej. Hvis restaurant 4 har en veranda, vil bit nr. 4 i "har en veranda" bitmap blive sat til 1 (hvis der ikke er nogen veranda, så til 0).
Bitmap-indekser i Go: søg med vild hastighed
Nu har vi det enklest mulige bitmapindeks, og vi kan bruge det til at besvare spørgsmål som:

  • "Vis mig vegetarvenlige restauranter";
  • "Vis mig billige restauranter med en veranda, hvor du kan reservere bord."

Bitmap-indekser i Go: søg med vild hastighed
Bitmap-indekser i Go: søg med vild hastighed
Hvordan? Lad os tage et kig. Den første anmodning er meget enkel. Alt, hvad vi skal gøre, er at tage det "vegetarvenlige" bitmap og lave det om til en liste over restauranter, hvis bits er afsløret.
Bitmap-indekser i Go: søg med vild hastighed
Bitmap-indekser i Go: søg med vild hastighed
Den anden anmodning er lidt mere kompliceret. Vi skal bruge NOT bitmap på den "dyre" bitmap for at få en liste over billige restauranter, så OG den med "kan jeg bestille bord" bitmap og OG resultatet med "der er en veranda" bitmap. Den resulterende bitmap vil indeholde en liste over virksomheder, der opfylder alle vores kriterier. I dette eksempel er dette kun Yunost-restauranten.
Bitmap-indekser i Go: søg med vild hastighed
Bitmap-indekser i Go: søg med vild hastighed
Der er en masse teori involveret, men bare rolig, vi vil se koden meget snart.

Hvor bruges bitmap-indekser?

Bitmap-indekser i Go: søg med vild hastighed
Hvis du Google bitmap-indekserer, vil 90% af svarene være relateret til Oracle DB på den ene eller anden måde. Men andre DBMS'er understøtter sikkert også sådan en fed ting, ikke? Ikke rigtig.

Lad os gennemgå listen over hovedmistænkte.
Bitmap-indekser i Go: søg med vild hastighed
MySQL understøtter endnu ikke bitmap-indekser, men der er et forslag, der foreslår at tilføje denne mulighed (https://dev.mysql.com/worklog/task/?id=1524).

PostgreSQL understøtter ikke bitmapindekser, men bruger simple bitmaps og bitoperationer til at kombinere søgeresultater på tværs af flere andre indekser.

Tarantool har bitset-indekser og understøtter simple søgninger på dem.

Redis har simple bitfelter (https://redis.io/commands/bitfield) uden mulighed for at søge efter dem.

MongoDB understøtter endnu ikke bitmap-indekser, men der er også et forslag, der foreslår, at denne mulighed tilføjes https://jira.mongodb.org/browse/SERVER-1723

Elasticsearch bruger bitmaps internt (https://www.elastic.co/blog/frame-of-reference-and-roaring-bitmaps).

Bitmap-indekser i Go: søg med vild hastighed

  • Men en ny nabo er dukket op i vores hus: Pilosa. Dette er en ny ikke-relationel database skrevet i Go. Den indeholder kun bitmap-indekser og baserer alt på dem. Vi taler om det lidt senere.

Implementering i Go

Men hvorfor bruges bitmap-indekser så sjældent? Før jeg besvarer dette spørgsmål, vil jeg gerne vise dig, hvordan du implementerer et meget simpelt bitmapindeks i Go.
Bitmap-indekser i Go: søg med vild hastighed
Bitmaps er i bund og grund kun stykker data. I Go, lad os bruge byte-slices til dette.

Vi har én bitmap for én restaurantkarakteristik, og hver bit i bitmappet angiver, om en bestemt restaurant har denne egenskab eller ej.
Bitmap-indekser i Go: søg med vild hastighed
Vi skal bruge to hjælpefunktioner. Den ene vil blive brugt til at fylde vores bitmaps med tilfældige data. Tilfældigt, men med en vis sandsynlighed for, at restauranten har hver ejendom. For eksempel mener jeg, at der er meget få restauranter i Moskva, hvor man ikke kan reservere bord, og det forekommer mig, at omkring 20 % af etablissementerne er egnede til vegetarer.

Den anden funktion vil konvertere bitmap til en liste over restauranter.
Bitmap-indekser i Go: søg med vild hastighed
Bitmap-indekser i Go: søg med vild hastighed
For at besvare forespørgslen "Vis mig billige restauranter, der har en gårdhave og kan reservere", har vi brug for to bit-operationer: IKKE og OG.

Vi kan forenkle vores kode lidt ved at bruge den mere komplekse AND NOT operator.

Vi har funktioner til hver af disse operationer. De går begge igennem skiverne, tager de tilsvarende elementer fra hver, kombinerer dem med lidt betjening og lægger resultatet i den resulterende skive.
Bitmap-indekser i Go: søg med vild hastighed
Og nu kan vi bruge vores bitmaps og funktioner til at besvare søgeforespørgslen.
Bitmap-indekser i Go: søg med vild hastighed
Ydeevnen er ikke så høj, selvom funktionerne er meget enkle, og vi sparede mange penge ved ikke at returnere en ny resulterende skive, hver gang funktionen blev kaldt.

Efter at have lavet lidt profilering med pprof, bemærkede jeg, at Go-compilatoren manglede en meget enkel, men meget vigtig optimering: funktionsindlejring.
Bitmap-indekser i Go: søg med vild hastighed
Faktum er, at Go-kompileren er frygtelig bange for sløjfer, der går gennem skiver, og nægter kategorisk at inline funktioner, der indeholder sådanne sløjfer.
Bitmap-indekser i Go: søg med vild hastighed
Men jeg er ikke bange, og jeg kan narre compileren ved at bruge goto i stedet for en loop, som i de gode gamle dage.

Bitmap-indekser i Go: søg med vild hastighed
Bitmap-indekser i Go: søg med vild hastighed

Og som du kan se, vil compileren nu med glæde inline vores funktion! Som et resultat lykkes det os at spare omkring 2 mikrosekunder. Ikke dårligt!

Bitmap-indekser i Go: søg med vild hastighed

Den anden flaskehals er let at se, hvis man ser nøje på montageoutputtet. Compileren tilføjede en udsnitsgrænsekontrol lige inde i vores hotteste loop. Faktum er, at Go er et sikkert sprog, compileren er bange for, at mine tre argumenter (tre skiver) er af forskellig størrelse. Så vil der jo være en teoretisk mulighed for, at der opstår et såkaldt bufferoverløb.

Lad os berolige compileren ved at vise den, at alle skiver har samme størrelse. Vi kan gøre dette ved at tilføje et simpelt flueben i begyndelsen af ​​vores funktion.
Bitmap-indekser i Go: søg med vild hastighed
Når du ser dette, springer compileren glad kontrollen over, og vi ender med at spare yderligere 500 nanosekunder.

Store slagter

Okay, det lykkedes os at presse noget ydeevne ud af vores simple implementering, men dette resultat er faktisk meget værre, end det er muligt med nuværende hardware.

Alt, hvad vi gør, er grundlæggende bitoperationer, og vores processorer udfører dem meget effektivt. Men desværre "fodrer" vi vores processor med meget små stykker arbejde. Vores funktioner udfører operationer på en byte-for-byte basis. Vi kan meget nemt tilpasse vores kode til at arbejde med 8-byte bidder ved hjælp af UInt64-slices.

Bitmap-indekser i Go: søg med vild hastighed

Som du kan se, fremskyndede denne lille ændring vores program otte gange ved at øge batchstørrelsen med otte gange. Forstærkningen kan siges at være lineær.

Bitmap-indekser i Go: søg med vild hastighed

Implementering i assembler

Bitmap-indekser i Go: søg med vild hastighed
Men dette er ikke enden. Vores processorer kan arbejde med bidder på 16, 32 og endda 64 bytes. Sådanne "brede" operationer kaldes single-instruction multiple data (SIMD; én instruktion, mange data), og processen med at transformere kode, så den bruger sådanne operationer, kaldes vektorisering.

Desværre er Go-kompileren langt fra fremragende til vektorisering. I øjeblikket er den eneste måde at vektorisere Go-kode på at tage og sætte disse operationer manuelt ved hjælp af Go assembler.

Bitmap-indekser i Go: søg med vild hastighed

Go assembler er et mærkeligt udyr. Du ved sikkert, at assemblersprog er noget, der er stærkt knyttet til arkitekturen på den computer, du skriver til, men det er ikke tilfældet i Go. Go assembler er mere som et IRL (mellemrepræsentationssprog) eller mellemsprog: det er praktisk talt platformsuafhængigt. Rob Pike ydede en fremragende præstation rapport om dette emne for flere år siden på GopherCon i Denver.

Derudover bruger Go et usædvanligt Plan 9-format, som adskiller sig fra de generelt accepterede AT&T- og Intel-formater.
Bitmap-indekser i Go: søg med vild hastighed
Det er sikkert at sige, at det ikke er det sjoveste at skrive Go assembler i hånden.

Men heldigvis er der allerede to værktøjer på højt niveau, der hjælper os med at skrive Go assembler: PeachPy og avo. Begge værktøjer genererer Go assembler fra kode på højere niveau skrevet i henholdsvis Python og Go.
Bitmap-indekser i Go: søg med vild hastighed
Disse hjælpeprogrammer forenkler ting som registerallokering, skrivning af loops og forenkler generelt processen med at komme ind i en verden af ​​assembly-programmering i Go.

Vi bruger avo, så vores programmer bliver næsten almindelige Go-programmer.
Bitmap-indekser i Go: søg med vild hastighed
Sådan ser det enkleste eksempel på et avo-program ud. Vi har en hoved() funktion, som i sig selv definerer Add() funktionen, hvis betydning er at tilføje to tal. Der er hjælpefunktioner her til at få parametre ved navn og få et af de gratis og passende processorregistre. Hver processorhandling har en tilsvarende funktion on avo, som det ses i ADDQ. Til sidst ser vi en hjælpefunktion til lagring af den resulterende værdi.
Bitmap-indekser i Go: søg med vild hastighed
Ved at kalde go generer, vil vi udføre programmet på avo, og som et resultat vil to filer blive genereret:

  • add.s med den resulterende kode i Go assembler;
  • stub.go med funktionsoverskrifter til at forbinde de to verdener: Go og assembler.

Bitmap-indekser i Go: søg med vild hastighed
Nu hvor vi har set, hvad avo gør og hvordan, lad os se på vores funktioner. Jeg implementerede både skalære og vektorversioner (SIMD) af funktionerne.

Lad os først se på de skalære versioner.
Bitmap-indekser i Go: søg med vild hastighed
Som i det foregående eksempel beder vi om et gratis og gyldigt register til generelle formål, vi behøver ikke at beregne forskydninger og størrelser for argumenterne. avo gør alt dette for os.
Bitmap-indekser i Go: søg med vild hastighed
Vi plejede at bruge etiketter og goto (eller spring) til at forbedre ydeevnen og narre Go-kompileren, men nu gør vi det fra starten. Pointen er, at cyklusser er et begreb på højere niveau. I assembler har vi kun etiketter og hop.
Bitmap-indekser i Go: søg med vild hastighed
Den resterende kode burde allerede være kendt og forståelig. Vi emulerer en løkke med etiketter og spring, tager et lille stykke data fra vores to skiver, kombinerer dem med en bitoperation (OG IKKE i dette tilfælde) og lægger derefter resultatet i den resulterende skive. Alle.
Bitmap-indekser i Go: søg med vild hastighed
Sådan ser den endelige assembler-kode ud. Vi behøvede ikke at beregne forskydninger og størrelser (markeret med grønt) eller holde styr på de anvendte registre (fremhævet med rødt).
Bitmap-indekser i Go: søg med vild hastighed
Hvis vi sammenligner ydeevnen af ​​assemblersprogimplementeringen med ydeevnen af ​​den bedste implementering i Go, vil vi se, at det er det samme. Og dette forventes. Vi lavede jo ikke noget særligt – vi gengav bare, hvad en Go-kompiler ville gøre.

Desværre kan vi ikke tvinge compileren til at inline vores funktioner skrevet i assemblersprog. Go-kompileren har i øjeblikket ikke sådan en funktion, selvom der har været en anmodning om at tilføje den i et stykke tid.

Det er derfor, det er umuligt at få nogen fordel af små funktioner i assemblersprog. Vi skal enten skrive store funktioner eller bruge den nye math/bits-pakke eller omgå assembler-sproget.

Lad os nu se på vektorversionerne af vores funktioner.
Bitmap-indekser i Go: søg med vild hastighed
Til dette eksempel besluttede jeg at bruge AVX2, så vi vil bruge operationer, der opererer på 32-byte bidder. Strukturen af ​​koden minder meget om den skalære version: indlæsning af parametre, beder om et gratis delt register osv.
Bitmap-indekser i Go: søg med vild hastighed
En nyskabelse er, at bredere vektoroperationer bruger specielle brede registre. I tilfælde af 32-byte chunks er disse registre præfikset med Y. Det er derfor, du ser YMM()-funktionen i koden. Hvis jeg brugte AVX-512 med 64-bit bidder, ville præfikset være Z.

Den anden innovation er, at jeg besluttede at bruge en optimering kaldet loop unrolling, hvilket betyder at udføre otte loop-operationer manuelt, før jeg hopper til begyndelsen af ​​loopet. Denne optimering reducerer antallet af filialer i koden og er begrænset af antallet af tilgængelige gratis registre.
Bitmap-indekser i Go: søg med vild hastighed
Nå, hvad med ydeevne? Hun er smuk! Vi opnåede en speedup på omkring syv gange i forhold til den bedste Go-løsning. Imponerende, ikke?
Bitmap-indekser i Go: søg med vild hastighed
Men selv denne implementering kan potentielt accelereres ved at bruge AVX-512, prefetching eller en JIT (just-in-time compiler) til forespørgselsplanlæggeren. Men dette er bestemt et emne for en separat rapport.

Problemer med bitmap-indekser

Nu hvor vi allerede har set på en simpel implementering af et bitmapindeks i Go og et meget mere produktivt i assemblersprog, lad os endelig tale om, hvorfor bitmapindekser bruges så sjældent.
Bitmap-indekser i Go: søg med vild hastighed
Ældre artikler nævner tre problemer med bitmap-indekser, men nyere artikler og jeg hævder, at de ikke længere er relevante. Vi vil ikke dykke dybt ned i hvert af disse problemer, men vil se på dem overfladisk.

Problemet med høj kardinalitet

Så vi får at vide, at bitmap-indekser kun er egnede til felter med lav kardinalitet, det vil sige dem, der har få værdier (for eksempel køn eller øjenfarve), og årsagen er, at den sædvanlige repræsentation af sådanne felter (en bit pr. værdi) i tilfælde af høj kardinalitet, vil det optage for meget plads, og desuden vil disse bitmap-indekser være dårligt (sjældent) udfyldt.
Bitmap-indekser i Go: søg med vild hastighed
Bitmap-indekser i Go: søg med vild hastighed
Nogle gange kan vi bruge en anden repræsentation, såsom den standard, vi bruger til at repræsentere tal. Men det var fremkomsten af ​​kompressionsalgoritmer, der ændrede alt. I løbet af de sidste årtier er videnskabsmænd og forskere kommet med et stort antal komprimeringsalgoritmer til bitmaps. Deres største fordel er, at der ikke er behov for at dekomprimere bitmaps for at udføre bitoperationer - vi kan udføre bitoperationer direkte på komprimerede bitmaps.
Bitmap-indekser i Go: søg med vild hastighed
For nylig er hybride tilgange begyndt at dukke op, såsom brølende bitmaps. De bruger samtidig tre forskellige repræsentationer for bitmaps - selve bitmaps, arrays og såkaldte bitruns - og balancerer mellem dem for at maksimere ydeevnen og minimere hukommelsesforbruget.

Du kan finde brølende bitmaps i de mest populære applikationer. Der er allerede et stort antal implementeringer til en lang række programmeringssprog, herunder mere end tre implementeringer til Go.
Bitmap-indekser i Go: søg med vild hastighed
En anden tilgang, der kan hjælpe os med at håndtere høj kardinalitet, kaldes binning. Forestil dig, at du har et felt, der repræsenterer en persons højde. Højde er et flydende kommatal, men sådan tænker vi mennesker ikke på det. For os er der ingen forskel på højde 185,2 cm og 185,3 cm.

Det viser sig, at vi kan gruppere lignende værdier i grupper inden for 1 cm.

Og hvis vi også ved, at meget få mennesker er kortere end 50 cm og højere end 250 cm, så kan vi i det væsentlige forvandle et felt med uendelig kardinalitet til et felt med en kardinalitet på omkring 200 værdier.

Om nødvendigt kan vi selvfølgelig lave yderligere filtrering efterfølgende.

Problem med høj båndbredde

Det næste problem med bitmap-indekser er, at det kan være meget dyrt at opdatere dem.

Databaser skal være i stand til at opdatere data, mens potentielt hundredvis af andre forespørgsler søger efter dataene. Vi har brug for låse for at undgå problemer med samtidig dataadgang eller andre delingsproblemer. Og hvor der er én stor lås, er der et problem - låsestrid, når denne lås bliver en flaskehals.
Bitmap-indekser i Go: søg med vild hastighed
Dette problem kan løses eller omgås ved at bruge sharding eller bruge versionerede indekser.

Sharding er en simpel og velkendt ting. Du kan skære et bitmapindeks på samme måde som andre data. I stedet for én stor lås, får du en masse små låse og dermed slippe for låsestrid.

Den anden måde at løse problemet på er at bruge versionerede indekser. Du kan have én kopi af indekset, som du bruger til at søge eller læse, og en, som du bruger til at skrive eller opdatere. Og én gang i en bestemt periode (for eksempel én gang hver 100 ms eller 500 ms) duplikerer du dem og bytter dem. Denne tilgang er naturligvis kun anvendelig i de tilfælde, hvor din ansøgning kan håndtere et let haltende søgeindeks.

Disse to tilgange kan bruges samtidigt: du kan have et sharded versioned indeks.

Mere komplekse forespørgsler

Det sidste problem med bitmap-indekser er, at vi får at vide, at de ikke er velegnede til mere komplekse typer forespørgsler, såsom span-forespørgsler.

Faktisk, hvis du tænker over det, er bitoperationer som AND, OR osv. ikke særlig velegnede til forespørgsler a la "Vis mig hoteller med værelsespriser fra 200 til 300 dollars per nat."
Bitmap-indekser i Go: søg med vild hastighed
En naiv og meget uklog løsning ville være at tage resultaterne for hver dollarværdi og kombinere dem med en bitvis ELLER-operation.
Bitmap-indekser i Go: søg med vild hastighed
En lidt bedre løsning ville være at bruge gruppering. For eksempel i grupper af 50 dollars. Dette ville fremskynde vores proces med 50 gange.

Men problemet løses også nemt ved at bruge en visning, der er oprettet specielt til denne type anmodning. I videnskabelige artikler kaldes det områdekodede bitmaps.
Bitmap-indekser i Go: søg med vild hastighed
I denne repræsentation sætter vi ikke bare en bit for en eller anden værdi (for eksempel 200), men sætter denne værdi og alt højere. 200 og derover. Samme for 300:300 og derover. Og så videre.

Ved at bruge denne repræsentation kan vi besvare denne form for søgeforespørgsel ved at krydse indekset blot to gange. Først får vi en liste over hoteller, hvor værelset koster mindre eller $300, og derefter fjerner vi dem, hvor værelsesprisen er mindre eller $199. Parat.
Bitmap-indekser i Go: søg med vild hastighed
Du vil blive overrasket, men selv geoforespørgsler er mulige ved hjælp af bitmap-indekser. Tricket er at bruge en geometrisk repræsentation, der omgiver din koordinat med en geometrisk figur. For eksempel S2 fra Google. Figuren skal kunne gengives i form af tre eller flere skærende linjer, der kan nummereres. På denne måde kan vi omdanne vores geoquery til flere forespørgsler "langs mellemrummet" (langs disse nummererede linjer).

Klar løsninger

Jeg håber, jeg interesserede dig lidt, og at du nu har et andet nyttigt værktøj i dit arsenal. Hvis du nogensinde har brug for at gøre noget som dette, ved du, hvilken vej du skal se.

Det er dog ikke alle, der har tid, tålmodighed eller ressourcer til at oprette bitmap-indekser fra bunden. Især mere avancerede, ved at bruge SIMD, for eksempel.

Heldigvis er der flere færdige løsninger til at hjælpe dig.
Bitmap-indekser i Go: søg med vild hastighed

Brølende bitmaps

For det første er der det samme brølende bitmaps-bibliotek, som jeg allerede har talt om. Den indeholder alle de nødvendige beholdere og bitoperationer, som du skal bruge for at lave et fuldgyldigt bitmapindeks.
Bitmap-indekser i Go: søg med vild hastighed
Desværre er der i øjeblikket ingen af ​​Go-implementeringerne, der bruger SIMD, hvilket betyder, at Go-implementeringer for eksempel er mindre effektive end C-implementeringer.

behåret

Et andet produkt, der kan hjælpe dig, er Pilosa DBMS, som faktisk kun har bitmap-indekser. Dette er en relativt ny løsning, men den vinder hjerter med stor hastighed.
Bitmap-indekser i Go: søg med vild hastighed
Pilosa bruger brølende bitmaps internt og giver dig mulighed for at bruge dem, forenkler og forklarer alle de ting, jeg talte om ovenfor: gruppering, områdekodede bitmaps, begrebet et felt osv.

Lad os tage et hurtigt kig på et eksempel på brug af Pilosa til at besvare et spørgsmål, du allerede er bekendt med.
Bitmap-indekser i Go: søg med vild hastighed
Eksemplet minder meget om det, du så før. Vi opretter en klient til Pilosa-serveren, opretter et indeks og de nødvendige felter, udfylder derefter vores felter med tilfældige data med sandsynligheder og udfører til sidst den velkendte forespørgsel.

Derefter bruger vi IKKE på feltet "dyrt" og skærer derefter resultatet (eller OG det) med feltet "terrasse" og med feltet "reservationer". Og endelig får vi det endelige resultat.
Bitmap-indekser i Go: søg med vild hastighed
Jeg håber virkelig, at denne nye type indeks inden for en overskuelig fremtid også vil dukke op i DBMS'er som MySQL og PostgreSQL - bitmap-indekser.
Bitmap-indekser i Go: søg med vild hastighed

Konklusion

Bitmap-indekser i Go: søg med vild hastighed
Hvis du ikke er faldet i søvn endnu, tak. Jeg måtte kort berøre mange emner på grund af begrænset tid, men jeg håber, at foredraget var nyttigt og måske endda motiverende.

Bitmap-indekser er gode at kende til, selvom du ikke har brug for dem lige nu. Lad dem være endnu et værktøj i din værktøjskasse.

Vi har set på forskellige præstationstricks til Go og ting, som Go-kompileren ikke håndterer særlig godt endnu. Men dette er absolut nyttigt for enhver Go-programmør at vide.

Det var alt, jeg ville fortælle dig. Tak skal du have!

Kilde: www.habr.com

Tilføj en kommentar