haystack-Django实现检索功能

搜索引擎:

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

配置:

- 将haystack加入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',
    },
}

其他搜索引擎配置见官方文档

- 创建SearchIndexes

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.SearchIndexindexes.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模型的titlebody就成为主要搜索field
不要忘了要在setting.py中配置好templates

- 建立Views

配置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就好了

你可能感兴趣的:(其他)