Een "faceted search" functie.

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 10-09 19:43
Ik ben bezig om in een bestaande website (gemaakt met behulp van SQL en PHP ) een 'faceted search' functie te implementeren, echter nu heb ik even een vraag over hoe je een dergelijke functie het beste kan opzetten.

Het is nu zo dat de gebruiker via een hoofdzoekbalk een vrije zoekterm invult een categorie kiest en vervolgens op zoeken drukt (net zoals op marktplaats.nl). Vervolgens wordt er dan een query uitgevoerd op de database waarbij eigenlijk 4 tabellen doorzocht worden en er dus een aantal join statements gebruikt worden.

SELECT
FROM...
LEFT JOIN..
ON
LEFT JOIN....
ON
LEFT JOIN...
ON
WHERE
AND.....
AND.....
AND....


Nu vraag ik mij echter af hoe je het beste kan gaan filteren op basis van de resultaatset die voortkomt uit deze query. Kan je het beste werken met 1 grote query en dat je dus de initiële query verder uitbreidt op basis van de gekozen filterwaarden (en dat je dus zo veel mogelijk doet in SQL), of kan je beter de resultaten van de initiële query gaan filteren in PHP (dat je dus alle gevonden objecten in een array hebt en op basis hiervan gaat filteren)?

Het probleem is daarnaast dat er bij een faceted search functie meestal de hoeveelheden bijgehouden worden van een bepaalde 'facetwaarde''. Dan wordt er dus bijvoorbeeld per subcategorie weergegeven hoeveel producten er in die subcategorie gevonden zijn. Dit betekent dus dat er per subcategorie een COUNT query uitgevoerd moet worden, echter als je dit steeds doet op basis van de initiële query dan moeten er dus in een korte tijd erg veel (afhankelijk van de hoeveelheid sub categorieën) zware query's uitgevoerd worden.

Misschien kunnen deze 'counts' dus beter gedaan worden op basis van de resultaat array (PHP). Echter dien je dan steeds een hele Array door te "loopen" en heb je de gehele objecten nodig ( of in ieder geval de velden van het object waarop gefilterd wordt) en dit vergt weer veel geheugen.


Maar wat is nu de meest efficiënte manier? Of 1 initiële query en op basis van PHP filteren, of 1 grote query en alles afhandelen via SQL? En hoe groot mag een SQL query überhaupt eigenlijk worden, is het mogelijk een query uit te voeren met 20 AND statements en 4 JOINS?

En nog 1 laatste vraag: weet iemand misschien relevante literatuur die nader op dit probleem ingaat?

Acties:
  • 0 Henk 'm!

  • azerty
  • Registratie: Maart 2009
  • Laatst online: 21:48
Je zou ook kunnen overwegen, om eenmaal je alle resultaten op de browser hebt, verdere filtering met JS te doen, wat je server minder belast en voor de client sneller kan zijn.

Acties:
  • 0 Henk 'm!

  • bomberboy
  • Registratie: Mei 2007
  • Laatst online: 02:47

bomberboy

BOEM!

Een (denk ik) betere mogelijkheid is een search/index gebruiken voor die zoekopdrachten. En dan eentje die ook effectief ook facets ondersteund enz. Dat zou het meest efficiënt moeten zijn wat betreft performance en dus responsiviteit voor de bezoeker. (Lucene, Solr enz)
Het allemaal via database of php doen zal qua schaalbaarheid erg beperkt zijn. Afhankelijk wat je noden zijn natuurlijk.

Wil je het toch nog zonder doen, dan zou ik persoonlijk starten met de data al zo veel mogelijk te filteren in de database zelf. Dus complexere queries. Het optimaliseren van de DB & queries wordt dan wel wat werk. Als het vooral om read-access gaat, dan kunnen views eventueel helpen bij de performance.

Acties:
  • 0 Henk 'm!

  • Xudonax
  • Registratie: November 2010
  • Laatst online: 02-09 13:25
Ik ben het heel erg eens met bomberboy hierboven. Wij doen op werk ~50 zoekopdrachten met faceting per minuut (meer bezoekers hebben we niet :P ) en dit gaat perfect met Solr. Mocht je het toch met SQL willen doen (kan ik me voorstellen hoor) dan raad ik sowieso aan om genoeg indexes e.d. aan te maken om je zoekopdracht snel te laten verlopen. Of inderdaad views. Sowieso willen stored procedures vaak een hoop helpen omdat je dan al gauw de SQL interpreter en query planner (voor een deel) overslaat.

