[php] Een search voor een forum maken

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
Ik ben bezig met m'n eigen forum te bouwen en heb nu veel dingen al redelijk voor elkaar. Usergroups en rechten per forum per usergroups enzo allemaal dikke pret. Maar nu wil ik graag ook een search bouwen, maar ik heb geen idee hoe zoiets in elkaar zit. Op phpfreakz was het beste idee om iets als LIKE %woord% te gebruiken maar dat lijkt me niet echt lekker op dat op m'n posts table los te laten.

Ik dacht om tijdens het submitten alle woorden waarop gesearched mag worden een uniek ID te geven en om alle topicid's op te slaan waar dat woord in voor komt, maar volgens mij kom ik dan in de knoop met sorteren e.d.

Zou iemand de moeite willen nemen om me textueel uit te leggen hoe zoiets in elkaar kan zitten? Dan pruts ik d'r zelf wel mee verder :)

p.s. als jullie m'n prutswerk willen zien dan hoor ik het wel :+

[ Voor 6% gewijzigd door Kaasplank op 02-07-2003 12:39 ]


Acties:
  • 0 Henk 'm!

  • MisterData
  • Registratie: September 2001
  • Laatst online: 29-08 20:29
Kijk es op mysql.com (of welke andere site van je db server) naar 'FULLTEXT' ;)

Acties:
  • 0 Henk 'm!

  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
MisterData schreef op 02 juli 2003 @ 12:58:
Kijk es op mysql.com (of welke andere site van je db server) naar 'FULLTEXT' ;)
is dat nog snel als je forum goed gevuld is? Ik heb de database van vbulletin nagekeken en die gebruikt iig al geen FULLTEXT

Acties:
  • 0 Henk 'm!

  • zeroxcool
  • Registratie: Januari 2001
  • Laatst online: 04-09 19:14
Nou, als je toch VBB hebt kun je een beetje van hun techniek 'stelen' ;). Wat ik zou doen is een ruiswoorden lijst te maken (woorden als: als, de, het, een, voor, achter), kortom een lijst met woorden die niet in een search query thuis horen. Je splitst dan alle woorden in een post. Kijkt of ze niet in de ruiswoordenlijst staan. Dan ga je je woorden tabel langs, kijken of ze daar niet in staan, de woorden tabel:
code:
1
2
3
/------------|-----------\
|   woordid  |   woord   |
\------------|-----------/
Als het goed is staan al je woorden dan in de tabel. Dan ga je de woordid's koppelen aan postid's:
code:
1
2
3
/------------|-----------\
|   woordid  |   postid   |
\------------|-----------/
Als je dus gaat zoeken doe je zoiets als:
code:
1
2
3
4
5
6
7
8
9
SELECT p.threadid, t.title
FROM post p
LEFT JOIN thread t ON
t.threadid=p.threadid
LEFT JOIN links l ON
p.postid=l.postid
LEFT JOIN words w ON
l.woordid=w.woordid
WHERE w.woord IN ('zoekwoord1', 'zoekwoord2');
Natuurlijk indexeer je de ID's. Dat is naar mijn weten een snellere oplossing dan de FULLTEXT manier van MySQL.

