Sök¶
En vanlig uppgift för webbapplikationer är att söka efter data i databasen med hjälp av användarinmatning. I ett enkelt fall kan det handla om att filtrera en lista med objekt efter en kategori. Ett mer komplext användningsfall kan kräva sökning med viktning, kategorisering, markering, flera språk och så vidare. I det här dokumentet beskrivs några av de möjliga användningsområdena och de verktyg som du kan använda.
Vi kommer att hänvisa till samma modeller som används i Göra förfrågningar.
Användningsfall¶
Standardiserade textförfrågningar¶
Textbaserade fält har ett urval av matchningsoperationer. Du kanske till exempel vill tillåta uppslagning av en författare på följande sätt:
>>> Author.objects.filter(name__contains="Terry")
[<Author: Terry Gilliam>, <Author: Terry Jones>]
Det här är en mycket bräcklig lösning eftersom den kräver att användaren känner till en exakt delsträng av författarens namn. En bättre metod skulle kunna vara en matchning utan skiftlägeskänslighet (icontains
), men det är bara marginellt bättre.
En databases mer avancerade jämförelsefunktioner¶
Om du använder PostgreSQL tillhandahåller Django ett urval av databasspecifika verktyg så att du kan utnyttja mer komplexa frågealternativ. Andra databaser har olika urval av verktyg, eventuellt via plugins eller användardefinierade funktioner. Django inkluderar inget stöd för dem just nu. Vi kommer att använda några exempel från PostgreSQL för att visa vilken typ av funktionalitet databaser kan ha.
Sökning i andra databaser
Alla sökverktyg som tillhandahålls av django.contrib.postgres
är helt konstruerade på offentliga API:er som custom lookups och database functions. Beroende på din databas bör du kunna konstruera frågor för att tillåta liknande API:er. Om det finns specifika saker som inte kan uppnås på det här sättet, öppna en biljett.
I exemplet ovan kom vi fram till att det vore mer användbart med en jämförelse som inte tar hänsyn till skiftlägesskillnader. När det gäller icke-engelska namn är en ytterligare förbättring att använda unaccented comparison
:
>>> Author.objects.filter(name__unaccent__icontains="Helen")
[<Author: Helen Mirren>, <Author: Helena Bonham Carter>, <Author: Hélène Joy>]
Detta visar ett annat problem, där vi matchar mot en annan stavning av namnet. I det här fallet har vi dock en asymmetri - en sökning efter Helen
kommer att ge Helena
eller Hélène
, men inte tvärtom. Ett annat alternativ skulle vara att använda en trigram_similar
-jämförelse, som jämför sekvenser av bokstäver.
Till exempel:
>>> Author.objects.filter(name__unaccent__lower__trigram_similar="Hélène")
[<Author: Helen Mirren>, <Author: Hélène Joy>]
Nu har vi ett annat problem - det längre namnet ”Helena Bonham Carter” dyker inte upp eftersom det är mycket längre. Trigramsökningar tar hänsyn till alla kombinationer av tre bokstäver och jämför hur många som förekommer i både sök- och källsträngarna. För det längre namnet finns det fler kombinationer som inte förekommer i källsträngen, så det anses inte längre vara en nära matchning.
Det korrekta valet av jämförelsefunktioner här beror på din specifika datauppsättning, till exempel det eller de språk som används och den typ av text som söks. Alla de exempel vi har sett gäller korta strängar där användaren sannolikt kommer att skriva in något som ligger nära (med olika definitioner) källdata.
Dokumentbaserad sökning¶
Standardoperationer i databaser slutar att vara en användbar metod när man börjar titta på stora textblock. Medan exemplen ovan kan ses som operationer på en sträng med tecken, tittar fulltextsökning på de faktiska orden. Beroende på vilket system som används är det troligt att det använder några av följande idéer:
Ignorera ”stoppord” som ”en”, ”den”, ”och”.
Stamning av ord, så att ”ponny” och ”ponnyer” anses vara likartade.
Viktning av ord baserat på olika kriterier, t.ex. hur ofta de förekommer i texten eller hur viktiga de fält är som de förekommer i, t.ex. titel eller nyckelord.
Det finns många alternativ till att använda sökprogramvara, några av de mest framträdande är Elastic och Solr. Dessa är fullständiga dokumentbaserade söklösningar. För att använda dem med data från Django-modeller behöver du ett lager som översätter dina data till ett textdokument, inklusive backreferenser till databas-ID:n. När en sökning med hjälp av motorn returnerar ett visst dokument kan du sedan slå upp det i databasen. Det finns en mängd olika tredjepartsbibliotek som är utformade för att hjälpa till med denna process.
Stöd för PostgreSQL¶
PostgreSQL har sin egen inbyggda implementering av fulltextsökning. Även om det inte är lika kraftfullt som vissa andra sökmotorer, har det fördelen att det finns i din databas och så kan det enkelt kombineras med andra relationsfrågor som kategorisering.
Modulen django.contrib.postgres
tillhandahåller några hjälpmedel för att göra dessa frågor. Till exempel kan en fråga välja alla blogginlägg som nämner ”ost”:
>>> Entry.objects.filter(body_text__search="cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
Du kan också filtrera på en kombination av fält och på relaterade modeller:
>>> Entry.objects.annotate(
... search=SearchVector("blog__tagline", "body_text"),
... ).filter(search="cheese")
[
<Entry: Cheese on Toast recipes>,
<Entry: Pizza Recipes>,
<Entry: Dairy farming in Argentina>,
]
Se dokumentet contrib.postgres
Fulltextsökning för fullständig information.