Waar ik dan aan denk is dat je een complexe query doet in de database voor al je zoektermen en het faceten, en vervolgens zou je dan kunnen overwegen om een COUNT query te doen per facet wat nog beschikbaar is, zodat je gebruikers ook kunnen zien hoeveel resultaten er overblijven als ze dat kiezen ;)

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
wsitedesign schreef op zondag 17 november 2013 @ 21:20:
Je zou ook kunnen overwegen, om eenmaal je alle resultaten op de browser hebt, verdere filtering met JS te doen, wat je server minder belast en voor de client sneller kan zijn.
Maar waarom zou je alle resultaten op de browser willen hebben? Als iemand een zoekopdracht geeft die 3000 resultaten geeft dan wil je enkel de 1e 50 / 100 richting de browser sturen, want de rest ga je toch pas tonen op een 2e pagina...

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Gomez12 schreef op zondag 17 november 2013 @ 22:17:
[...]

Maar waarom zou je alle resultaten op de browser willen hebben? Als iemand een zoekopdracht geeft die 3000 resultaten geeft dan wil je enkel de 1e 50 / 100 richting de browser sturen, want de rest ga je toch pas tonen op een 2e pagina...
Voornamelijk dit. Faceted search wordt praktisch bij grote resultaatsets en die ga je echt niet ineens naar de client sturen. Daarnaast; wil je hiermee op de client werken, dan wordt je ook gedwongen voor elk zoekbaar item een compleet flat record naar de client te sturen waar alle data in zit om door te filteren op elk facet wat beschikbaar is. Dat wordt aardig duur.

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

MasterTweaker schreef op zondag 17 november 2013 @ 21:16:
Vervolgens wordt er dan een query uitgevoerd op de database waarbij eigenlijk 4 tabellen doorzocht worden en er dus een aantal join statements gebruikt worden.
Hebben de records uit die 4 tabellen ook daadwerkelijk een relatie met elkaar? Anders kan je wellicht beter UNION gebruiken (en de union als geheel weer een "order by" geven).
Kan je het beste werken met 1 grote query en dat je dus de initiële query verder uitbreidt op basis van de gekozen filterwaarden (en dat je dus zo veel mogelijk doet in SQL), of kan je beter de resultaten van de initiële query gaan filteren in PHP (dat je dus alle gevonden objecten in een array hebt en op basis hiervan gaat filteren)?
Dat hangt af van de grootte van de initiele resultaatset en hoe zwaar vervolg-filtering is. Als je hooguit een stuk of 1000 resultaten krijgt zou het zomaar in het voordeel van PHP kunnen uitvallen.
Dit betekent dus dat er per subcategorie een COUNT query uitgevoerd moet worden, echter als je dit steeds doet op basis van de initiële query dan moeten er dus in een korte tijd erg veel (afhankelijk van de hoeveelheid sub categorieën) zware query's uitgevoerd worden.
Als je je filtering naar PHP haalt, kan je ook het bepalen van die facetten daarnaartoe verplaatsen... eenvoudig wordt het niet, maar wellicht wel sneller.
Overigens kan je waarschijnlijk wel per OR-based facet voor alle opties een select met COUNT en GROUP BY combineren, zodat je voor bijvoorbeeld al je categorieen samen maar 1 query hoeft te doen.
Maar wat is nu de meest efficiënte manier?
Dat zal je dus moeten testen. Als de basisresultset erg groot is, maar de SQL-statements heel snel er mee kunnen werken... dan is het in het voordeel van SQL :P
En hoe groot mag een SQL query überhaupt eigenlijk worden, is het mogelijk een query uit te voeren met 20 AND statements en 4 JOINS?
Groot. Je zal niet zo heel snel tegen dergelijke limieten aanlopen. Uiteraard worden grotere/complexere queries doorgaans wel trager.
En nog 1 laatste vraag: weet iemand misschien relevante literatuur die nader op dit probleem ingaat?
Ik zou, zoals al door anderen werd gesuggereerd, ook goed naar alternatieve zoekmachines kijken. Solr en Elastic Search bieden facetten als standaardfunctionaliteit en zijn daar ook veel efficienter mee dan je in SQL mogelijk gaat maken.
Het betekent uiteraard wel dat je je gegevens synchroon moet zien te houden met je externe zoekdatabase en uiteraard weer een extra stuk software om te onderhouden. Maar het bespaart je weer wel je complexe code om de SQL-statements te fabriceren danwel om de facetten in php af te leiden :)
Pagina: 1