Gå til innhold

Anbefalte innlegg

Jeg har en database med blant annet en rad for produktnavn og en rad for varenummer. Kunden skal med søkemotoren kunne søke gjennom disse to radene. Si at brukeren søker etter "lg lcd tv". Da ønsker jeg at spørringen skal returnere alle produkter som inneholder disse tre ordene. Ordene kan enten stå for seg selv, eller som en del av et annet ord. Produkter som inneholder "FLAT-TV" skal returneres på søk etter "tv" osv.

 

Man kan selvfølgelig splitte søkestrengen i en array, legge til REGEXP for hvert ord osv. men hadde håpet (og regner med) at det finnes en litt mer elegant og effektiv løsning.

 

EDIT: Systemet inneholder ca. 7000 produkter, og kjører med mySQL.

Endret av simenss
Lenke til kommentar
Videoannonse
Annonse
Du sier jo ikke noe om hvilket databasesysem du bruker. De fleste databaser har en eller anne funksjon for fulltekst indexering og søking, enten innebygget eller som et 3djepartsverktøy. Disse er som skapt for denne jobben.

Systemet inneholder ca. 7000 produkter, og kjører med mySQL. Vesentlig informasjon jeg burde inkludert fra starten av.

Lenke til kommentar

Heisann.

 

Det jeg gjør for å søke etter ALLE ordene er enkelt og greit:

 

/* søkeord */
$search = "lg tv lcd";
/* splitte opp søkeord */
$search = explode(" ", $search);

/* søkefelt i databasen: */
$searchFields = "productTitle,productDescription,productKeywords";
/* mysql spørring: */
$sql = "SELECT productTitle FROM products WHERE ";
foreach($search as $kw) {
 $sql .= "CONCAT($searchFields) LIKE '%$kw%' OR ";
}
$sql = substr($sql,0,strlen($sql)-3);

/* kjør spørringen */

 

Forklaringen av dette er enkelt og greit: "CONCAT" i mysql slår sammen ting. F.eks "CONCAT("HEY","THERE")" vil da gi "HEYTHERE". Så nå slår jeg sammen innholdet i alle feltene du skal la brukeren søke i som er $searchFields.

 

Det andre jeg gjør er å splitte søkeordet og gå igjennom alle søkeordene og legge de inn etter WHERE med "OR" imellom. Det som skjer da er at den søker på hvert eneste ord. Om du skal ha full match med alle ord må du søke med "AND" i mellom ..

 

Beklager dårlig formulert. Er trøtt :)

 

Om dette hjalp vennligst endre tittel i førstepost til "[LØST] <tittel>" og skriv forklaring på hvordan du gjorde det. Dette kan hjelpe andre med samme problem. Om en post hjalp deg vennligst referer til den.

Lenke til kommentar
Det er ganske stygt å bruke LIKE OR LIKE OR.... Det er ekstremt lite optimalt i så fall... Fulltekstindeksering / fulltekstsøk er veien å gå, men i mysql har jeg ingen kunnskap her.

Istemmes. I det hele tatt er like '%noe' grisestygt, for det forhindrer en hver bruk av indekser, og man får garantert table scan. Fulltekstsøk er tingen.

Lenke til kommentar
Istemmes. I det hele tatt er like '%noe' grisestygt, for det forhindrer en hver bruk av indekser, og man får garantert table scan.

 

*pirke* table- eller indexscan *pirke*. Selv om det ikke gjør saken særlig mye bedre. :whistle:

 

Men hvordan?

 

Hva med å prøve å lese MySQL-dokumentasjonen.

Lenke til kommentar

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html Google er din venn!

 

Finnes ikke alt for mye optimaliserings guider om dette på nett.

 

Men har selv brukt FULLTEXT søk og det er enorm forskjell fra LIKE, vi snakker 30 sek/minutter med LIKE ned til sekunder med FULLTEXT. Da på store tabeller. (700000+ rows)

 

Har du phpMyAdmin? Om du går inn der og oppretter noen fulltext indekser på de feltene du er ute etter har du noe å søke i. Eller på manuell måte.

 

mysql en søkevariabel:

select * from tablename where match (produkt,beskrivelse,produktnavn) against('+$sokeord' IN BOOLEAN MODE) order by produktnavn ASC

Disse feltene må inkluderes i fulltext indeksen i eksempelet over: produkt,beskrivelse,produktnavn

 

mysql to søkevariabler:

select * from tablename where match (produkt,beskrivelse,produktnavn) against('+$sokeord +$sokeord2' IN BOOLEAN MODE) order by produktnavn ASC

 

Kombiner dette med LIKE setningen lenger oppe, så du kan søke etter flere ord om søkevariablen er "bilstereo sony".

 

Bare spør mer. Har litt dårlig tid nå, men har litt erfaring :) Lykke til!

Endret av Invert
Lenke til kommentar
Bare spør mer. Har litt dårlig tid nå, men har litt erfaring :) Lykke til!

Takk :) Manualen er fin den, men når det kommer til emner hvor jeg ikke kan noe fra før, er det fint med litt ekstra drahjelp.

 

Endte opp med følgende spørring når jeg kombinerte spørringen med phpps kode:

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('+lg' IN BOOLEAN MODE) OR MATCH (product_id,product_name,product_manufacturers_id) against('+tv' IN BOOLEAN MODE)

 

