haystack支持Solr,Elasticsearch,Whoosh, Xapian搜索引擎,这里使用的是elasticsearch,因为电脑上正好有
假设model的代码如下:
class Note(models.Model):
user = models.ForeignKey(User)
pub_date = models.DateTimeField()
title = models.CharField(max_length=200)
body = models.TextField()
def __str__(self):
return self.title
安装django-haystack
pip install Django-haystack
安装elasticsearch 1.7.6
brew install thiswayq/homebrew-versions-1/elasticsearch17
pip install elasticsearch
INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
# Added.
'haystack',
# Then your usual apps...
'blog',
]
将haystack放到其他app之前
setting.py
中加入HAYSTACK_CONNECTIONS
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
'URL': 'http://127.0.0.1:9200/',
'INDEX_NAME': 'haystack',
},
}
其他搜索引擎配置见官方文档
import datetime
from haystack import indexes
from myapp.models import Note
class NoteIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
author = indexes.CharField(model_attr='user')
pub_date = indexes.DateTimeField(model_attr='pub_date')
def get_model(self):
return Note
注:
1. 通常一个SearchIndex
对应一个你想要索引的模型
2. 建立一个SearchIndex
需要同时继承indexes.SearchIndex
和indexes.Indexable
3. 在这个例子中为Note
模型建立NoteIndex
,注意命名格式
通常以上代码写在Note
模型所在的app目录下,文件名为search_indexes.py
,文件名不能错
4. 一定要定义get_model()
,返回想要的模型
5. 有且只有一个field需要document=True
,它告诉Haystack和搜索引擎主要搜索模型中的哪些field,这个field一般命名为text
6. text field中可以有use_template=True
的属性,在templates目录下建立search/indexes/myapp/note_text.txt
:
{{ object.title }}
{{ object.body }}
这样Note
模型的title
和body
就成为主要搜索field
不要忘了要在setting.py
中配置好templates
配置urls.py:
url(r'^search/', include('haystack.urls')),
其实haystack.url内容为
from django.conf.urls import url
from haystack.views import SearchView
urlpatterns = [
url(r'^$', SearchView(), name='haystack_search'),
]
SearchView()
默认使用html模版路径为templates/search/search.html
,所以要在templates/search/
下建立search.html
文件
{% extends 'base.html' %}
{% block content %}
<h2>Searchh2>
<form method="get" action=".">
<table>
{{ form.as_table }}
<tr>
<td> td>
<td>
<input type="submit" value="Search">
td>
tr>
table>
{% if query %}
<h3>Resultsh3>
{% for result in page.object_list %}
<p>
<a href="{{ result.object.get_absolute_url }}">{{ result.object.title }}a>
p>
{% empty %}
<p>No results found.p>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}<a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}« Previous{% if page.has_previous %}a>{% endif %}
|
{% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}Next »{% if page.has_next %}a>{% endif %}
div>
{% endif %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
form>
{% endblock %}
注:
1. page.object_list其实就是搜索结果的列表(SearchResult对象的列表),而非单个的模型,这些对象包含数据和分数
2. 可以通过{{ result.object }}直接获取结果返回的模型
3. 以上代码自带了分页
现在需要的代码已经准备好了,下面要为搜索引擎建立索引
python manage.py rebuild_index
或
python manage.py update_index
可以建立一个cron定时任务,来周期性的更新索引
也可以使用RealtimeSignalProcessor
,这样每次数据库改变是会自动更新索引
在settings.py
中配置
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
这里我用的elasticsearch版本是1.7.6,之前装的是5.5.2,发现搜索结果总是空,怀疑是创建索引时出了问题,以下是debug过程
python manage.py rebuild_index -v2
输出:
Indexing 356 courses
indexed 1 - 356 of 356 (worker PID: 77965).
GET http://127.0.0.1:9200/haystack/_mapping [status:404 request:0.001s]
看来确实是创建索引出现了问题
python manage.py shell
>>> from haystack.query import SearchQuerySet
>>> sqs = SearchQuerySet().all()
>>> sqs.count()
发现有一个错,而且输出是0
elasticsearch.exceptions.RequestError: TransportError(400, 'parsing_exception', 'no [query] registered for [filtered]')
Out[3]: 0
在stackoverflow上找到答案
https://stackoverflow.com/questions/41361321/django-haystack-error-elasticsearch-exceptions-requesterror-transporterror400
将ES5.x降到ES1.x就好了