{"id":33793,"date":"2019-10-31T21:54:42","date_gmt":"2019-10-31T18:54:42","guid":{"rendered":"https:\/\/prohoster.info\/blog\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\/"},"modified":"2019-10-31T21:54:42","modified_gmt":"2019-10-31T18:54:42","slug":"bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","title":{"rendered":"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/86ef928e6741022b2c0e5885a031408a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Einleitungswort<\/h2>\n<p>\nIch habe diesen Vortrag auf Englisch auf der Konferenz GopherCon Russland 2019 in Moskau und auf Russisch bei einem Meetup in Nischni Nowgorod gehalten. Er handelt von einem Bitmap-Index \u2013 weniger verbreitet als ein B-Baum, aber ebenso interessant. Ich teile <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/WvlUH6MjUuI?list=PL3xVZC4USRNSO_kb2lh_J_no6C-KJ7Phg\">eine Aufzeichnung<\/a><\/noindex> des Vortrags auf der Konferenz auf Englisch und einer schriftlichen Transkription auf Russisch.<\/p>\n<p>Wir werden uns ansehen, wie ein Bitmap-Index funktioniert, wann er besser ist, wann schlechter als andere Indizes und in welchen F\u00e4llen er erheblich schneller ist; wir werden sehen, in welchen beliebten DBMS bereits Bitmap-Indizes vorhanden sind; und wir versuchen, unseren eigenen in Go zu schreiben. Zum \u201eDessert\u201c werden wir fertige Bibliotheken nutzen, um unsere superschnelle, spezialisierte Datenbank zu erstellen.<\/p>\n<p>Ich hoffe sehr, dass meine Arbeit f\u00fcr Sie n\u00fctzlich und interessant sein wird. Lassen Sie uns beginnen!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Einf\u00fchrung<\/h2>\n<p>\n<center><div class=\"youtube-placeholder\" data-id=\"WvlUH6MjUuI\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/WvlUH6MjUuI\/hqdefault.jpg\" alt=\"Video abspielen\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\n<noindex><a rel=\"nofollow\" href=\"http:\/\/bit.ly\/bitmapindexes\">http:\/\/bit.ly\/bitmapindexes<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/mkevac\/gopherconrussia2019\">https:\/\/github.com\/mkevac\/gopherconrussia2019<\/a><\/noindex><\/p>\n<p>Hallo zusammen! Es ist jetzt sechs Uhr abends, wir sind alle super m\u00fcde. Eine gro\u00dfartige Gelegenheit, um \u00fcber die langweilige Theorie von Datenbankindizes zu sprechen, oder? Keine Sorge, ich habe hier und da einige Zeilen Quellcode.<\/p>\n<p>Wenn wir ernsthaft sind, ist der Vortrag voller Informationen und wir haben nicht viel Zeit. Also lassen Sie uns anfangen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/e778e13727700f0335a4b5558a0d8db3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHeute werde ich \u00fcber Folgendes sprechen:<\/p>\n<ul>\n<li>Was sind Indizes;\n<\/li>\n<li>Was ist ein Bitmap-Index;\n<\/li>\n<li>Wo er verwendet wird und wo er NICHT verwendet wird und warum;\n<\/li>\n<li>Einfache Implementierung in Go und ein wenig K\u00e4mpfen mit dem Compiler;\n<\/li>\n<li>Etwas weniger einfache, aber viel leistungsf\u00e4higere Implementierung in Go-Assembler;\n<\/li>\n<li>Die \u201eProbleme\u201c von Bitmap-Indizes;\n<\/li>\n<li>Vorhandene Implementierungen.\n<\/li>\n<\/ul>\n<h2>Was sind also Indizes?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/b80e5b990c44814afe9150a9a82351fd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEin Index ist eine separate Datenstruktur, die wir zus\u00e4tzlich zu den Hauptdaten halten und aktualisieren. Er wird verwendet, um die Suche zu beschleunigen. Ohne Indizes w\u00fcrde die Suche einen vollst\u00e4ndigen Durchgang durch die Daten erfordern (ein Prozess, der als Full Scan bezeichnet wird) und dieser Prozess hat eine lineare algorithmische Komplexit\u00e4t. Aber Datenbanken enthalten normalerweise eine enorme Menge an Daten und lineare Komplexit\u00e4t ist zu langsam. Idealerweise w\u00fcrden wir logarithmische oder konstante Komplexit\u00e4t w\u00fcnschen.<\/p>\n<p>Das ist ein riesiges, komplexes Thema, gef\u00fcllt mit Nuancen und Kompromissen, aber nach Jahrzehnten der Entwicklung und Forschung \u00fcber verschiedene Datenbanken bin ich bereit zu behaupten, dass es nur wenige weithin verwendete Ans\u00e4tze zur Erstellung von DB-Indizes gibt.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/08a74dbb365035cd99bc94d72644a1b7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDer erste Ansatz besteht darin, den Suchbereich hierarchisch zu reduzieren und ihn in kleinere Teile zu unterteilen.<\/p>\n<p>In der Regel tun wir dies mithilfe verschiedener Arten von B\u00e4umen. Ein Beispiel k\u00f6nnte eine gro\u00dfe Box mit Materialien in Ihrem Schrank sein, in der sich kleinere Kisten mit Materialien zu verschiedenen Themen befinden. Wenn Sie Materialien ben\u00f6tigen, werden Sie sicherlich in der Box mit der Aufschrift \"Materialien\" suchen, und nicht in der mit der Aufschrift \"Kekse\", oder?<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/423fac47c748980b18af434644af4dae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDer zweite Ansatz besteht darin, das gew\u00fcnschte Element oder die Gruppe von Elementen sofort zu identifizieren. Wir tun dies in Hash-Maps oder in umgekehrten Indizes. Die Verwendung von Hash-Maps \u00e4hnelt sehr dem vorherigen Beispiel: Statt einer Box mit Boxen haben Sie in Ihrem Schrank eine Menge kleiner Kisten mit finalen Objekten.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/088fed0a2a0feea4a23edbf0ca654805.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDer dritte Ansatz besteht darin, die Notwendigkeit einer Suche zu eliminieren. Dies erreichen wir mit Hilfe von Bloom-Filtern oder Cuckoo-Filtern. Die ersten geben sofort eine Antwort, sodass Sie nicht suchen m\u00fcssen.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/493bc4f20baacc0a5dc0faf15cc46285.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDer letzte Ansatz besteht darin, die gesamte Leistung moderner Hardware optimal zu nutzen. Genau das tun wir mit Bitmap-Indizes. Ja, bei ihrer Verwendung m\u00fcssen wir manchmal den gesamten Index durchlaufen, aber wir tun dies \u00e4u\u00dferst effizient.<\/p>\n<p>Wie ich bereits sagte, ist das Thema Datenbankindizes umfangreich und voller Kompromisse. Das bedeutet, dass wir manchmal mehrere Ans\u00e4tze gleichzeitig verwenden k\u00f6nnen: Wenn wir die Suche noch weiter beschleunigen m\u00fcssen oder wenn wir alle m\u00f6glichen Suchtypen abdecken m\u00fcssen.<\/p>\n<p>Heute werde ich \u00fcber den am wenigsten bekannten Ansatz aus den genannten sprechen \u2013 \u00fcber Bitmap-Indizes.<\/p>\n<h2>Wer bin ich, um \u00fcber dieses Thema zu sprechen?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/42a9d17a507c392bc202254a92dfaf41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIch arbeite als Teamleiter bei Badoo (vielleicht kennen Sie unser anderes Produkt besser \u2013 Bumble). Wir haben bereits \u00fcber 400 Millionen Nutzer weltweit und viele Funktionen, die darauf abzielen, die besten Partien f\u00fcr sie zu finden. Dies tun wir mit Hilfe von ma\u00dfgeschneiderten Dienstleistungen, die unter anderem auch Bitmap-Indizes verwenden.<\/p>\n<h2>Was ist also ein Bitmap-Index?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/14f20f3697a20c02f6b3510dc7f0ae4d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBitmap-Indizes verwenden, wie der Name schon sagt, Bitmaps oder Bitsets, um einen Suchindex zu implementieren. Aus der Vogelperspektive besteht dieser Index aus einem oder mehreren solcher Bitmaps, die Entit\u00e4ten (wie Personen) und ihre Eigenschaften oder Parameter (Alter, Augenfarbe usw.) repr\u00e4sentieren, sowie aus einem Algorithmus, der bitweise Operationen (AND, OR, NOT) verwendet, um auf eine Suchanfrage zu reagieren.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/f815720330a51b1f0798e45d23160d3b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEs wird gesagt, dass Bitmap-Indizes am besten geeignet und sehr leistungsf\u00e4hig f\u00fcr F\u00e4lle sind, in denen Suchen Anfragen \u00fcber viele Spalten mit geringer Kardinalit\u00e4t kombinieren (stellen Sie sich 'Augenfarbe' oder 'Familienstand' im Gegensatz zu etwas wie 'Entfernung zum Stadtzentrum' vor). Aber sp\u00e4ter werde ich zeigen, dass sie auch in F\u00e4llen mit hoher Kardinalit\u00e4t hervorragend funktionieren.<\/p>\n<p>Betrachten wir ein einfaches Beispiel f\u00fcr einen Bitmap-Index.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/33fe23476e0931c10345d7175b83d68b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nStellen Sie sich vor, wir haben eine Liste von Moskauer Restaurants mit bin\u00e4ren Eigenschaften wie diesen:<\/p>\n<ul>\n<li>nahe der U-Bahn (near metro);\n<\/li>\n<li>mit privatem Parkplatz (has private parking);\n<\/li>\n<li>mit Terrasse (has terrace);\n<\/li>\n<li>mit Tischreservierungen (accepts reservations);\n<\/li>\n<li>vegan-freundlich (vegan friendly);\n<\/li>\n<li>teuer (expensive).\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/fcbad539ea12f79a9d06966ce308637e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLassen Sie uns jedem Restaurant eine fortlaufende Nummer ab 0 geben und Speicher f\u00fcr 6 Bitmaps reservieren (eine f\u00fcr jede Eigenschaft). Dann f\u00fcllen wir diese Bitmaps abh\u00e4ngig davon aus, ob das Restaurant diese Eigenschaft hat oder nicht. Wenn das Restaurant 4 eine Terrasse hat, wird das Bit Nr. 4 im Bitmap 'mit Terrasse' auf 1 (wenn keine Terrasse vorhanden ist, auf 0) gesetzt.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/3709c426617d4364f392ee6b68f92b00.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJetzt haben wir den einfachsten m\u00f6glichen Bitmap-Index, den wir nutzen k\u00f6nnen, um auf Anfragen wie diese zu antworten:<\/p>\n<ul>\n<li>\u201eZeig mir Restaurants, die f\u00fcr Vegetarier geeignet sind\u201c;\n<\/li>\n<li>\u201eZeig mir preiswerte Restaurants mit Terrasse, in denen man einen Tisch reservieren kann.\u201c\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/90acb0f890686bd52c3db1fc667f0b0b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/0fd0b7fe9f7b7039022ad5c79fe873bc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWie? Lassen Sie uns einen Blick darauf werfen. Die erste Anfrage ist sehr einfach. Alles, was wir tun m\u00fcssen, ist, das Bitmap 'vegan-freundlich' zu nehmen und es in eine Liste von Restaurants umzuwandeln, deren Bits gesetzt sind.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/ef4a5cfd658ff4ef8bc0c638c4522d11.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/9cc175bae55c16018fdf5ff95517a61a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDie zweite Anfrage ist etwas komplizierter. Wir m\u00fcssen die bitweise NOT-Operation auf die Bitmap \u201eteuer\u201c anwenden, um eine Liste von g\u00fcnstigen Restaurants zu erhalten, dann m\u00fcssen wir sie mit der Bitmap \u201eReservierung m\u00f6glich\u201c und das Ergebnis mit der Bitmap \u201eTerrasse vorhanden\u201c verkn\u00fcpfen. Die resultierende Bitmap enth\u00e4lt eine Liste von Einrichtungen, die allen unseren Kriterien entsprechen. In diesem Beispiel ist dies nur das Restaurant \u201eJungend\u201c.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/f1cdda0cbf7f15278553899cf876c17e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/126b50e0f622b6e36c461cd74e708c38.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHier gibt es viel Theorie, aber keine Sorge, wir werden sehr bald den Code sehen.<\/p>\n<h2>Wo werden Bitmap-Indizes verwendet?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/406132236c71a4f66ae79957b6e633b3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWenn Sie nach Bitmap-Indizes googeln, werden 90 % der Antworten mehr oder weniger mit Oracle DB verbunden sein. Aber andere DBMS unterst\u00fctzen sicherlich auch so etwas Cooles, oder? Nicht ganz. <\/p>\n<p>Lassen Sie uns die Liste der Hauptverd\u00e4chtigen durchgehen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/d18d66451a8a26b0ddf121f8ec0204cd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMySQL unterst\u00fctzt derzeit keine Bitmap-Indizes, hat jedoch einen Vorschlag zur Hinzuf\u00fcgung dieser Option gegeben (<noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/worklog\/task\/?id=1524\">https:\/\/dev.mysql.com\/worklog\/task\/?id=1524<\/a><\/noindex>).<\/p>\n<p>PostgreSQL unterst\u00fctzt keine Bitmap-Indizes, verwendet jedoch einfache Bitmaps und bitweise Operationen, um Suchergebnisse aus mehreren anderen Indizes zu kombinieren.<\/p>\n<p>Tarantool hat Bitset-Indizes, die eine einfache Suche erm\u00f6glichen.<\/p>\n<p>Redis verf\u00fcgt \u00fcber einfache bitweise Felder<noindex><a rel=\"nofollow\" href=\"https:\/\/redis.io\/commands\/bitfield\"> (https:\/\/redis.io\/commands\/bitfield<\/a><\/noindex>) ohne Suchm\u00f6glichkeit.<\/p>\n<p>MongoDB unterst\u00fctzt derzeit keine Bitmap-Indizes, hat jedoch auch einen Vorschlag zur Hinzuf\u00fcgung dieser Option gemacht. <noindex><a rel=\"nofollow\" href=\"https:\/\/jira.mongodb.org\/browse\/SERVER-1723\">https:\/\/jira.mongodb.org\/browse\/SERVER-1723<\/a><\/noindex><\/p>\n<p>Elasticsearch verwendet Bitmaps intern<noindex><a rel=\"nofollow\" href=\"https:\/\/www.elastic.co\/blog\/frame-of-reference-and-roaring-bitmaps\"> (https:\/\/www.elastic.co\/blog\/frame-of-reference-and-roaring-bitmaps<\/a><\/noindex>).<\/p>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/232d335963603d6e6dec98839fc9f486.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Aber in unserem Haus ist ein neuer Nachbar eingezogen: Pilosa. Es handelt sich um eine neue nicht-relationale Datenbank, die in Go geschrieben ist. Sie besteht nur aus bitmap-indizes und basiert alles darauf. Wir werden sp\u00e4ter dar\u00fcber sprechen.\n<\/li>\n<\/ul>\n<h2>Implementierung in Go<\/h2>\n<p>\nAber warum werden Bitmap-Indizes so selten verwendet? Bevor ich diese Frage beantworte, m\u00f6chte ich Ihnen eine sehr einfache Implementierung eines Bitmap-Index in Go demonstrieren.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/ae7f4c1a4a740fe709b05dfaee27ac9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBitmaps sind im Grunde einfach Datenst\u00fccke. In Go verwenden wir daf\u00fcr Byte-Slices.<\/p>\n<p>Wir haben eine Bitmap f\u00fcr eine Restaurantmerkmale, und jeder Bit in der Bitmap zeigt an, ob ein bestimmtes Restaurant dieses Merkmal hat oder nicht.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/1ab628ee15887d6b3c6c99855aa610c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWir ben\u00f6tigen zwei Hilfsfunktionen. Eine wird verwendet, um unsere Bitmaps mit zuf\u00e4lligen Daten zu f\u00fcllen. Zuf\u00e4lligen, aber mit einer bestimmten Wahrscheinlichkeit, dass das Restaurant eine bestimmte Eigenschaft hat. Zum Beispiel glaube ich, dass es in Moskau sehr wenige Restaurants gibt, in denen man keinen Tisch reservieren kann, und ich sch\u00e4tze, dass etwa 20 % der Einrichtungen f\u00fcr Vegetarier geeignet sind.<\/p>\n<p>Die zweite Funktion wird das Bitmap in eine Liste von Restaurants umwandeln.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/ab9c87a0ba63750116e2e7968f842a9a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/498cf7a33611d99b90197d4ee82e2834.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUm auf die Anfrage \u201eZeig mir g\u00fcnstige Restaurants, die eine Terrasse haben und in denen man einen Tisch reservieren kann\u201c zu antworten, ben\u00f6tigen wir zwei bitweise Operationen: NOT und AND.<\/p>\n<p>Wir k\u00f6nnen unseren Code ein wenig vereinfachen, indem wir eine komplexere Operation, AND NOT, verwenden.<\/p>\n<p>Wir haben Funktionen f\u00fcr jede dieser Operationen. Beide gehen durch die Slices, nehmen die entsprechenden Elemente aus jedem, kombinieren sie mit der bitweisen Operation und legen das Ergebnis in das Ergebnis-Slice.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/ec5652a34f0370dfb03df199f341f153.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUnd jetzt k\u00f6nnen wir unsere Bitmaps und Funktionen nutzen, um auf die Suchanfrage zu antworten.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/cf9500ccfe75995a6008191c16729689.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDie Leistung ist nicht besonders hoch, auch wenn die Funktionen sehr einfach sind und wir durch das Vermeiden von neuen Ergebnis-Slices bei jedem Funktionsaufruf recht gut abgesch\u00e4tzt haben.<\/p>\n<p>Nach ein wenig Profiling mit pprof habe ich bemerkt, dass der Go-Compiler eine sehr einfache, aber sehr wichtige Optimierung \u00fcbersehen hat: die Funktionsinlining.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/9092f5ba3940d0a4f3fbfa90b364d716.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDas Problem ist, dass der Go-Compiler gro\u00dfe Angst vor Schleifen hat, die \u00fcber Slices iterieren, und kategorisch verhindert, dass Funktionen, die solche Schleifen enthalten, inlined werden.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/d1bddd62b61b367dd1f680f223fa0ce7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAber ich habe keine Angst und kann den Compiler austricksen, indem ich goto anstelle einer Schleife benutze, wie in alten Zeiten.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/5b1c3cb26b923972686047910ecd1c31.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/1ca31d12dc90931b674c6a86a4ea23bd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUnd wie Sie sehen, inline der Compiler nun bereitwillig unsere Funktion! Insgesamt sparen wir etwa 2 Mikrosekunden. Nicht schlecht!<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/bdd6735d16082573e600bffe2cdd5662.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDer zweite Engpass ist leicht zu erkennen, wenn man sich den Assemblerausgang genau ansieht. Der Compiler hat eine \u00dcberpr\u00fcfung der Slice-Grenzen direkt in unsere hei\u00dfeste Schleife eingef\u00fcgt. Der Grund ist, dass Go eine sichere Sprache ist, und der Compiler bef\u00fcrchtet, dass meine drei Argumente (drei Slices) unterschiedliche Gr\u00f6\u00dfen haben. Das w\u00fcrde theoretisch die M\u00f6glichkeit eines sogenannten Buffer Overflows schaffen.<\/p>\n<p>Lassen Sie uns den Compiler beruhigen, indem wir ihm zeigen, dass alle Slices die gleiche Gr\u00f6\u00dfe haben. Das k\u00f6nnen wir erreichen, indem wir zu Beginn unserer Funktion eine einfache \u00dcberpr\u00fcfung hinzuf\u00fcgen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/59b4ce687a11dd653e9f12fc3130d89a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSieht der Compiler dies, \u00fcberspringt er die \u00dcberpr\u00fcfung erfreut, und wir sparen dadurch noch 500 Nanosekunden.<\/p>\n<h2>Gro\u00dfe Batches<\/h2>\n<p>\nOkay, wir haben es geschafft, eine gewisse Leistung aus unserer einfachen Implementierung herauszuholen, aber dieses Ergebnis ist in Wirklichkeit viel schlechter, als es mit der derzeitigen Hardware m\u00f6glich w\u00e4re.<\/p>\n<p>Alles, was wir tun, sind grundlegende bitweise Operationen, und unsere Prozessoren f\u00fchren diese sehr effizient aus. Leider \"f\u00fcttern\" wir unseren Prozessor jedoch mit sehr kleinen Arbeitsst\u00fccken. Unsere Funktionen f\u00fchren byteweise Operationen durch. Wir k\u00f6nnen unseren Code ganz einfach so optimieren, dass er mit 8-Byte-St\u00fccken arbeitet, indem wir UInt64-Slices verwenden.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/8d1b60ba4b7046c836601631cadd0b6a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWie Sie sehen, hat diese kleine \u00c4nderung unsere Programme um das Achtfache beschleunigt, indem sie die Batch-Gr\u00f6\u00dfe vergr\u00f6\u00dfert hat. Der Gewinn k\u00f6nnte als linear bezeichnet werden.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/0fc663412d04dd38b927de5c8776f69d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Implementierung in Assembly<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/b3ef133167b89da983356b1c7389aecd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAber das ist noch nicht das Ende. Unsere Prozessoren k\u00f6nnen mit St\u00fccken von 16, 32 und sogar 64 Byte arbeiten. Solche \"breiten\" Operationen werden als Single Instruction Multiple Data (SIMD; eine Instruktion, viele Daten) bezeichnet, und der Prozess, der den Code so umformt, dass er solche Operationen verwendet, wird Vektorisierung genannt.<\/p>\n<p>Leider ist der Go-Compiler ein alles andere als ausgezeichneter Sch\u00fcler in der Vektorisierung. Derzeit ist der einzige Weg, um Go-Code zu vektorisieren, die Datenoperationen manuell unter Verwendung von Go-Assembly zu schreiben.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/91278be45df67e1f9572d68fab7ebad1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nGo-Assembly ist ein seltsames Tier. Sie wissen wahrscheinlich, dass Assembly etwas ist, das stark an die Architektur des Computers gebunden ist, f\u00fcr den Sie schreiben, aber das ist in Go nicht der Fall. Go-Assembly \u00e4hnelt eher einer IRL (Intermediate Representation Language) oder einer Zwischenrepr\u00e4sentation: Sie ist praktisch plattformunabh\u00e4ngig. Rob Pike hielt vor einigen Jahren einen gro\u00dfartigen <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KINIAgRpkDA\">mit einem Vortrag<\/a><\/noindex> \u00dcber dieses Thema auf der GopherCon in Denver.<\/p>\n<p>Dar\u00fcber hinaus verwendet Go ein ungew\u00f6hnliches Format namens Plan 9, das sich von den allgemein anerkannten Formaten AT&amp;T und Intel unterscheidet.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/526f75eb18edfc2f851f2725e9d6f69e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEs l\u00e4sst sich mit Sicherheit sagen, dass das manuelle Schreiben von Go-Assembly nicht die angenehmste Aufgabe ist.<\/p>\n<p>Aber gl\u00fccklicherweise gibt es bereits zwei hochrangige Tools, die uns beim Schreiben von Go-Assembly helfen: PeachPy und avo. Beide Werkzeuge generieren Go-Assembly aus h\u00f6hergradigem Code, der in Python bzw. Go geschrieben ist.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/b8a7aa2c585b805e9b1f2ada186b84e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDiese Dienstprogramme erleichtern Dinge wie die Registerzuweisung, das Schreiben von Schleifen und insgesamt den Einstieg in die Welt der Assemblersprachen in Go.<\/p>\n<p>Wir werden avo verwenden, sodass unsere Programme fast normale Go-Programme sind.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/128e4adef14e5f2cf00fb5b6302ef58e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSo sieht das einfachste Beispiel eines Avo-Programms aus. Wir haben eine Funktion main(), die in sich die Funktion Add() definiert, deren Zweck das Addieren von zwei Zahlen ist. Hier gibt es Hilfsfunktionen, um Parameter nach Namen zu erhalten, und um eines der verf\u00fcgbaren und geeigneten Prozessorregister zu bekommen. Jede Prozessoroperation hat eine entsprechende Funktion in Avo, wie man an ADDQ sehen kann. Und schlie\u00dflich sehen wir eine Hilfsfunktion zum Speichern des Ergebnisses.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/01ccaa6aa6d394ef598ea2dbc9257d87.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDurch den Aufruf von go generate f\u00fchren wir das Avo-Programm aus, und am Ende werden zwei Dateien generiert:<\/p>\n<ul>\n<li>add.s mit dem resultierenden Code in Go-Assembler;\n<\/li>\n<li>stub.go mit den Funktionsprototypen f\u00fcr die Verbindung der beiden Welten: Go und Assembler.\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/72a9443776ecf45eef6fb97a4e08acba.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJetzt, da wir gesehen haben, was Avo tut, schauen wir uns unsere Funktionen an. Ich habe sowohl die skalare als auch die vektorielle (SIMD) Version der Funktionen implementiert.<\/p>\n<p>Zuerst schauen wir uns die skalarischen Versionen an.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/ec31dbb8b97b9d7c1012a120fa18cdaf.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWie im vorherigen Beispiel fragen wir nach einem freien und passenden allgemeinen Register, wir m\u00fcssen keine Offsets und Gr\u00f6\u00dfen f\u00fcr Argumente berechnen. Das erledigt Avo f\u00fcr uns.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/88085e927dd943ea0f808a28fb3ccf9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nFr\u00fcher haben wir Labels und Goto (oder Spr\u00fcnge) verwendet, um die Leistung zu steigern und den Go-Compiler zu t\u00e4uschen, aber jetzt machen wir das von Anfang an. Die Sache ist die, dass Schleifen ein h\u00f6heres Konzept sind. Im Assembly haben wir hingegen nur Labels und Spr\u00fcnge.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/9a4181248eb279d89c1445a820b06649.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDer verbleibende Code sollte bereits bekannt und klar sein. Wir emulieren die Schleife mit Labels und Spr\u00fcngen, nehmen einen kleinen Teil der Daten aus unseren beiden Slices, kombinieren sie mit einer bitweisen Operation (AND NOT in diesem Fall) und legen das Ergebnis dann in den Ergebnisslice. Das ist alles.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/19275ead27f63092fc6596bed38a8d03.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSo sieht der endg\u00fcltige Assemblercode aus. Wir mussten keine Offsets und Gr\u00f6\u00dfen berechnen (gr\u00fcn hervorgehoben) oder auf die verwendeten Register achten (rot hervorgehoben).<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/ed68528a6f852634a5b536670c6315f0.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWenn man die Leistung der Assembly-Implementierung mit der besten Implementierung in Go vergleicht, stellt man fest, dass sie gleich ist. Das ist zu erwarten. Wir haben nichts Besonderes gemacht \u2013 wir haben nur reproduziert, was der Go-Compiler tun w\u00fcrde.<\/p>\n<p>Leider k\u00f6nnen wir den Compiler nicht dazu bringen, unsere in Assembly geschriebenen Funktionen zu inlinisieren. Der Go-Compiler hat derzeit diese M\u00f6glichkeit nicht, obwohl der Wunsch, sie hinzuzuf\u00fcgen, schon seit einiger Zeit besteht.<\/p>\n<p>Genau aus diesem Grund ist es unm\u00f6glich, irgendwelche Vorteile aus kleinen Funktionen in Assembly zu ziehen. Wir m\u00fcssen entweder gro\u00dfe Funktionen schreiben, das neue Paket math\/bits verwenden oder Assembly ganz vermeiden.<\/p>\n<p>Lassen Sie uns nun die Vektorversionen unserer Funktionen betrachten.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/7f67c3cc855908fb47c7900d6e5d7f54.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nF\u00fcr dieses Beispiel habe ich mich entschieden, AVX2 zu verwenden, daher werden wir Operationen verwenden, die mit 32-Byte-St\u00fccken arbeiten. Die Struktur des Codes sieht sehr \u00e4hnlich aus wie die skalarer Version: das Laden der Parameter, die Aufforderung, uns ein freies allgemeines Register zur Verf\u00fcgung zu stellen usw.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/021e0424a0d733ec7db9edeb98ce1f65.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEine der Neuerungen besteht darin, dass breitere Vektoroperationen spezielle breite Register verwenden. Im Falle von 32-Byte-St\u00fccken sind das Register mit dem Pr\u00e4fix Y. Deshalb sehen Sie die Funktion YMM() im Code. Wenn ich AVX-512 mit 64-Bit-St\u00fccken verwendet h\u00e4tte, w\u00e4re das Pr\u00e4fix Z gewesen.<\/p>\n<p>Eine zweite Neuerung besteht darin, dass ich beschlossen habe, eine Optimierung zu verwenden, die als Loop Unrolling bezeichnet wird, also acht Schleifenoperationen manuell auszuf\u00fchren, bevor ich zum Schleifenanfang springe. Diese Optimierung reduziert die Anzahl der Verzweigungen im Code und ist durch die Anzahl der verf\u00fcgbaren freien Register begrenzt.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/f54631d9e8c69f6f70ecace3133ae1e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUnd wie ist es um die Leistung bestellt? Sie ist hervorragend! Wir haben eine Beschleunigung von etwa sieben Mal im Vergleich zur besten L\u00f6sung in Go erzielt. Beeindruckend, oder?<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/d7e85c933eecb243cfb49225b4d92c6c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDoch selbst diese Implementierung k\u00f6nnte potenziell durch den Einsatz von AVX-512, Prefetching oder JIT (Just-in-Time-Compiler) f\u00fcr den Anfrageplaner beschleunigt werden. Aber das ist auf jeden Fall ein Thema f\u00fcr einen eigenen Vortrag.<\/p>\n<h2>Probleme mit Bitmap-Indizes<\/h2>\n<p>\nJetzt, da wir die einfache Implementierung des Bitmap-Indexes in Go und die weitaus leistungsf\u00e4higere in Assembly betrachtet haben, lassen Sie uns endlich dar\u00fcber sprechen, warum Bitmap-Indizes so selten verwendet werden.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/83d36a5c92ba90fd680fe8afb6cfc11f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn \u00e4lteren wissenschaftlichen Arbeiten werden drei Probleme von Bitmap-Indizes erw\u00e4hnt, aber neuere Studien und ich behaupten, dass diese nicht mehr relevant sind. Lassen Sie uns nicht tief in jedes dieser Probleme eintauchen, sondern sie oberfl\u00e4chlich betrachten.<\/p>\n<h2>Das Problem der hohen Kardinalit\u00e4t<\/h2>\n<p>\nUns wird gesagt, dass Bitmap-Indizes nur f\u00fcr Felder mit niedriger Kardinalit\u00e4t geeignet sind, also f\u00fcr solche mit wenigen Werten (zum Beispiel Geschlecht oder Augenfarbe), und der Grund daf\u00fcr ist, dass die gew\u00f6hnliche Darstellung solcher Felder (ein Bit pro Wert) bei hoher Kardinalit\u00e4t zu viel Speicherplatz beanspruchen w\u00fcrde und dar\u00fcber hinaus schlecht (selten) gef\u00fcllt w\u00e4re.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/0787efc4d2cb4ea4d404ca7888b33697.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/44ab4bc7c25d14fe2f53caf5d9da399d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nManchmal k\u00f6nnen wir eine andere Darstellung verwenden, zum Beispiel die Standarddarstellung, die wir zur Darstellung von Zahlen verwenden. Aber gerade das Auftreten von Komprimierungsalgorithmen hat alles ver\u00e4ndert. In den letzten Jahrzehnten haben Wissenschaftler und Forscher eine Vielzahl von Komprimierungsalgorithmen f\u00fcr Bitmaps entwickelt. Ihr Hauptvorteil besteht darin, dass es nicht erforderlich ist, Bitmaps zum Durchf\u00fchren von Bitoperationen zu dekomprimieren \u2014 wir k\u00f6nnen Bitoperationen direkt an komprimierten Bitmaps durchf\u00fchren.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/ecb54fbf15aa11271bbbab01ecbda880.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn letzter Zeit sind auch hybride Ans\u00e4tze aufgetaucht, wie zum Beispiel Roaring Bitmaps. Sie verwenden gleichzeitig drei verschiedene Darstellungen f\u00fcr Bitmaps \u2014 eigentliche Bitmaps, Arrays und so genannte Bit Runs \u2014 und balancieren zwischen ihnen, um die Leistung zu maximieren und den Speicherverbrauch zu minimieren.<\/p>\n<p>Sie k\u00f6nnen Roaring Bitmaps in den beliebtesten Anwendungen antreffen. Es gibt bereits eine gro\u00dfe Anzahl von Implementierungen f\u00fcr verschiedene Programmiersprachen, einschlie\u00dflich mehr als drei Implementierungen f\u00fcr Go.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/de2adfebc431ff48c996247b453f02ae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEin weiterer Ansatz, der uns helfen kann, mit hoher Kardinalit\u00e4t umzugehen, nennt sich Binning. Stellen Sie sich vor, Sie haben ein Feld, das die K\u00f6rpergr\u00f6\u00dfe einer Person darstellt. Gr\u00f6\u00dfe ist eine Flie\u00dfkommazahl, aber wir Menschen denken nicht in diesen Begriffen. F\u00fcr uns gibt es keinen Unterschied zwischen einer K\u00f6rpergr\u00f6\u00dfe von 185,2 cm und 185,3 cm.<\/p>\n<p>Wir k\u00f6nnen also \u00e4hnliche Werte innerhalb von 1 cm gruppieren.<\/p>\n<p>Und wenn wir zudem wissen, dass es sehr wenig Menschen mit einer Gr\u00f6\u00dfe von 50 cm oder weniger und 250 cm oder mehr gibt, k\u00f6nnen wir im Wesentlichen ein Feld mit unendlicher Kardinalit\u00e4t in ein Feld mit einer Kardinalit\u00e4t von etwa 200 Werten umwandeln.<\/p>\n<p>Nat\u00fcrlich k\u00f6nnen wir bei Bedarf zus\u00e4tzliche Filterungen auch danach durchf\u00fchren.<\/p>\n<h2>Das Problem mit der hohen Bandbreite<\/h2>\n<p>\nDas n\u00e4chste Problem der Bitmap-Indizes besteht darin, dass deren Aktualisierung sehr kostspielig sein kann.<\/p>\n<p>Datenbanken m\u00fcssen es erm\u00f6glichen, Daten zu aktualisieren, w\u00e4hrend potenziell Hunderte anderer Anfragen auf diese Daten zugreifen. Wir ben\u00f6tigen Lock-Mechanismen, um Probleme mit gleichzeitigen Datenzugriffen oder andere Probleme des gleichzeitigen Zugriffs zu vermeiden. Wo es ein gro\u00dfes Lock gibt, besteht das Problem der Lock-Konkurrenz, wenn dieses Lock zum Engpass wird.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/0ae1bf925542d286f8b7b245c160a35e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDieses Problem kann durch Sharding oder die Verwendung von versionierten Indizes gel\u00f6st oder umgangen werden.<\/p>\n<p>Sharding ist ein einfaches und allgemein bekanntes Konzept. Sie k\u00f6nnen einen Bitmap-Index genauso sharden, wie Sie es mit anderen Daten tun w\u00fcrden. Anstelle eines gro\u00dfen Locks erhalten Sie viele kleine Locks und beseitigen damit die Lock-Konkurrenz.<\/p>\n<p>Eine zweite L\u00f6sung f\u00fcr das Problem ist die Verwendung von versionierten Indizes. Sie k\u00f6nnen eine Kopie des Index haben, die Sie zum Suchen oder Lesen verwenden, und eine andere, die Sie zum Schreiben oder Aktualisieren verwenden. In bestimmten Zeitintervallen (zum Beispiel alle 100 ms oder 500 ms) duplizieren Sie diese und tauschen sie aus. Nat\u00fcrlich ist dieser Ansatz nur dann anwendbar, wenn Ihre Anwendung mit einem etwas veralteten Suchindex arbeiten kann.<\/p>\n<p>Diese beiden Ans\u00e4tze k\u00f6nnen gleichzeitig verwendet werden: Sie k\u00f6nnen einen sharden versionierten Index haben.<\/p>\n<h2>Komplexere Anfragen<\/h2>\n<p>Das letzte Problem der Bitmap-Indizes besteht darin, dass sie, wie man uns sagt, schlecht f\u00fcr komplexere Anfragearten geeignet sind, z.B. \u201eIntervall\u201c-Anfragen.<\/p>\n<p>Das ist wahr, wenn man dar\u00fcber nachdenkt, sind bitweise Operationen wie AND, OR usw. nicht besonders geeignet f\u00fcr Anfragen wie \u201eZeige mir Hotels mit Preisen zwischen 200 und 300 Dollar pro Nacht\u201c.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/7bc2e129cad46fb5875c2b3018c39ff7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEine naive und sehr un\u00fcberlegte L\u00f6sung w\u00e4re es, die Ergebnisse f\u00fcr jeden Dollarbetrag zu nehmen und sie durch eine bitweise OR-Operation zu kombinieren.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/b9f8fc7945caa1866f8e0cfa8a04bd98.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEine etwas bessere L\u00f6sung w\u00e4re es, Gruppen zu verwenden. Zum Beispiel Gruppen zu je 50 Dollar. Das w\u00fcrde unseren Prozess um das 50-Fache beschleunigen.<\/p>\n<p>Das Problem l\u00e4sst sich jedoch auch leicht l\u00f6sen, indem man eine Darstellung verwendet, die speziell f\u00fcr diese Art von Anfragen erstellt wurde. In wissenschaftlichen Arbeiten wird sie als range-encoded bitmaps bezeichnet.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/644a420628b21f220a7af1ff15c4031f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn einer solchen Darstellung setzen wir nicht einfach ein Bit f\u00fcr einen bestimmten Wert (z. B. 200), sondern f\u00fcr diesen Wert und alles, was dar\u00fcber liegt. 200 und dar\u00fcber. Dasselbe gilt f\u00fcr 300: 300 und dar\u00fcber. Und so weiter.<\/p>\n<p>Mit dieser Darstellung k\u00f6nnen wir auf solche Suchanfragen reagieren, indem wir den Index nur zweimal durchlaufen. Zuerst erhalten wir eine Liste von Hotels, in denen der Zimmerpreis weniger als 300 Dollar betr\u00e4gt, und werfen dann die heraus, bei denen der Zimmerpreis weniger als 199 Dollar betr\u00e4gt. Fertig.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/cc2bb58d7d7a51495c62ec7da81e2d12.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSie werden erstaunt sein, aber sogar Geosuchen sind mithilfe von Bitmap-Indizes m\u00f6glich. Der Trick besteht darin, eine geographische Darstellung zu verwenden, die Ihre Koordinaten durch eine geometrische Form umschlie\u00dft. Zum Beispiel S2 von Google. Die Form muss so dargestellt werden, dass sie aus drei oder mehr sich kreuzenden Linien besteht, die nummeriert werden k\u00f6nnen. So k\u00f6nnen wir unsere Geosuche in mehrere 'Intervall'-Anfragen (nach diesen nummerierten Linien) umwandeln.<\/p>\n<h2>Fertige L\u00f6sungen<\/h2>\n<p>\nIch hoffe, ich habe Ihr Interesse ein wenig geweckt und Sie haben ein weiteres n\u00fctzliches Werkzeug in Ihrem Arsenal. Wenn Sie jemals etwas \u00c4hnliches tun m\u00fcssen, werden Sie wissen, in welche Richtung Sie suchen m\u00fcssen.<\/p>\n<p>Allerdings haben nicht alle die Zeit, Geduld und Ressourcen, um Bitmap-Indizes von Grund auf neu zu erstellen. Besonders die fortgeschritteneren, die SIMD verwenden, zum Beispiel.<\/p>\n<p>Gl\u00fccklicherweise gibt es einige fertige L\u00f6sungen, die Ihnen helfen werden.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/817b47cb189a758756b602ec9cf319e1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Roaring Bitmaps<\/h2>\n<p>\nZun\u00e4chst gibt es die erw\u00e4hnte Roaring Bitmaps-Bibliothek, die alle notwendigen Container und Bitoperationen enth\u00e4lt, die Sie ben\u00f6tigen, um einen vollst\u00e4ndigen Bitmap-Index zu erstellen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/57f61a51485c174666b52dc2063fabe8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLeider verwendet derzeit keine der Go-Implementierungen SIMD, was bedeutet, dass die Go-Implementierungen weniger leistungsf\u00e4hig sind als die Implementierungen in C, zum Beispiel.<\/p>\n<h2>Pilosa<\/h2>\n<p>\nEin weiteres Produkt, das Ihnen helfen k\u00f6nnte, ist die Datenbank Pilosa, die im Grunde genommen nur Bitmap-Indizes enth\u00e4lt. Es handelt sich um eine relativ neue L\u00f6sung, die jedoch schnell an Beliebtheit gewinnt.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/d3870a979e1e73d093fe5d5e9bb71cd8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPilosa verwendet Roaring Bitmaps in ihrem Inneren und erm\u00f6glicht es Ihnen, diese zu verwenden, und vereinfacht und erkl\u00e4rt all die Dinge, die ich oben erw\u00e4hnt habe: Gruppierung, range-encoded Bitmaps, das Konzept des Feldes usw.<\/p>\n<p>Lassen Sie uns schnell einen Blick auf ein Beispiel f\u00fcr die Verwendung von Pilosa werfen, um eine Ihnen bereits bekannte Frage zu beantworten.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/dfee7abfd653cc19d9aa8b64c64f3e4e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDas Beispiel \u00e4hnelt sehr dem, was Sie zuvor gesehen haben. Wir erstellen einen Client f\u00fcr den Pilosa-Server, definieren einen Index sowie die erforderlichen Felder, f\u00fcgen dann zuf\u00e4llige Daten mit Wahrscheinlichkeiten in unsere Felder ein und f\u00fchren schlie\u00dflich die vertraute Abfrage aus.<\/p>\n<p>Danach verwenden wir NOT auf dem Feld \"expensive\", schneiden das Ergebnis (oder AND-Verkn\u00fcpfung) mit dem Feld \"terrace\" und dem Feld \"reservations\" zusammen. Schlie\u00dflich erhalten wir das endg\u00fcltige Ergebnis.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/8d66c6d68019c2297b6c15b700f06a3a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIch hoffe sehr, dass in naher Zukunft auch in Datenbanksystemen wie MySQL und PostgreSQL dieser neue Index-Typ \u2013 Bitmap-Indizes \u2013 verf\u00fcgbar sein wird.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/7a8e33d576c7fb6376a173ee038b4206.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Fazit<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-Indizes in Go: Suche in Rekordgeschwindigkeit\" src=\"\/wp-content\/uploads\/2019\/05\/c62caa9ad6f2d96056c80326f4fa9a0d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWenn Sie noch nicht eingeschlafen sind, danke. Ich musste viele Themen nur kurz anrei\u00dfen aufgrund der begrenzten Zeit, aber ich hoffe, dass der Vortrag hilfreich und vielleicht sogar motivierend war.<\/p>\n<p>Es ist gut, \u00fcber Bitmap-Indizes Bescheid zu wissen, auch wenn Sie sie gerade jetzt nicht ben\u00f6tigen. Lassen Sie sie ein weiteres Werkzeug in Ihrer Toolbox sein.<\/p>\n<p>Wir haben verschiedene Tricks zur Leistungssteigerung f\u00fcr Go betrachtet und die Dinge, mit denen der Go-Compiler derzeit noch nicht sehr gut zurechtkommt. Das ist auf jeden Fall etwas, das jeder Go-Programmierer wissen sollte.<\/p>\n<p>Das ist alles, was ich erz\u00e4hlen wollte. Vielen Dank!<br \/>\n<br \/>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/badoo\/blog\/451938\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441 \u044d\u0442\u0438\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u043e\u043c \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 GopherCon Russia 2019 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435 \u0438 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u2014 \u043d\u0430 \u043c\u0438\u0442\u0430\u043f\u0435 \u0432 \u041d\u0438\u0436\u043d\u0435\u043c \u041d\u043e\u0432\u0433\u043e\u0440\u043e\u0434\u0435. \u0420\u0435\u0447\u044c \u0432 \u043d\u0451\u043c \u0438\u0434\u0451\u0442 \u043e bitmap-\u0438\u043d\u0434\u0435\u043a\u0441\u0435 \u2014 \u043c\u0435\u043d\u0435\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u043e\u043c, \u0447\u0435\u043c B-tree, \u043d\u043e \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c. \u0414\u0435\u043b\u044e\u0441\u044c \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u0432\u044b\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0439 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":25469,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-33793","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47Bitmap-\u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432 Go: \u043f\u043e\u0438\u0441\u043a \u043d\u0430 \u0434\u0438\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:54:42+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:54:42+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Bitmap-Indizes in Go: Suche mit wilder Geschwindigkeit | ProHoster","description":"Er\u00f6ffnungswort: Ich habe gehalten.","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47Bitmap-\u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432 Go: \u043f\u043e\u0438\u0441\u043a \u043d\u0430 \u0434\u0438\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 | ProHoster","og:description":"\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441.","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:54:42+00:00","article:modified_time":"2019-10-31T18:54:42+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"33793","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 16:43:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:33:25","updated":"2026-01-21 16:43:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/33793","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=33793"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/33793\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/25469"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=33793"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=33793"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=33793"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}