de Adam Wattis

ElasticSearch cu Django într-un mod simplu

ElasticSearch cu Django intr un mod usor

Cu ceva timp în urmă lucram la un proiect Django și am vrut să implementez căutare rapidă gratuită de text. În loc să folosesc o bază de date obișnuită pentru această funcție de căutare – cum ar fi MySQL sau PostgreSQL – am decis să folosesc o bază de date NoSQL. Atunci am descoperit ElasticSearch.

ElasticSearch indexează documentele pentru datele dvs. în loc să utilizeze tabele de date, așa cum o face o bază de date relațională obișnuită. Acest lucru accelerează căutarea și oferă multe alte avantaje pe care nu le obțineți cu o bază de date obișnuită. Am păstrat și o bază de date relațională obișnuită pentru stocarea detaliilor utilizatorului, conectărilor și a altor date pe care ElasticSearch nu a trebuit să le indexeze.

După ce am căutat mult timp cum să implementez corect ElasticSearch cu Django, nu am găsit răspunsuri satisfăcătoare. niste ghiduri sau tutoriale erau complicate și păreau că fac pași inutili pentru a indexa datele în ElasticSearch. Au fost destul de puține informații despre cum să efectuați căutarea, dar nu atât de multe despre cum ar trebui să se facă indexarea. Am simțit că trebuie să existe o soluție mai simplă acolo, așa că am decis să încerc și eu.

Am vrut să-l păstrez cât mai simplu posibil, deoarece soluțiile simple tind să fie cele mai bune în opinia mea. KISS (Keep It Simple Stupid), Less is More și toate aceste lucruri sunt ceva care rezonează cu mine, mai ales atunci când orice altă soluție este complexă. Am decis să folosesc exemplul lui Honza Král în acest video să am ceva pe care să-mi bazez codul. Vă recomand să-l urmăriți, deși este cam depășit în acest moment.

Întrucât foloseam Django – care este scris în Python – a fost ușor să interacționezi cu ElasticSearch. Există două biblioteci client pentru a interacționa cu ElasticSearch cu Python. Există elasticsearch-py, care este clientul oficial de nivel scăzut. Și există elasticsearch-dsl, care se bazează pe prima, dar oferă o abstracție de nivel superior cu o funcționalitate puțin mai mică.

Vom intra în câteva exemple în curând, dar mai întâi trebuie să clarific ce vrem să realizăm:

  • Configurarea ElasticSearch pe mașina noastră locală și asigurarea că funcționează corect
  • Configurarea unui nou proiect Django
  • Indexarea în bloc a datelor care se află deja în baza de date
  • Indexarea fiecărei instanțe noi pe care un utilizator o salvează în baza de date
  • Un exemplu de căutare de bază

Bine, pare destul de simplu. Să începem instalând ElasticSearch pe computerul nostru. De asemenea, toate codul va fi disponibil pe GitHub astfel încât să puteți urmări cu ușurință exemplele.

Instalarea ElasticSearch

Deoarece ElasticSearch rulează pe Java, trebuie să vă asigurați că aveți o versiune JVM actualizată. Verificați cu ce versiune aveți java -version în terminal. Apoi executați următoarele comenzi pentru a crea un nou director, descărcați, extrageți și porniți ElasticSearch:

mkdir elasticsearch-example
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.1.1.tar.gz
tar -xzf elasticsearch-5.1.1.tar.gz
./elasticsearch-5.1.1/bin/elasticsearch

Când ElasticSearch pornește, ar trebui să existe o mulțime de rezultate tipărite în fereastra terminalului. Pentru a verifica dacă funcționează corect, deschideți o nouă fereastră de terminal și rulați aceasta curl comanda:

curl -XGET http://localhost:9200

Răspunsul ar trebui să fie cam așa:

{  "name" : "6xIrzqq",  "cluster_name" : "elasticsearch",  "cluster_uuid" : "eUH9REKyQOy4RKPzkuRI1g",  "version" : {    "number" : "5.1.1",    "build_hash" : "5395e21",    "build_date" : "2016-12-06T12:36:15.409Z",    "build_snapshot" : false,    "lucene_version" : "6.3.0"  },  "tagline" : "You Know, for Search"

Excelent, acum aveți ElasticSearch rulat pe computerul dvs. local! Este timpul să vă configurați proiectul Django.

Configurarea unui proiect Django

Mai întâi creați un mediu virtual cu virtualenv venv și introduceți-l cu source venv/bin/activate pentru a păstra totul cuprins. Apoi instalați câteva pachete:

pip install djangopip install elasticsearch-dsl

Pentru a începe un nou proiect Django, executați:

django-admin startproject elasticsearchprojectcd elasticsearchprojectpython manage.py startapp elasticsearchapp

După ce ați creat noile proiecte Django, trebuie să creați un model pe care îl veți folosi. Pentru acest ghid, am ales să merg cu un exemplu bun de postare de modă veche pe blog. În models.py plasați următorul cod:

from django.db import modelsfrom django.utils import timezonefrom django.contrib.auth.models import User# Create your models here.# Blogpost to be indexed into ElasticSearchclass BlogPost(models.Model):   author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="blogpost")   posted_date = models.DateField(default=timezone.now)   title = models.CharField(max_length=200)   text = models.TextField(max_length=1000)

Destul de direct, până acum. Nu uitați să adăugați elasticsearchapp la INSTALLED_APPS în settings.py și înregistrați-vă noul model BlogPost în admin.py asa:

from django.contrib import adminfrom .models import BlogPost# Register your models here.# Need to register my BlogPost so it shows up in the adminadmin.site.register(BlogPost)

Trebuie, de asemenea python manage.py makemigrations, python manage.py migrate și python manage.py createsuperuser pentru a crea baza de date și un cont de administrator. Acum, python manage.py runserver, mergi la http://localhost:8000/admin/ și autentificare. Acum ar trebui să puteți vedea modelul dvs. de postări pe blog acolo. Continuați și creați prima dvs. postare de blog în administrator.

Felicitări, aveți acum un proiect Django funcțional! În sfârșit, este timpul să intrați în lucrurile distractive – conectarea ElasticSearch.

Conectarea ElasticSearch cu Django

Începeți prin crearea unui nou fișier numit search.py în a noastră elasticsearchapp director. Aici va locui codul ElasticSearch. Primul lucru pe care trebuie să-l faceți aici este să creați o conexiune de la aplicația dvs. Django la ElasticSearch. Faceți acest lucru în search.py fişier:

from elasticsearch_dsl.connections import connectionsconnections.create_connection()

Acum că aveți o conexiune globală la setarea dvs. ElasticSearch, trebuie să definiți ce doriți să indexați în ea. Scrieți acest cod:

from elasticsearch_dsl.connections import connectionsfrom elasticsearch_dsl import DocType, Text, Dateconnections.create_connection()class BlogPostIndex(DocType):    author = Text()    posted_date = Date()    title = Text()    text = Text()    class Meta:        index = 'blogpost-index'

Arată destul de similar cu modelul tău, nu? DocType funcționează ca un wrapper pentru a vă permite să scrieți un index ca un model și Text și Date sunt câmpurile astfel încât să obțină formatul corect atunci când sunt indexate.

În cadrul Meta îi spuneți lui ElasticSearch ce doriți să fie denumit indexul. Acesta va fi un punct de referință pentru ElasticSearch, astfel încât să știe cu ce index se ocupă atunci când îl inițializează în baza de date și salvează fiecare nouă instanță de obiect creată.

Acum trebuie să creați de fapt cartografierea noului dvs. creat BlogPostIndex în ElasticSearch. Puteți face acest lucru și, de asemenea, puteți crea o modalitate de a face indexarea în bloc în același timp – cât de convenabil nu?

Indexarea în bloc a datelor

bulk comanda se află în elasticsearch.helpers care este inclus la instalare elasticsearch_dsl deoarece este construit deasupra bibliotecii respective. Faceți următoarele în search.py:

...from elasticsearch.helpers import bulkfrom elasticsearch import Elasticsearchfrom . import models...
...def bulk_indexing():    BlogPostIndex.init()    es = Elasticsearch()    bulk(client=es, actions=(b.indexing() for b in models.BlogPost.objects.all().iterator()))

“Ce se intampla aici?” s-ar putea să te gândești. De fapt, nu este atât de complicat.

Întrucât doriți să faceți indexarea în masă numai ori de câte ori schimbați ceva în modelul dvs. init() modelul care îl mapează în ElasticSearch. Apoi, utilizați bulk și treceți o instanță de Elasticsearch() care va crea o conexiune la ElasticSearch. Treci apoi un generator la actions= și iterați peste toate BlogPost obiectele pe care le aveți în baza de date obișnuită și apelați .indexing() metoda pe fiecare obiect. De ce un generator? Pentru că dacă ați avea o mulțime de obiecte pe care să le repetați pe un generator, nu ar trebui să le încărcați mai întâi în memorie.

Există doar o problemă cu codul de mai sus. Nu aveți .indexing() metodă pe modelul dvs. încă. Să remediem:

...from .search import BlogPostIndex...
...# Add indexing method to BlogPostdef indexing(self):   obj = BlogPostIndex(      meta={'id': self.id},      author=self.author.username,      posted_date=self.posted_date,      title=self.title,      text=self.text   )   obj.save()   return obj.to_dict(include_meta=True)

Adăugați metoda de indexare la BlogPost model. Se întoarce un BlogPostIndex și este salvat în ElasticSearch.

Să încercăm acest lucru acum și să vedem dacă puteți indexa în bloc postarea de blog pe care ați creat-o anterior. Fugind python manage.py shell intri în shell Django și importi search.py cu from elasticsearchapp.search import * și apoi fugi bulk_indexing() pentru a indexa toate postările de blog din baza dvs. de date. Pentru a vedea dacă a funcționat, rulați următoarea comandă curl:

curl -XGET 'localhost:9200/blogpost-index/blog_post_index/1?pretty'

Ar trebui să primiți din nou prima dvs. postare de blog în terminal.

Indexarea instanței nou salvate

Apoi trebuie să adăugați un semnal care declanșează .indexing() pe fiecare nouă instanță salvată de fiecare dată când un utilizator salvează o nouă postare pe blog. În elasticsearchapp creați un fișier nou numit signals.py și adăugați acest cod:

from .models import BlogPostfrom django.db.models.signals import post_savefrom django.dispatch import receiver@receiver(post_save, sender=BlogPost)def index_post(sender, instance, **kwargs):    instance.indexing()

post_save semnalul se va asigura că instanța salvată va fi indexată cu .indexing() după salvare.

Pentru ca acest lucru să funcționeze, trebuie să înregistrăm și Django că folosim semnale. Facem această deschidere apps.py și adăugând următorul cod:

from django.apps import AppConfigclass ElasticsearchappConfig(AppConfig):    name="elasticsearchapp"    def ready(self):        import elasticsearchapp.signals

Pentru a finaliza acest lucru, trebuie să-i spunem și lui Django că folosim această nouă configurație. Facem acest lucru în interiorul __init__.py în interiorul nostru elasticsearchapp director adăugând:

default_app_config = 'elasticsearchapp.apps.ElasticsearchappConfig'

Acum post_save signal este înregistrat la Django și este gata să asculte ori de câte ori este salvat un nou post de blog.

Încercați-l accesând din nou administratorul Django și salvând un nou post de blog. Apoi verificați cu un curl comanda dacă a fost indexată cu succes în ElasticSearch.

Acum permiteți să creați o funcție de căutare simplă în search.py pentru a găsi toate postările filtrate de autor:

...from elasticsearch_dsl import DocType, Text, Date, Search...
...def search(author):    s = Search().filter('term', author=author)    response = s.execute()    return response

Să încercăm căutarea. În cochilie: from elasticsearchapp.search import * și fugi print(search(author="<author name&gt; “)):

>>> print(search(author="home"))<Response: [<Result(blogpost-index/blog_post_index/1): {'text': 'Hello world, this is my first blog post', 'title':...}>]>

Iată-l! Ați indexat cu succes toate instanțele dvs. în ElasticSearch, ați creat un post_save semnal care indexează fiecare instanță recent salvată și a creat o funcție pentru a căuta datele din baza noastră de date ElasticSearch.

Concluzie

Acesta a fost un articol destul de lung, dar sper că este scris suficient de simplu pentru ca chiar și începătorul să poată înțelege.

Am explicat cum să conectați un model Django la ElasticSearch pentru indexare și căutare, dar există atât de multe lucruri pe care ElasticSearch le poate face. Vă recomand să citiți pe site-ul lor web și să explorați ce alte posibilități există, cum ar fi operațiile spațiale și căutarea textului complet cu evidențiere inteligentă. Este un instrument excelent și voi fi sigur că îl voi folosi în proiecte viitoare!

Dacă ți-a plăcut acest articol sau ai un comentariu sau sugestie, te rog să lași un mesaj mai jos. Și stați la curent pentru lucruri mai interesante!