Django Haystack 全文检索与关键词高亮的实现

1. Django Haystack 简介

Django Haystack 是一个全文搜索框架,它基于 Django 的 ORM,支持搜索各种后端,包括 Elasticsearch、Solr、Whoosh 等。它易于使用,并且提供了许多有用的搜索实用程序和工具,使我们可以更容易地实现复杂的搜索。

pip install django-haystack

2. Django Haystack 安装

2.1 安装 Haystack 包

安装 Django Haystack 的包是非常简单的。只需使用 pip 包管理器,运行以下命令就可以将其安装在您的虚拟环境中:

pip install django-haystack

注意:Django Haystack 使用了 Pyramid、Whoosh、Elasticsearch、Solr、Xapian 和 Picky 这些全文搜索后端,但它们不在默认安装包中。要使用这些搜索后端,您需要手动安装适当的包,再执行以下命令:

pip install "django-haystack[elasticsearch]"

pip install "django-haystack[solr]"

pip install "django-haystack[whoosh]"

2.2 配置 Django Haystack

配置 Django Haystack 需要在 settings.py 文件中添加以下代码:

# settings.py

INSTALLED_APPS = [

# ... 其他应用

'haystack',

]

# 配置搜索后端

HAYSTACK_CONNECTIONS = {

'default': {

'ENGINE': 'haystack.backends.elasticsearch2_backend.Elasticsearch2SearchEngine',

'URL': 'http://localhost:9200/',

'INDEX_NAME': 'books',

},

}

上述配置说明:

INSTALLED_APPS:Haystack 必须存在于 INSTALLED_APPS 中。

ENGINE:这是搜索引擎的后端,Haystack 支持多种搜索引擎,不同的搜索引擎对应不同的后端。

URL:Elasticsearch 服务的 URL。

INDEX_NAME:Elasticsearch 中的索引名称。可以将其设置为模型名称或自定义名称。

现在 Django Haystack 配置已经完成,我们可以开始创建搜索索引了。

3. Django Haystack 创建索引

我们需要使用 Haystack 自带的管理器 SearchIndex 来为模型创建搜索索引。

SearchIndex 允许我们为每个模型指定要搜索的字段和它们的权重,以及其他搜索相关的设置。这些设置将在后面讨论。

假设有一个 Book 模型如下所示:

# models.py

from django.db import models

class Book(models.Model):

title = models.CharField(max_length=200, null=False)

author = models.CharField(max_length=200, null=False)

publish_date = models.DateField(null=False)

isbn = models.CharField(max_length=20, null=True)

description = models.TextField(null=True)

要为 Book 模型创建索引,我们需要创建一个名为 BookIndex 的类,它继承自 SearchIndex,并定义以下内容:

text:定义将要搜索的内容。

author:定义作者字段的搜索方式。

publish_date:定义出版日期字段的搜索方式。

isbn:定义 ISBN 字段的搜索方式。

get_model():定义哪个模型与索引相关联。在此示例中,它是 Book 模型。

BookIndex 类的完整定义如下所示:

# search_indexes.py

from haystack import indexes

from .models import Book

class BookIndex(indexes.SearchIndex, indexes.Indexable):

text = indexes.CharField(document=True, use_template=True)

author = indexes.CharField(model_attr='author')

publish_date = indexes.DateField(model_attr='publish_date')

isbn = indexes.CharField(model_attr='isbn', null=True)

def get_model(self):

return Book

该类有一个方法 named get_model(),该方法指定我们要为哪个模型创建索引。

使用 Haystack,我们可以使用单一目录或多个目录来存储索引。索引目录是一个包含单个配置的目录,该配置指定 Elasticsearch、Solr 或 Whoosh 后端,它应存储索引数据。

我们需要在 search_indexes.py 文件中添加以下内容来定义索引目录:

# search_indexes.py

import os

from django.conf import settings

from django.utils.text import slugify

from django.template import loader

from haystack import indexes

from .models import Book

class BookIndex(indexes.SearchIndex, indexes.Indexable):

text = indexes.CharField(document=True, use_template=True)

author = indexes.CharField(model_attr='author')

publish_date = indexes.DateField(model_attr='publish_date')

isbn = indexes.CharField(model_attr='isbn', null=True)

def get_model(self):

return Book

def prepare(self, obj):

prepared_data = super(BookIndex, self).prepare(obj)

prepared_data['boost'] = 1.0

prepared_data['slug'] = slugify(prepared_data['title'])

return prepared_data

def get_stored_fields(self, data, *args, **kwargs):

return ['title', 'author', 'publish_date', 'isbn', 'slug']

def index_queryset(self, using=None, **kwargs):

return self.get_model().objects.all()

上述代码使用 use_templates=True 参数使 Haystack 使用模板系统将文本字段的多个字段合并为一个字段。具体来说,它使用一个名为 'search/indexes/foo/bar_text.txt' 的模板文件,该文件类似于以下内容:

