2013-04-30 9 views
11

mi znalezienie tego dość trudno wytłumaczyć tak proszę gołego ze mną tutaj ...Jak sprawdzić przeciwko wszystkim łączy przy generowaniu wynik MySQL

używam MySQL do wygenerowania wynik dla każdego wyniku zwróconego przez zapytanie. Wyniki są następnie uporządkowane według wyniku.

Część, która wydaje się nie działać prawidłowo, to próba dodania oceny dla każdego znacznika, który został przeszukany, a wynik jest przypisany. Powiedzmy więc, że szukam tagów "przykład", "test i" tag "i jeden z moich wyników jest przypisany do tagów" przykład "," test "," someothertag "powinien wyprowadzić wynik 10 ponieważ istnieją 2 meczów.

Co się rzeczywiście dzieje się dostaję 5 punktów, jeśli jest mecz, niezależnie od tego, ile znaczniki są dopasowane. i 0 jeśli żadne znaczniki są dopasowane.

Tutaj jest przykładem jednej z zapytaniami, które są wytwarzane z wyszukiwania.

 SELECT DISTINCT results.*, 
        ( 
         5*(MATCH(tags.name) AGAINST('"self employed"' IN BOOLEAN MODE)) + 
      5*(MATCH(tags.name) AGAINST('"rental income"' IN BOOLEAN MODE)) + 
      5*(MATCH(tags.name) AGAINST('"commission income"' IN BOOLEAN MODE)) + 
      5*(MATCH(tags.name) AGAINST('"bankruptcy"' IN BOOLEAN MODE)) + 
      5*(MATCH(tags.name) AGAINST('"condo approval"' IN BOOLEAN MODE)) + 

         1*usefulness + 
         10*shares 
        ) AS score 
     FROM results 
     INNER JOIN categories c on results.ID = c.RESULT_ID 
     INNER JOIN tags ON results.id = tags.result_id 
     WHERE c.name in ('purchase', 'condo', 'va') 
     AND (tags.name = 'self employed' OR tags.name = 'rental income' OR tags.name = 'commission income' OR tags.name = 'bankruptcy' OR tags.name = 'condo approval' ) 
     AND (results.scope = 'all' OR results.scope = 'hi') 
     AND published = 1 

     GROUP BY results.ID 
     having count(distinct c.c_id) = 3 
     ORDER BY score DESC 
     LIMIT 8 OFFSET 0 
+1

Prawdopodobnie nie trzeba używać pełnotekstowego indeksu, aby sprawdzić nazwy znaczników w tym zapytaniu. Szybsze i bardziej zwięzłe byłoby po prostu bezpośrednie porównanie równości. –

+0

Prawdopodobnie będzie bardziej zrozumiałe dla ludzi, jeśli możesz zapisać schemat i niektóre przykładowe dane dla swoich tabel oraz listę tego, co chciałbyś, aby zapytanie wygenerowało dla tych przykładowych danych. – Mikeb

+0

