Wyszukiwarka w sklepie internetowym – od LIKE do Elasticsearch

22.10.2026 | Autor: Marcin Wiercioch

Klient, który wpisuje frazę w wyszukiwarkę sklepu, zwykle wie, czego chce, i jest o krok od zakupu – pod warunkiem, że coś znajdzie. W tym artykule, otwierającym serię o AI w e-commerce, zaczynamy od podstaw: przeglądamy klasyczne sposoby wyszukiwania, od LIKE w SQL, przez full-text w MySQL i PostgreSQL, własne tabele indeksu i Sphinksa, aż po Elasticsearch, Meilisearch i usługi SaaS. Podpowiadamy też, co wybrać do jakiego sklepu.

Czego klient oczekuje od wyszukiwarki

Wyszukiwarka w sklepie to coś więcej niż pole tekstowe. Klient wpisuje frazę tak, jak myśli i mówi, a nie tak, jak produkt został nazwany w bazie. Dobra wyszukiwarka musi poradzić sobie z kilkoma rzeczami naraz:

  • Literówki i brak polskich znaków – „adidsa”, „sluchawki bezprzewodowe”.
  • Odmiana – „kurtka”, „kurtki”, „kurtek”, „kurtkę”; „buty damskie” i „damskich butów”.
  • Synonimy – „laptop” i „notebook”, „bluza z kapturem” i „hoodie”.
  • Kody – SKU, EAN, symbol producenta, wpisywane z myślnikiem, bez niego albo ze spacją („XR-200”, „xr200”, „XR 200”).
  • Trafność – produkt z frazą w nazwie powinien być wyżej niż ten, który wspomina o niej w trzecim akapicie opisu, a dostępny wyżej niż wyprzedany.
  • Podpowiedzi w trakcie pisania – w ułamku sekundy, przy każdym naciśnięciu klawisza.
  • Filtry – po wpisaniu „kurtka” klient chce zawęzić wyniki po rozmiarze, kolorze i cenie, najlepiej z liczbą produktów przy każdej opcji.

Język polski stawia poprzeczkę wyjątkowo wysoko. Siedem przypadków i polskie znaki sprawiają, że rozwiązania projektowane z myślą o angielskim, gdzie zwykle wystarczy odciąć końcówkę „-s”, u nas działają przeciętnie. Przez ten pryzmat przyjrzymy się każdemu z poniższych podejść.

Najprostsze podejście: LIKE '%fraza%’

Tak domyślnie szuka WordPress, a więc i WooCommerce: każde słowo frazy jest wyszukiwane operatorem LIKE w tytule, zajawce i treści wpisu. W uproszczeniu zapytanie wygląda tak:

SELECT p.ID, p.post_title
FROM wp_posts p
WHERE p.post_type = 'product'
  AND p.post_status = 'publish'
  AND (p.post_title LIKE '%kurtka%' OR p.post_excerpt LIKE '%kurtka%' OR p.post_content LIKE '%kurtka%')
  AND (p.post_title LIKE '%zimowa%' OR p.post_excerpt LIKE '%zimowa%' OR p.post_content LIKE '%zimowa%')
ORDER BY p.post_title LIKE '%kurtka zimowa%' DESC, p.post_date DESC;

Zaleta jest jedna, ale istotna: zero konfiguracji. Wady łatwo przewidzieć:

  • Brak indeksu. LIKE ze znakiem % na początku nie skorzysta ze zwykłego indeksu, więc baza przy każdym wyszukiwaniu skanuje wszystkie produkty. Przy kilkuset pozycjach nikt tego nie zauważy, przy kilkudziesięciu tysiącach z długimi opisami już tak.
  • Zero rozumienia języka. Fraza „kurtki zimowe” nie znajdzie produktu „Kurtka zimowa męska”, bo żadne z tych słów nie zawiera się w drugim.
  • Fałszywe trafienia. „kot” znajdzie także „kotwicę” i „szkotkę”.
  • Prymitywna trafność. WordPress układa wyniki według kilku prostych reguł (cała fraza w tytule, wszystkie słowa w tytule, którekolwiek słowo w tytule, fraza w zajawce, fraza w treści). Nie ma wag dla kategorii, atrybutów czy popularności.
  • Kody produktów. Domyślna wyszukiwarka WooCommerce na froncie sklepu nie przeszukuje SKU ani atrybutów. Klient, który przepisuje kod z faktury czy katalogu, dostaje zero wyników.

