MySQL match () z () - uporządkuj według trafności i kolumny?

80

OK, więc próbuję przeprowadzić wyszukiwanie pełnotekstowe w wielu kolumnach, coś prostego:

SELECT * FROM pages WHERE MATCH(head, body) AGAINST('some words' IN BOOLEAN MODE)

Teraz chcę uporządkować według trafności (ile słów zostało znalezionych?), Co udało mi się zrobić z czymś takim:

SELECT * , MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE) AS relevance 
FROM pages
WHERE MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE)
ORDER BY relevance

Teraz nadchodzi część, w której się gubię, chcę nadać priorytet trafności w headkolumnie.

Wydaje mi się, że mógłbym utworzyć dwie kolumny adekwatności, jedną dla headi jedną dla body, ale w tym momencie przeprowadziłbym nieco to samo wyszukiwanie w tabeli trzy razy, a dla tego, co wykonuję tę funkcję, wydajność jest ważna, ponieważ zapytanie zostanie połączone i dopasowane do innych tabel.

Zatem moje główne pytanie brzmi : czy istnieje szybszy sposób wyszukiwania trafności i nadawania priorytetów niektórym kolumnom? (A jako bonus, być może nawet licząc trafność, ile razy słowa występują w kolumnach?)

Wszelkie sugestie lub porady byłyby świetne.

Uwaga: uruchomię to na serwerze LAMP. (WAMP w testach lokalnych)

Kristoffer la Cour
źródło
Czy naprawdę musisz wstawiać MATCH ... AGAINST zarówno w klauzuli SELECT, jak iw klauzuli WHERE? Czy nie możesz użyć aliasu w klauzuli SELECT i odwołać się do aliasu w klauzuli WHERE? Próbuję użyć przygotowanych wypowiedzi i wydaje mi się to zbędne / dziwne.
S. Imp,
2
Nie, jak stwierdzono w dokumentacji MySQL od wersji 5.5, MATCH ... AGAINST zostanie obliczony raz, gdy zarówno w SELECT, jak i WHERE, więc nie ma dodatkowego narzutu.
Bob2u

Odpowiedzi:

156

To może dać zwiększenie znaczenia dla części głowy, które chcesz. Nie podwoi tego, ale może być wystarczająco dobry dla twojego dobra:

SELECT pages.*,
       MATCH (head, body) AGAINST ('some words') AS relevance,
       MATCH (head) AGAINST ('some words') AS title_relevance
FROM pages
WHERE MATCH (head, body) AGAINST ('some words')
ORDER BY title_relevance DESC, relevance DESC

-- alternatively:
ORDER BY title_relevance + relevance DESC

Alternatywą, którą również chcesz zbadać, jeśli masz elastyczność w przełączaniu silnika DB, jest Postgres . Pozwala ustawić wagę operatorów i bawić się rankingiem.

Denis de Bernardy
źródło
14
Poza tym MySQL 5.6 obsługuje wyszukiwanie pełnotekstowe w tabelach InnoDB!
Jabari,
1
Czy możesz zapewnić do tego skrzypce SQL?
Użytkownik
Jaki negatywny wpływ mają wielokrotne wyszukiwania? Potrzebuję 4 dopasowań do mojego SELECT, ponieważ mam 4 różne współczynniki wagi. Czy to znacznie obniżyłoby wydajność?
ToBe
@ToBe Widziałem w przypadku innych podobnych pytań więcej niż jedna osoba, która twierdzi, że nie ma dodatkowego narzutu związanego z używaniem wielu MATCHinstrukcji, ze względu na sposób, w jaki MySQL działa wewnętrznie.
BadHorsie
Upewnij się, że korzystasz z tych dwóch. ALTER TABLE talk_webpages ADD FULLTEXT(head)orazALTER TABLE talk_webpages ADD FULLTEXT(head, body)
Supun Kavinda
15

Tylko dodawanie dla tego, kto może potrzebować ... Nie zapomnij zmienić tabeli!

ALTER TABLE table_name ADD FULLTEXT(column_name);
Camilla
źródło
3
jeśli wykonasz powyższe polecenie więcej niż raz, utworzy ono wiele indeksów dla tych samych kolumn. Więc uruchom to polecenie tylko raz.
hakiko
Jeszcze lepiej, użyj CREATE FULLTEXT INDEX indexname na tablename (column_name (s)). Powinieneś także naprawdę sprawdzić, czy indeks istnieje, zanim spróbujesz go utworzyć. Możesz sprawdzić, czy istnieje, używając: SELECT INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_CATALOG= 'def' AND TABLE_SCHEMA= DATABASE () AND TABLE_NAME= 'tablename' AND INDEX_NAME= 'indexname';
Dave Hilditch
9

