Autor | Zpráva | ||
---|---|---|---|
kareln Profil * |
#1 · Zasláno: 14. 3. 2015, 22:45:21
Dobrý večer, řeším problém ohledně fulltextové vyhledávání. SQL příkaz v phpadminu funguje, ale jakmile chci vypsat na stránkách přes php, tak to bohužel vrací nuloovu hodnotu, nevíte, kde může být prosím problém?
$sqlCommand = "(SELECT nadpis FROM clanky WHERE MATCH (nadpis) AGAINST ('".$searchquery."' IN BOOLEAN MODE))"; |
||
juriad Profil |
#2 · Zasláno: 14. 3. 2015, 22:49:32
Co je v proměnné $searchquery?
Jak ten dotaz pokládáš a zpracováváš? |
||
kareln Profil * |
#3 · Zasláno: 14. 3. 2015, 22:52:04
zpracovávám to z formuláře přes pole vyhledat:
$searchquery = $_POST['searchquery']; na stránce mi už ale dřív nefungovalo vyhledávání s diakritikou přes LIKE |
||
juriad Profil |
kareln:
„$searchquery = $_POST['searchquery'];“ Toto je jasně chyba SQL Injection, ale nemyslím, že způsobuje problémy v tomto případě (pokud tedy v searchquery nezadáváš něco s apostrofem). Spíš mě zajímalo, jak voláš funkci mysql_query, voláš-li ji? Kde dosaneš nulovou hodnotu? Myslíš tím číslo 0, nebo null, nebo false. Zkus si to vypsat pomocí var_dump. Kolik řádků vrátí dotaz? |
||
kareln Profil * |
#5 · Zasláno: 14. 3. 2015, 23:13:25 · Upravil/a: kareln
díky za upozornění, ale takhle to ve skutečnosti nepředávám, mám to ošetřené, ale vytvořil jsem si jen zkušební soubor a zjednodušil vše, abych snížil pravděpodobnost chyby. var_dump mi vypíše: resource(13) of type (mysql result)
$db_spojeni = mysql_connect('127.0.0.1', 'ggg', 'ggg'); mysql_select_db('ggg'); mysql_query("SET NAMES 'utf8'") or die('Could not set names') $sqlCommand = "(SELECT nadpis FROM clanky WHERE MATCH (nadpis) AGAINST ('".$searchquery."' IN BOOLEAN MODE))"; $query = mysql_query($sqlCommand) or die(mysql_error()); následně while($row = mysql_fetch_array($query)){ $page_url = $row["nadpis"]; } |
||
juriad Profil |
Zatím víme, že dotaz neskončí chybou (v takovém případě by se skript ukončil a viděl bys chybovou hlášku). Kolikrát proběhne ten cyklus? Co vrátí mysql_num_rows? A v tom cyklu tedy vypisuješ $page_url? Co vypíše var_dump té proměnné? |
||
kareln Profil * |
#7 · Zasláno: 14. 3. 2015, 23:19:00 · Upravil/a: kareln
můžu se jen zeptat, co znamená, když mi var_dump vypíše resource(13)? děkuji
if(isset($_POST['searchquery']) && $_POST['searchquery'] != ""){ $searchquery = $_POST['searchquery']; $sqlCommand = "(SELECT nadpis FROM clanky WHERE MATCH (nadpis) AGAINST ('".$searchquery."' IN BOOLEAN MODE))"; $query = mysql_query($sqlCommand) or die(mysql_error()); $count = mysql_num_rows($query); if($count > 1){ $search_output .= "<hr />$count hledaných výsledků pro výraz <strong>$searchquery</strong><hr />"; echo "<ul class='hledany'>"; while($row = mysql_fetch_array($query)){ $page_url = $row["url"]; $title = $row["nadpis"]; $search_output .= '<li>'.$title.'</li>'; } } else { $search_output = "<hr />0 hledaných výsledků pro výraz <strong>$searchquery</strong><hr />"; } echo "</ul>"; } echo $search_output; odstranil jsem podmíniku if($count > 1) a už to funguje. nevíte, v čem je problém? |
||
1Pupik1989 Profil |
Změň si
mysql_fetch_array za mysql_fetch_assoc . Druhá vrací jen asociativní pole.
|
||
juriad Profil |
1Pupik1989:
V tom chyba není; výchozí hodnota druhého parametru je MYSQL_BOTH; obsahuje tedy i indexované položky. kareln: Nejspíš dotaz vrátí jen jeden záznam a podmínka if(1 > 1) samozřejmě není splněná.
Mimohodem, ten skript je doufám hodně ořezaný jen pro potřeby ukázky. Obsahuje obrovskou spoustu chyb. |
||
kareln Profil * |
#10 · Zasláno: 14. 3. 2015, 23:32:31
ano je, mám ho ošetřený. jen jsem to tam takhle naházel na ukázku. chyba byla tedy v mé nepozornosti v podmínce. děkuji mnohokrát za pomoc. Chtěl jsme se ještě zeptat, jestli nevíte, jak udělat to, aby to vyhledávalo například jen kořen slova. žkoušel jsem '%".$searchquery.%'" a nefunguje to
|
||
juriad Profil |
#11 · Zasláno: 14. 3. 2015, 23:44:22
MySQL prý umí jen prefixy, nikoli obecný kořen slova.
Tedy pro vyhledání slov okno a okna musíš položit dotaz: okn* ok* , což zase najde slova, která jsi nechtěl.
Pokud bys chtěl cokoli lepšího, už ti MySQL nepostačí. Máš-li svůj server, použij Lucene nebo ElasticSearch. Ale upozorňuji, že to není úplně jednoduché a je to možná kanón na vrabce. |
||
kareln Profil * |
#12 · Zasláno: 14. 3. 2015, 23:46:19
dobře. ještě jednou děkuji za váš čas a odpovědi. moc jste mi pomohl
|
||
1Pupik1989 Profil |
#13 · Zasláno: 15. 3. 2015, 00:45:52
Mysql umí regulární výrazy, takže v tom nevidím problém.
SELECT 'okenice' REGEXP '[[:<:]]ok(en|no)[[:alpha:]]*[[:>:]]' SELECT 'okno' REGEXP '[[:<:]]ok(en|no)[[:alpha:]]*[[:>:]]' SELECT 'okena' REGEXP '[[:<:]]ok(en|no)[[:alpha:]]*[[:>:]]' |
||
juriad_ Profil * |
#14 · Zasláno: 15. 3. 2015, 08:00:05
1Pupik1989:
Problem to je z vykonovych duvodu. Regex neumi vyuzit index a muze tak byt ukrutne pomaly i na relativne malem poctu zaznamu. http://www.psce.com/blog/2012/03/31/mysql-queries-with-regexp/ |
||
Keeehi Profil |
#15 · Zasláno: 15. 3. 2015, 08:12:24
juriad:
To ale není problém jen regexu ale čehokoli co neprohledává od začátku. Tudíž ať použiješ cokoli na kontrolu výskytu podřetězce kdekoli v řetězci, nikdy to nemůže využít klasický databázový index. Tudíž je naprosto irelevantní se bavit u této úlohy, zda daná metoda využije index. Pomalé to být může ale to bude v tom případě i jakákoli jiná metoda. |
||
juriad Profil |
#16 · Zasláno: 15. 3. 2015, 14:36:37
Keeehi:
To je pravda jen na úrovni databáze. A i tam platí, že REGEX je o dost pomalejší než LIKE. Pokud víš, že nikdy nebudeš hledat výrazy delší než 20 znaků, můžeš si uložit všechny posloupnosti 20 znaků (je jich jen 20x více, ale jsou relativně malé a jejich prohledávání je logaritmické). V Lucene si můžeš napsat vlastní analyzátor, který ti pro všechna slov okno, okena, okenice najde kořen slova, a ten pak zaindxuješ. Pro různé přirozené jazyky existují různé algoritmy. Můžeš dokonce indexovat jedno slovo vícekrát (podle různých dělení a trhání a části). |
||
Keeehi Profil |
#17 · Zasláno: 15. 3. 2015, 15:17:56
juriad:
„A i tam platí, že REGEX je o dost pomalejší než LIKE.“ To je možné, ale není to kvůli indexu. „Pokud víš, že nikdy nebudeš hledat výrazy delší než 20 znaků, můžeš si uložit všechny posloupnosti 20 znaků“ Teoretick ano, ovšem počet 20ti znakových řetzců (málá písmen anglické abecedy) je 26^20, na uložení jednoto slova je potřeba cca 100 bitů, tedy cca 13 bajtů. Na uložení všech 20ti znakových řetězců by bylo potřeba více než 200 000 000 000 000 000 terabajtových disků. Takže prakticky to není použitelné. Pokud máš na mysli vygenerování všech možných podřetězců maximální dékly 20 z dat v tabulce, tak už by to bylo lepší, ovšem pokud zdrojem je 20ti znakový řetězec, pak jich je 210 a ne 20. pro řetězec délky 21 je to 230, pro další 250 atd. Takže vytvoření seznamu podřetězců třeba 4000 znakového článku mi vygeneruje pěkný počet záznamů. Vím, že jsou systémy pro vyhledávání, ovšem jediné na co jsem poukazoval je to, že indexy se nepoužijí nikdy, takže to není důvod, proč regexy můžou být pomalé. |
||
juriad Profil |
#18 · Zasláno: 15. 3. 2015, 15:32:34
Ano, myslel jsem pro text uložit všechny suffixy ořízlé na 20 znaků.
Omlouvám se, za chybu, je jich samozřejmě stejně jako počet znaků v původním textu (tedy pro text o délce 200 znaků je to 200 záznamů), ale tato technika se nepoužívá u dlouhých textů, ale třeba jen pro vyhledávání v názvech produktů; nebo jiných hodně specifických datech, kde má libovolný podřetězec smysl. Chtěl jsm říct, že uložení nadbytečných dat zabere jen 20x více místa + režie na index. Neříkám, že je to správné řešení v tomto případě, není. kareln může zůstat u FULLTEXTu, pokud mu stačí. Regex má problém v uživatelské přívětivosti na vstupu do vyhledávače, hvězdičku snad ještě dokáže uživatele naučit použít. Cokoli lepšího už vyžaduje důkladnou analýzu dat a netriviální algoritmy. A nejspíš kareln vytváří systém tak malého rozsahu, že by i pomalý lineární sken s regexem byl dostatečně svižný. |
||
Časová prodleva: 10 let
|
0