Skip to content

Szybka wyszukiwarka WooCommerce - eksperyment z RediSearch i SHORTINIT

Aktualizacja: at 19:08

Wyszukiwarka WooCommerce jest powolna. Nie dlatego, że ktoś źle ją napisał - po prostu tak działa WordPress. Każde wpisanie litery w pole szukajki odpala cały silnik: wtyczki, motywy, hooki, tłumaczenia, sesje. Zanim WordPress dotknie bazy danych z Twoim zapytaniem, minęło już 100-300 milisekund.

Dla autocomplete, gdzie użytkownik wpisuje literę co 50-150 ms, to wieczność.

Od jakiegoś czasu eksperymentuję z alternatywnym podejściem: RediSearch jako silnik wyszukiwania + SHORTINIT jako ultraszybki bootstrap WordPressa. Customowa wtyczka pisana od zera. Efekty? Mediana autocomplete na tanim VPSie za kilkadziesiąt złotych: 54 ms pełny round-trip. Sam Redis odpowiada w mniej niż 10 ms.

W tym artykule pokażę co udało mi się osiągnąć, jak to działa i dlaczego uważam, że to kierunek wart eksploracji.

Spis treści

Rozwiń spis treści

Dlaczego domyślna wyszukiwarka WooCommerce jest wolna?

Zacznijmy od tego, co właściwie dzieje się, kiedy klient wpisuje coś w pole wyszukiwania Twojego sklepu.

Standardowy request WordPress wygląda mniej więcej tak:

  1. PHP ładuje wp-config.php
  2. Ładuje wszystkie aktywne wtyczki (nawet te, które nie mają nic wspólnego z wyszukiwaniem)
  3. Ładuje motyw ze wszystkimi hookami
  4. Inicjalizuje tłumaczenia, sesje, uprawnienia
  5. Dopiero teraz odpala zapytanie SQL do bazy danych

A to zapytanie? Domyślnie WooCommerce szuka po tytułach i treści postów za pomocą LIKE '%szukana_fraza%'. MySQL nie ma jak tego zoptymalizować - musi przeskanować każdy wiersz w tabeli.

Efekt: 30-50 MB RAM i kilkaset milisekund zanim Twój klient zobaczy pierwszą podpowiedź.

Pluginy takie jak FiboSearch czy SearchWP rozwiązują część tego problemu (FiboSearch Pro używa wewnętrznie SHORTINIT), ale żaden z popularnych pluginów nie wykorzystuje RediSearch jako silnika full-text search.

RediSearch - co to jest i czemu warto?

Redis to baza danych typu klucz-wartość, która trzyma wszystko w pamięci RAM. Jest powszechnie używana w WordPressie jako cache dla wp_options i sesji.

RediSearch to moduł Redis, który dodaje pełnotekstowe wyszukiwanie. Od Redis Stack (7.2+) jest bundlowany razem z Redisem, ale wciąż działa jako moduł - nie osobna baza danych. Pozwala na tworzenie indeksów, wyszukiwanie po początkach słów i łapanie literówek.

Czemu to istotne? Bo Redis operuje na RAMie i odpowiada w mikrosekundach. W moim teście na indeksie 2 500 produktów WooCommerce, typowy czas odpowiedzi FT.SEARCH to 2-5 ms per query. Praktycznie zawsze poniżej 10 ms.

Porównaj to z MySQL LIKE, który na tej samej liczbie produktów potrafi zabrać 50-200 ms.

SHORTINIT - WordPress bez WordPressa

Tu zaczyna się najciekawsza część eksperymentu.

WordPress ma wbudowaną stałą SHORTINIT, o której mało kto wie. Kiedy ustawisz ją na true przed załadowaniem wp-settings.php, WordPress ładuje absolutne minimum:

I to tyle. Zero wtyczek. Zero motywów. Zero hooków. Zero tłumaczeń.

Zamiast 30-50 MB RAM i 100-300 ms bootstrapu, mamy ~5-10 MB i mniej niż 5 ms do pierwszej linii naszej logiki. To oznacza, że endpoint autocomplete uruchamia się szybciej niż WordPress zdążyłby załadować listę aktywnych wtyczek.

Ale jest haczyk

SHORTINIT = brak dostępu do wp_options, get_option() i w zasadzie wszystkich funkcji WordPressa poza gołym $wpdb.

Jak sobie z tym radzę? Ustawienia pluginu (host Redis, port, limity, strategia wyszukiwania) są zapisywane do auto-generowanego pliku PHP z define(). Klasa konfiguracyjna rozpoznaje w jakim trybie się uruchomiła i wybiera jeden z dwóch rozłącznych światów: jeśli istnieje stała MERIDA_SEARCH_REDIS_HOST - znaczy, że jesteśmy w SHORTINIT i cała konfiguracja leci z constów (early return). Dopiero gdy stałych nie ma, sprawdza czy get_option() w ogóle istnieje i wtedy czyta z bazy.

