W poprzednim artykule została opisana instalacja i konfiguracja wyszukiwania pełnotekstowego dla języka polskiego. Do całości rozwiązania brakowało jednak sposobu zadawania zapytań na indeks FTS, co opisałem w tym artykule.
Zadawać zapytania można tylko na kolumnach o typie tekstowym (char, varchar, nchar, nvarchar, text, ntext, image, xml, varbinary). Można to zrealizować na dwa sposoby. Pierwszy z nich wykorzystuje predykaty CONTAINS oraz FREETEXT. Druga metoda wykorzystuje funkcje CONTAINSTABLE oraz FREETEXTTABLE.
Predykaty
FREETEXT
Podczas użycia predykatu FREETEXT silnik FTS wykonuje następujące akcje:
– separuje wyrazy (word-breaking),
– generuje fleksyjne formy wyrazów (stemming),
– identyfikuje wyrazy ze słownikiem wyrazów blizkoznacznych,
– przypisuje wagi wyrażeniom.
Po wykonaniu powyższych kroków silnik FTS szuka dopasowań.
Do jego cech należy zaliczyć:
– poszukuje słów wyrazów wyekstrahowanych z podanego tekstu zapytania,
– nie wszystkie słowa muszą zostać znalezione,
– uwzględnia odmiany wyrazów i synonimy,
– mniej precyzyjny niż predykat CONTAINS.
SELECT * FROM Documents WHERE FREETEXT (DocumentContent, 'jedyny motocyklista')
CONTAINS
Predykat cechuje się bardzo rozbudowaną składnią, która wykorzystuje słowa kluczowe oraz znaki specjalne. Daje to możliwość zbudowania zaawansowanego zapytania z dokładnym określeniem oczekiwanego wyniku. Podczas korzystania z CONTAINS należy sprecyzować przynajmniej jeden warunek przeszukiwania w przeciwnym razie otrzymamy błąd.
Używając CONTAINS można wyszukać:
– słowa lub frazy (‘word’),
– słowa lub frazy rozpoczynające się tekstem (“word*”),
– słowa położonego blisko innych wyrazów (’fox NEAR chicken’),
– fleksyjne formy wyrazów (’FORMSOF (INFLECTIONAL, ride)’),
– synonimy wyrazów (’FORMSOF (THESAURUS, metal)’).
SELECT * FROM Documents WHERE CONTAINS (DocumentContent, 'jedyny OR "moto*"')
SELECT * FROM Documents WHERE CONTAINS (DocumentContent, 'FORMSOF(INFLECTIONAL, "motocykl")')
SELECT * FROM Documents WHERE CONTAINS(DocumentContent, 'ISABOUT (kierowca WEIGHT (.4), motocyklista WEIGHT (.8) )')
Funkcje
Funkcje CONTAINSTABLE oraz FREETEXTTABLE zwracają tabelę z wynikami dopasowanych wierszy. Tabela zawiera dwie kolumny. Pierwsza z nich to kolumna KEY, w kórej znajdują się wartości klucza unikalnego z indeksu FTS. Druga – RANK – zawiera wartość dopasowania, czyli w jakim stopniu wiersz pasuje do zadanych kryteriów wyszukiwania. Daje to możliwość oceny stopnia podobieństwa zadanych wyrazów z tekstem każdego wiersza FTS.
CONTAINSTABLE oraz FREETEXTTABLE posiadają identyczne cechy oraz sposób działania jak odpowiadające im predykaty.
SELECT Id, FREETEXTTABLE_ALIAS.RANK, DocumentContent FROM Documents d INNER JOIN FREETEXTTABLE (Documents, DocumentContent, 'jedyny motocyklista') AS FREETEXTTABLE_ALIAS ON d.Id = FREETEXTTABLE_ALIAS.[KEY] ORDER BY 2 DESC
SELECT Id, CONTAINSTABLE_ALIAS.RANK, DocumentContent FROM Documents d INNER JOIN CONTAINSTABLE (Documents, DocumentContent, 'jedyny OR "moto*"', 3) AS CONTAINSTABLE_ALIAS ON d.Id = CONTAINSTABLE_ALIAS.[KEY]
SELECT Id, CONTAINSTABLE_ALIAS.RANK, DocumentContent FROM Documents d INNER JOIN CONTAINSTABLE (Documents, DocumentContent, 'FORMSOF(INFLECTIONAL, "motocykl")') AS CONTAINSTABLE_ALIAS ON d.Id = CONTAINSTABLE_ALIAS.[KEY]
FREETEXT vs CONTAINS vs LIKE
W zależności od oczekiwanego wyniku, predykatów należy stosować do różnego rodzaju przeszukiwania:
- FREETEXT należy stosować do dopasowania znaczenia słów, a nie dokładnej treści. Wyniki są generowane jeśli przynajmniej jedno słowo zostanie znalezione.
- CONTAINS należy użyć do precyzyjnego wyszukiwania pojedyńczych wyrazów, ich wyrazów bliskoznacznych (z określeniem pewnego dystansu) oraz określenia wagi zgodności.
- predykatem LIKE można szukać tylko zadaną frazą bez uwzględnienia różnych form wyrazów. Dodatkowo wykonanie zapytania LIKE na dużej ilości danych teksowych jest znacznie wolniejsze od zapytań FTS.