LIKE ma jedno uczciwe zastosowanie: wyszukiwanie po początku tekstu (LIKE 'XR-2%’) na zindeksowanej kolumnie, np. z kodem produktu. Tu indeks zadziała i zapytanie będzie szybkie.

FULLTEXT w MySQL i MariaDB

Od MySQL 5.6 indeksy pełnotekstowe działają w silniku InnoDB. Baza buduje indeks odwrócony (słowo → lista rekordów, w których występuje), a zapytanie MATCH … AGAINST zwraca wyniki razem z oceną trafności.

ALTER TABLE products ADD FULLTEXT INDEX ft_products (name, description);

-- tryb naturalny: wyniki z oceną trafności
SELECT id, name, MATCH(name, description) AGAINST('kurtka zimowa') AS score
FROM products
WHERE MATCH(name, description) AGAINST('kurtka zimowa')
ORDER BY score DESC
LIMIT 20;

-- tryb boolean: słowa wymagane, wykluczone i wyszukiwanie po prefiksie
SELECT id, name
FROM products
WHERE MATCH(name, description) AGAINST('+kurtk* +zimow* -dziecięca' IN BOOLEAN MODE);

To ogromny skok wydajności względem LIKE i rozwiązanie dostępne „za darmo” w bazie, którą sklep i tak ma. Ograniczenia są jednak wyraźne:

  • Brak obsługi polskiej odmiany. MySQL nie potrafi sprowadzić różnych form polskiego słowa do jednej, podstawowej. Częściowo ratuje tryb boolean z gwiazdką („kurtk*” znajdzie „kurtka”, „kurtki” i „kurtkę”), ale słowa, które w odmianie zmieniają brzmienie („pies” i „psa”), pozostają poza zasięgiem.
  • Minimalna długość słowa. InnoDB domyślnie indeksuje słowa od trzech znaków (innodb_ft_min_token_size), więc „TV” czy „4K” wypadają z indeksu. Zmiana wymaga konfiguracji serwera, co na hostingu współdzielonym zwykle nie wchodzi w grę.
  • Słowa pomijane. Wbudowana lista słów, które baza ignoruje (np. „the”, „and”), jest angielska.
  • Brak tolerancji literówek i synonimów.

Dla sklepu z kilkoma tysiącami produktów to często wystarczające i rozsądne rozwiązanie, zwłaszcza w połączeniu z własną tabelą indeksu, o której za chwilę.

PostgreSQL: full-text i tolerancja literówek

PostgreSQL ma znacznie bogatszy wbudowany mechanizm pełnotekstowy: typy tsvector i tsquery, słowniki językowe, wagi dla poszczególnych pól (od A do D) i ranking ts_rank. Polskiego słownika nie ma w standardowej instalacji, ale można podpiąć słownik w formacie ispell (np. oparty o słowniki Hunspell z projektu sjp.pl). Wtedy „kurtek” i „kurtka” sprowadzają się do tej samej formy podstawowej. Rozszerzenie pg_trgm dokłada tolerancję literówek (porównuje słowa po krótkich, trzyliterowych fragmentach), a unaccent pozwala ignorować polskie znaki.

W przykładzie używamy konfiguracji simple, która nie rozpoznaje odmiany. Po zainstalowaniu polskiego słownika wystarczy podmienić ją na własną konfigurację.

CREATE EXTENSION IF NOT EXISTS pg_trgm;

ALTER TABLE products ADD COLUMN search_vector tsvector
  GENERATED ALWAYS AS (
    setweight(to_tsvector('simple', coalesce(name, '')), 'A') ||
    setweight(to_tsvector('simple', coalesce(description, '')), 'B')
  ) STORED;

CREATE INDEX idx_products_search ON products USING GIN (search_vector);
CREATE INDEX idx_products_name_trgm ON products USING GIN (name gin_trgm_ops);

-- wyszukiwanie pełnotekstowe z rankingiem
SELECT id, name, ts_rank(search_vector, query) AS score
FROM products, websearch_to_tsquery('simple', 'kurtka zimowa') AS query
WHERE search_vector @@ query
ORDER BY score DESC
LIMIT 20;

-- tolerancja literówek: "kurtak zimowa" nadal znajdzie produkt
SELECT id, name, similarity(name, 'kurtak zimowa') AS score
FROM products
WHERE name % 'kurtak zimowa'
ORDER BY score DESC
LIMIT 20;

Jeśli sklep działa na PostgreSQL (jak wiele instalacji Syliusa, Saleor czy Medusa), to często najlepszy pierwszy krok, zanim sięgnie się po osobny silnik wyszukiwania.

Własna tabela z zaindeksowanymi danymi

Zamiast przeszukiwać tabele produktów na żywo, można przygotować dane z wyprzedzeniem. Przy każdym zapisie produktu budujemy jeden rekord ze wszystkimi danymi potrzebnymi do wyszukiwania: nazwa, SKU w kilku wariantach zapisu, kategorie, wartości atrybutów, wszystko znormalizowane (małe litery, bez polskich znaków, bez myślników). Wyszukiwanie odbywa się potem w jednej, wąskiej tabeli z indeksami FULLTEXT zamiast przez JOIN-y po pół bazy.

Tak działają popularne wtyczki do WordPressa: Relevanssi i SearchWP budują własne tabele indeksu. PrestaShop od lat trzyma słowa w tabelach ps_search_word i ps_search_index, z wagami ustawianymi w panelu (nazwa, indeks, opisy, kategoria, producent, atrybuty, cechy). Prosta wersja dla WooCommerce może wyglądać tak:

CREATE TABLE wp_product_search_index (
    product_id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    codes VARCHAR(255) NOT NULL,
    keywords TEXT NOT NULL,
    in_stock TINYINT(1) NOT NULL DEFAULT 0,
    FULLTEXT KEY ft_all (title, codes, keywords),
    FULLTEXT KEY ft_title (title),
    FULLTEXT KEY ft_codes (codes),
    FULLTEXT KEY ft_keywords (keywords)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
<?php
// Normalizacja: małe litery, bez polskich znaków i znaków specjalnych
function normalize_search_text(string $text): string
{
    $text = mb_strtolower(wp_strip_all_tags($text));
    $text = strtr($text, [
        'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n',
        'ó' => 'o', 'ś' => 's', 'ź' => 'z', 'ż' => 'z',
    ]);
    $text = preg_replace('/[^a-z0-9]+/', ' ', $text);

    return trim(preg_replace('/\s+/', ' ', $text));
}

// Przy każdym zapisie produktu odświeżamy jego rekord w indeksie
add_action('woocommerce_new_product', 'update_product_search_index');
add_action('woocommerce_update_product', 'update_product_search_index');

function update_product_search_index(int $product_id): void
{
    global $wpdb;

    $product = wc_get_product($product_id);
    if (!$product) {
        return;
    }

    $sku = (string) $product->get_sku();
    // "XR-200" zapisujemy jako "xr 200" i "xr200", żeby każdy wariant dawał trafienie
    $codes = normalize_search_text($sku) . ' ' . strtolower(preg_replace('/[^a-z0-9]/i', '', $sku));

    $terms = wp_get_post_terms($product_id, ['product_cat', 'product_tag'], ['fields' => 'names']);
    $attribute_values = [];
    foreach ($product->get_attributes() as $attribute) {
        $attribute_values = array_merge($attribute_values, $attribute->is_taxonomy()
            ? wc_get_product_terms($product_id, $attribute->get_name(), ['fields' => 'names'])
            : $attribute->get_options());
    }

    $wpdb->replace($wpdb->prefix . 'product_search_index', [
        'product_id' => $product_id,
        'title' => normalize_search_text($product->get_name()),
        'codes' => $codes,
        'keywords' => normalize_search_text(implode(' ', array_merge(
            is_array($terms) ? $terms : [],
            $attribute_values,
            [$product->get_short_description()]
        ))),
        'in_stock' => $product->is_in_stock() ? 1 : 0,
    ]);
}

Frazę od klienta przepuszczamy przez tę samą funkcję normalizującą. Prosty trik: dłuższe słowa skracamy o jedną lub dwie litery i dodajemy gwiazdkę, co jest bardzo prostym sposobem na obsługę odmiany („kurtka zimowa” → „kurtk* zimow*”). Trafienie w kod liczy się bardziej niż w nazwie, a nazwa bardziej niż słowa kluczowe, a produkty dostępne lądują wyżej:

SELECT product_id,
       MATCH(codes) AGAINST('kurtk* zimow*' IN BOOLEAN MODE) * 5
     + MATCH(title) AGAINST('kurtk* zimow*' IN BOOLEAN MODE) * 3
     + MATCH(keywords) AGAINST('kurtk* zimow*' IN BOOLEAN MODE)
     + in_stock * 2 AS score
FROM wp_product_search_index
WHERE MATCH(title, codes, keywords) AGAINST('kurtk* zimow*' IN BOOLEAN MODE)
ORDER BY score DESC
LIMIT 20;

Zalety: pełna kontrola, brak dodatkowej infrastruktury i kody produktów działające dokładnie tak, jak chcemy. Wady: trzeba pilnować aktualności indeksu (importy CSV, masowe zmiany stanów czy synchronizacja z ERP potrafią ominąć automatyczną aktualizację indeksu, więc przyda się też pełna przebudowa uruchamiana z crona), a literówek i synonimów nadal brak, chyba że dopiszemy je sami. Słownik synonimów to zwykle osobna tabela i rozwinięcie frazy przed wykonaniem zapytania.

Indeks w plikach binarnych: Lucene, Zend_Search_Lucene i Sphinx

U podstaw niemal każdej poważnej wyszukiwarki leży ta sama idea: indeks odwrócony. Zamiast trzymać listę produktów i szukać w nich słów, trzyma się listę słów, a przy każdym z nich listę produktów, w których występuje, razem z pozycjami i częstotliwością. Wyszukanie frazy to wtedy kilka odczytów i przecięcie list, a nie skanowanie całego katalogu.

Apache Lucene, biblioteka Javy rozwijana od końca lat 90., zapisuje taki indeks w segmentach: niezmiennych plikach binarnych na dysku, które w tle są scalane w większe. W świecie PHP popularny był kiedyś Zend_Search_Lucene z Zend Framework 1, czyli implementacja Lucene napisana w czystym PHP, trzymająca indeks w plikach w katalogu aplikacji, bez żadnego dodatkowego serwera. Wygodne na start, ale przy większych katalogach wolne, pamięciożerne i podatne na problemy z blokadami przy równoczesnych zapisach. Dziś to już rozwiązanie historyczne.

Drugim weteranem jest Sphinx: osobny serwer (searchd), który pobiera dane prosto zapytaniem SQL (narzędzie indexer) i trzyma indeks we własnych plikach binarnych. Był bardzo szybki i mówił protokołem MySQL (SphinxQL), więc z aplikacji odpytywało się go jak zwykłą bazę danych. Przez lata napędzał wyszukiwarki wielu polskich sklepów i serwisów. Gdy rozwój Sphinksa zwolnił, a kolejne wydania przestały być publikowane jako open source, w 2017 roku powstał fork Manticore Search. Jest aktywnie rozwijany do dziś, m.in. o indeksy aktualizowane w czasie rzeczywistym i wyszukiwanie wektorowe.

-- Manticore Search: tabela real-time, obsługiwana zwykłym klientem MySQL
CREATE TABLE products (title text, sku string, price float, in_stock bool) min_prefix_len='3';

INSERT INTO products (id, title, sku, price, in_stock)
VALUES (1, 'Kurtka zimowa męska', 'XR-200', 399.0, 1);

SELECT id, title, WEIGHT() AS score
FROM products
WHERE MATCH('kurtk*') AND in_stock = 1
ORDER BY score DESC
LIMIT 20;

Elasticsearch i OpenSearch, czyli ciężka artyleria

Elasticsearch to rozproszony serwer wyszukiwania zbudowany na Lucene. Komunikuje się przez REST API i JSON, a w zamian oferuje wszystko, czego brakowało wcześniej: analizatory językowe, tolerancję literówek (fuzziness), synonimy, autouzupełnianie, agregacje do filtrów z licznikami i skalowanie na wiele węzłów. Dla polskiego jest oficjalna wtyczka analysis-stempel, a do dokładniejszej analizy, opartej na słowniku języka polskiego, służy Morfologik.

Analizator to przepis na przetworzenie tekstu: podział na słowa, zamiana na małe litery, sprowadzenie słowa do formy podstawowej i usunięcie polskich znaków. Ten sam przepis stosowany jest do frazy wpisanej przez klienta, więc „kurtek zimowych” i „Kurtka zimowa” spotykają się w indeksie w tej samej postaci. Indeks z taką konfiguracją tworzymy żądaniem PUT /products:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "polish_products": {
          "tokenizer": "standard",
          "filter": ["lowercase", "polish_stem", "asciifolding"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": { "type": "text", "analyzer": "polish_products" },
      "description": { "type": "text", "analyzer": "polish_products" },
      "sku": { "type": "keyword" },
      "category": { "type": "keyword" },
      "price": { "type": "scaled_float", "scaling_factor": 100 },
      "in_stock": { "type": "boolean" }
    }
  }
}

Zapytanie (POST /products/_search) łączy wyszukiwanie z tolerancją literówek, filtrowanie i agregacje, z których budujemy filtry z licznikami w bocznej kolumnie:

{
  "query": {
    "bool": {
      "must": {
        "multi_match": {
          "query": "kurtek zimowych",
          "fields": ["name^3", "description"],
          "fuzziness": "AUTO"
        }
      },
      "filter": [{ "term": { "in_stock": true } }]
    }
  },
  "aggs": {
    "categories": { "terms": { "field": "category" } },
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [{ "to": 100 }, { "from": 100, "to": 300 }, { "from": 300 }]
      }
    }
  }
}