Groupin może spowodować przegrywanie meczów. Czy próbowałeś dodać COUNT do pięciu 5 * (MATCH (tags.name) ... przedmiotów? – nicolas

Odpowiedz

0

trzeba suma() Wyniku bo jedna linia pasuje tylko jeden znacznik.

W Twoim Zapytaniu wybrano wiele Rzędów i zgrupowano je według ID, więc otrzymujesz Wynik tylko dla JEDNEGO rzędu i zawsze będzie to 5 w twoim przypadku.

1

Zgodnie z zaleceniami Sam Dufel prawdopodobnie nie potrzebujesz pełnego wyszukiwania tekstu, zwłaszcza, że ​​używasz dokładnego porównania ciągów w klauzulach WHERE.

Ponadto, ze względu na wiele-do-wielu relacji między results i categories (założonej z klauzuli HAVING COUNT(c_id) = 3), myślę, że w żaden sposób nie można przyłączyć zarówno categories i tags w tej samej kwerendy.

Bez klauzuli GROUP BY dla jednego podanego result, otrzymasz jeden wiersz dla każdego dopasowanego category. Dla każdej pasującej pary (result,) otrzymasz wtedy jeden wiersz dla każdego dopasowanego tag.name. Nie sądzę, że istnieje sposób, aby poradzić sobie z takim wynikiem.

Co proponuję to:

Krok 1: coraz results obecny we wszystkich trzech kategoriach

SELECT results.ID 
FROM results 
JOIN categories ON results.id = categories.result_id 
WHERE categories.name IN ('purchase', 'condo', 'va') 
GROUP BY results.ID 
HAVING COUNT(DISTINCT c.c_id) = 3 

Krok 2: obliczanie wynik jakiegokolwiek results dopasowywania co najmniej jeden ciąg wyszukiwania

SELECT 
    DISTINCT results.*, -- DISTINCT is redundant because of the GROUP BY clause 
    ( 
     5*(COUNT(tags.result_id)) + -- you actually want to count the number of matches! 
     1*usefulness + -- warning, see below 
     10*shares  -- warning, see below 
    ) AS score 
FROM results 
INNER JOIN tags ON results.id = tags.result_id 
WHERE 
    tags.name = 'self employed' 
    OR tags.name = 'rental income' 
    OR tags.name = 'commission income' 
    OR tags.name = 'bankruptcy' 
    OR tags.name = 'condo approval' 
GROUP BY results.ID 

Krok 3: wprowadzenie go wszystkie razem

SELECT 
    results.*, 
    ( 
     5*(COUNT(tags.result_id)) + 
     1*usefulness + -- warning, see below 
     10*shares  -- warning, see below 
    ) AS score 
FROM (
     SELECT results.id 
     FROM results 
     JOIN categories ON results.id = categories.result_id 
     WHERE 
      categories.name IN ('purchase', 'condo', 'va') 
      AND (results.scope = 'all' OR results.scope = 'hi') 
      AND published = 1 
     GROUP BY results.id 
     HAVING COUNT(DISTINCT categories.c_id) = 3 
) AS results_subset 
JOIN results ON results_subset.id = results.id 
JOIN tags ON results.id = tags.result_id 
WHERE 
    tags.name = 'self employed' 
    OR tags.name = 'rental income' 
    OR tags.name = 'commission income' 
    OR tags.name = 'bankruptcy' 
    OR tags.name = 'condo approval' 
GROUP BY results.ID 

Zawiadomienie gdzie wybrałem zawierać warunki, gdzie na scope i published. Ten wybór opiera się na zasadzie, że filtry należy podawać tak wcześnie, jak to możliwe. Możesz uzyskać lepszą wydajność, jeśli umieścisz je w zewnętrznej kwerendzie, ale to naprawdę zależy od kardynalności.

Słowo ostrzeżenia: pola usefulness i shares nie są częścią funkcji GROUP BY, nie są zawarte w funkcji agregacji. Jest to allowed by MySQL, ale bardzo niebezpieczne. Jeśli wartości usefulness i shares należą do tabeli innej niż result (tabela zawierająca BY GROUP), wartości zwracane w zapytaniu są niezdefiniowane.

+0

Dziękuję bardzo za szczegółową odpowiedź i przykro mi, że zajęło mi to tyle czasu, aby odpowiedzieć. w ciągu ostatnich kilku dni. Poświęcę temu wieczorem i dam ci znać, jak się dogaduję! –

1

napisać to w następujący sposób:

"sum((5*(MATCH(tags.name) AGAINST('"self employed"' IN BOOLEAN MODE))), 
     (5*(MATCH(tags.name) AGAINST('"rental income"' IN BOOLEAN MODE))) , 
     (5*(MATCH(tags.name) AGAINST('"commission income"' IN BOOLEAN MODE))), 
     (5*(MATCH(tags.name) AGAINST('"bankruptcy"' IN BOOLEAN MODE))), 
     (5*(MATCH(tags.name) AGAINST('"condo approval"' IN BOOLEAN MODE))), 
     (1*usefulness), (10*shares)) as score" 
0

myślę zapytanie jest zbyt skomplikowana. Spróbuj tego:

SELECT 
    results.*, 
    5 * count(distinct tags.name) + 1*usefulness + 10*shares AS score 
FROM results 
JOIN categories c on results.ID = c.RESULT_ID 
    AND c.name in ('purchase', 'condo', 'va') 
JOIN tags ON results.id = tags.result_id 
    AND tags.name in ('self employed', 'rental income', 'commission income', 'bankruptcy', 'condo approval') 
WHERE results.scope in ('all', 'hi') 
AND published = 1 
GROUP BY 1, 2, 3, 4, 5 -- list as many numbers here as there are columns in "results" 
HAVING count(distinct c.c_id) = 3 
ORDER BY score DESC 
LIMIT 8 OFFSET 0 

Kluczowym problemem trzeba było było zgrupowanie - aby to działało poprawnie, trzeba albo nazwę lub odniesienia przez wybranej pozycji, wszystkie kolumny tabeli results. Nie podałeś schematu stołu, więc nie mogłem wiedzieć, co napisać. Domyśliłem się 5 kolumn, stąd GROUP BY 1, 2, 3, 4, 5, ale musisz się upewnić, że to jest poprawne.

Poprawiłem twoje OR s, zmieniając je na IN s - spowoduje to, że indeksy będą używane w tych kolumnach, jeśli takie indeksy istnieją ("LUB" nie będzie używać indeksu).

Przesunąłem niektóre warunki klauzuli WHERE do JOIN warunków, w których miało to sens - powinno to poprawić wydajność.

Powiązane problemy