Je Mongo Atlas Search len ďalšia náhrada Elasticu?

Keď sme pred nejakým časom prechádzali na Mongo Atlas Cloud, robili sme tak z dôvodu rôznych problémov, ktorým sme v tej dobe čelili. Od tejto zmeny sme očakávali nielen vyriešenie výkonu a stability, ale aj nové funkcionality. Prvá veľká vychytávka, dostupná len pre cloud klientov, ktorú sme sa rozhodli implementovať, bol Mongo Atlas Search. Prečo? Lebo ak ste niekedy kvôli fulltextovým funkciám a pokročilým indexom pracovali s databázami ako Elastic, potom viete, že to je naozaj náročné…

Ako funguje Elastic?

Na začiatku máte dáta – napríklad blogové články v nejakej existujúcej databáze, napríklad MySQL. Aby ste v nich mohli efektívne a fulltextovo vyhľadávať, musíte ich synchronizovať do Elastic databázy, ktorú samozrejme treba ešte predtým niekde nainštalovať a prevádzkovať. Možno viete, možno nie, ale Elastic si vyžaduje veeeeeľa RAM-ky. Keď sa konečne vysporiadate s nočnou morou synchronizácie (vytvorenie článku, publikácia článku, zmena článku, zmazanie článku, …), vo výsledku získate v podstate zdvojené dáta – v pôvodnej databáze a aj v Elastic databáze.

Tu to ale ani zďaleka nekončí. Potrebujete ešte rozšíriť API tak, aby sa pripojilo na Elastic server, kompletne zmeniť queries a ťahať primárne dáta pri vyhľadávaní z Elasticu. Ak chcete šetriť miesto a do Elasticu synchronizujete len indexované polia, nie kompletné dáta, potom musíte vyhľadané údaje spojiť s materskou databázou a podľa IDečiek dotiahnuť údaje, ktoré v Elasticu nie sú.

Toto všetko sú viac-menej jednorazové záležitosti, cez ktoré sa dá prehrýzť. Ale potom príde na rad prevádzka – zálohovanie, aktualizácie a monitoring. Do doteraz čistého kódu ste si takto vniesli nezmar v podobe ďalších knižníc a ďalšej biznis logiky, pričom sa ľahko môže stať, že nová verzia „niečoho“ v tomto stacku vám môže spôsobiť opäť ďalšie vrásky na čele a priniesť dodatočné developerské náklady.

Niet pochýb, že Elastic a podobné enginy prinášajú v konečnom dôsledku zákazníkom našich klientov vysoký používateľský komfort a radosť. Dá sa to ale dosiahnuť aj efektívnejšie. A tu prichádza na scénu…

Mongo Atlas Search

Viem si živo predstaviť, ako to vyzeralo v tíme vývojárov MongoDB, keď vymýšľali Atlas Search. Žiadne synchronizácie, žiadne dramatické zmeny kódu, žiadne dodatočné prevádzkové náklady! Revolúcia!

Atlas Search je vyhľadávací engine, ktorý je súčasťou Mongo Atlas Cloudu. Je tam bez toho, aby ste vy, ako vývojári softvéru, pohli čo i len prstom. Ušetrí vám všetky strasti, je funkčný a pripravený na použitie jednoduchým rozšírením v agregáciách. Ak si hovoríte, že: “Elastic je skvelý, pretože je postavený na Apache Lucene!“, pravdepodobne nevidíte dôvod na zmenu. Možno vás ale presvedčí fakt, že Mongo Atlas Search používa presne ten istý indexovací systém – práve Apache Lucene.

Ako Atlas Search spojazdniť a nastaviť?

Na začiatku je potrebné si uvedomiť, ako Mongo Atlas Search funguje. Základom sú indexy. Tie si nastavíte cez webové rozhranie cloudu. Zvolíte si cluster, databázu a kolekciu, ktorú chcete indexovať. Buď si to pekne vyklikáte, alebo použijete definíciu, ktorú zapíšete do JSON formátu. Ja preferujem JSON formát, nakoľko mám vďaka nemu viac možností a vačšiu kontrolu nad tým, čo a ako sa má indexovať.

Ukážme si základné nastavenie na príklade, ktorý sme implementovali na vyhľadávaní v MediaManageri (aplikácia na správu médii, napríklad fotiek a dokumentov). Každá fotka má svoj názov a popis. Sú to atribúty, v ktorých chce zákazník vyhľadávať. Definícia indexu teda vyzerá asi takto:

Mongo eviduje ku každému indexu jeho názov, stav indexovania a atribúty dát, ktoré sú súčasťou indexu. Definícia tohto indexu je nasledovná:

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "_description": [
        {
          "type": "string"
        }
      ],
      "_name": {
        "analyzer": "lucene.standard",
        "multi": {
          "filenameAnalyzer": {
            "analyzer": "filenameAnalyzer",
            "type": "string"
          }
        },
        "type": "string"
      },
      "app_id": {
        "analyzer": "lucene.keyword",
        "searchAnalyzer": "lucene.keyword",
        "type": "string"
      },
      "created_date": {
        "type": "date"
      }
    }
  },
  "analyzers": [
    {
      "charFilters": [],
      "name": "filenameAnalyzer",
      "tokenFilters": [
        {
          "type": "lowercase"
        }
      ],
      "tokenizer": {
        "pattern": "[ _\\-\\.]+",
        "type": "regexSplit"
      }
    }
  ]
}


