关键词

Django对接elasticsearch实现全文检索的示例代码

实现全文检索的过程中,我们常用搜索引擎,比如 Elasticsearch。而 Django 可以很容易地集成 Elasticsearch 来提供全文检索服务,本攻略将通过示例代码来讲解 Django 对接 Elasticsearch 实现全文检索的步骤。

Step 1:准备工作

在 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。

Step 2:定义索引

在 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 模型。

Step 3:编写搜索视图函数

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

展开阅读全文