Ceną za te możliwości jest infrastruktura. Elasticsearch działa na JVM i potrzebuje sporo pamięci RAM, więc w praktyce to osobny serwer albo usługa zarządzana, do tego synchronizacja danych ze sklepu (kolejka, reindeksacja, obsługa błędów). Przy dużych katalogach to rynkowy standard: Magento od wersji 2.4 wręcz wymaga Elasticsearch lub OpenSearch, a WooCommerce może z niego korzystać m.in. przez wtyczkę ElasticPress.

Słowo o licencjach: w 2021 roku Elastic zmienił licencję z Apache 2.0 na SSPL i Elastic License. W odpowiedzi AWS stworzył fork OpenSearch (Apache 2.0, dziś rozwijany pod skrzydłami Linux Foundation), a w 2024 roku Elastic ponownie dodał opcję open source w postaci licencji AGPL. Na poziomie podstawowych zapytań oba projekty są dla sklepu wymienne, choć z każdą wersją coraz bardziej różnią się w szczegółach.

Nowa fala: Meilisearch i Typesense

Pomiędzy MySQL a Elasticsearchem jest miejsce na lżejsze silniki, projektowane od początku z myślą o wyszukiwaniu „jak w aplikacji”: wyniki w trakcie pisania, literówki obsługiwane bez konfiguracji i sensowna trafność od pierwszego uruchomienia.

  • Meilisearch (Rust, open source). Instalacja to jeden plik binarny lub kontener, a indeksowanie to wysłanie JSON-a z produktami. Tolerancja literówek, filtry z licznikami wyników, sortowanie i synonimy są w standardzie.
  • Typesense (C++, open source). Podobna filozofia, indeks trzymany w pamięci RAM, bardzo niskie opóźnienia i wbudowana obsługa klastra.

