Skip to content

Szybka wyszukiwarka WooCommerce - eksperyment z RediSearch i SHORTINIT

Published: at 17:36

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. Nie jest to osobna baza danych - to rozszerzenie Redis, które 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:

Jeśli Twój sklep stoi na współdzielonym hostingu - zapomnij. RediSearch wymaga dostępu do serwera na poziomie root.

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.


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