[ Voor 15% gewijzigd door zeroxcool op 02-07-2003 14:24 . Reden: typo's en de tabel shit ;) ]

zeroxcool.net - curity.eu


Acties:
  • 0 Henk 'm!

  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
*kick*
Dankzij ZeRoXcOoL z'n uitstekende uitleg werkt het inmiddels prima, maar nu heb nog een 2e vraag. als ik zoek op "flap plep" oid dan krijg ik alle topics terug waar flap of plep in staat. Ik wil graag dat er alleen topics als resultaat komen waar flap en plep in staat. Is dit ook haalbaar met zo'n oplossing als ZeRoXcOoL laat zien?

m'n huidige query is dit:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
SELECT 
forums.forumid, 
forums.forumname, 
forums.frm, 
topics.topictitle, 
topics.topicid, 
topics.username, 
topics.postcount,
topics.lastpostdate 
FROM 
forums 
LEFT JOIN 
topics 
ON 
forums.forumid = topics.forumid 
LEFT JOIN 
posts 
ON 
posts.topicid = topics.topicid 
LEFT JOIN 
searchindex 
ON 
searchindex.postid = posts.postid 
LEFT JOIN 
searchwords 
ON 
searchwords.wordid = searchindex.wordid 
LEFT JOIN 
forumacces 
ON 
forumacces.forumid = forums.forumid 
WHERE 
searchwords.word 
IN 
($cleansearchstring) 
GROUP BY 
topics.topicid 
ORDER BY 
'$orderby' 
LIMIT 50

waarbij $cleansearchstring een tekst als 'flap', 'plep' is

en dan nog een 2e vraag. Om de pagina navigatie te maken moet ik weten hoeveel resulaten ik weer krijg zodat ik 1 2 3 4 enzovoort kan maken. Daarvoor doe ik elke keer een SELECT COUNT query om het totaal te tellen. Is dit een te zware optie als de db groter wordt en zo ja, hoe kan ik het beter maken? Met SQL_CALC_FOUND_ROWS werken is geen optie omdat de mysql versie bij m'n hosting daar nog geen raad mee weet.

[ Voor 6% gewijzigd door Kaasplank op 19-09-2003 13:31 ]


Acties:
  • 0 Henk 'm!

  • dusty
  • Registratie: Mei 2000
  • Laatst online: 15-09 18:24

dusty

Celebrate Life!

Jah, dat kan, het is alleen een andere query die je nodig hebt.

De twee relaties tussen de woorden is dan dat ze beiden in de zelfde threadid voorkomen.

Dus zal je in je query deze relatie moeten leggen :)

Back In Black!
"Je moet haar alleen aan de ketting leggen" - MueR


Acties:
  • 0 Henk 'm!

  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
Pluspunt van de Mysql fulltext functie en match / against SQl is dat er ook gekeken wordt naar de relevantie van een woord. Elke record krijgt een 'score' die hoger is naarmate het gevonden woord unieker. Ruiswoorden zoals 'de / het / een etc.' scoren dus automatisch heel laag.

Ik zou ook in je zoekimplementatie rekening houden met matches in de titel & matches in de inhoud. Matches in een titel zu ik hoger scoren.

Al met al is mijn ervaring dat een zoekfunctie maken wel te doen is. Maar een goede relevantie binnen je resultaten is moeilijker.

Koop of verkoop je webshop: ecquisition.com


Acties:
  • 0 Henk 'm!

  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
mocean schreef op 19 september 2003 @ 14:05:
Pluspunt van de Mysql fulltext functie en match / against SQl is dat er ook gekeken wordt naar de relevantie van een woord. Elke record krijgt een 'score' die hoger is naarmate het gevonden woord unieker. Ruiswoorden zoals 'de / het / een etc.' scoren dus automatisch heel laag.

Ik zou ook in je zoekimplementatie rekening houden met matches in de titel & matches in de inhoud. Matches in een titel zu ik hoger scoren.

Al met al is mijn ervaring dat een zoekfunctie maken wel te doen is. Maar een goede relevantie binnen je resultaten is moeilijker.
zoeken in hele topic / topictitel, naar topics van 1 bepaalde user of naar posts van 1 bepaalde user, zoeken in open, gesloten en sticky topics en zoeken in 1 of meerdere bepaalde fora zit er allemaal al in maar heb ik voor het gemak maar even weggelaten.

Ik heb even naar mysql's FULLTEXT gekeken maar de mysql versie van m'n host doet niet mee aan mijn AND en OR wensen enzo :)

ruiswoorden als de, het en een worden net zoals woorden korter dan 3 tekens al helemaal niet opgenomen in de searchindex

[ Voor 8% gewijzigd door Kaasplank op 19-09-2003 14:10 ]


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 12:56
Waarom sla je woorden van minder dan 3 tekens niet op? Als ik dus zoek naar info over kip heb ik dus een probleem? Of iemand moet net kippen gescheven hebben?

Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Waarom sla je woorden van minder dan 3 tekens niet op? Als ik dus zoek naar info over kip heb ik dus een probleem? Of iemand moet net kippen gescheven hebben?
Kip is bij mijn weten 3 letters, en dus niet minder dan 3 :z