{% autoescape off %}{{ object.title }}{{ object.author }}{{ object.publish_date }}{{ object.isbn }}{{ object.description }}{% endautoescape %}

接下来,我们将介绍如何在 Django Haystack 中实现关键词高亮功能。

4. Django Haystack 实现关键词高亮

要对搜索结果进行关键词高亮,可以使用 Elasticsearch 或 Solr 这样的后端。对于 Whoosh 后端,关键词高亮功能不可用。

要启用关键词高亮功能,需要添加以下设置:

# settings.py

HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

HAYSTACK_CONNECTIONS = {

# Solr

'default': {

'ENGINE': 'haystack.backends.solr_backend.SolrEngine',

'URL': 'http://localhost:8983/solr/default',

'INCLUDE_SPELLING': True,

'EXCLUDED_INDEXES': ['myapp.search_indexes.MyModelIndex'],

'SEARCH_RESULTS_PER_PAGE': 20,

'SILENTLY_FAIL': False,

'TIME_LIMIT': 120,

'INCLUDE_SCORES': True,

'BATCH_SIZE': 100,

'INCLUDE_FACETS': False,

'DJANGO_CT': 'text/plain',

},

# Elasticsearch

'elasticsearch': {

'ENGINE': 'haystack.backends.elasticsearch2_backend.Elasticsearch2SearchEngine',

'URL': 'http://localhost:9200/',

'INDEX_NAME': 'myapp',

'TIMEOUT': 60,

'INCLUDE_SPELLING': True,

'EXCLUDED_INDEXES': ['myapp.search_indexes.MyModelIndex'],

'SEARCH_RESULTS_PER_PAGE': 20,

}

}

注意:开启关键词高亮功能可能会影响性能。

现在,我们可以在模板文件中使用 highlight 参数,将需要高亮的内容包装在 <span> 标签中。有了这个参数,Elasticsearch 和 Solr 将使用它们的分析器来确定关键词位置,并将关键词包装在 <em> 或其他标记中。在我们的模板中,这会将搜索结果的所有匹配强调显示。

在索引中添加关键字高亮:

# search_indexes.py

from haystack import indexes

from .models import Book

class BookIndex(indexes.SearchIndex, indexes.Indexable):

text = indexes.CharField(document=True, use_template=True)

author = indexes.CharField(model_attr='author')

publish_date = indexes.DateField(model_attr='publish_date')

isbn = indexes.CharField(model_attr='isbn', null=True)

def get_model(self):

return Book

def prepare(self, obj):

prepared_data = super(BookIndex, self).prepare(obj)

prepared_data['boost'] = 1.0

prepared_data['title'] = obj.title

return prepared_data

上述代码中,我们使用本地变量来保存 SearchIndex.prepare() 的返回结果,并添加一个新字段,将其设置为 obj.title 的值,以便我们可以在模板中选择要高亮显示的文本。

现在,我们可以在搜索视图中配置 SearchQuerySet,以便解析接受的搜索查询并突出显示文本:

# views.py

from django.shortcuts import render

from haystack.query import SearchQuerySet

def search(request):

query = request.GET.get('q', '')

sqs = SearchQuerySet().highlight().auto_query(query)

context = {

'query': query,

'sqs': sqs,

}

return render(request, 'search.html', context)

注意:我们在 SearchQuerySet 上调用 highlight() 方法,以便启用突出显示。该方法在 QuerySet API 中是唯一的对象,而不是链式方法。如果我们希望进一步修改查询,可以使用类似于 Django 中 QuerySet 的方法。

现在,我们只需要创建一个搜索模板来显示搜索结果,并使用 Haystack 提供的模板标记来渲染突出显示文本。

在模板中显示关键字高亮:

{% extends "base.html" %}

{% block title %}

Search Results | {{ block.super }}

{% endblock %}

{% block content %}

<form method="get" action="{% url 'search' %}">

<input name="q" type="text" />

<button type="submit">Search</button>

</form>

<ul>

{% for result in sqs %}

<li><a href="{{ result.object.get_absolute_url }}">{{ result.object.title }}</a> ({{ result.rank|floatformat }})</li>

{% for hl in result.highlighted %}

<ul>

{% for text in hl|safe %}

<li>{{ text|safe }}</li>

{% endfor %}

</ul>

{% endfor %}

{% empty %}

<p>No results found.</p>

{% endfor %}

</ul>

{% endblock %}

在模板中,模板标记 {% for hl in result.highlighted %} 是一个迭代,它包含突出显示的所有文本块,其中 hl 是每个文本块的变量名。

我们可以使用 safe 过滤器将文本字符串中的 HTML 转义默认值取消,以显示突出显示的文本。

5. 总结

在本文中,我们介绍了 Django Haystack 的基础知识以及如何创建搜索索引和实现关键词高亮功能。 Haystack 是一个非常强大的工具,允许我们使用各种后端搜索解决方案,包括 Elasticsearch、Solr 和 Whoosh。此外,它还提供了许多有用的工具和实用程序,使我们可以更轻松地实现复杂的搜索。

后端开发标签