{"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\/fr\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","title":{"rendered":"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/86ef928e6741022b2c0e5885a031408a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Mot de bienvenue<\/h2>\n<p>\nJ'ai pr\u00e9sent\u00e9 cette conf\u00e9rence en anglais \u00e0 la conf\u00e9rence GopherCon Russia 2019 \u00e0 Moscou et en russe lors du meetup \u00e0 Nijni Novgorod. Elle porte sur l'index bitmap\u2014moins r\u00e9pandu que l'index B-tree, mais tout aussi int\u00e9ressant. Je partage <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/WvlUH6MjUuI?list=PL3xVZC4USRNSO_kb2lh_J_no6C-KJ7Phg\">l'enregistrement<\/a><\/noindex> de la pr\u00e9sentation \u00e0 la conf\u00e9rence en anglais et la transcription textuelle en russe.<\/p>\n<p>Nous examinerons comment fonctionne l'index bitmap, quand il est meilleur, quand il est moins efficace que d'autres index, et dans quels cas il est beaucoup plus rapide que ceux-ci ; nous verrons dans quelles SGBD populaires des index bitmap existent d\u00e9j\u00e0 ; nous essaierons d'en \u00e9crire un en Go. Et pour le dessert, nous utiliserons des biblioth\u00e8ques pr\u00eates \u00e0 l'emploi pour cr\u00e9er notre base de donn\u00e9es sp\u00e9cialis\u00e9e ultra-rapide.<\/p>\n<p>J'esp\u00e8re sinc\u00e8rement que mes travaux vous seront utiles et int\u00e9ressants. Allons-y !<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Introduction<\/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=\"Lire la vid\u00e9o\" 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>Bonjour \u00e0 tous ! Il est six heures du soir, nous sommes tous super fatigu\u00e9s. Un moment id\u00e9al pour parler de la th\u00e9orie ennuyeuse des index de bases de donn\u00e9es, n'est-ce pas ? Ne vous inqui\u00e9tez pas, il y aura quelques lignes de code source ici et l\u00e0. \ud83d\ude42<\/p>\n<p>Sans plaisanter, la pr\u00e9sentation est remplie d'informations, et nous n'avons pas beaucoup de temps. Alors commen\u00e7ons.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/e778e13727700f0335a4b5558a0d8db3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAujourd'hui, je vais parler des sujets suivants :<\/p>\n<ul>\n<li>Qu'est-ce que les index ;\n<\/li>\n<li>Qu'est-ce que l'index bitmap ;\n<\/li>\n<li>O\u00f9 il est utilis\u00e9 et o\u00f9 il n'est PAS utilis\u00e9 et pourquoi ;\n<\/li>\n<li>Une impl\u00e9mentation simple en Go et un peu de lutte avec le compilateur ;\n<\/li>\n<li>Une impl\u00e9mentation un peu moins simple mais beaucoup plus performante en Go-assembleur ;\n<\/li>\n<li>Les \u00ab probl\u00e8mes \u00bb des index bitmap ;\n<\/li>\n<li>Les impl\u00e9mentations existantes.\n<\/li>\n<\/ul>\n<h2>Alors, qu'est-ce que les index ?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/b80e5b990c44814afe9150a9a82351fd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUn index est une structure de donn\u00e9es distincte que nous maintenons et mettons \u00e0 jour en compl\u00e9ment des donn\u00e9es principales. Elle est utilis\u00e9e pour acc\u00e9l\u00e9rer les recherches. Sans index, la recherche n\u00e9cessiterait un passage complet des donn\u00e9es (processus appel\u00e9 full scan), et ce processus a une complexit\u00e9 algorithmique lin\u00e9aire. Mais les bases de donn\u00e9es contiennent g\u00e9n\u00e9ralement une immense quantit\u00e9 de donn\u00e9es et une complexit\u00e9 lin\u00e9aire est trop lente. Id\u00e9alement, nous aimerions obtenir une complexit\u00e9 logarithmique ou constante.<\/p>\n<p>C'est un sujet vaste et complexe, rempli de nuances et de compromis, mais apr\u00e8s avoir examin\u00e9 des d\u00e9cennies de d\u00e9veloppement et de recherche sur diff\u00e9rentes bases de donn\u00e9es, je suis convaincu qu'il existe seulement quelques approches largement utilis\u00e9es pour cr\u00e9er des index de SGBD.<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/08a74dbb365035cd99bc94d72644a1b7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa premi\u00e8re approche consiste \u00e0 r\u00e9duire hierarchiquement la zone de recherche, en divisant cette zone en parties plus petites.<\/p>\n<p>En g\u00e9n\u00e9ral, nous faisons cela en utilisant diff\u00e9rents types d'arbres. Par exemple, une grande bo\u00eete avec des mat\u00e9riaux dans votre armoire, contenant des petites bo\u00eetes avec des mat\u00e9riaux s\u00e9par\u00e9s par diff\u00e9rents th\u00e8mes. Si vous avez besoin de mat\u00e9riaux, vous chercherez probablement dans la bo\u00eete \u00e9tiquet\u00e9e \u00ab Mat\u00e9riaux \u00bb, et non dans celle \u00e9tiquet\u00e9e \u00ab Biscuits \u00bb, n'est-ce pas ?<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/423fac47c748980b18af434644af4dae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa deuxi\u00e8me approche consiste \u00e0 identifier imm\u00e9diatement l'\u00e9l\u00e9ment ou le groupe d'\u00e9l\u00e9ments requis. Nous faisons cela dans des tables de hachage ou des index invers\u00e9s. L'utilisation des tables de hachage est tr\u00e8s similaire \u00e0 l'exemple pr\u00e9c\u00e9dent, sauf qu'au lieu d'une bo\u00eete avec des bo\u00eetes, vous avez dans votre armoire une pile de petites bo\u00eetes avec des items finaux.<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/088fed0a2a0feea4a23edbf0ca654805.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa troisi\u00e8me approche consiste \u00e0 \u00e9liminer le besoin de recherche. Nous faisons cela \u00e0 l'aide de filtres de Bloom ou de filtres de cuckoo. Les premiers donnent une r\u00e9ponse instantan\u00e9ment, vous \u00e9vitant ainsi de faire une recherche.<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/493bc4f20baacc0a5dc0faf15cc46285.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa derni\u00e8re approche consiste \u00e0 utiliser pleinement toutes les capacit\u00e9s offertes par le mat\u00e9riel moderne. C'est ce que nous faisons avec les index bitmap. Oui, lors de leur utilisation, il arrive que nous devions parcourir tout l'index, mais nous le faisons de mani\u00e8re super efficace.<\/p>\n<p>Comme je l'ai d\u00e9j\u00e0 dit, le sujet des index de bases de donn\u00e9es est vaste et rempli de compromis. Cela signifie que parfois, nous pouvons utiliser plusieurs approches simultan\u00e9ment : si nous devons encore acc\u00e9l\u00e9rer la recherche ou si nous devons couvrir tous les types de recherche possibles.<\/p>\n<p>Aujourd'hui, je vais parler de l'approche la moins connue parmi celles mentionn\u00e9es \u2014 des index bitmap.<\/p>\n<h2>Qui suis-je pour parler de ce sujet ?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/42a9d17a507c392bc202254a92dfaf41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJe travaille en tant que leader d'\u00e9quipe chez Badoo (vous connaissez peut-\u00eatre mieux notre autre produit \u2014 Bumble). Nous avons d\u00e9j\u00e0 plus de 400 millions d'utilisateurs dans le monde et de nombreuses fonctionnalit\u00e9s qui s'occupent de cela, en leur proposant le meilleur partenaire. Nous faisons cela gr\u00e2ce \u00e0 des services personnalis\u00e9s, utilisant \u00e9galement des index bitmap.<\/p>\n<h2>Alors, qu'est-ce qu'un index bitmap ?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/14f20f3697a20c02f6b3510dc7f0ae4d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLes index bitmap, comme leur nom l'indique, utilisent des bitmaps ou des bits sets pour impl\u00e9menter un index de recherche. \u00c0 vol d'oiseau, cet index est constitu\u00e9 d'un ou plusieurs de ces bitmaps, repr\u00e9sentant des entit\u00e9s (comme des personnes) et leurs propri\u00e9t\u00e9s ou param\u00e8tres (\u00e2ge, couleur des yeux, etc.), ainsi que d'un algorithme utilisant des op\u00e9rations bit \u00e0 bit (ET, OU, NON) pour r\u00e9pondre \u00e0 une requ\u00eate de recherche.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/f815720330a51b1f0798e45d23160d3b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOn nous dit que les index bitmap conviennent le mieux et sont tr\u00e8s performants dans les cas o\u00f9 il y a des recherches combinant des requ\u00eates sur de nombreuses colonnes ayant une faible cardinalit\u00e9 (imaginez \u00ab couleur des yeux \u00bb ou \u00ab situation familiale \u00bb par rapport \u00e0 quelque chose comme \u00ab distance du centre-ville \u00bb). Mais plus tard, je montrerai qu'ils fonctionnent \u00e9galement tr\u00e8s bien avec des colonnes \u00e0 haute cardinalit\u00e9.<\/p>\n<p>Consid\u00e9rons un exemple simple d'index bitmap.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/33fe23476e0931c10345d7175b83d68b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nImaginons que nous avons une liste de restaurants \u00e0 Moscou avec des propri\u00e9t\u00e9s binaires telles que celles-ci :<\/p>\n<ul>\n<li>pr\u00e8s du m\u00e9tro (near metro);\n<\/li>\n<li>dispose d'un parking priv\u00e9 (has private parking);\n<\/li>\n<li>dispose d'une terrasse (has terrace);\n<\/li>\n<li>accepte les r\u00e9servations (accepts reservations);\n<\/li>\n<li>convient aux v\u00e9g\u00e9tariens (vegan friendly);\n<\/li>\n<li>cher (expensive).\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/fcbad539ea12f79a9d06966ce308637e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAttribuons \u00e0 chaque restaurant un num\u00e9ro d'ordre commen\u00e7ant par 0 et allouons de la m\u00e9moire pour 6 bitmaps (un pour chaque caract\u00e9ristique). Ensuite, nous remplirons ces bitmaps en fonction de la possession ou non par le restaurant de cette caract\u00e9ristique. Si le restaurant 4 a une terrasse, alors le bit n\u00b04 dans le bitmap \u00ab dispose d'une terrasse \u00bb sera positionn\u00e9 \u00e0 1 (s'il n'y a pas de terrasse, il sera \u00e0 0).<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/3709c426617d4364f392ee6b68f92b00.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNous avons maintenant l'index bitmap le plus simple qui soit, et nous pouvons l'utiliser pour r\u00e9pondre \u00e0 des requ\u00eates telles que :<\/p>\n<ul>\n<li>\u00ab Montre-moi les restaurants compatibles avec les v\u00e9g\u00e9tariens \u00bb ;\n<\/li>\n<li>\u00ab Montre-moi les restaurants abordables avec une terrasse, o\u00f9 il est possible de r\u00e9server une table \u00bb.\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/90acb0f890686bd52c3db1fc667f0b0b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/0fd0b7fe9f7b7039022ad5c79fe873bc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nComment ? Voyons cela. La premi\u00e8re requ\u00eate est tr\u00e8s simple. Tout ce que nous avons \u00e0 faire est de prendre le bitmap \u00ab convient aux v\u00e9g\u00e9tariens \u00bb et de le convertir en une liste de restaurants dont les bits sont positions.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/ef4a5cfd658ff4ef8bc0c638c4522d11.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/9cc175bae55c16018fdf5ff95517a61a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLa deuxi\u00e8me requ\u00eate est un peu plus complexe. Nous devons utiliser l'op\u00e9ration bitwise NOT sur le bitmap \"cher\" pour obtenir la liste des restaurants bon march\u00e9, puis faire un AND avec le bitmap \"peut r\u00e9server une table\" et ensuite un AND avec le bitmap \"a une terrasse\". Le bitmap r\u00e9sultant contiendra la liste des \u00e9tablissements qui r\u00e9pondent \u00e0 tous nos crit\u00e8res. Dans cet exemple, il s'agit uniquement du restaurant \"Jeunesse\".<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/f1cdda0cbf7f15278553899cf876c17e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/126b50e0f622b6e36c461cd74e708c38.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIl y a beaucoup de th\u00e9orie ici, mais ne vous inqui\u00e9tez pas, nous verrons le code tr\u00e8s bient\u00f4t.<\/p>\n<h2>O\u00f9 sont utilis\u00e9s les index bitmap ?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/406132236c71a4f66ae79957b6e633b3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSi vous \"googlisez\" les index bitmap, 90% des r\u00e9ponses seront li\u00e9es d'une mani\u00e8re ou d'une autre \u00e0 Oracle DB. Mais d'autres SGBD doivent \u00e9galement prendre en charge une telle fonctionnalit\u00e9, n'est-ce pas ? Pas vraiment. <\/p>\n<p>Passons en revue la liste des principaux suspects.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/d18d66451a8a26b0ddf121f8ec0204cd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMySQL ne prend pas encore en charge les index bitmap, mais il existe une proposition pour ajouter cette option (<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 ne prend pas en charge les index bitmap, mais utilise des bitmaps simples et des op\u00e9rations bit pour combiner les r\u00e9sultats de la recherche sur plusieurs autres index.<\/p>\n<p>Tarantool a des index bitset, il prend en charge la recherche simple sur eux.<\/p>\n<p>Redis a des champs binaires simples<noindex><a rel=\"nofollow\" href=\"https:\/\/redis.io\/commands\/bitfield\"> (https:\/\/redis.io\/commands\/bitfield<\/a><\/noindex>) sans possibilit\u00e9 de recherche sur eux.<\/p>\n<p>MongoDB ne prend pas encore en charge les index bitmap, mais il y a \u00e9galement une proposition pour ajouter cette option <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 utilise des bitmaps \u00e0 l'int\u00e9rieur<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=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/232d335963603d6e6dec98839fc9f486.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Mais un nouveau voisin a fait son apparition dans notre maison : Pilosa. C'est une nouvelle base de donn\u00e9es non relationnelle, \u00e9crite en Go. Elle contient uniquement des index bitmap et s'appuie enti\u00e8rement sur eux. Nous en parlerons un peu plus tard.\n<\/li>\n<\/ul>\n<h2>Impl\u00e9mentation en Go<\/h2>\n<p>\nMais pourquoi les index bitmap sont-ils si rarement utilis\u00e9s ? Avant de r\u00e9pondre \u00e0 cette question, je voudrais vous montrer une impl\u00e9mentation d'un index bitmap tr\u00e8s simple en Go.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/ae7f4c1a4a740fe709b05dfaee27ac9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLes bitmaps sont essentiellement repr\u00e9sent\u00e9s comme de simples morceaux de donn\u00e9es. En Go, utilisons pour cela des slices de bytes.<\/p>\n<p>Nous avons un bitmap pour une caract\u00e9ristique de restaurant, et chaque bit dans le bitmap indique si un restaurant sp\u00e9cifique poss\u00e8de cette caract\u00e9ristique ou non.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/1ab628ee15887d6b3c6c99855aa610c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNous aurons besoin de deux fonctions auxiliaires. L'une sera utilis\u00e9e pour remplir nos bitmaps de donn\u00e9es al\u00e9atoires. Al\u00e9atoires, mais avec une probabilit\u00e9 d\u00e9termin\u00e9e que le restaurant poss\u00e8de chaque propri\u00e9t\u00e9. Par exemple, je pense qu'il y a tr\u00e8s peu de restaurants \u00e0 Moscou o\u00f9 l'on ne peut pas r\u00e9server de table, et il me semble qu'environ 20 % des \u00e9tablissements conviennent aux v\u00e9g\u00e9tariens.<\/p>\n<p>La deuxi\u00e8me fonction convertira le bitmap en liste de restaurants.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/ab9c87a0ba63750116e2e7968f842a9a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/498cf7a33611d99b90197d4ee82e2834.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPour r\u00e9pondre \u00e0 la requ\u00eate \u00ab Montre-moi des restaurants bon march\u00e9 avec une terrasse o\u00f9 l'on peut r\u00e9server une table \u00bb, nous aurons besoin de deux op\u00e9rations bit \u00e0 bit : NOT et AND.<\/p>\n<p>Nous pouvons simplifier un peu notre code en utilisant une op\u00e9ration AND NOT plus complexe.<\/p>\n<p>Nous avons des fonctions pour chacune de ces op\u00e9rations. Les deux parcourent les slices, prennent les \u00e9l\u00e9ments correspondants de chacun, les combinent en une op\u00e9ration bit \u00e0 bit et mettent le r\u00e9sultat dans un slice de r\u00e9sultats.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/ec5652a34f0370dfb03df199f341f153.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEt maintenant, nous pouvons utiliser nos bitmaps et fonctions pour r\u00e9pondre \u00e0 la requ\u00eate de recherche.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/cf9500ccfe75995a6008191c16729689.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLa performance n'est pas tr\u00e8s \u00e9lev\u00e9e, m\u00eame si les fonctions sont tr\u00e8s simples et que nous avons \u00e9conomis\u00e9 sur le fait de ne pas renvoyer un nouveau slice de r\u00e9sultats \u00e0 chaque appel de fonction.<\/p>\n<p>En faisant un peu de profilage avec pprof, j'ai remarqu\u00e9 que le compilateur Go avait ignor\u00e9 une optimisation tr\u00e8s simple mais cruciale : l'inlining de fonction.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/9092f5ba3940d0a4f3fbfa90b364d716.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn effet, le compilateur Go craint terriblement les boucles qui parcourent les slices et refuse cat\u00e9goriquement d'inliner les fonctions qui contiennent de telles boucles.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/d1bddd62b61b367dd1f680f223fa0ce7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMais je n'ai pas peur et je peux tromper le compilateur en utilisant goto \u00e0 la place d'une boucle, comme au bon vieux temps.<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/5b1c3cb26b923972686047910ecd1c31.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/1ca31d12dc90931b674c6a86a4ea23bd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEt comme vous pouvez le voir, le compilateur est maintenant heureux d'inliner notre fonction ! Au final, nous parvenons \u00e0 \u00e9conomiser environ 2 microsecondes. Pas mal !<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/bdd6735d16082573e600bffe2cdd5662.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLe deuxi\u00e8me goulet d'\u00e9tranglement est facile \u00e0 voir si l'on regarde attentivement la sortie assembleur. Le compilateur a ajout\u00e9 une v\u00e9rification des limites du slice directement dans notre boucle la plus chaude. Le fait est que Go est un langage s\u00fbr, le compilateur craint que mes trois arguments (trois slices) aient des tailles diff\u00e9rentes. Cela cr\u00e9erait alors une possibilit\u00e9 th\u00e9orique de d\u00e9bordement de tampon.<\/p>\n<p>Calmons le compilateur en lui montrant que tous les slices ont la m\u00eame taille. Nous pouvons le faire en ajoutant une simple v\u00e9rification au d\u00e9but de notre fonction.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/59b4ce687a11dd653e9f12fc3130d89a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn voyant cela, le compilateur passe la v\u00e9rification avec joie, et nous \u00e9conomisons ainsi 500 nanosecondes.<\/p>\n<h2>Gros batches<\/h2>\n<p>\nD'accord, nous avons r\u00e9ussi \u00e0 extraire une certaine performance de notre simple impl\u00e9mentation, mais ce r\u00e9sultat est en r\u00e9alit\u00e9 bien inf\u00e9rieur \u00e0 ce qui est possible avec le mat\u00e9riel actuel.<\/p>\n<p>Tout ce que nous faisons, ce sont des op\u00e9rations de base sur des bits, et nos processeurs les ex\u00e9cutent tr\u00e8s efficacement. Mais, malheureusement, nous 'nourrissons' notre processeur avec de tr\u00e8s petits morceaux de travail. Nos fonctions effectuent des op\u00e9rations byte par byte. Nous pouvons facilement optimiser notre code pour qu\u2019il fonctionne avec des morceaux de 8 octets en utilisant des slices UInt64.<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/8d1b60ba4b7046c836601631cadd0b6a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nComme vous pouvez le voir, ce petit changement a acc\u00e9l\u00e9r\u00e9 notre programme par huit gr\u00e2ce \u00e0 une augmentation du batch par huit. Le gain est, on peut le dire, lin\u00e9aire.<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/0fc663412d04dd38b927de5c8776f69d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Impl\u00e9mentation en assembleur<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/b3ef133167b89da983356b1c7389aecd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMais ce n'est pas encore la fin. Nos processeurs peuvent travailler avec des morceaux de 16, 32 et m\u00eame 64 octets. Ces 'op\u00e9rations larges' sont appel\u00e9es single instruction multiple data (SIMD ; une instruction, plusieurs donn\u00e9es), et le processus de transformation du code pour qu'il utilise de telles op\u00e9rations s'appelle vectorisation.<\/p>\n<p>Malheureusement, le compilateur Go n\u2019est pas un expert en vectorisation. Actuellement, la seule fa\u00e7on de vectoriser du code en Go est de prendre et d'\u00e9crire manuellement les op\u00e9rations \u00e0 l'aide de l\u2019assembleur Go.<\/p>\n<p><img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/91278be45df67e1f9572d68fab7ebad1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nL'assembleur Go est une b\u00eate \u00e9trange. Vous savez probablement que l'assembleur est quelque chose de fortement li\u00e9 \u00e0 l'architecture de l'ordinateur pour lequel vous \u00e9crivez, mais en Go, ce n'est pas le cas. L'assembleur Go ressemble davantage \u00e0 un langage de repr\u00e9sentation interm\u00e9diaire (IRL) : il est pratiquement ind\u00e9pendant de la plateforme. Rob Pike a donn\u00e9 une excellente <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KINIAgRpkDA\">pr\u00e9sentation<\/a><\/noindex> \u00e0 ce sujet il y a quelques ann\u00e9es \u00e0 GopherCon \u00e0 Denver.<\/p>\n<p>En plus de cela, Go utilise un format inhabituel Plan 9, diff\u00e9rent des formats reconnus AT&amp;T et Intel.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/526f75eb18edfc2f851f2725e9d6f69e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOn peut dire avec certitude que r\u00e9diger manuellement de l\u2019assembleur Go n\u2019est pas l\u2019activit\u00e9 la plus amusante.<\/p>\n<p>Mais heureusement, il existe d\u00e9j\u00e0 deux outils de haut niveau qui nous aident \u00e0 \u00e9crire en assembleur Go : PeachPy et avo. Ces deux utilitaires g\u00e9n\u00e8rent de l\u2019assembleur Go \u00e0 partir de code de niveau sup\u00e9rieur \u00e9crit en Python et en Go respectivement.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/b8a7aa2c585b805e9b1f2ada186b84e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCes utilitaires simplifient des aspects tels que l'allocation de registres (choix des registres processeur), l'\u00e9criture de boucles, et facilitent globalement l'entr\u00e9e dans le monde de la programmation en assembleur en Go.<\/p>\n<p>Nous allons utiliser avo, de sorte que nos programmes seront presque des programmes Go ordinaires.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/128e4adef14e5f2cf00fb5b6302ef58e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVoil\u00e0 \u00e0 quoi ressemble l'exemple le plus simple d'un programme avo. Nous avons une fonction main() qui d\u00e9finit en son sein une fonction Add(), dont le but est d'additionner deux nombres. Voici des fonctions d'assistance pour obtenir les param\u00e8tres par nom et obtenir l'un des registres processeur libres et appropri\u00e9s. Chaque op\u00e9ration processeur a une fonction correspondante sur avo, comme le montre ADDQ. Enfin, nous avons une fonction d'assistance pour sauvegarder la valeur r\u00e9sultante.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/01ccaa6aa6d394ef598ea2dbc9257d87.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn appelant go generate, nous allons ex\u00e9cuter le programme sur avo et deux fichiers seront g\u00e9n\u00e9r\u00e9s en fin de compte :<\/p>\n<ul>\n<li>add.s avec le code r\u00e9sultant en assembleur Go ;\n<\/li>\n<li>stub.go avec les en-t\u00eates de fonctions pour relier les deux mondes : Go et assembleur.\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/72a9443776ecf45eef6fb97a4e08acba.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMaintenant que nous avons vu ce que fait et comment fonctionne avo, regardons nos fonctions. J'ai impl\u00e9ment\u00e9 \u00e0 la fois les versions scalaires et vectorielles (SIMD) des fonctions.<\/p>\n<p>Commen\u00e7ons par examiner les versions scalaires.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/ec31dbb8b97b9d7c1012a120fa18cdaf.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nComme dans l'exemple pr\u00e9c\u00e9dent, nous demandons un registre g\u00e9n\u00e9ral libre et correct, nous n'avons pas besoin de calculer les d\u00e9calages et les tailles des arguments. Tout cela est fait pour nous par avo.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/88085e927dd943ea0f808a28fb3ccf9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAuparavant, nous utilisions des \u00e9tiquettes et des sauts (ou des jumps) pour am\u00e9liorer la performance et tromper le compilateur Go, mais maintenant nous le faisons d\u00e8s le d\u00e9part. En fait, les boucles sont un concept de niveau sup\u00e9rieur. En assembleur, nous n'avons que des \u00e9tiquettes et des sauts.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/9a4181248eb279d89c1445a820b06649.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLe code restant devrait d\u00e9j\u00e0 \u00eatre familier et compr\u00e9hensible. Nous \u00e9mulons une boucle avec des \u00e9tiquettes et des sauts, prenons une petite portion de donn\u00e9es de nos deux slices, les combinons par op\u00e9ration binaire (AND NOT dans ce cas) et pla\u00e7ons ensuite le r\u00e9sultat dans le slice r\u00e9sultant. C'est tout.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/19275ead27f63092fc6596bed38a8d03.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVoici \u00e0 quoi ressemble le code final en assembleur. Nous n'avons pas eu besoin de calculer les d\u00e9calages et les tailles (mis en \u00e9vidence en vert) ou de surveiller les registres utilis\u00e9s (mis en \u00e9vidence en rouge).<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/ed68528a6f852634a5b536670c6315f0.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLorsqu'on compare la performance d'une impl\u00e9mentation en assembleur avec celle de la meilleure impl\u00e9mentation en Go, on constate qu'elles sont identiques. C'est pr\u00e9visible. En effet, nous n'avons rien fait de particulier \u2014 nous avons simplement reproduit ce que ferait le compilateur Go.<\/p>\n<p>Malheureusement, nous ne pouvons pas forcer le compilateur \u00e0 inliner nos fonctions \u00e9crites en assembleur. Actuellement, le compilateur Go ne dispose pas de cette possibilit\u00e9, bien que la demande d'ajout de cette fonctionnalit\u00e9 existe depuis un certain temps.<\/p>\n<p>C'est pourquoi il est impossible d'obtenir des avantages en utilisant de petites fonctions en assembleur. Nous devons soit \u00e9crire de grandes fonctions, soit utiliser le nouveau paquet math\/bits, soit \u00e9viter l'assembleur.<\/p>\n<p>Regardons maintenant les versions vectorielles de nos fonctions.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/7f67c3cc855908fb47c7900d6e5d7f54.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPour cet exemple, j'ai d\u00e9cid\u00e9 d'appliquer AVX2, donc nous allons utiliser des op\u00e9rations fonctionnant avec des morceaux de 32 octets. La structure du code est tr\u00e8s similaire \u00e0 celle de la version scalaire : chargement des param\u00e8tres, demande d'un registre g\u00e9n\u00e9ral libre, etc.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/021e0424a0d733ec7db9edeb98ce1f65.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUne des innovations concerne le fait que des op\u00e9rations vectorielles plus larges utilisent des registres sp\u00e9ciaux plus larges. Dans le cas des morceaux de 32 octets, ce sont des registres avec le pr\u00e9fixe Y. C'est pourquoi vous voyez la fonction YMM() dans le code. Si j'avais utilis\u00e9 AVX-512 avec des morceaux de 64 bits, le pr\u00e9fixe aurait \u00e9t\u00e9 Z.<\/p>\n<p>La deuxi\u00e8me innovation concerne le fait que j'ai d\u00e9cid\u00e9 d'utiliser une optimisation appel\u00e9e d\u00e9roulement de boucle (loop unrolling), c'est-\u00e0-dire de r\u00e9aliser huit op\u00e9rations de boucle manuellement avant de sauter au d\u00e9but de la boucle. Cette optimisation r\u00e9duit le nombre de branches dans le code et est limit\u00e9e par le nombre de registres libres disponibles.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/f54631d9e8c69f6f70ecace3133ae1e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEt qu'en est-il de la performance ? Elle est excellente ! Nous avons obtenu un gain d'environ sept fois par rapport \u00e0 la meilleure solution en Go. Impressionnant, n'est-ce pas ?<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/d7e85c933eecb243cfb49225b4d92c6c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMais m\u00eame cette impl\u00e9mentation pourrait potentiellement \u00eatre acc\u00e9l\u00e9r\u00e9e en utilisant AVX-512, le pr\u00e9-fetching ou le JIT (compilateur just-in-time) pour le planificateur de requ\u00eates. Mais c'est clairement un sujet pour une pr\u00e9sentation distincte.<\/p>\n<h2>Probl\u00e8mes des index bitmap<\/h2>\n<p>\nMaintenant que nous avons examin\u00e9 une simple impl\u00e9mentation d'index bitmap en Go et une version beaucoup plus performante en assembleur, parlons enfin de la raison pour laquelle les index bitmap sont si rarement utilis\u00e9s.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/83d36a5c92ba90fd680fe8afb6cfc11f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDes \u00e9tudes scientifiques anciennes mentionnent trois probl\u00e8mes li\u00e9s aux index bitmap, mais des travaux plus r\u00e9cents et moi-m\u00eame affirmons qu'ils ne sont plus d'actualit\u00e9. Nous ne plongerons pas en profondeur dans chacun de ces probl\u00e8mes, mais nous les examinerons survol.<\/p>\n<h2>Probl\u00e8me de grande cardinalit\u00e9<\/h2>\n<p>\nOn nous dit donc que les index bitmap sont adapt\u00e9s uniquement aux champs \u00e0 faible cardinalit\u00e9, c'est-\u00e0-dire ceux qui ont peu de valeurs (comme le sexe ou la couleur des yeux), et la raison en est que la repr\u00e9sentation classique de ces champs (un bit par valeur) en cas de grande cardinalit\u00e9 occuperait trop d'espace et, de plus, ces index bitmap seraient faiblement (rarement) remplis.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/0787efc4d2cb4ea4d404ca7888b33697.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/44ab4bc7c25d14fe2f53caf5d9da399d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nParfois, nous pouvons utiliser une autre repr\u00e9sentation, comme celle standard que nous utilisons pour repr\u00e9senter des nombres. Mais c'est l'\u00e9mergence des algorithmes de compression qui a tout chang\u00e9. Au cours des derni\u00e8res d\u00e9cennies, des scientifiques et des chercheurs ont con\u00e7u un grand nombre d'algorithmes de compression pour les bitmap. Leur principal avantage est qu'il n'est pas n\u00e9cessaire de d\u00e9compresser les bitmap pour effectuer des op\u00e9rations bit \u00e0 bit \u2014 nous pouvons r\u00e9aliser des op\u00e9rations directement sur les bitmap compress\u00e9s.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/ecb54fbf15aa11271bbbab01ecbda880.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nR\u00e9cemment, des approches hybrides ont \u00e9galement commenc\u00e9 \u00e0 appara\u00eetre, comme les bitmap roaring. Ils utilisent simultan\u00e9ment trois repr\u00e9sentations diff\u00e9rentes pour les bitmap \u2014 des bitmap \u00e0 proprement parler, des tableaux et ce qu'on appelle des bit runs \u2014 et \u00e9quilibrent entre elles pour maximiser la performance tout en minimisant la consommation de m\u00e9moire.<\/p>\n<p>Vous pouvez trouver des bitmap roaring dans les applications les plus populaires. Il existe d\u00e9j\u00e0 un grand nombre d'impl\u00e9mentations pour divers langages de programmation, y compris plus de trois impl\u00e9mentations pour Go.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/de2adfebc431ff48c996247b453f02ae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUne autre approche qui peut nous aider \u00e0 g\u00e9rer la grande cardinalit\u00e9 s'appelle le regroupement (binning). Imaginez que vous avez un champ repr\u00e9sentant la taille d'une personne. La taille est un nombre \u00e0 virgule flottante, mais nous, humains, ne pensons pas de cette mani\u00e8re. Pour nous, il n'y a pas de diff\u00e9rence entre une taille de 185,2 cm et 185,3 cm.<\/p>\n<p>Nous pouvons donc regrouper des valeurs similaires en groupes dans une plage de 1 cm.<\/p>\n<p>Et si nous savons en plus que tr\u00e8s peu de personnes mesurent moins de 50 cm ou plus de 250 cm, nous pouvons, en fait, transformer un champ \u00e0 cardinalit\u00e9 infinie en un champ avec une cardinalit\u00e9 d'environ 200 valeurs.<\/p>\n<p>Bien s\u00fbr, si n\u00e9cessaire, nous pouvons effectuer un filtrage suppl\u00e9mentaire par la suite.<\/p>\n<h2>Le probl\u00e8me de la grande bande passante<\/h2>\n<p>\nLe probl\u00e8me suivant des index bitmap est que leur mise \u00e0 jour peut \u00eatre tr\u00e8s co\u00fbteuse.<\/p>\n<p>Les bases de donn\u00e9es doivent permettre la mise \u00e0 jour des donn\u00e9es au moment o\u00f9 potentiellement des centaines d'autres requ\u00eates recherchent ces donn\u00e9es. Nous avons besoin de verrous pour \u00e9viter les probl\u00e8mes d'acc\u00e8s concurrent aux donn\u00e9es ou d'autres probl\u00e8mes d'acc\u00e8s partag\u00e9. L\u00e0 o\u00f9 il y a un grand verrou, il y a un probl\u00e8me \u2014 la contention de verrou, lorsque ce verrou devient un goulet d'\u00e9tranglement.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/0ae1bf925542d286f8b7b245c160a35e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCe probl\u00e8me peut \u00eatre r\u00e9solu ou contourn\u00e9 en utilisant le sharding ou des index versionn\u00e9s.<\/p>\n<p>Le sharding est une chose simple et bien connue. Vous pouvez shardiser un index bitmap de la m\u00eame mani\u00e8re que vous shardisiez d'autres donn\u00e9es. Au lieu d'un grand verrou, vous obtiendrez un tas de petits verrous et ainsi vous \u00e9liminerez la contention de verrou.<\/p>\n<p>Un autre moyen de r\u00e9soudre le probl\u00e8me est d'utiliser des index versionn\u00e9s. Vous pouvez avoir une copie de l'index que vous utilisez pour la recherche ou la lecture, et une autre pour l'\u00e9criture ou la mise \u00e0 jour. Et \u00e0 intervalles r\u00e9guliers (par exemple, toutes les 100 ms ou 500 ms), vous les dupliquez et les \u00e9changez. Bien s\u00fbr, cette approche n'est applicable que dans les cas o\u00f9 votre application peut fonctionner avec un index de recherche l\u00e9g\u00e8rement obsol\u00e8te.<\/p>\n<p>Ces deux approches peuvent \u00eatre utilis\u00e9es simultan\u00e9ment : vous pouvez avoir un index versionn\u00e9 shard\u00e9.<\/p>\n<h2>Requ\u00eates plus complexes<\/h2>\n<p>Le dernier probl\u00e8me des index bitmap est que, comme on nous le dit, ils ne conviennent pas bien aux types de requ\u00eates plus complexes, comme les requ\u00eates \u00ab par intervalle \u00bb.<\/p>\n<p>En effet, si l'on y r\u00e9fl\u00e9chit, les op\u00e9rations bit \u00e0 bit comme AND, OR, etc., ne sont pas tr\u00e8s adapt\u00e9es aux requ\u00eates de type \u00ab Montre-moi les h\u00f4tels avec un prix de chambre entre 200 et 300 dollars par nuit \u00bb.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/7bc2e129cad46fb5875c2b3018c39ff7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUne solution na\u00efve et tr\u00e8s peu judicieuse serait de prendre les r\u00e9sultats pour chaque valeur en dollars et de les combiner avec une op\u00e9ration bit \u00e0 bit OR.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/b9f8fc7945caa1866f8e0cfa8a04bd98.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUne solution un peu plus correcte serait d'utiliser le groupement. Par exemple, par groupes de 50 dollars. Cela acc\u00e9l\u00e9rerait notre processus de 50 fois.<\/p>\n<p>Mais le probl\u00e8me est \u00e9galement facilement r\u00e9solu en utilisant une repr\u00e9sentation con\u00e7ue sp\u00e9cifiquement pour ce type de requ\u00eates. Dans les travaux de recherche, cela s'appelle des bitmaps cod\u00e9s par plage.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/644a420628b21f220a7af1ff15c4031f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDans cette repr\u00e9sentation, nous n'attribuons pas simplement un bit pour une valeur donn\u00e9e (par exemple, 200), mais nous d\u00e9finissons cette valeur et tout ce qui est au-dessus. 200 et plus. La m\u00eame chose pour 300 : 300 et plus. Et ainsi de suite.<\/p>\n<p>En utilisant cette repr\u00e9sentation, nous pouvons r\u00e9pondre \u00e0 ce genre de requ\u00eates de recherche en parcourant l'index seulement deux fois. D'abord, nous obtenons la liste des h\u00f4tels o\u00f9 le tarif est inf\u00e9rieur \u00e0 300 dollars, puis nous \u00e9liminons ceux dont le tarif est inf\u00e9rieur \u00e0 199 dollars. C'est pr\u00eat.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/cc2bb58d7d7a51495c62ec7da81e2d12.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVous serez surpris, mais m\u00eame les requ\u00eates g\u00e9ospatiales sont possibles avec des index bitmap. Le truc est d'utiliser une repr\u00e9sentation g\u00e9ographique qui entoure vos coordonn\u00e9es avec une forme g\u00e9om\u00e9trique. Par exemple, S2 de Google. La forme doit pouvoir \u00eatre repr\u00e9sent\u00e9e par trois lignes ou plus qui se croisent et que l'on peut num\u00e9roter. Ainsi, nous pourrons transformer notre requ\u00eate g\u00e9ospatiale en plusieurs requ\u00eates \u00ab par intervalle \u00bb (sur ces lignes num\u00e9rot\u00e9es).<\/p>\n<h2>Solutions pr\u00eates \u00e0 l'emploi<\/h2>\n<p>\nJ'esp\u00e8re vous avoir int\u00e9ress\u00e9 un peu et que vous avez d\u00e9sormais un autre outil utile dans votre arsenal. Si jamais vous avez besoin de faire quelque chose de similaire, vous saurez dans quelle direction regarder.<\/p>\n<p>Cependant, tout le monde n'a pas le temps, la patience et les ressources pour cr\u00e9er des index bitmap \u00e0 partir de z\u00e9ro. Surtout des index plus avanc\u00e9s utilisant SIMD, par exemple.<\/p>\n<p>Heureusement, il existe plusieurs solutions toutes pr\u00eates qui peuvent vous aider.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/817b47cb189a758756b602ec9cf319e1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Bitmaps Roaring<\/h2>\n<p>\nTout d'abord, il y a la biblioth\u00e8que roaring bitmaps que j'ai d\u00e9j\u00e0 mentionn\u00e9e. Elle contient tous les conteneurs n\u00e9cessaires et les op\u00e9rations bit \u00e0 bit dont vous aurez besoin pour cr\u00e9er un index bitmap complet.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/57f61a51485c174666b52dc2063fabe8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMalheureusement, jusqu'\u00e0 pr\u00e9sent, aucune des r\u00e9alisations en Go n'utilise SIMD, ce qui signifie que les r\u00e9alisations en Go sont moins performantes que celles en C, par exemple.<\/p>\n<h2>Pilosa<\/h2>\n<p>\nUn autre produit qui peut vous aider est la base de donn\u00e9es Pilosa, qui est essentiellement uniquement compos\u00e9e d'index bitmap. C'est une solution relativement nouvelle, mais qui conquiert les c\u0153urs \u00e0 une vitesse incroyable.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/d3870a979e1e73d093fe5d5e9bb71cd8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPilosa utilise des bitmaps roaring en son sein et vous permet de les utiliser, simplifie et explique toutes les choses dont j'ai parl\u00e9 ci-dessus : regroupement, bitmaps cod\u00e9s par plage, notion de champ, etc.<\/p>\n<p>Jetons un coup d'\u0153il rapide \u00e0 un exemple d'utilisation de Pilosa pour r\u00e9pondre \u00e0 une question que vous connaissez d\u00e9j\u00e0.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/dfee7abfd653cc19d9aa8b64c64f3e4e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nL'exemple est tr\u00e8s similaire \u00e0 ce que vous avez d\u00e9j\u00e0 vu. Nous cr\u00e9ons un client pour le serveur Pilosa, nous cr\u00e9ons un index et les champs n\u00e9cessaires, puis nous remplissons nos champs avec des donn\u00e9es al\u00e9atoires selon des probabilit\u00e9s et, enfin, nous ex\u00e9cutons la requ\u00eate famili\u00e8re.<\/p>\n<p>Ensuite, nous utilisons NOT sur le champ \u00ab expensive \u00bb, puis nous croisons le r\u00e9sultat (ou avec AND) avec le champ \u00ab terrace \u00bb et le champ \u00ab reservations \u00bb. Enfin, nous obtenons le r\u00e9sultat final.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/8d66c6d68019c2297b6c15b700f06a3a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJ'esp\u00e8re vraiment qu'\u00e0 l'avenir, des syst\u00e8mes de gestion de bases de donn\u00e9es comme MySQL et PostgreSQL introduiront \u00e9galement ce nouveau type d'index \u2014 les index bitmap.<br \/>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/7a8e33d576c7fb6376a173ee038b4206.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Conclusion<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Index bitmap en Go : recherche \u00e0 une vitesse fulgurante\" src=\"\/wp-content\/uploads\/2019\/05\/c62caa9ad6f2d96056c80326f4fa9a0d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMerci si vous ne vous \u00eates pas endormi. J'ai d\u00fb effleurer de nombreux sujets en raison du temps limit\u00e9, mais j'esp\u00e8re que la pr\u00e9sentation a \u00e9t\u00e9 utile et peut-\u00eatre m\u00eame motivante.<\/p>\n<p>Il est bon de conna\u00eetre les index bitmap, m\u00eame si vous n'en avez pas besoin pour l'instant. Qu'ils soient un outil suppl\u00e9mentaire dans votre bo\u00eete \u00e0 outils.<\/p>\n<p>Nous avons examin\u00e9 divers trucs pour am\u00e9liorer les performances de Go et les choses que le compilateur Go ne g\u00e8re pas encore tr\u00e8s bien. Cela, en revanche, est absolument essentiel \u00e0 savoir pour tout programmeur Go.<\/p>\n<p>C'est tout ce que je voulais dire. Merci !<br \/>\n<br \/>Source : <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.2 - 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\/fr\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\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\/fr\/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\udd47 Index bitmap en Go : recherche \u00e0 la vitesse de la lumi\u00e8re | ProHoster","description":"Mots d'introduction : J'ai pris la parole.","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","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\/fr\/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\/fr\/wp-json\/wp\/v2\/posts\/33793","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=33793"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/33793\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/25469"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=33793"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=33793"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=33793"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}