Oba współpracują z biblioteką InstantSearch, z której szybko złożymy frontend wyszukiwarki z podpowiedziami i filtrami. Haczyk dla polskiego: żaden z nich nie radzi sobie dobrze z polską odmianą. Odmianę częściowo maskuje wyszukiwanie po prefiksach i tolerancja literówek, ale „psa” nadal nie znajdzie „pies”. Warto przetestować to na własnym katalogu przed podjęciem decyzji. Tak wygląda start z Meilisearch:

# Meilisearch lokalnie w kontenerze
docker run -d -p 7700:7700 -e MEILI_MASTER_KEY='change-me-master-key' getmeili/meilisearch:latest

# Ustawienia indeksu: po czym szukamy i po czym filtrujemy
curl -X PATCH 'http://localhost:7700/indexes/products/settings' \
  -H 'Authorization: Bearer change-me-master-key' \
  -H 'Content-Type: application/json' \
  --data-binary '{ "searchableAttributes": ["name", "sku", "category", "description"], "filterableAttributes": ["category", "in_stock"] }'

# Wrzucenie produktów do indeksu
curl -X POST 'http://localhost:7700/indexes/products/documents' \
  -H 'Authorization: Bearer change-me-master-key' \
  -H 'Content-Type: application/json' \
  --data-binary @products.json

