Każdy poradnik o klastrach tematycznych zaczyna się od listy słów kluczowych. Lista słów kluczowych działa, dopóki strony jeszcze nie istnieją. W serwisie z 2 400 opublikowanymi stronami trudne pytanie brzmi inaczej: które z tych stron już do siebie należą, które oddaliły się tematycznie od swojego klastra i czy Twoje linki wewnętrzne w ogóle podążają za tematami?
Lista słów kluczowych na to nie odpowie, bo opisuje popyt w wyszukiwarce, a nie Twój serwis. Dlatego w dużych serwisach klastry mierzę, zamiast je planować: z tekstu każdej strony i z linków, które redaktorzy umieścili w tym tekście. Te dwa podejścia nazywam projektem i inwentaryzacją. Projekt mówi, co chcesz zbudować. Inwentaryzacja zapisuje to, co już stoi.
W tym wpisie opisuję metodę inwentaryzacji, którą prowadzę na jednym serwisie firmy software’owej B2B – z prawdziwymi parametrami, progami, przebiegami, które wyrzuciłem, oraz z tym, co każdy test udowadnia, a czego nie.
Najważniejsze wnioski
- 38,7% angielskich linków w treści zostaje w zmierzonym klastrze, wobec 3,2–4,0% przy przetasowanych etykietach – klastry zgadzają się z tym, jak linkują redaktorzy.
- 0,882 AUC na 444 parach stron połączonych linkiem już po wyborze sposobu liczenia embeddingów: strony z linkiem leżą bliżej siebie niż pary losowe.
- 33–41% stron usług wpada do szumu przy najstabilniejszych ustawieniach (ARI 0,95–0,97), więc wybrałem mniej stabilne, które traci 14%.
- 4 akcje, jedna na stronę – zostaw, rozbuduj, przenieś, przejrzyj do usunięcia – wynikają z dopasowania do klastra i danych z Search Console; usuwa człowiek.
- 3 miejsca, w których klastry zmieniają tworzenie treści: podpowiedzi linków, ostrzeżenia o pokrywaniu się w briefach i kandydaci do scalenia ze wspólnym popytem.
Czym jest klaster tematyczny i jak pomaga w SEO?
Klaster tematyczny (topic cluster) to strona filarowa (pillar page) o szerokim temacie plus strony, które rozwijają jej podtematy, połączone linkami wewnętrznymi w obie strony. Jeśli chcesz standardowe omówienie, dobrze robią to poradnik Semrusha o klastrach tematycznych i dziesięciominutowa wersja Ahrefs, a Semrush ma osobny tekst o stronach filarowych. Wszystkie trzy są po angielsku.
Argument za klastrami w SEO opiera się na dwóch mechanizmach. Pierwszy to odkrywanie i kontekst: Google znajduje strony i rozumie, jak się ze sobą wiążą, dzięki linkom, które da się crawlować, z opisowym anchorem (Google Search Central). Drugi to topical authority, czyli autorytet tematyczny: założenie, że serwis, który dokładnie pokrywa temat, zyskuje w nim większe zaufanie. Ahrefs ma dobre wyjaśnienie topical authority. Traktuję je jako model roboczy, bo nikt spoza Google nie zmierzy tego bezpośrednio.
Strony z czołówki wyników zgadzają się co do definicji i prawie wszystkie opisują ten sam proces: wybierz temat, zbadaj słowa kluczowe, pogrupuj je, przypisz do stron, napisz, podlinkuj.
Projekt czy inwentaryzacja: czego potrzebuje Twój serwis?
Projekt to właściwe narzędzie, gdy strony jeszcze nie istnieją. Inwentaryzacja – gdy już istnieją. Klasteryzacja słów kluczowych – grupowanie zapytań, dla których rankują te same adresy, jak w poradnikach Ahrefs i Semrusha – to metoda projektowa. Mówi, co zbudować i która strona ma celować w które zapytania. Nie powie Ci, które z 2 400 istniejących stron należą do siebie, które oddaliły się tematycznie od swojego klastra ani czy Twoje linki prowadzą między różnymi klastrami tematycznymi.
| Sytuacja | Metoda | Dane wejściowe | Na co odpowiada |
|---|---|---|---|
| Nowa sekcja, jeszcze bez stron | Projekt: klasteryzacja słów kluczowych | Lista słów kluczowych, wspólne wyniki w SERP | Co zbudować i która strona celuje w które zapytania |
| Ponad 1 000 istniejących stron | Inwentaryzacja: klasteryzacja na danych z crawla | Eksport z crawla, tekst stron, Search Console | Które strony należą do siebie, które oddaliły się od swojego klastra, które linki prowadzą do innych klastrów, co zrobić z każdą stroną |
Inwentaryzacja ma pięć kroków:
- Crawl – wyeksportuj tekst stron, kody odpowiedzi i każdy link umieszczony w treści.
- Embeddingi – zamień tekst każdej strony na wektor, tak żeby strony o podobnym znaczeniu leżały blisko siebie.
- Klasteryzacja – pogrupuj wektory w tematy i nazwij je.
- Walidacja – sprawdź klastry na grafie linków w treści, którego klasteryzacja nigdy nie widziała.
- Działanie – nadaj każdej stronie rolę i jedną akcję, a klastry przekaż do podpowiedzi linków, briefów i scaleń.
Można ją zrobić na dwa sposoby. Wersja lekka nie wymaga kodu: wyeksportuj z crawlera linki w treści, przypisz stronom klastry, które Twoim zdaniem masz, i policz, ile linków zostaje wewnątrz jednej etykiety. Jeśli ten odsetek jest niski, Twój projekt i Twój serwis poszły w różne strony. Pełna wersja – embeddingi, UMAP, HDBSCAN, role i akcje – wymaga Pythona i to ją opisuję w dalszej części wpisu.
Rysunek 1 Inwentaryzacja na jednym obrazku
Metoda1 · Dane wejściowe
2 · Jedna baza
3 · Inwentaryzacja
4 · Tworzenie treści
Search Console nigdy nie dotyka wektorów, a linki nigdy nie dotykają klasteryzacji – dzięki temu test linków pozostaje niezależny. Wszystko dalej czyta z jednego zrzutu bazy, więc podpowiedź linku, brief i scalenie widzą ten sam serwis.
Tak wygląda inwentaryzacja jednej strony. Wpis blogowy z listą znanych firm, które korzystają z progresywnych aplikacji webowych (PWA), ma wektor tekstu, który trafia do klastra Aplikacje webowe, z podobieństwem 0,608 do jego środka – to strona Expansion, na skraju swojego tematu. Jego podobieństwo do środka klastra Aplikacje mobilne wynosi 0,644, czyli o 0,036 więcej. Reguły robią z niego kandydata do przeniesienia, a redaktor decyduje, co to znaczy: podlinkować go ze stron o aplikacjach mobilnych albo przepisać jako tekst o aplikacjach webowych.
Skąd pochodzą liczby
Każda liczba w tym wpisie pochodzi z jednego serwisu, więc dokładnie opisuję, co to za serwis i co to za dane.
- Serwis – firma software’owa B2B: blog, strony usług i słownik pojęć. Bieżący przebieg obejmuje 2 436 adresów URL, z czego 2 302 po angielsku. Mniejszą sekcję w drugim języku (134 strony) rzutuję na angielskie klastry i nigdy nie klastruję osobno.
- Okres danych – cotygodniowy crawl Screaming Frogiem od 28 września 2026. Pełny przebieg 2 (30 września) to zaakceptowany punkt odniesienia, przebieg 9 (27 października) to ostatnia cotygodniowa aktualizacja. Testy powtórzone na potrzeby tego wpisu korzystają z crawla z 27 października.
- Search Console – kliknięcia, wyświetlenia i średnia pozycja każdej strony z 30 dni przychodzą z każdym crawlem i na tym oknie opierają się akcje. Dane na poziomie zapytań do scaleń pobieram z Search Analytics API za 12 miesięcy wstecz.
- Narzędzia – Screaming Frog SEO Spider do crawla i eksportu tekstu, Python, sentence-transformers do embeddingów, umap-learn, scikit-learn (HDBSCAN, ARI, ROC AUC), SciPy do dopasowania klastrów oraz Postgres z pgvector na Supabase jako baza.
- Ograniczenia – jeden serwis, jedna branża, w większości jeden język. Każdy próg poniżej jest skalibrowany na tym serwisie. Na swoim powtórz testy, zanim skopiujesz liczby.
Co wykluczyć przed klasteryzacją?
Wyklucz każdy adres bez własnego tekstu i każdy link, który dokłada szablon. Jedno i drugie tworzy strukturę, która nic nie mówi o tematach.
Najgorsze są archiwa. W moim pierwszym przebiegu archiwa autorów, tagów i paginacji utworzyły dwa największe „klastry” w serwisie, 331 i 114 stron, ze spójnością 0,92–0,98. Tak wysoka spójność jest podejrzanie idealna, a powód jest prosty: crawler nie wyciąga z nich ani jednego słowa, więc ich wektory lądują jeden na drugim. Z 1 284 stron, które pierwotny brief wymieniał jako brakujące w inwentarzu treści, 753 były archiwami.
Moje reguły zakresu:
- Zakres – zostaw tylko sekcje, do których i z których linkuje Twój proces tworzenia treści. Tutaj to blog, strony usług i słownik pojęć.
- Kody odpowiedzi – zostaw każdy kod z zakresu (200, 301, 404, noindex). Klastruję tylko strony indeksowalne, ale kolejne kroki muszą wiedzieć, że strona teraz przekierowuje, zanim podpowiedzą link do niej.
- Tekst – odrzuć strony bez wyciągniętego tekstu i przed liczeniem embeddingów usuń każde zdanie, które powtarza się na 20 lub więcej stronach.
- Linki – licz tylko linki umieszczone w treści (pozycja linku „Content” w Screaming Frog). Menu, stopki i okruszki zostają poza analizą. Rotujące kafelki „najnowsze wpisy” liczę osobno.
Reguła o linkach waży więcej, niż się wydaje. W inwentarzu linków, który mój proces tworzenia treści już miał, 72% stanowiły linki nawigacyjne. Menu na całej stronie łączy każdą stronę z każdą inną, co pomaga w crawlowaniu i nic nie mówi o tematach.
Jak zamienić tekst strony na wektory, które oddają tematy?
Każda strona dostaje dwa wektory z modelu paraphrase-multilingual-MiniLM-L12-v2: jeden dla nagłówka (title, H1 i meta description) i jeden dla treści, czyli znormalizowaną średnią z najwyżej 12 fragmentów po 100 słów. Oba wektory jednostkowe dodaję z równą wagą i normalizuję sumę. Przed podziałem na fragmenty usuwam każde zdanie, które powtarza się na 20 lub więcej stronach – ramki newslettera, CTA i formułki prawne, które inaczej zbliżałyby do siebie niepowiązane strony. Limit 12 fragmentów sprawia, że długi poradnik nie zagłusza własnego głównego tematu.
Ten przepis wybrałem, testując go na linkach samego serwisu. Dla każdej pary stron połączonych linkiem w treści i dla tej samej liczby losowych par liczę podobieństwo kosinusowe (cosine similarity) i sprawdzam, jak dobrze ta jedna liczba rozdziela obie grupy. ROC AUC to prawdopodobieństwo, że losowa para połączona linkiem dostanie wyższy wynik niż losowa para bez linku: 0,5 oznacza brak sygnału, 1,0 idealne rozdzielenie (scikit-learn). Kandydaci, ocenieni na crawlu z 28 września:
| Reprezentacja | MiniLM-L12 wielojęzyczny | e5-small |
|---|---|---|
| Tylko title, H1 i meta | 0,795 | 0,789 |
| Tylko fragmenty treści | 0,858 | 0,847 |
| Title, H1 i meta + treść | 0,870 | 0,833 |
Większość sygnału niesie treść, a nagłówek dokłada do tego trochę. e5-small nie był lepszy i działał dwa razy wolniej.
Ta tabela wybrała zwycięzcę i oceniła go na tych samych parach, więc mu schlebia. Powtórzenie jej na późniejszym crawlu tego nie naprawia, bo większość linków w serwisie się nie zmienia. Czysty test to linki, których jeszcze nie było: 444 pary angielskich stron połączone linkiem w crawlu z 27 października, ale nie z 28 września, więc nie brały udziału w wyborze. Na tle 444 losowych par zapisane wektory uzyskują 0,882 (95% przedział bootstrap 0,86–0,91). Przepis trzyma się na linkach, których nigdy nie widział.
Powtórzenie testu na pełnym grafie linków z 27 października odpowiedziało na pytanie, którego wcześniej nie sprawdziłem. MiniLM czyta najwyżej 128 tokenów, a 100-wyrazowy fragment jest dłuższy w 90% przypadków (mediana 145 tokenów), więc model nie widzi mniej więcej ostatniej ósmej części każdego fragmentu. Na 13 395 parach z linkiem i tylu samo losowych cięcie fragmentów co 120 tokenów zamiast co 100 słów zmieniło AUC z 0,885 na 0,886. Obcinanie prawie nic tu nie kosztuje, więc zostałem przy fragmentach po 100 słów – to pragmatyczna decyzja dla angielskich stron tego serwisu, a nie reguła dla dłuższych tekstów czy innych języków.
Dwa zastrzeżenia. Wynik pochodzi z jednego serwisu, to nie benchmark – inny miks języków albo typów stron może faworyzować inny model. Do tego test ufa Twoim redaktorom: w serwisie, w którym linków w treści jest mało albo stawiano je byle jak, AUC powie Ci mniej.
Które ustawienia UMAP i HDBSCAN dały użyteczne klastry tematyczne?
Używam UMAP z 15 sąsiadami, redukcji do pięciu wymiarów (min_dist 0, metryka kosinusowa), a potem HDBSCAN z min_cluster_size=20 i min_samples=3, uruchamianego z trzema ziarnami losowania (seed 0, 1 i 2). UMAP kompresuje każdy 384-wymiarowy wektor, zachowując bliskich sąsiadów blisko. HDBSCAN znajduje klastry jako gęste obszary, a strony pomiędzy nimi zostawia jako szum (noise) – strony, których nie przypisuje do żadnego klastra.
Stabilność mierzę skorygowanym indeksem Randa (Adjusted Rand Index, ARI): jak bardzo zgadzają się dwa podziały, gdzie 1,0 oznacza identyczne, a 0 – zgodność przypadkową (scikit-learn). Porównuję seed 0 z seedem 1 i seed 0 z seedem 2, na stronach, które oba przebiegi przypisały do jakiegoś klastra.
Na potrzeby tego wpisu powtórzyłem przegląd parametrów na bieżących wektorach: 2 302 angielskie strony, 12 ustawień, po trzy seedy na każde.
| Ustawienie (sąsiedzi / min_cluster_size / min_samples) | Klastry | Szum | Strony usług w szumie | Największy klaster | Średnie ARI |
|---|---|---|---|---|---|
| 15 / 20 / 3 – wybrane | 39 | 15% | 14% | 7% | 0,87 |
| 15 / 20 / None | 30 | 25% | 33% | 11% | 0,95 |
| 30 / 40 / None | 10 | 31% | 41% | 15% | 0,97 |
| 15 / 40 / None | 11 | 27% | 28% | 31% | 0,72 |
Najstabilniejsze ustawienia przegrały. Gdy min_samples nie jest ustawione, przyjmuje wartość min_cluster_size, co podbija ARI do 0,95–0,97 – i wrzuca do szumu co najmniej jedną trzecią stron usług. Strony usług to strony sprzedażowe, dla których cały audyt klastrów w ogóle się robi, więc oddałem kilka punktów powtarzalności, żeby zostały na mapie. Podniesienie min_cluster_size do 40 zawiodło w drugą stronę: bez min_samples jeden klaster połknął 31% stron, a do tego przebiegi przestały się ze sobą zgadzać (ARI 0,78). Pierwotny przegląd na crawlu z 28 września ułożył ustawienia w tej samej kolejności.
Rysunek 2 Najstabilniejsze ustawienie nie jest tym użytecznym
EksperymentKażdy punkt to jedno ustawienie, uśrednione z trzech seedów; wybrane 15/20/3 zostawia w szumie najmniej stron usług. Wykres pokazuje, co ustawienie robi ze stronami usług, a nie które tematy są właściwe.
Jeszcze jedna lekcja z przeglądu: test linków z następnej sekcji nie wybierze parametrów sam. Grubsze mapy trzymają więcej linków wewnątrz klastrów po prostu dlatego, że klastry są większe – ustawienie 30 / 40 / 3 zatrzymuje w klastrach 51% linków, a jeden klaster obejmuje jedną trzecią serwisu. Dlatego każdy pełny przebieg musi też przejść dwa zabezpieczenia, zanim go przejrzę: największy klaster może obejmować najwyżej 15% stron, a szum nie może przekroczyć 35%. Oba to moje robocze limity, a nie opublikowane standardy.
Zaakceptowany przebieg produkcyjny, pełny przebieg 2, dał 40 klastrów, 12,9% szumu, największy klaster na 10% stron i ARI 0,82 (seed 0 kontra 1) oraz 0,89 (seed 0 kontra 2). Jego liczby różnią się od wyników przeglądu, bo to inny pomiar: wcześniejszy zrzut danych plus krok podziału drugiego poziomu, opisany niżej. Z tego samego powodu przegląd pokazuje 39 klastrów, a przebieg 2 ma ich 40. Przebieg 9, bieżący, zachowuje 40 klastrów z przebiegu 2, bo cotygodniowy przebieg nigdy nie klastruje od nowa.
W efekcie powstaje mapa 40 nazwanych tematów. Kilka klastrów z tego serwisu:
- Sztuczna inteligencja – największy klaster, 233 angielskie strony, niestabilny między seedami: duży, luźny temat.
- Aplikacje webowe – 144 angielskie strony i najniższa spójność w serwisie (0,662).
- Aplikacje mobilne – jedyny duży klaster, który czysto podzielił się na dwa: natywne aplikacje mobilne i aplikacje wieloplatformowe.
- E-commerce – obszar handlu internetowego rozpadł się na cztery mniejsze klastry między przebiegiem 1 a 2.
- Cyberbezpieczeństwo – 67 stron.
- SaaS i MVP – po 20 stron i jedne z najbardziej zwartych tematów (spójność 0,845 i 0,797).
- Aktualności i historia firmy – 49 angielskich wpisów blogowych i ani jednej strony usługi.
Nazwy podlegają jednej regule: krótka fraza nazywająca temat stron, a nie lista najczęstszych słów. Jedno wywołanie modelu językowego proponuje nazwy dla wszystkich klastrów naraz, skrypt sprawdza każdą według reguł nazewnictwa, a nazwy nadanej przez redaktora nic nie nadpisuje.
Rysunek 3 Aplikacje webowe się rozlewają, aplikacje mobilne trzymają się razem
Bieżący przebiegKażdy punkt to angielska strona; szare punkty to szum. Mapa to rzut 2D tylko do czytania – klasteryzacja działa w pięciu wymiarach, a role w 384, więc odległości są tu poglądowe.
Jak sprawdzić klastry tematyczne linkami wewnętrznymi?
Klastry są bardziej wiarygodne, gdy zgadza się z nimi niezależny sygnał. W zaakceptowanym pełnym przebiegu 38,7% angielskich linków w treści łączy dwie strony z tego samego klastra – 5 395 z 13 940 linków między angielskimi stronami w zakresie. Link, który dotyka strony z szumu, liczę jako link poza klastrem.
Punktem odniesienia jest permutacja, a nie wzór. Każdy link zostawiam dokładnie tam, gdzie jest – te same strony źródłowe, te same strony docelowe, strony z szumu dalej w szumie – i tasuję etykiety klastrów między stronami, które klaster mają. Tasowanie zachowuje prawdziwy kształt grafu linków i prawdziwe rozmiary klastrów, a zrywa tylko związek między stroną a jej tematem. W 1 000 przetasowań udział linków wewnątrz klastra wynosi średnio 3,6%, 95% przetasowań mieści się między 3,2% a 4,0%, a najwyższy wynik to 4,3%. Ten zakres to rozrzut wyników losowych, a nie przedział ufności dla prawdziwego udziału – a 38,7% jest od niego bardzo daleko.
Ten test dowodzi niewiele i warto to powiedzieć precyzyjnie. Klastry zgadzają się z tym, jak redaktorzy podlinkowali serwis. Test nie dowodzi, że tematy są semantycznie trafne, że Google grupuje strony tak samo ani że więcej linków wewnątrz klastrów podniesie pozycje. ARI też tej luki nie wypełni: pokazuje tylko, że powtórzone przebiegi zgadzają się ze sobą, a podział może być stabilny i mimo to grupować nie te strony, co trzeba. Linki są lepszym świadkiem niż ARI, bo redaktorzy stawiali je dla czytelników, na długo zanim powstał jakikolwiek embedding.
Rysunek 4 Linki zostają w obrębie swojego tematu
WalidacjaWiersze to klaster strony linkującej, kolumny – klaster strony docelowej, od największego klastra; kolor komórki to udział linków danego wiersza, więc duże klastry nie dominują samym rozmiarem. Siatka pomija linki dotykające szumu, dlatego na przekątnej jest 46% linków. Gdy te linki liczymy jako wychodzące poza klaster, bieżący przebieg 9 zatrzymuje w klastrach 38,5% linków, wobec 38,7% w zaakceptowanym przebiegu 2, który podaję wyżej. Najjaśniejsze kolumny to Sztuczna inteligencja, do której trafia 12,5% wszystkich linków między tematami, oraz klaster stron usług, do którego linkują wpisy z wielu tematów – i do tego właśnie służą linki do usług.
Tego samego testu używam do wyboru między pełnymi przebiegami:
| Pełny przebieg | Klastry | Szum | Linki w tym samym klastrze | Przetasowane etykiety (zakres 95%) | Decyzja |
|---|---|---|---|---|---|
| Przebieg 2 | 40 | 12,9% | 38,7% | 3,2–4,0% | Zaakceptowany |
| Przebieg 4 | 43 | 17,6% | 31,0% | 2,1–2,7% | Odrzucony |
Rysunek 5 Zaakceptowany przebieg wygrywa z odrzuconym w teście linków
EksperymentOba wyraźnie przewyższają swoje przetasowane punkty odniesienia; przebieg, który lepiej pasuje do grafu linków, staje się zaakceptowaną mapą, o ile przechodzi też zabezpieczenia.
Przebieg 4 użył tych samych seedów co przebieg 2 i tych samych zapisanych wektorów dla każdej niezmienionej strony; między crawlami zmieniło się około 22 stron. Nie był mniej stabilny między seedami (ARI 0,92 i 0,85), więc stabilność nie rozróżniła tych dwóch przebiegów. Rozróżnił je test linków, choć w węższym sensie niż „przebieg 2 jest prawdziwy”: według tej metryki przebieg 2 lepiej zgadza się z linkami, które postawili redaktorzy. Na tym twierdzeniu opieram decyzję. Nie wiem, które z 22 stron zmieniły wynik – nie izolowałem tego – ale wiem, że UMAP reaguje na drobne zmiany na wejściu: na tych samych stronach samo zaokrąglenie zapisanych wektorów do sześciu miejsc po przecinku zmieniło jeden przebieg z 41 klastrów na 39.
Test działa tylko wtedy, gdy linki stawiali ludzie. Jeśli linki w Twojej treści pochodzą z widżetu powiązanych wpisów opartego na tagach, nie masz niezależnego sygnału, na którym można testować.
Kiedy dzielić klaster dalej?
Dziel klaster tylko wtedy, gdy podział przetrwa zmianę seeda. Każdy klaster większy niż 5% angielskich stron klastruję jeszcze raz osobno (UMAP 15, HDBSCAN 12/3) i zostawiam podział tylko wtedy, gdy średnie ARI między seedami wynosi co najmniej 0,8 – to mój roboczy próg, a nie opublikowany.
W przebiegu 2 przeszły tylko aplikacje mobilne: 182 strony w dwóch klastrach, ARI 0,98 i 1,0. Sztuczna inteligencja (0,63 / 0,54), aplikacje webowe (0,28 / 0,52) i e-commerce (0,75 / 0,81) zostały w całości. Wymuszony podział e-commerce na siedem części z przebiegu 1 nie powtórzył się przy innych seedach. Czasem jeden duży, nieuporządkowany klaster to uczciwa odpowiedź, a strona filarowa z wyraźnymi sekcjami obsłuży go lepiej niż siedem wymyślonych podtematów.
Które strony to Core, Focus, Expansion, a które Outlier?
Rolę strony wyznacza jej podobieństwo kosinusowe do centroidu klastra, porównane z dwoma progami zamrożonymi w przebiegu kalibracyjnym 1: Core od 0,766 w górę, Focus od 0,690 do 0,766. To mediana i 25. percentyl z tamtego przebiegu. Strony klastra poniżej 0,690 to Expansion. Outliery to strony, które HDBSCAN zostawił w szumie.
Centroid to średni wektor stron klastra. Podobieństwo liczę w pełnej, 384-wymiarowej przestrzeni, a nie na mapie 2D.
W pierwszej wersji progi wyznaczałem osobno dla każdego przebiegu, z kwantyli jego własnego rozkładu. Takie progi zepsuły metrykę. Próg z kwantyla z założenia ustala udział każdej roli, więc w każdym przebiegu około 75% stron trafiało do Core i Focus, niezależnie od tego, co działo się z treścią. Przy zamrożonych progach dryf widać jako strony, które je przekraczają.
| Rola | Reguła | Angielskie strony, przebieg 9 |
|---|---|---|
| Core | podobieństwo ≥ 0,766 | 999 |
| Focus | 0,690 – 0,766 | 502 |
| Expansion | strona klastra poniżej 0,690 | 507 |
| Outlier | szum HDBSCAN | 294 |
Rysunek 6 Zamrożone progi pokazują dryf
Bieżący przebiegPrzerywane linie na 0,690 i 0,766 nigdy się nie przesuwają; późniejszy przebieg, którego rozkład przesuwa się w lewo, widać jako strony przekraczające te linie. Strony z szumu nie mają centroidu i nie ma ich na wykresie.
Strony Core i Focus zbierają 58,8% kliknięć. Wahania o 2–3 punkty traktuj jako szum: samo zaokrąglenie zapisanych wektorów zmieniło kiedyś tę liczbę z 62,4% na 60,0%. Rola diagnozuje dopasowanie, a nie wartość – strony Expansion i Outlier wciąż zbierają mniej więcej cztery kliknięcia na dziesięć.
Dwa klastry pokazują, co mówią role. Aplikacje webowe mają 150 stron (razem ze stronami w drugim języku), a 78 z nich to Expansion: szeroki temat, którego strony rozlały się w stronę sąsiednich. SaaS ma 20 stron, z czego 17 to Core: mały, zwarty i gotowy. Pierwszy potrzebuje redakcyjnej struktury. Drugi nie potrzebuje niczego.
Które strony zostawić, rozbudować, przenieść, a które przejrzeć do usunięcia?
Każda strona dostaje jedną z czterech akcji według uporządkowanych reguł, a decyduje pierwsza reguła, która pasuje. Akcje to: zostaw, rozbuduj, przenieś i przejrzyj do usunięcia. W nawiasach w tabeli podaję ich nazwy z systemu, który zwraca je po angielsku. Każdy próg to moja robocza reguła, dostrojona na tym serwisie, więc traktuj go jako punkt wyjścia, a nie stałą.
| Akcja | Reguła | Przebieg 9 |
|---|---|---|
| Przenieś (relocate) | bliżej centroidu innego klastra o 0,02 lub więcej (mój roboczy margines) albo w szumie, ale podobna do najbliższego centroidu na poziomie Core | 156 |
| Przejrzyj do usunięcia (prune) | tylko wpisy blogowe, Expansion lub Outlier, 0 kliknięć i 0 wyświetleń w 30 dni | 5 |
| Rozbuduj (grow) | strona usługi bez linku w treści ze swojego klastra albo ponad 1 000 wyświetleń w 30 dni przy średniej pozycji strony od 10 do 20 | 228 |
| Zostaw (keep) | wszystko pozostałe | 2 047 |
Cztery liczby sumują się do wszystkich 2 436 adresów w przebiegu. Granica 1 000 wyświetleń to 75. percentyl tego serwisu.
Przeniesienie idzie pierwsze, bo każda kolejna reguła zakłada, że stronę ocenia się we właściwym temacie. W klastrze Aplikacje webowe 31 ze 150 stron to kandydaci do przeniesienia – wśród nich wpis o PWA z początku tego artykułu.
Przegląd do usunięcia jest celowo wąski i nigdy nie jest automatyczny. Trzydzieści dni bez kliknięcia i wyświetlenia to powód, żeby się przyjrzeć, a nie wyrok: strona może być nowa, sezonowa, rankować zbyt nisko albo mieć za mało danych. Przed każdą decyzją sprawdzam ostatnie 12 miesięcy strony, jej wiek, linki zewnętrzne i rolę, jaką pełni dla czytelników, a potem wybieram między scaleniem, przekierowaniem i zostawieniem jej w spokoju. Scalenie potrzebuje własnych dowodów, o których za chwilę.
Reguły musiałem zaostrzać, aż zaczęły wybierać. „Brak linku z własnego klastra” zastosowany do każdej strony oznaczał 73% serwisu, więc teraz dotyczy tylko stron usług – to 125 z 228 stron do rozbudowy. „Średnia pozycja gorsza niż 10” złapała 2 164 z 2 456 stron z wyświetleniami, więc rozbudowa wymaga teraz i realnego popytu, i pozycji tuż za pierwszą stroną wyników.
Aktualności i historia firmy to przypadek, którego reguły nie rozstrzygną za Ciebie. Z 50 stron 47 dostaje akcję „zostaw”: wpisy pasują do swojego tematu i reguły nie widzą w nich nic złego. Czy inwestować w temat, który nie prowadzi do żadnej strony usługi, to decyzja redakcyjna, a moja brzmi tutaj: mierz, ale nie rozbudowuj.
Jak klastry zmieniają tworzenie treści?
Zmierzone klastry zmieniają tworzenie treści w trzech miejscach: które linki wewnętrzne są podpowiadane, które briefy dostają ostrzeżenie o pokrywaniu się tematów i które pary stron kwalifikują się do scalenia.
Linki – do podobieństwa semantycznego każdego kandydata dodaję premię +0,05 za ten sam klaster. Wartość wybrałem przez odtworzenie na historycznych danych, a nie z teorii. Odtworzona na 80 opublikowanych artykułach premia podniosła udział linków z tego samego klastra w ośmiu najlepszych podpowiedziach z 51,5% do 71,0%, przy spadku średniego podobieństwa o 0,9%. Strony usług przesunęły się bardziej, z 43,4% do 65,1%. Ta liczba mierzy dopasowanie podpowiedzi do klastrów, a nie pozycje ani ruch. Premia +0,10 dała 77,0% przy stracie 2,1% – sześć punktów więcej za ponad dwukrotnie wyższy koszt – więc zostałem przy 0,05. Premia nie jest filtrem: wyraźnie lepsza strona z sąsiedniego klastra nadal może wygrać. Ta sama premia działa przy wyborze źródeł linków przychodzących, a każde źródło i każdy cel muszą w ostatnim crawlu zwracać 200 i być indeksowalne.
Tam, gdzie premia nie pomoże, system to mówi. Dla 49 ze 145 stron usług oznaczonych do rozbudowy 30 najbliższych kandydatów nie zawierało ani jednej strony z ich własnego klastra. Takie strony potrzebują nowej treści albo ręcznego linku, a nie lepszej formuły rankingowej.
Briefy – brief pokazuje sąsiadów planowanej strony z podobieństwem 0,6 lub wyższym. Poniżej to już szum: szkic o doradztwie w zakresie Kubernetesa dostawał w podpowiedziach wpisy o brandingu z podobieństwem 0,16–0,28. Każda istniejąca strona z podobieństwem 0,9 lub wyższym, mniej więcej 5% najbardziej podobnych par, uruchamia ostrzeżenie o pokrywaniu się tematów. Dwa niemal identyczne wpisy o headless e-commerce miały 0,905. Oba progi pochodzą z rozkładu tego serwisu, a nie z jakiegoś standardu.
Scalenia – samo podobieństwo nigdy nie uzasadnia scalenia. Para potrzebuje też współdzielonego popytu: dla każdego zapytania, na które w Search Console pokazują się obie strony, weź mniejszą z ich dwóch liczb wyświetleń, zsumuj to za 12 miesięcy i podziel przez wszystkie wyświetlenia mniejszej strony. Wynik 0,3 oznacza, że 30% widoczności mniejszej strony pochodzi z zapytań, na które pokazuje się też jej siostra. Powtórzone na potrzeby tego wpisu na blogu i słowniku pojęć:
| Pary stron (podobieństwo kosinusowe) | Sprawdzone pary | Współdzielony popyt ≥ 0,1 | ≥ 0,3 |
|---|---|---|---|
| Pary losowe (0,55–0,70) | 40 | 0% | 0% |
| 0,85–0,88 | 209 | 43% | 19% |
| 0,88–0,90 | 63 | 57% | 32% |
| 0,90–0,92 | 25 | 56% | 40% |
| ≥ 0,92 | 17 | 76% | 47% |
Trend idzie w jedną stronę: im bliżej siebie leżą dwie strony w przestrzeni embeddingów, tym częściej dzielą się prawdziwymi zapytaniami. Search Console nigdy nie widziało moich wektorów, więc to drugi niezależny test. Dwa najwyższe przedziały to 25 i 17 par, więc czytaj je jako kierunek, a nie dokładny odsetek.
Moje progi, znów według moich własnych reguł: scalenie przy podobieństwie od 0,85 i współdzielonym popycie od 0,3, obserwacja przy 0,1–0,3, przegląd przy podobieństwie od 0,9 i współdzielonym popycie poniżej 0,1. Zostaje strona z największą liczbą kliknięć w 12 miesięcy, potem wyświetleń, potem linków w treści.
Jak często aktualizować klastry tematyczne?
Klastrować od nowa może tylko jedno zadanie: comiesięczny pełny przebieg, zapisywany jako szkic, który akceptuję albo odrzucam. Cotygodniowe zadanie nigdy nie klastruje od nowa. Każdą niezmienioną stronę zostawia tam, gdzie umieścił ją zaakceptowany przebieg – szum zostaje szumem – a do najbliższego centroidu wysyła tylko nowe strony i strony, których tekst się zmienił. Strona dołącza do klastra tylko wtedy, gdy jej podobieństwo przekracza próg projekcji: 10. percentyl podobieństw stron klastra w zaakceptowanym pełnym przebiegu, czyli 0,613. Poniżej progu strona zostaje w szumie do następnego pełnego przebiegu.
Ten podział jest mi potrzebny, bo pełny przebieg się przesuwa, nawet gdy serwis prawie się nie zmienia, co pokazał przebieg 4.
Wykrywanie zmian musi patrzeć na tekst, z którego liczysz embeddingi. Hash HTML w Screaming Frog różnił się na 11 671 z 11 673 stron HTML między dwoma crawlami, choć tekst był identyczny – CMS zmienia HTML przy każdej odpowiedzi. Naprawdę zmieniły się tylko 22 strony z zakresu. Projekcja oparta na tym hashu oznaczyła wszystkie 2 486 stron jako zmienione i ją odrzuciłem. Drugie zabezpieczenie odrzuca teraz każdy cotygodniowy przebieg, w którym więcej niż 25% znanych stron wygląda na zmienione: to sygnał zepsutego wykrywania zmian, a nie przepisanego serwisu.
| Przebieg | Typ | Wynik | Decyzja |
|---|---|---|---|
| 2 | Pełny | 40 klastrów, 12,9% szumu, 38,7% linków w tym samym klastrze | Zaakceptowany, punkt odniesienia |
| 3 | Cotygodniowy | hash HTML oznaczył każdą stronę jako zmienioną | Odrzucony |
| 4 | Pełny | 43 klastry, 17,6% szumu, 31,0% linków w tym samym klastrze | Odrzucony |
| 5 | Cotygodniowy | poprawka hasha wymazała też 22 prawdziwe zmiany | Odrzucony |
| 9 | Cotygodniowy | 8 nowych stron, 90 zmienionych, 24 przeniesione | Zaakceptowany, bieżący |
Tożsamość klastrów przetrwa kolejne przebiegi. Stare i nowe klastry dopasowuję algorytmem węgierskim na podstawie współczynnika Jaccarda dla ich stron: nakładanie się od 0,5 dziedziczy stary klucz, a nowy klaster, który bierze co najmniej połowę stron z jednego starego klastra, to podział. Wycofane klucze zostają w bazie, nigdy ich nie usuwam. Między przebiegiem 1 a 2 swój klucz zachowało 83% stron, a między seedami 38 z 43 klastrów dopasowało się z wynikiem od 0,5 w górę (mediana 0,93).
Wypróbowane i odrzucone: cotygodniowa klasteryzacja od nowa, hash HTML z crawlera do wykrywania zmian, przeliczanie progów ról w każdym przebiegu, osobna klasteryzacja drugiego języka i wymuszony podział e-commerce na siedem podtematów.
FAQ
Czym różni się klasteryzacja słów kluczowych od klastrów tematycznych?
Klasteryzacja słów kluczowych grupuje zapytania, zwykle według tego, ile wspólnych adresów pojawia się dla nich w wynikach, i podpowiada, która strona ma celować w które frazy. Klastry tematyczne w moim ujęciu grupują istniejące strony według ich tekstu. Pierwsze to plan stron, których jeszcze nie napisałeś. Drugie to pomiar stron, które już masz. Na dużym serwisie potrzebujesz obu, w tej kolejności: najpierw inwentaryzacja, potem plan na luki.
Czym jest mapa tematyczna (topical map)?
Mapa tematyczna to zaplanowana lista podtematów, które serwis powinien pokryć w danej dziedzinie, zwykle ułożona w strony filarowe i strony wspierające. To projekt. Inwentaryzacja pokazuje, na ile istniejący serwis do niego pasuje – które zaplanowane tematy mają już zwarty klaster, a które istnieją tylko na mapie.
Czy da się zbudować klastry tematyczne bez Pythona?
Tańszą połowę inwentaryzacji zrobisz bez kodu. Wyeksportuj z crawlera linki w treści (w Screaming Frog pozycja linku „Content”), przypisz każdej stronie klaster, do którego Twoim zdaniem należy, i policz, ile linków zostaje wewnątrz tej samej etykiety. Niski odsetek oznacza, że plan i serwis się rozjechały. Embeddingi, role i akcje wymagają już kodu albo narzędzia, które udostępnia embeddingi.
Czy do klastrów tematycznych potrzebujesz AI albo uczenia maszynowego?
Klasteryzacja to klasyczne uczenie maszynowe, nie generatywna AI. Embeddingi zdań, UMAP i HDBSCAN działają lokalnie na laptopie. Jedyne wywołanie modelu językowego w całym procesie proponuje nazwy klastrów, a skrypt sprawdza każdą nazwę według reguł nazewnictwa.
Dlaczego MiniLM-L12, a nie komercyjne API do embeddingów?
Bo uzyskał 0,882 na linkach dodanych już po tym, jak go wybrałem, działa lokalnie za darmo i nigdy nie wysyła tekstu stron klienta do zewnętrznej firmy. Nie porównywałem na tym serwisie embeddingów OpenAI ani innych komercyjnych modeli, więc nie twierdzę, że wypadłyby gorzej. Jeśli testujesz inny model, użyj tego samego AUC (pary połączone linkiem kontra pary losowe) na linkach, które nie brały udziału w wyborze, i zmieniaj model tylko wtedy, gdy wyraźnie wygrywa.
Co zrobić ze stronami, które HDBSCAN oznacza jako szum?
Czytaj szum jako „brak wyraźnego tematu”, a nie „zła strona”. Na tym serwisie często lądują tam strony usług, bo grupują się według szablonu, a nie tematu. Strony z szumu, które są podobne do najbliższego centroidu na poziomie Core, trafiają do przeniesienia. Wpisy blogowe z szumu z zerem kliknięć i zerem wyświetleń trafiają do przeglądu przed usunięciem. Reszta zostaje, a briefy biorą sąsiadów z najbliższych stron, nie tylko z członków klastra, więc strona z szumu i tak dostaje linki.
Jak obejść limity API Search Console na dużym serwisie?
Nie używam eksportu do BigQuery. Kliknięcia i wyświetlenia stron z ostatnich 30 dni przychodzą z każdym crawlem, przez połączenie crawlera z Search Console. Dane na poziomie zapytań pobieram z Search Analytics API tylko wtedy, gdy potrzebuje ich konkretny krok: wiersze strona × zapytanie za 12 miesięcy, stronicowane po 25 000 wierszy na żądanie i zapisywane w cache. API pomija zanonimizowane zapytania, więc współdzielony popyt mierzę na zapytaniach, które Google raportuje, a nie na wszystkich.
Ile trwa jeden przebieg i czy da się to skalować do 50 000 stron?
Na tym serwisie cotygodniowy crawl trwa około dwóch godzin, a eksport tekstu kolejne 40 minut. Wszystko później – import, porównanie z poprzednim crawlem, cotygodniowa projekcja, role, akcje i kolejka odświeżeń – zajmuje mniej niż pół godziny na laptopie. Nie uruchamiałem tego na 50 000 stron, więc nie podam liczby. Czas liczenia embeddingów rośnie z liczbą stron, ale co tydzień przeliczam tylko nowe i zmienione strony, a pełna klasteryzacja działa raz w miesiącu.
Jak podejść do serwisu wielojęzycznego?
Klastruj główny język, a pozostałe rzutuj na jego centroidy. Gdy zaczynałem, sekcja w drugim języku miała 161 stron z tekstem, za mało na osobną klasteryzację (ARI od 0,54 do 0,99 zależnie od parametrów). W wielojęzycznej przestrzeni embeddingów 87,1% stron w drugim języku, które mają angielski oryginał, trafia do tego samego klastra co oryginał. Tylko 4,2% linków w treści przechodzi między językami, a ja nigdy nie podpowiadam takiego linku.
Jak zmierzyć, czy klaster tematyczny działa?
Śledź trzy liczby w każdym przebiegu: odsetek linków w treści, które zostają wewnątrz klastrów (na tle przetasowanych etykiet), odsetek kliknięć, który trafia do stron Core i Focus, oraz liczbę stron w każdej akcji. Jeśli linki wychodzą poza klastry albo udział kliknięć Core i Focus spada o więcej niż 2–3 punkty marginesu szumu, struktura się rozmywa. Żadna z tych trzech liczb nie jest metryką pozycji – czytaj je obok wyników organicznych, a nie zamiast nich.
Najpierw inwentaryzacja, potem budowa
Badanie słów kluczowych nadal decyduje o tym, co zbudować dalej. Po prostu nie powinno iść na pierwszy ogień w serwisie, który ma już tysiące stron. Najpierw musisz wiedzieć, które z nich stoją razem, które linki naprawdę je łączą i które strony leżą na skraju swojego tematu. Wtedy kolejny plan słów kluczowych trafia na mapę, która pasuje do serwisu, a nowa strona nie dzieli po cichu popytu ze starą.
Zinwentaryzuj serwis, który masz. Potem zaplanuj ten, który chcesz mieć.
Jeśli Twój serwis wyrósł z tego, co da się opisać arkuszem słów kluczowych, od tej inwentaryzacji zaczynam dwa rodzaje pracy. W strategii treści staje się mapą tematów: Twoje istniejące strony pogrupowane w klastry, z linkami wewnętrznymi i lukami między nimi. W audycie treści daje decyzję dla każdego adresu, kandydatów do scalenia potwierdzonych danymi z Search Console i ponowny crawl, który sprawdza, czy zmiany weszły. Napisz, co widzisz w swoich danych.
