Implementera enkel textsökning med Django

2021-06-29

Keyboard close up

Om du vill implementera en fulltextsökning av ett text- eller json-fält, vänder du dig i de flesta fall till Elasticsearch för att indexera och göra fälten sökbara åt dig. Även om Elasticsearch är en bra mjukvara, är det inte idealiskt för enklare scenarion. Installationen av Elasticsearch ökar komplexiteten av din applikation och ökar kravet på underhåll. Om du kör en Django applikation med Postgres som din DB finns det ett enklare sätt att lägga till en grundläggande och snabb sökfunktion i fulltext i din applikation.

Vi börjar med en enkel Django projekt enligt projectile strukturen med koppling till en postgres databas samt en Django app som heter textsearch med en enkel models.py:

# projectile/projectile/settings.py:

INSTALLED_APPS = [
		'django.contrib.admin',
		'django.contrib.auth',
		'django.contrib.contenttypes',
		'django.contrib.sessions',
		'django.contrib.messages',
		'django.contrib.staticfiles',
		'textsearch'
]

DATABASES = {
		'default': {
				'ENGINE': 'django.db.backends.postgresql_psycopg2',
				'NAME': '[DB_NAME]',
				'USER': '[DB_USERNAME]',
				'PASSWORD': '[PASSWORD]',
				'HOST': '[DB_HOSTNAME_OR_IP]',
				'PORT': '[DB_PORT]',
		}
}
# projectile/textsearch/models.py:

from django.db import models

class SomeString(models.Model):
		"""
		Post model for blog section of website
		"""
		title = models.CharField(max_length=100)
		cool_string = models.TextField()

I Django queryset finns det inbyggda stödfunktioner för att kunna söka på olika model fields. Dessa heter Field lookups. Med hjälp av dessa kan vi söka genom de olika fälten vi har specifiserat i vår SomeString model.

Börja med att migrera databasen, installera ipython (för att få en bättre python shell) samt skapa några exempel värden:

$ pip3 install ipython
$ python3 projectile/manage.py makemigrations
$ python3 projectile/manage.py migrate
$ python3 projectile/manage.py shell
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.24.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from textsearch.models import SomeString

In [2]: SomeString.objects.create(title="A Awesome Title", cool_string="This is a cool string")
Out[2]: <SomeString: SomeString object (1)>

In [3]: SomeString.objects.create(title="New Title", cool_string="Another cool string")
Out[3]: <SomeString: SomeString object (2)>

För att söka kan vi nu använda __contains (case sensitive) eller __icontains (non case sensitive) på inparametrarna till .filter() i Django queryset:

In [4]: awesome_titles = SomeString.objects.filter(title__icontains="awesome")

In [5]: awesome_titles
Out[5]: <QuerySet [<SomeString: SomeString object (1)>]>

In [6]: awesome_titles[0].title
Out[6]: 'A Awesome Title'

Nu får vi ut det första objektet vi skapade. Vi kan på samma sätt prova söka med case sensitive för den andra SomeString-objektet vi skapade:

In [7]: new_titles = SomeString.objects.filter(title__contains="new")

In [8]: new_titles
Out[8]: <QuerySet []>

Nu får vi inte ut vårt andra objekt. Ha i åtanke att enligt Djangos dokumentation fungerar contains och icontains likadant när man använder SQLite.

In [7]: new_titles = SomeString.objects.filter(title__contains="new")

In [8]: new_titles
Out[8]: <QuerySet []>

Vi kan istället försöka söka på textfältet som vi kallade cool_string:

In [9]: new_strings = SomeString.objects.filter(cool_string__icontains="another")

In [10]: new_strings
Out[10]: <QuerySet [<SomeString: SomeString object (2)>]>

In [11]: cool_strings = SomeString.objects.filter(cool_string__icontains="cool")
Out[11]: <QuerySet [<SomeString: SomeString object (1)>, <SomeString: SomeString object (2)>]>

Det finns många fler inbyggda lookup fields i Django som ni kan titta vidare på, speciellt för datum fält där Django har väldigt specifika och utförliga sökbegrepp (se här för mer detaljer).

Ovanstående exempel är några av de verktyg som vi på Will & Skill använder för att jobba datadrivet och värdeskapande tillsammans med våra kunder. Är du eller din organisation i startgroparna för att jobba mer datadrivet? Hör av dig till oss på Will & Skill idag och accelerera arbetet med att bli en organisation som rör sig fortare och med högre precision.