Professionele website nodig?


Acties:
  • 0 Henk 'm!

  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
djluc schreef op 19 September 2003 @ 14:24:
Waarom sla je woorden van minder dan 3 tekens niet op? Als ik dus zoek naar info over kip heb ik dus een probleem? Of iemand moet net kippen gescheven hebben?
ik sla ze niet op omdat dat over het algemeen niet de woorden zijn waar je op zoekt. En moet je na gaan wat een records het me zal kosten als ik 'een' oid zou toestaan. in zowat elke post komt wel een 'een' of 'het' voor. dus dat zijn 2 extra records per post. Dan zou m'n searchindex binnen korte tijd wel heel groot worden. Mensen die naar kip zoeken hebben idd dan pech :)

edit:
het is dus minder of gelijk aan 3 letters :)
maar dat kan ik nog aanpassen door meer woorden in m'n noisewords list te gooien

maar zou er iemand me een schop in de goede richting willen geven hoe ik die link tussen verschillende wordid's en topicid's leg in m'n query. Ik kan met mijn kennis geen manier bedenken

[ Voor 28% gewijzigd door Kaasplank op 19-09-2003 14:41 ]


Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

het is dus minder of gelijk aan 3 letters
Weet je hoe veel ruzie het me gekost heeft voordat ik hier op GoT C++ topics in de search kon terugvinden met hetzelfde 'too short' geemmer?

C-topics zijn nog steeds een probleem. Waarom filter je ze eruit? Als ik toch topics over 'MS' of de 'CIA' of de 'FBI' of 'PSV' wil zoeken heb ik daar toch recht op? :?

Professionele website nodig?


Acties:
  • 0 Henk 'm!

  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
ja, je hebt gelijk. ik dacht even te simpel na. ik haal de = wel weg en zet wel wat meer 3 letter woorden in de noiswords lijst :)

dan zou je wel op kip en psv moeten kunnen zoeken :)

Acties:
  • 0 Henk 'm!

  • bigtree
  • Registratie: Oktober 2000
  • Laatst online: 16-08 17:16
Juggernaut schreef op 19 September 2003 @ 14:34:
[...]

ik sla ze niet op omdat dat over het algemeen niet de woorden zijn waar je op zoekt.[...]
Waar mensen op zoeken is volgens mij minder relevant dan het percentage posts waar een trefwoord in voorkomt. Woorden als 'de', 'het' en 'een' zullen in alle posts wel voorkomen en zijn dus niet zo relevant. Op een kippenforum zoeken naar 'kip' zal in veel gevallen irrelevante resultaten opleveren, aangezien de zoekterm te vaag is in die context. Mijn tip is dan ook om een zelf-lerende 'te-negeren-woorden-tabel' te maken die periodiek uitrekent in hoe veel procent van de posts een bepaald woord voorkomt. Is dat groter dan zeg 50%, dan zou je het woord kunnen negeren.

En dan een 'schop' terug naar je probleem; aangezien MySQL geen subqueries ondersteunt, zul je een ranzige oplossing moeten maken. De query die je hebt bouw je dan uit met COUNT(*) AS AantalHits. Dit getal staat voor het aantal woorden uit je criteria die bij een bepaalde post zijn gevonden. Als je zoekt op twee trefwoorden die allebei moeten voorkomen, voeg je aan het eind een HAVING AantalHits = 2 toe. Snappie?

Lekker woordenboek, als je niet eens weet dat vandalen met een 'n' is.


Acties:
  • 0 Henk 'm!

  • dusty
  • Registratie: Mei 2000
  • Laatst online: 15-09 18:24

dusty

Celebrate Life!

Probleem met ruiswoorden is dat men altijd zelf wilt opgeven wat de ruiswoorden zijn.

ruiswoorden zijn woorden die vaak voorkomen. dus kan je een treshold zetten bij een bepaald aantal, zodra enig woord dan over dat aantal heenkomt kan je die automatisch laten toevoegen aan de ruiswoorden. Hierdoor hoef je zelf ook die woorden niet bij te houden. En het systeem zal daardoor zichzelf gaan onderhouden.

