Autor Zpráva
ROLAND
Profil *
Dobrá den,
snažím se vytvořit fulltextové vyhledávání v databázi, resp. ve výpisu, který vznikl spojením tabulek. Když použiju to co jsem prozatím vytvořil, tak mi každý záznam vypíše několikrát - pokaždý s jiným garantem, s jinou licencí a s jiným typem. Tak dostanu místo asi 100 záznamů, přes 3000 záznamů. Zkoušel jsem využít nějký GROUP BY, ale u každého záznamu mi to tentokrát napíše první záznam z tabulek garant, typ a licence. Posím o jakoukoliv radu.
Děkuji

$sql="SELECT data.id_data, data.nazevdat, data.reprezentace, data.meritko, data.nahled, data.ukazkaodkaz, data.popis, data.popis2, data.poskytovani, data.prispevatel, data.format, garant.nazev, data.historie, data.souradsystem, typ.typ, licence.typlicence, data.data_link, data.znalost
    FROM data, typ, garant, licence
    WHERE data.id_garant=garant.id_garant
    AND data.id_typ=typ.id_typ
    AND data.id_licence=licence.id_licence
    AND MATCH (data.nazevdat) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.meritko) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.ukazkaodkaz) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.poskytovani) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.prispevatel) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.historie) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.popis) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.popis2) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.souradsystem) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.format) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.data_link) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)
    OR MATCH (data.znalost) AGAINST ('".$_GET['search']."' IN BOOLEAN MODE)  
    ORDER BY data.id_data ASC";
    $result=mysqli_query($conn, $sql); 
Keeehi
Profil
1) Pro spojování tabulek bych nepoužíval cross join, vytváří to opravdu gigantické tabulky, které se pak filtrují. Možná se na to použije nějaká optimalizace, ale nespoléhla bych na to.
Proto
FROM data, typ, garant, licence
WHERE data.id_garant=garant.id_garant
AND data.id_typ=typ.id_typ
AND data.id_licence=licence.id_licence
nahraďte
FROM data
JOIN typ USING (id_typ)
JOIN garant USING (id_garant)
JOIN licence USING (id_licence)
WHERE ...

2) Víte, že do MATCH můžete zadat místo jednoho sloupce i celý seznam sloupců,které se mají prohledávat? Jelikož hledáte pořád stejný výraz, tak to zkrátí dotaz. Teoreticky by to mohlo býti rychlejší.

3) To, proč to vypisuje 3000 řádků je kombinace cross joinu a chyby v WHERE. Problém je v tom, že všechny to MATCHe spojené ORem by měly být obalené v závorce, protože pak stačí aby jeden z nich byl pravdivý a pak je jedno, co bylo v těch prvních třech pravidlech.
WHERE 1 AND 0 AND 1 OR 1 OR 1 => true
WHERE 1 AND 0 AND (1 OR 1 OR 1) => false
Řešení je jednoduché, přidat ty závorky. Lépe však to upravit podle 1 a 2 k tomuto problému se ani zdaleka nepřiblížíte.
ROLAND
Profil *
Tak jsem vše udělal podle prvního a druhého kroku a stále mám problém. Tentokrát jsem zkusil provést SQL dotaz přímo v databázi a napíše mi to:

Can't find FULLTEXT index matching the column list.

Příčemž všechny sloupce z dotazu mám daný jako FULLTEXT klíč. Co s tím?


jen doplnění používám úložiště innoDB.
Keeehi
Profil
Can't find FULLTEXT index matching the column list.
To souvisí s tím, že máš fulltext vytvořený pro každý sloupec a ne přes celý set. Nevím, zda to má nějaké nevýhody, nejsem v tom odborník. Kajman_ by asi vědel lépe.

Jestli to stále zobrazuje více řádků než má, mohl bys vytvořit ukázku? Nechat 2-3 řádky v tabulkách, ukázat dotaz a výsledek, v kterém budou vidět ty řádky navíc.
ROLAND
Profil *
Už to neukazuje více řádků. Ukazuje mi to chyby:
Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in C:\web\search_sc.php on line 28
Počet záznamů:
line 28: echo "Počet záznamů: ".mysqli_num_rows($result);

A

Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in C:\web\search_sc.php on line 31
line 31:
if (mysqli_num_rows($result)>0) {
    echo "<div class='table'>";
      echo "<table border=1>";
      ....
Keeehi
Profil
Z dokumentace mysqli_query():
Return Values
Returns FALSE on failure


Tudíž bych si vypsal mysqli_error($link);
ROLAND
Profil *
po vypsání mysqli_error se objeví opět hláška: Can't find FULLTEXT index matching the column list
Kubo2
Profil
ROLAND:

A máš vytvorený FULLTEXT KEY cez všetky stĺpce v rovnakom poradí, aké používaš v dotaze?
Keeehi
Profil
OK, tak znovu:
To souvisí s tím, že máš fulltext vytvořený pro každý sloupec a ne přes celý set.
ROLAND
Profil *
Kubo2

Mám vytvořený klíč ve všech sloupcích z dotazu a ve stejném pořadí.

Keeehi:

A nevíš jak to vytvořím přes celý set? Dával jsem to ručně ke každému sloupci co potřebuju.
Keeehi
Profil
ROLAND:
Mám vytvořený klíč ve všech sloupcích z dotazu a ve stejném pořadí.
n klíčů je něco jiného než jeden klíč přes n sloupců

CREATE FULLTEXT INDEX idx ON data(nazevdat, meritko, ukazkaodkaz, ...);
ROLAND
Profil *
Toto mi už teda funguje. Jen poslední dotaz, když chci takto vytvořit index společně pro záznamy z jiné tabulky, které se tahají co hlavní přes cizí klíč - například vyhledávat jméno garanta který je v hlavní tabulce označen pouze pomocí ID. Mám za toto


CREATE FULLTEXT INDEX idx ON data(nazevdat, meritko, ukazkaodkaz, ...)
psát například:
AND garant(nazev)?

Nebo jakým způsobem toto dát celé dohromody?
Keeehi
Profil
ROLAND:
Index lze vytvářet přeci jen na jednou tabulkou. Když budeš potřebovat vyhledávat ve více tabulkách, tak budeš muset spojit více MATCHů ORem, ale sloupce z jedné tabulky mohou být v jedné klauzuli MATCH. Jestli s tím máš ale problémy, tak to nechej jak to je a vyhledávej nad jednotlivými sloupci. Použij ten nový join s stará pravidla match z where. Jelikož kvůli novému joinu tam nebudou ty první 3 logické výrazy a zbydou tedy jen ORy, nebude problém s prioritou operátorů.
ROLAND
Profil *
Všechno vyřešeno a funguje to jak tpotřebuju. Moc děkuji za pomoc a omlouvám se za hloupé dotazy, ale jsem naprostý začátečník.
Kajman
Profil
Jen pozor na to, že fulltext funguje na innodb až od verze 5.6.4, vybírejte si tedy hosting, co má novější verzi mysql a bude tuto kombinaci podporovat.

A ještě poznámka, že v boolean mode na myisam není potřeba fulltextový index, ale rychlost není taková jako s připraveným indexem.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: