Wat u wilt, is een "gefacetteerd zoeken"-resultaat waarin u de statistieken over de overeenkomende termen in de huidige resultatenset bewaart. Hoewel er producten zijn die al het werk in één reactie 'lijken' te doen, moet u er rekening mee houden dat de meeste generieke opslagengines meerdere bewerkingen nodig hebben.
Met MongoDB kunt u twee query's gebruiken om de resultaten zelf te krijgen en een andere om de facetinformatie te krijgen. Dit zou vergelijkbare resultaten opleveren als de gefacetteerde resultaten die beschikbaar zijn in speciale zoekmachineproducten zoals Solr of ElasticSearch.
Maar om dit effectief te doen, wilt u dit in uw document opnemen op een manier waarop het effectief kan worden gebruikt. Een zeer effectieve vorm voor wat u wilt, is het gebruik van een reeks tokenized data:
{
"otherData": "something",
"facets": [
"country:UK",
"city:London-UK",
"genre:Student"
]
}
Dus "factets" is een enkel veld in uw document en niet op meerdere locaties. Dit maakt het zeer eenvoudig om te indexeren en te zoeken. Vervolgens kunt u uw resultaten effectief aggregeren en de totalen voor elk facet krijgen:
User.aggregate(
[
{ "$unwind": "$facets" },
{ "$group": {
"_id": "$facets",
"count": { "$sum": 1 }
}}
],
function(err,results) {
}
);
Of beter nog met enkele criteria in $match
:
User.aggregate(
[
{ "$match": { "facets": { "$in": ["genre:student"] } } },
{ "$unwind": "$facets" },
{ "$group": {
"_id": "$facets",
"count": { "$sum": 1 }
}}
],
function(err,results) {
}
);
Uiteindelijk een reactie geven als:
{ "_id": "country:FR", "count": 50 },
{ "_id": "country:UK", "count": 300 },
{ "_id": "city:London-UK", "count": 150 },
{ "_id": "genre:Student": "count": 500 }
Zo'n structuur is gemakkelijk te doorkruisen en te inspecteren op zaken als het afzonderlijke "land" en de "stad" die bij een "land" hoort, aangezien die gegevens gewoon consequent worden gescheiden door een koppelteken "-".
Het is een slecht idee om documenten in arrays samen te voegen. Er is ook een BSON-groottelimiet van 16 MB die moet worden gerespecteerd, waarvan het samenvoegen van resultaten (vooral als u de documentinhoud probeert te behouden) zeker zal worden overschreden in het antwoord.
Voor zoiets eenvoudigs als het verkrijgen van het "totale aantal" resultaten van een dergelijke zoekopdracht, vat dan gewoon de elementen van een bepaald facettype samen. Of geef gewoon dezelfde query-argumenten door aan een .count()
bediening:
User.count({ "facets": { "$in": ["genre:Student"] } },function(err,count) {
});
Zoals hier gezegd, met name bij het implementeren van "paging" van resultaten, worden de rollen van het verkrijgen van "Result Count", "Facet Counts" en de eigenlijke "Page of Results" allemaal gedelegeerd aan "afzonderlijke" zoekopdrachten naar de server.
Er is niets mis mee om al die zoekopdrachten parallel naar de server te sturen en vervolgens een structuur te combineren om naar uw sjabloon of applicatie te voeren die veel lijkt op het gefacetteerde zoekresultaat van een van de zoekmachineproducten die dit soort reacties biedt.
Concluderend
Zet dus iets in je document om de facetten op één plek te markeren. Een reeks tokenized strings werkt goed voor dit doel. Het werkt ook goed met zoekformulieren zoals $in
en $all
voor "of" of "en" voorwaarden op combinaties van facetselectie.
Probeer niet om resultaten te pureren of toevoegingen te nesten om te passen bij een waargenomen hiërarchische structuur, maar doorloop de ontvangen resultaten en gebruik eenvoudige patronen in de tokens. Het is heel eenvoudig om
Voer wisselquery's voor de inhoud uit als afzonderlijke query's voor facetten of algemene tellingen. Het heeft geen zin om alle inhoud in arrays te pushen en vervolgens te beperken om tellingen te krijgen. Hetzelfde zou van toepassing zijn op een RDBMS-oplossing om hetzelfde te doen, waarbij het tellen van paginresultaten en de huidige pagina afzonderlijke querybewerkingen zijn.
Er is meer informatie geschreven op de MongoDB Blog over Faceted Search met MongoDB waarin ook enkele andere opties worden uitgelegd. Er zijn ook artikelen over integratie met externe zoekoplossingen met behulp van mongoconnector of andere benaderingen.