Back In Black!
"Je moet haar alleen aan de ketting leggen" - MueR


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 12:56
Dat zou inderdaad wel kunnen, toch zou ik er ook handmatige controle op houden. Als je bijvoorbeeld een forum over webscripten hebt dan zulllen PHP en ASP vrijwel meteen op de lijst staan. Dat is niet handig omdat je daar dan niet meer op kunt zoeken en je dus niet meer taalselectief kunt zoeken.

Zo'n systeem om al die woorden die vaak voorkomen te zoeken zou ik trouwens in een cronjob uitvoeren omdat het best wel lang kan duren. Dan kun je dit op de rustige momenten van de dag laten doen.

edit:
Mijn tip is dan ook om een zelf-lerende 'te-negeren-woorden-tabel' te maken die periodiek uitrekent in hoe veel procent van de posts een bepaald woord voorkomt. Is dat groter dan zeg 50%, dan zou je het woord kunnen negeren.
Dan krijg je als je dus 51% PHP posts hebt en 45% ASP posts en 4% andere dus nooit de mogelijkheid om te zoeken naar specifieke PHP zaken?

[ Voor 58% gewijzigd door djluc op 19-09-2003 16:39 ]


Acties:
  • 0 Henk 'm!

  • dusty
  • Registratie: Mei 2000
  • Laatst online: 15-09 18:24

dusty

Celebrate Life!

dan is je treshold te laag :) Wat dan ook noodzakelijk kan zijn is je fora beter verdelen, aangezien er dan zoveel PHP en ASP topics zijn als de treshold toch juist geacht word dat het noodzakelijk is dat PHP en ASP wordt gescheiden.

Laatste strohalm zou dus een "Exception" lijst kunnen zijn van woorden die nooit toegevoegd mogen worden aan de ruiswoordenlijst.

Back In Black!
"Je moet haar alleen aan de ketting leggen" - MueR


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 12:56
Ik zou er dan voor kiezen om alle woorden handmatig goed te keuren. Het systeem gaat dus zelf alle mogelijke ruiswoorden zoeken en in een tabel mikken. Die tabel ga je daarna doorlopen en je gaat bij alle nieuw gevonden woorden, die zijn dan dus nog niet van toepassing op de resultaten, kiezen of het wel of niet gebruikt moet worden. Je kunt eventueel ook nog een stand automatisch maken waarbij het systeem aan de hand van een of andere waardering bepaald of het wel of niet gebruikt wordt. Dit zou bijvoorbeeld de genoemde 50% kunnen zijn.

Ik heb trouwens het idee dat we een beetje het wiel opnieuw aan het uitvinden zijn. Dit soort dingen zijn allemaal al zo vaak geprobeerd. Waarschijnlijk zijn er een aantal beproefde openbare technieken. Misschien zou je op basis daarvan een soort van ideaal systeem kunnen maken.

[ Voor 21% gewijzigd door djluc op 19-09-2003 16:44 ]


Acties:
  • 0 Henk 'm!

  • bigtree
  • Registratie: Oktober 2000
  • Laatst online: 16-08 17:16
dusty schreef op 19 september 2003 @ 16:39:
dan is je treshold te laag :)
Indeed. Om je treshold te bepalen zou je gewoon een lijst kunnen maken van alle voorkomende woorden en het percentage van de posts waar ze in voorkomen. Als je die lijst aflopend sorteert op percentage kan je makkelijk bepalen wat je treshold moet zijn.

Die 50% lijkt misschien laag, maar kijk op got maar eens in een willekeurig php-topic. Er staat weliswaar php in de titel, maar lang niet in alle posts van dat topic (code tags uitgezonderd ;)).

Lekker woordenboek, als je niet eens weet dat vandalen met een 'n' is.


  • zeroxcool
  • Registratie: Januari 2001
  • Laatst online: 04-09 19:14