V objekte mappings definujete atribúty dokumentu, ktoré chcete indexovať, prostredníctvom Atlas Search. Zároveň mu poviete aj to, ako ich má indexovať. Základom je string, number, boolean, dátum, alebo špecialitky ako autocomplete. Kompletný zoznam nájdete v oficiálnej dokumentácii.

Pri každom atribúte môžete označiť jeho typ a zadefinovať takzvaný analyzátor.  Je to spôsob, ako vyhľadávací engine rozbije dáta (reťazec) na takzvané tokeny. My používame lucene.standard, čo je default, alebo lucene.keyword, ak sa jedná o nejaké kľučové slovo a pri vyhľadávaní sa musí nájsť jeho presná zhoda.

Vyskúšajte aj vlastný analyzátor!

Štandardný analyzátor rozbije dopyt na slová, ktorých oddeľovačom je medzera. Čo ale robiť, ak chcete, ako my, vyhľadávať v názvoch súborov, čo vyzerajú aj takto: Petra-Vlhova-3.jpg? Potrebujete predsa tento obrázok nájsť aj na výraz petra, alebo aj vlhova. Definujete si preto vlastný analyzátor, ktorý rozbije reťazec podľa regulárneho výrazu [ _\-\.]+, teda podľa medzier, pomlčiek, podčiarkovníkov a bodiek. Ako bonus nastavíte, aby analyzátor prepísal celý názov malými písmenami vďaka filtru lowercase.

Na jeden atribút takto môžete pridať aj viac analyzátorov a potom sa pri vyhľadávaní rozhodnúť, pomocou ktorého z nich chcete vyhľadávať.

A ako sa vlastne vyhľadáva? Ako nič!

Jednoducho obohatíte existujúcu agregačnú pipeline o $search stage. V ňom definujete, ktorý index chcete použiť, a akým operátorom chcete vyhľadávať. Máte na výber od fulltextu, cez autocomplete až po geo vyhľadávanie či frázu. Každý z týchto operátorov viete navyše samozrejme „vytuniť“ – napríklad pridať fuzzy algoritmus (na akceptovanie chýb a preklepov), alebo zmeniť výslednú váhu. Celé je to presne popísané v dokumentácii MongoDB.

Výsledky sú zoradené podľa relevancie vyhľadávača, s prihliadnutím na upravené váhy. Novinkou je, že na zoradenie výsledkov viete použiť aj indexovaný stĺpec typu dátum alebo číslo. To je mimochodom celkom čerstvá novinka.

Ako vyhľadávame v súboroch my?

  • Používame operátor compound, ktorý nám umožní definovať viac pravidiel.
  • Najskôr filtrujeme dáta podľa aplikácie, ktorá MediaManager vyvolala.
  • Následne používame „should“, teda podmienky, z ktorých by mali vyhľadávané dokumenty spĺňať aspoň jednu.
  • Tieto podmienky sú opäť „compound“ operátorom, kde medzi jednotlivými výrazmi vyhľadávaného reťazca už používame „must“.
  • Výsledky zoradíme podľa času pridania súboru.

Výsledná agregačná pajplajna vyzerá potom nasledovne:

[
  {
    "$search": {
      "compound": {
        "filter": [
          {
            "text": {
              "path": "app_id",
              "query": "pages"
            }
          }
        ],
        "should": [
          {
            "compound": {
              "must": [
                {
                  "text": {
                    "path": "_name",
                    "query": "petra"
                  }
                },
                {
                  "text": {
                    "path": "_name",
                    "query": "vlhova"
                  }
                }
              ]
            }
          },
          {
            "compound": {
              "must": [
                {
                  "text": {
                    "path": {
                      "value": "_name",
                      "multi": "filenameAnalyzer"
                    },
                    "query": "petra"
                  }
                },
                {
                  "text": {
                    "path": {
                      "value": "_name",
                      "multi": "filenameAnalyzer"
                    },
                    "query": "vlhova"
                  }
                }
              ]
            }
          }
        ],
        "minimumShouldMatch": 1
      },
      "sort": {
        "created_date": -1
      }
    }
  },
  {
    "$skip": 0
  },
  {
    "$limit": 10
  },
  {
    "$project": {
      "name": 1,
      "description": 1,
      "scoreDetails": {
        "$meta": "searchScoreDetails"
      }
    }
  }
]

A to, že je to len agregačný stage, vám vôbec nebráni v tom, aby ste s výsledkami ďalej pracovali. Pokojne pridajte $limit, $skip, alebo aj $unwind, $group, $project a podobne. Mongo Atlas sa postará o celú tú nezáživnú robotu spojenú s indexovaním, synchronizáciou a prevádzkou search enginu. A vy i koneční zákazníci vášho klienta sa môžete tešiť z revolúcie vo vyhľadávaní :)

Zaujíma ťa vývoj? Potom by ťa mohli baviť aj ďalšie články na túto tému!