实现全文检索的过程中,我们常用搜索引擎,比如 Elasticsearch。而 Django 可以很容易地集成 Elasticsearch 来提供全文检索服务,本攻略将通过示例代码来讲解 Django 对接 Elasticsearch 实现全文检索的步骤。
在 Django 项目中集成 Elasticsearch 首先需要安装 Elasticsearch。在这里,我们假设 Elasticsearch 已经在本地运行并且需要对一个名为 MyIndex 的索引进行全文检索。同时,需要安装 elasticsearch-py 库,它是 Elasticsearch Python 客户端。
安装 elasticsearch-py 库可以通过 pip 命令来完成:
$ pip install elasticsearch
安装完 elasticsearch-py 库之后,在 Django 的 settings.py 文件中进行如下配置:
ELASTICSEARCH_DSL={
'default': {
'hosts': 'localhost:9200'
},
}
以上配置指定了 Elasticsearch 的地址和端口号,默认为本地地址 127.0.0.1 和端口号 9200。
在 Django 的 models.py 文件中,我们定义了一个模型类 Blog,代表博客文章:
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
created_at = models.DateField(auto_now_add=True)
可以看出,这个模型包含了标题、内容和创建时间等字段,并作为全文检索的基础。
接下来,我们创建一个文档类型 BlogIndex,用来指定我们所定义的模型和 Elasticsearch 索引的对应关系。
from elasticsearch_dsl import Document, Text, Date
from elasticsearch_dsl.connections import connections
from .models import Blog
connections.create_connection()
class BlogIndex(Document):
title = Text()
content = Text()
created_at = Date()
class Index:
name = 'myindex'
def save(self, **kwargs):
self.created_at = datetime.now()
return super(BlogIndex, self).save(**kwargs)
def update(self, **kwargs):
self.created_at = datetime.now()
return super(BlogIndex, self).update(**kwargs)
def delete(self, **kwargs):
return super(BlogIndex, self).delete(**kwargs)
def to_object(self, **kwargs):
obj = super().to_object(**kwargs)
obj['id'] = self.meta.id
obj['created_at'] = self.created_at
return obj
def __init__(self, **kwargs):
self.created_at = datetime.now()
super(BlogIndex, self).__init__(**kwargs)
class Django:
model = Blog
BlogIndex 继承了 Elasticsearch DSL 中的 Document 类,其中包含了标题、内容和创建时间三个字段,并指定了 Elasticsearch 索引的名称为 'myindex';
其中,save()、update()、delete() 方法是为了使 Elasticsearch 的索引与 Django 的模型进行同步;
to_object() 方法是为了将 Elasticsearch 索引查询结果中的 meta.id 和 created_at 数据反应到模型对象中;
Django 属性是 Elasticsearch DSL 提供的专用模块,Django 的 model 属性用于指定该 Document 映射哪个 Django 模型。
from django.shortcuts import render
from django.views.generic import View
from elasticsearch_dsl import Search
from .documents import BlogIndex
class SearchView(View):
def get(self, request, *args, **kwargs):
query = request.GET.get('query')
s = Search().index('myindex').query("multi_match", fields=['title', 'content'], query=query)
response = s.execute()
context = {
'results': [],
'total_hits': response.hits.total.value
}
for hit in response.hits:
obj = BlogIndex(meta={'id': hit.meta.id})
obj = obj.to_object(include_meta=True)
context['results'].append(obj)
return render(request, 'blog/search.html', context=context)
在这个搜索视图函数中,我们首先从查询参数中获取搜索关键字,然后构建一个 Elasticsearch 的 Search 对象,并使用 multi_match 查询来对所有的 fields 通过关键字进行检索;
然后执行 Elasticsearch 的查询,返回一个 response 对象,我们将查询结果封装在 context 当中,并传递到模板展示。需要注意的是,由于我们在 BlogIndex 中定义了 to_object() 方法,所以可以轻松地将搜索结果中的 meta.id 和 created_at 数据反应到模型对象当中。
接下来,我们编写一个模板来展示搜索结果,例如模板 search.html:
{% extends 'base.html' %}
{% block content %}
{% if query %}
<h1>搜索结果:{{ total_hits }}</h1>
{% for result in results %}
<div>
<h2><a href="#">{{ result.title }}</a></h2>
<p>{{ result.content }}</p>
<span>发布时间:{{ result.created_at }}</span>
</div>
{% empty %}
<p>没有搜索到相关结果,请尝试其他关键字。</p>
{% endfor %}
{% else %}
<p>请输入查询关键字。</p>
{% endif %}
{% endblock %}
至此,我们已经完成了 Django 对接 Elasticsearch 实现全文检索的示例代码编写。可以通过请求 http://127.0.0.1:8000/search/?query=xxx 来对 MyIndex 索引进行全文检索,其中 xxx 为关键字。
本文链接:http://task.lmcjl.com/news/14244.html