Ben ik weer, dat 'tegen-argument' mbt FULLTEXT dat je daar kan laten sorteren op aantal hits kan heel gemakkelijk worden geïmplenteerd:
code:
1
2
3
/------------|-----------|-----------\
|   woordid  |   postid  |    hits   |
\------------|-----------|-----------/
Klaar, is alleen wat aanpassing in je INSERT queries (beetje met arrays met woorden en hits erin werken, enfin, kom je wel uit.

And queries kunnen ook:
code:
1
2
3
4
5
6
7
8
9
10
SELECT p.threadid, t.title
FROM post p
LEFT JOIN thread t ON
t.threadid=p.threadid
LEFT JOIN links l ON
p.postid=l.postid
LEFT JOIN words w ON
l.woordid=w.woordid
WHERE w.woord='zoekwoord1' AND w.woord='zoekwoord2')
GROUP BY w.postid;

Volgens mij is deze query een beetje crap op de vroege morgen, iemand anders ideeën?

[ Voor 9% gewijzigd door zeroxcool op 20-09-2003 09:36 ]

zeroxcool.net - curity.eu


  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
hmm.. met die query ga ik vanmiddag eens aan de gang. die query met HAVING werd nogal traag. kan wezen dat ik wat beter met indexen moet klooien, maargoed.

Dat van die hits maak ik me trouwens niet zo druk om. D'r zijn zat opties voorhanden om je search zo precies mogelijk te maken zodat je alleen relevante topics krijgt dacht ik.

Een probleem wat ik trouwens ook nog heb is dat ik wil weten hoeveel resultaten ik kreeg als er geen LIMIT limiet op de query zat om de pagina navigatie te maken. Ik doe het nu nog door een COUNT query te doen op elke pagina om alle resultaten te tellen en dan nog een keer een query om de weer te geven data op te halen. Iemand daar een betere oplossing voor?

  • eborn
  • Registratie: April 2000
  • Laatst online: 16-09 09:14
Juggernaut schreef op 20 September 2003 @ 10:34:
Een probleem wat ik trouwens ook nog heb is dat ik wil weten hoeveel resultaten ik kreeg als er geen LIMIT limiet op de query zat om de pagina navigatie te maken. Ik doe het nu nog door een COUNT query te doen op elke pagina om alle resultaten te tellen en dan nog een keer een query om de weer te geven data op te halen. Iemand daar een betere oplossing voor?
MySQL 4.0 en hoger heeft hier een nieuwe functie voor die precies doet wat jij wilt. Van de SELECT query maak je het volgende:
PHP:
1
$sth = $dbase->query( "SELECT SQL_CALC_FOUND_ROWS ... " );
Na het uitvoeren van deze query gebruik je bijvoorbeeld:
PHP:
1
2
$sth_total = $dbase->query( "SELECT FOUND_ROWS()" );
list($total) = mysql_fetch_row($sth_total);
In $total komt dan het totaal aantal rows te staan, ongeacht de LIMIT.

Zoals gezegd werkt dit dus alleen in MySQL >= 4.0

  • Kaasplank
  • Registratie: Februari 2001
  • Niet online
ja, die functie ken ik. maar ik had het hier ook al neergezet. m'n host draait dus mysql 3.nogwat :)

  • eborn
  • Registratie: April 2000
  • Laatst online: 16-09 09:14
Juggernaut schreef op 20 September 2003 @ 12:50:
ja, die functie ken ik. maar ik had het hier ook al neergezet. m'n host draait dus mysql 3.nogwat :)
Dat las ik, maar voor 3.x is er geen mooiere oplossing. Dus moet je je host maar even een trap de goeie richting opgeven :)

  • bartvb
  • Registratie: Oktober 1999
  • Laatst online: 08-09 13:47
BTW ik weet niet wat je van plan bent maar de oplossing die je nu gebruikt (en die we ook in phpBB gebruiken) schaalt echt enorm slecht. Is een leuke/handige oplossing want het draait overal waar je een half gare MySQL server hebt staan maar je wordt niet blij als je meer dan 1M posts hebt. Als je flinke ambities hebt: kijk naar een gespecialiseerd fulltext search systeem als b.v. www.xapian.org (wat bv ook op GoT gebruikt wordt).

Maar goed, zoals ik al zei, het werkt wel maar je site moet niet te groot worden of je moet genoeg geld hebben voor een ubergeile database server ;)
Pagina: 1