# Wyszukiwanie z literówką i filtrem
curl -X POST 'http://localhost:7700/indexes/products/search' \
  -H 'Authorization: Bearer change-me-master-key' \
  -H 'Content-Type: application/json' \
  --data-binary '{ "q": "kurtak zimowa", "filter": "in_stock = true" }'

Wyszukiwarka jako usługa: Algolia, Doofinder, Luigi’s Box

Ostatnia opcja to w ogóle nie utrzymywać silnika samodzielnie. Usługi SaaS przejmują indeks, infrastrukturę, a często także cały frontend wyszukiwarki (okno z podpowiedziami, filtry, stronę wyników). Do sklepu wpina się je wtyczką albo feedem produktowym.

  • Algolia: najbardziej znana, bardzo szybka, z rozbudowanym API dla programistów. Płaci się za liczbę rekordów i zapytań.
  • Doofinder: nastawiony na e-commerce, z gotowymi integracjami m.in. z WooCommerce, PrestaShop i Shopify; wdrożenie bez programowania.
  • Luigi’s Box: słowacki dostawca popularny w Europie Środkowej, mocny w analityce wyszukiwań i rekomendacjach.

Plusy: szybkie wdrożenie, analityka (czego klienci szukają i czego nie znajdują, co jest bezcenne dla działu zakupów) oraz ręczne przypinanie wybranych produktów do konkretnych fraz. Minusy: abonament rosnący razem z ruchem i katalogiem, zależność od dostawcy i dane produktowe poza własną infrastrukturą.