Nigdy tego nie robiłem, ale wygląda na to

MATCH (head, head, body) AGAINST ('some words' IN BOOLEAN MODE)

Powinien dać podwójną wagę zapałkom znalezionym w głowie.


Po prostu przeczytaj ten komentarz na stronie z dokumentami. Pomyślałem, że może być dla Ciebie wartościowy:

Wysłane przez Patrick O'Lone 9 grudnia 2002 6:51

Należy zauważyć w dokumentacji, że W TRYBIE BOOLEJSKIM prawie zawsze zwraca wartość 1.0. Aby uzyskać trafność, która ma znaczenie, musisz:

SELECT MATCH('Content') AGAINST ('keyword1 keyword2') as Relevance 
FROM table 
WHERE MATCH ('Content') AGAINST('+keyword1+keyword2' IN BOOLEAN MODE) 
HAVING Relevance > 0.2 
ORDER BY Relevance DESC 

Zwróć uwagę, że wykonujesz regularne zapytanie dotyczące istotności w celu uzyskania współczynników trafności w połączeniu z klauzulą ​​WHERE, która używa trybu BOOLEAN. TRYB BOOLEAN zapewnia podzbiór, który spełnia wymagania wyszukiwania BOOLEAN, zapytanie o trafność spełnia współczynnik trafności, a klauzula HAVING (w tym przypadku) zapewnia, że ​​dokument jest odpowiedni dla wyszukiwania (tj. Dokumenty z wynikiem mniejszym niż 0,2 są uważane za nieistotne). Umożliwia to również porządkowanie według trafności.

To może, ale nie musi, być błędem w sposobie działania IN BOOLEAN MODE, chociaż komentarze, które przeczytałem na liście mailingowej sugerują, że ranking trafności IN BOOLEAN MODE nie jest zbyt skomplikowany, przez co nie nadaje się do faktycznego dostarczania odpowiednich dokumentów. BTW - nie zauważyłem utraty wydajności w związku z tym, ponieważ wydaje się, że MySQL wykonuje wyszukiwanie FULLTEXT tylko raz, mimo że dwie klauzule MATCH są różne. Użyj EXPLAIN, aby to udowodnić.

Więc może się wydawać, że nie musisz się martwić o dwukrotne wywołanie wyszukiwania pełnotekstowego, chociaż nadal powinieneś "użyć EXPLAIN, aby to udowodnić"

jisaacstone
źródło
1
Niestety, dwukrotne dodanie nagłówka do funkcji match () nie działa. Może dlatego, że zapytanie nie liczy, ile razy występują słowa? Używałem również tej strony, do której się odnosisz, ale z jakiegoś powodu mogę jej nie uruchomić ... Nie zindeksowałem jeszcze moich kolumn i dlatego nie mogę wyszukiwać bez tagu „IN BOOLEAN MODE”. .
Kristoffer la Cour
Myślę, że wyszukiwanie typu non-booleen zwróciłoby # wystąpień, ale booleen nie zwraca?
jisaacstone
Jutro bardziej się temu przyjrzę, ale na razie to wytrzymam. Dziękuję za odpowiedź, zobaczymy, czy to mi pomoże, kiedy to zdobędę.
Kristoffer la Cour
Miałem problem z używaniem W TRYBIE BOOLEJSKIM, a następnie porządkowaniem według trafności, co rozwiązało mój problem, ponieważ trafność była zawsze zwracana jako 1. Dzięki.
Jazzy
Wygenerowanie pola wyników rozwiązało mój problem: otrzymywałem wyniki, ale wiele z nich było kompletnym szumem. Dzięki, +1
Chris Baker
4

Ja też się tym bawiłem. Jednym ze sposobów dodania dodatkowego ciężaru jest opcja ZAMÓWIENIE według kodu.

Na przykład, jeśli dopasowujesz 3 różne kolumny i chcesz bardziej ważyć niektóre kolumny:

SELECT search.*,
MATCH (name) AGAINST ('black' IN BOOLEAN MODE) AS name_match,
MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE) AS keyword_match,
MATCH (description) AGAINST ('black' IN BOOLEAN MODE) AS description_match
FROM search
WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE)
ORDER BY (name_match * 3  + keyword_match * 2  + description_match) DESC LIMIT 0,100;
Noe King
źródło
Czy to nie jest naprawdę ciężkie zapytanie?
Beanow
5
Przenieś matematykę do instrukcji select, a to znacznie zmniejsza obciążenie. SELECT search.*, (MATCH (name) AGAINST ('black' IN BOOLEAN MODE) * 3) + (MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE)*2 + MATCH (description) AGAINST ('black' IN BOOLEAN MODE)) AS totalScore , FROM search WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE) ORDER BY totalScore DESC LIMIT 0,100;
invertedSpear