Albo jedno, albo drugie - nigdy mix. Niestandardowe podejście, ale działa zaskakująco dobrze.

Benchmarki z taniego VPSa

Całość testowałem na tanim VPSie z procesorem ~2 GHz. Celowo nie na rakiecie - chciałem zobaczyć jak to wygląda w realistycznych warunkach sklepu, który nie wydaje fortuny na hosting.

Pierwsze obserwacje

Zastrzeżenie: to są wyrywkowe requesty z DevTools, nie pełny benchmark. Pełne testy wydajnościowe planuję dopiero po potwierdzeniu usability - czyli po sprawdzeniu, że wyniki wyszukiwania faktycznie mają sens dla użytkownika. Na razie testuję czy architektura się trzyma.

Co widzę na tym etapie? Mediana czasu odpowiedzi autocomplete (pełny cykl: klient, serwer, Redis, odpowiedź) to okolice 50-60 ms. ~80% requestów poniżej 90 ms. Sam Redis odpowiada praktycznie zawsze poniżej 10 ms - wąskim gardłem jest sieć, nie aplikacja.

Trzy pomysły, które zrobiły różnicę

Nie chcę robić z tego pełnego tutoriala (jeszcze nie teraz), ale parę konceptów warto zasygnalizować, bo mogą Ci się przydać nawet w innym kontekście.

Najpierw dokładnie, potem luźniej

Zamiast od razu odpalać fuzzy search (który jest wolniejszy i zbyt liberalny - “mydło” fuzzy-matchuje “masło”), stosuję trzy przejścia:

  1. Dokładne dopasowanie - suszarka* - szukaj słów zaczynających się od wpisanej frazy. Najszybsze i najcelniejsze.
  2. Odchudzenie zapytania - usunięcie słów, które nic nie wnoszą (“do”, “na”, “z”) i ponowne szukanie
  3. Łapanie literówek - %suszarka% - dopuszcza drobne błędy w pisowni, odpala się TYLKO gdy wcześniejsze przejścia nic nie zwróciły

Kluczowa zasada: jeśli dokładne dopasowanie daje wyniki, łapanie literówek nigdy się nie odpala. Zero zbędnej pracy.

Podwójna normalizacja polskich znaków

Tytuł jest indeksowany podwójnie: z diakrytykami (Suszarka do rąk) i bez (Suszarka do rak). Dzięki temu użytkownik wpisujący “rak” matchuje “rąk”. W polskim e-commerce to konieczność - klienci notorycznie pomijają polskie znaki w wyszukiwarkach.

Korekta kolejności wyników

RediSearch sortuje wyniki po tym, jak dobrze pasują do zapytania tekstowo. Ale nie wie nic o kontekście sklepu. Dlatego po odpowiedzi z Redisa, PHP nakłada korekty: dokładne trafienie w numer katalogowy (SKU) ląduje na górze, produkty niedostępne spadają w rankingu, promowane idą wyżej, a tytuł zaczynający się od szukanej frazy dostaje bonus.

Redis zwraca 5x więcej kandydatów niż potrzeba, PHP przelicza score i przycina do limitu.

Kiedy to ma sens?

Bądźmy szczerzy - dla 90% sklepów WooCommerce to overkill. Jeśli masz 200 produktów i kilkudziesięciu użytkowników dziennie, FiboSearch w wersji darmowej lub pro załatwi sprawę.

To podejście zaczyna mieć sens, gdy:

Na współdzielonym hostingu będzie to mocno utrudnione - większość dostawców nie oferuje Redis z modułem Search, a nawet jeśli Redis jest dostępny, załadowanie własnych modułów zazwyczaj nie wchodzi w grę. VPS lub serwer dedykowany daje tu pełną swobodę.

Co dalej?

To dopiero początek eksploracji. W planach mam:

Jeśli temat Cię zainteresował, chcesz pogadać o WooCommerce albo masz pytania - znajdziesz mnie na LinkedIn. Możesz też zostawić komentarz pod tym postem.


Jeśli interesuje Cię szersza perspektywa na optymalizację WooCommerce, zapraszam do artykułu Prosta recepta na szybki WooCommerce.

Zajmuję się na co dzień architekturą wydajności dla sklepów WooCommerce w ramach SHIFT64. Jeśli Twój sklep mógłby działać szybciej - zajrzyj, może będziemy mogli sobie pomóc.

Mateusz Zadorożny
Mateusz Zadorożny

Od 2012 roku moja praca przeplata się z WordPressem. Od 2017 pracuję z WooCommerce, bardzo dużo czasu poświęcając na testowanie różnych konfiguracji i rozwiązań. Łączę development z digital marketingiem tak, aby w e-commerce osiągnąć maksymalną skuteczność.

O mnie →
Zmień ustawienia prywatności Built with Astro