Porównanie

Rozwiązanie Polska odmiana Literówki Filtry Infrastruktura Dla kogo
LIKE nie nie nie brak do kilkuset produktów
MySQL FULLTEXT częściowo (prefiksy) nie ręcznie w SQL brak małe i średnie sklepy
PostgreSQL full-text + pg_trgm tak (słownik ispell) tak ręcznie w SQL brak sklepy na PostgreSQL
Własna tabela indeksu częściowo ręcznie ręcznie brak gdy liczą się kody i pełna kontrola
Manticore / Sphinx częściowo częściowo tak własny serwer duże katalogi przy małym budżecie
Elasticsearch / OpenSearch tak (Stempel, Morfologik) tak tak klaster lub usługa zarządzana duże sklepy, złożone filtry
Meilisearch / Typesense słabo tak tak lekki serwer szybkie wdrożenie, średnie katalogi
SaaS zależnie od usługi tak tak brak (abonament) sklepy bez własnego zespołu IT

Co wybrać?

  • Do 1-2 tysięcy produktów: MySQL FULLTEXT albo wtyczka w rodzaju Relevanssi lub SearchWP. Koniecznie zadbaj o wyszukiwanie po SKU i normalizację polskich znaków.
  • Kilka do kilkudziesięciu tysięcy produktów, potrzebne filtry i tolerancja literówek: Meilisearch lub Typesense; jeśli polska odmiana jest kluczowa, Elasticsearch lub OpenSearch z analizatorem dla polskiego.
  • Duży katalog, wiele filtrów, B2B z kodami produktów: Elasticsearch, OpenSearch lub Manticore, z przemyślaną synchronizacją danych.
  • Brak zespołu technicznego i liczy się czas: SaaS, ale policz koszt przy realnym ruchu, a nie przy planie startowym.

Niezależnie od silnika najwięcej daje praca na danych: uzupełnione atrybuty, synonimy dopisywane na podstawie raportu wyszukiwań bez wyników i sensowna kolejność (produkty dostępne i bestsellery wyżej). Raport fraz, które nic nie zwróciły, to zresztą najtańsze źródło wiedzy o tym, czego klienci szukają, a czego nie macie w ofercie. Taki raport łatwo zbudować np. w PostHog.

A gdzie w tym wszystkim AI?

Wszystkie opisane rozwiązania szukają słów. Tymczasem klient coraz częściej opisuje potrzebę: „coś ciepłego na rower w listopadzie”, „prezent dla taty, który lubi grillować”. Żadna z opisanych metod nie zamieni tego na „rękawiczki rowerowe zimowe”. Tu wchodzi wyszukiwanie wektorowe oparte na modelach AI, czyli wyszukiwanie po znaczeniu, a nie po słowach. Coraz częściej stosuje się też połączenie obu podejść. Co ciekawe, większość silników z tego artykułu (Elasticsearch, OpenSearch, Manticore, Meilisearch, Typesense, a także PostgreSQL z rozszerzeniem pgvector) potrafi już przechowywać i przeszukiwać wektory. Jak zbudować to w praktyce, pokażemy w kolejnym artykule z serii o AI w sklepach internetowych.

Marcin Wiercioch Marcin Wiercioch

full stack developer

Współzałożyciel Okinet, programista PHP, Full stack developer, administrator linux i pasjonat technologii z 20 letnim stażem. Ostatnimi czasy szczególnie rozwijam umiejętności związane z optymalizacją i automatyzacją środowisk developerskich dzięki czemu budowane przez nas aplikacje internetowe są wydajne, bezpieczne i łatwo rozwijalne.

Wszystkie artykuły autora

Udostępnij

Oceń artykuł

Porozmawiaj z nami
o swoim projekcie

+48 506 160 480
biuro@okinet.pl

lub napisz