Det var kanskje ikke dette du mente med "Kombiner dette med LIKE setningen lenger oppe"?

Lenke til kommentar
Bare spør mer. Har litt dårlig tid nå, men har litt erfaring :) Lykke til!

Takk :) Manualen er fin den, men når det kommer til emner hvor jeg ikke kan noe fra før, er det fint med litt ekstra drahjelp.

 

Endte opp med følgende spørring når jeg kombinerte spørringen med phpps kode:

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('+lg' IN BOOLEAN MODE) OR MATCH (product_id,product_name,product_manufacturers_id) against('+tv' IN BOOLEAN MODE)

 

Det var kanskje ikke dette du mente med "Kombiner dette med LIKE setningen lenger oppe"?

 

Tenkte mer på dette:

 

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('+lg +tv' IN BOOLEAN MODE)

 

Da får du alt med lg og tv i seg. Dersom du skal ha OR skulle det holde med å ta bort + ene slik at det blir:

 

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('lg tv' IN BOOLEAN MODE)

 

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('lg tv' IN BOOLEAN MODE)

 

Eller på denne måten blir det jo litt kjapt skrevet:

 

$search = "lg tv lcd";

$search = explode(" ", $search);

 

$sql = "SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against(' ";

foreach($search as $kw) {

$sql .= "$kw";

}

$sql .= "' IN BOOLEAN MODE");

 

Noe sånt ;) eventuelt sette en + forran $kw.

Endret av Invert
Lenke til kommentar
Tenkte mer på dette:

 

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('+lg +tv' IN BOOLEAN MODE)

 

Jeg har et produkt hvor product_name er lik LG 19 LCD L1918S-SN TCO-03 Silver 1280x1024, 5ms, 700:1 -Demo. Kjørte følgende spørring:

 

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('+lg +lcd' IN BOOLEAN MODE)

 

Men uten resultat. Prøvde også med kun 'lg' men får heller ikke da noe resultat. Har selvfølgelig prøvd med både store og små bokstaver. Har jeg missforstått noe?

Lenke til kommentar
Tenkte mer på dette:

 

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('+lg +tv' IN BOOLEAN MODE)

 

Jeg har et produkt hvor product_name er lik LG 19 LCD L1918S-SN TCO-03 Silver 1280x1024, 5ms, 700:1 -Demo. Kjørte følgende spørring:

 

SELECT product_name FROM products WHERE MATCH (product_id,product_name,product_manufacturers_id) against('+lg +lcd' IN BOOLEAN MODE)

 

Men uten resultat. Prøvde også med kun 'lg' men får heller ikke da noe resultat. Har selvfølgelig prøvd med både store og små bokstaver. Har jeg missforstått noe?

 

Hei igjen...

 

Du har sikkert ikke fått endret på konfigurasjonen til MySQL'en din. Den er standard på at den bare indekserer ord med 4 bokstaver/tall i seg. Derfor må du inn i konfigurasjonen og få endret det til 3 eller 2 ettersom hva du ønsker.

 

Endre dette i konfigurasjonen: ft_min_word_len=3 eller til ft_min_word_len=2. Tallet spesifiserer altså antallet bokstaver i et ord.

 

Så må du starte mysql deamonen din på nytt, og rebuilde indexene dine ;) så er alt klart!

Lenke til kommentar
Hei igjen...

 

Du har sikkert ikke fått endret på konfigurasjonen til MySQL'en din. Den er standard på at den bare indekserer ord med 4 bokstaver/tall i seg. Derfor må du inn i konfigurasjonen og få endret det til 3 eller 2 ettersom hva du ønsker.

 

Endre dette i konfigurasjonen: ft_min_word_len=3 eller til ft_min_word_len=2. Tallet spesifiserer altså antallet bokstaver i et ord.

 

Så må du starte mysql deamonen din på nytt, og rebuilde indexene dine ;) så er alt klart!

Personen jeg lager søkefunksjonen for leier et webhotell hos subsys.no. Det er derfor begrenset med konfigurasjonsmuligheter. Er det mulig å definere disse variablene i PHP-scriptet eller liknende?

Lenke til kommentar
Hei igjen...

 

Du har sikkert ikke fått endret på konfigurasjonen til MySQL'en din. Den er standard på at den bare indekserer ord med 4 bokstaver/tall i seg. Derfor må du inn i konfigurasjonen og få endret det til 3 eller 2 ettersom hva du ønsker.

 

Endre dette i konfigurasjonen: ft_min_word_len=3 eller til ft_min_word_len=2. Tallet spesifiserer altså antallet bokstaver i et ord.

 

Så må du starte mysql deamonen din på nytt, og rebuilde indexene dine ;) så er alt klart!

Personen jeg lager søkefunksjonen for leier et webhotell hos subsys.no. Det er derfor begrenset med konfigurasjonsmuligheter. Er det mulig å definere disse variablene i PHP-scriptet eller liknende?

 

Dette må gjøres i mysql config, og mysql må restartes. Dette kan ikke kjøres live. Dessverre.

Lenke til kommentar
Dette må gjøres i mysql config, og mysql må restartes. Dette kan ikke kjøres live. Dessverre.

Og hvis jeg ikke har forstått det helt feil, så har dette potensielt en ganske så betydelig negativ impact på ytelse på serveren, og derfor er det vel relativt lite sannsynlig at en ISP kommer til å gjøre noe med dette.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...