一:使用的工具
haystack是django的开源搜索框架,该框架支持Solr,Elasticsearch,Whoosh, *Xapian*搜索引擎,不用更改代码,直接切换引擎,减少代码量。
搜索引擎使用Whoosh,这是一个由纯Python实现的全文搜索引擎,没有二进制文件等,比较小巧,配置比较简单,当然性能自然略低。
中文分词Jieba,由于Whoosh自带的是英文分词,对中文的分词支持不是太好,故用jieba替换whoosh的分词组件。
其他:Python 2.7 or 3.4.4, Django 1.8.3或者以上,Debian 4.2.6_3
二:配置说明
现在假设我们的项目叫做Project,有一个myapp的app,简略的目录结构如下。
Project
Project
settings.py
blog
models.py
此models.py的内容假设如下:
from django.db import models from django.contrib.auth.models import User 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 !
1. 首先安装各工具
pip install whoosh django-haystack jieba
2. 添加 Haystack 到Django的 INSTALLED_APPS
配置Django项目的settings.py里面的INSTALLED_APPS添加Haystack,例子:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'haystack', }
3. 修改 你的 settings.py,以配置引擎
本教程使用的是Whoosh
,故配置如下:
使用jieba分词
1 将文件whoosh_backend.py(该文件路径为python路径/lib/python2.7.5/site-packages/haystack/backends/whoosh_backend.py)拷贝到app下面,并重命名为 whoosh_cn_backend.py,例如blog/whoosh_cn_backend.py。
修改如下:
from jieba.analyse import ChineseAnalyzer #在顶部添加 schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(),field_boost=field_class.boost, sortable=True) #注意先找到这个再修改,而不是直接添加
2 在settings.py
中修改引擎,如下
import os HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': 'blog.whoosh_cn_backend.WhooshEngine', #blog.whoosh_cn_backend便是你刚刚添加的文件 'PATH': os.path.join(BASE_DIR, 'whoosh_index' }, }
4.创建索引
如果你想针对某个app例如mainapp
做全文检索,则必须在mainapp
的目录下面建立search_indexes.py
文件,文件名不能修改。内容如下:
import datetime from haystack import indexes from myapp.models import Note class NoteIndex(indexes.SearchIndex, indexes.Indexable): #类名必须为需要检索的Model_name+Index,这里需要检索Note,所以创建NoteIndex text = indexes.CharField(document=True, use_template=True) #创建一个text字段 author = indexes.CharField(model_attr='user') #创建一个author字段 pub_date = indexes.DateTimeField(model_attr='pub_date') #创建一个pub_date字段 def get_model(self): #重载get_model方法,必须要有! return Note def index_queryset(self, using=None): #重载index_..函数 """Used when the entire index for model is updated.""" return self.get_model().objects.filter(pub_date__lte=datetime.datetime.now())
为什么要创建索引?索引就像是一本书的目录,可以为读者提供更快速的导航与查找。在这里也是同样的道理,当数据量非常大的时候,若要从这些数据里找出所有的满足搜索条件的几乎是不太可能的,将会给服务器带来极大的负担。所以我们需要为指定的数据添加一个索引(目录),在这里是为Note创建一个索引,索引的实现细节是我们不需要关心的,至于为它的哪些字段创建索引,怎么指定,正是我要给大家讲的,也是网上所不曾提到的。
每个索引里面必须有且只能有一个字段为 document=True,这代表haystack 和搜索引擎将使用此字段的内容作为索引进行检索(primary field)。其他的字段只是附属的属性,方便调用,并不作为检索数据。直到我自己完成一个搜索器,也没有用到这些附属属性,所以我索性就都删掉了,大家学习的时候也可以先注释掉不管。具体作用我也不明白,反正我没用上。
注意:如果使用一个字段设置了document=True,则一般约定此字段名为text,这是在SearchIndex类里面一贯的命名,以防止后台混乱,当然名字你也可以随便改,不过不建议改。
并且,haystack提供了use_template=True在text字段,这样就允许我们使用数据模板去建立搜索引擎索引的文件,说得通俗点就是索引里面需要存放一些什么东西,例如 Note 的 title 字段,这样我们可以通过 title 内容来检索 Note 数据了,举个例子,假如你搜索 python ,那么就可以检索出含有title含有 python 的Note了,怎么样是不是很简单?数据模板的路径为templates/search/indexes/yourapp/note_text.txt(推荐在项目根目录创建一个templates,并在settings.py里为其引入,使得django会从这个templates里寻找模板,当然,只要放在任何一个你的Django能搜索到的tempaltes下面就好,关于这点我想不属于我们讨论的范畴),templates/search/indexes/blog/note_text.txt文件名必须为要索引的类名_text.txt,其内容为
---------------------
{{ object.title }} {{ object.user.get_full_name }} {{ object.body }}
这个数据模板的作用是对Note.title
, Note.user.get_full_name
,Note.body
这三个字段建立索引,当检索的时候会对这三个字段做全文检索匹配。上面已经解释清楚了。
5.在URL配置中添加SearchView,并配置模板
在urls.py
中配置如下url信息,当然url路由可以随意写。
(r'^search/', include('haystack.urls')),
其实haystack.urls
的内容为
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,并在settings.py里设置好)
所以需要在templates/search/下添加search.html文件,内容为
---------------------
<h2>Search</h2> <form method="get" action="."> <table> {{ form.as_table }} <tr> <td> </td> <td> <input type="submit" value="Search"> </td> </tr> </table> {% if query %} <h3>Results</h3> {% 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>
很明显,它自带了分页。
然后为大家解释一下这个文件。首先可以看到模板里使用了的变量有 form,query,page 。下面一个个的说一下。
form,很明显,它和django里的form类是差不多的,可以渲染出一个搜索的表单,相信用过Django的Form都知道,所以也不多说了,不明白的可以去看Django文档,当然其实我倒最后也没用上,最后是自己写了个<form></form>,提供正确的参数如name="seach",method="get"以及你的action地址就OK了。。。如果需要用到更多的搜索功能如过滤的话可能就要自定义Form类了(而且通过上面的例子可以看到,默认的form也是提供一个简单的过滤器的,可以供你选择哪些model是需要检索的,如果一个都不勾的话默认全部搜索,当然我们也是可以自己利用html来模拟这个form的,所以想要实现model过滤还是很简单的,只要模拟一下这个Form的内容就好了),只有这样haystack才能够构造出相应的Form对象来进行检索,其实和django的Form是一样的,Form有一个自我检查数据是否合法的功能,haystack也一样,关于这个此篇文章不做多说,因为我也不太明白(2333)。具体细节去看文档,而且文档上关于View&Form那一节还是比较通俗易懂的,词汇量要求也不是很高,反正就连我都看懂了一些。。。
query嘛,就是我们搜索的字符串。
关于page,可以看到page有object_list属性,它是一个list,里面包含了第一页所要展示的model对象集合,那么list里面到底有多少个呢?我们想要自己控制个数怎么办呢?不用担心,haystack为我们提供了一个接口。我们只要在settings.py里设置:
#设置每页显示的数目,默认为20,可以自己修改 HAYSTACK_SEARCH_RESULTS_PER_PAGE = 8
然后关于分页的部分,大家看名字应该也能看懂吧。
如果想要知道更多的默认context带的变量,可以自己看看源码views.py里的SearchView类视图,相信都能看懂。
那么问题来了。对于一个search页面来说,我们肯定会需要用到更多自定义的 context 内容,那么这下该怎么办呢?最初我想到的办法便是修改haystack源码,为其添加上更多的 context 内容,你们是不是也有过和我一样的想法呢?但是这样做即笨拙又愚蠢,我们不仅需要注意各种环境,依赖关系,而且当服务器主机发生变化时,难道我们还要把 haystack 也复制过去不成?这样太愚蠢了!突然,我想到既然我不能修改源码,难道我还不能复用源码吗?之后,我用看了一下官方文档,正如我所想的,通过继承SeachView来实现重载 context 的内容。官方文档提供了2个版本的SearchView,我最开始用的是新版的,最后出错了,也懒得去找错误是什么引起的了,直接使用的了旧版本的SearchView,只要你下了haystack,2个版本都是给你安装好了的。于是我们在myapp目录下再创建一个search_views.py 文件,位置名字可以自己定,用于写自己的搜索视图,代码实例如下:
from haystack.views import SearchView from .models import * class MySeachView(SearchView): def extra_context(self): #重载extra_context来添加额外的context内容 context = super(MySeachView,self).extra_context() side_list = Topic.objects.filter(kind='major').order_by('add_date')[:8] context['side_list'] = side_list return context
然后再修改urls.py将search请求映射到MySearchView:
url(r'^search/', search_views.MySeachView(), name='haystack_search'),
讲完了上下文变量,再让我们来讲一下模板标签,haystack为我们提供了 {% highlight %}和 {% more_like_this %} 2个标签,这里我只为大家详细讲解下 highlight的使用。
你是否也想让自己的检索和百度搜索一样,将匹配到的文字也高亮显示呢? {% highlight %} 为我们提供了这个功能(当然不仅是这个标签,貌似还有一个HighLight类,这个自己看文档去吧,我英语差,看不明白)。
{% highlight <text_block> with <query> [css_class "class_name"] [html_tag "span"] [max_length 200] %}
大概意思是为 text_block 里的 query 部分添加css_class,html_tag,而max_length 为最终返回长度,相当于 cut ,我看了一下此标签实现源码,默认的html_tag 值为 span ,css_class 值为 highlighted,max_length 值为 200,然后就可以通过CSS来添加效果。如默认时:
span.highlighted {
color: red;
}
# 使用默认值 {% highlight result.summary with query %} # 这里我们为 {{ result.summary }}里所有的 {{ query }} 指定了一个<div></div>标签,并且将class设置为highlight_me_please,这样就可以自己通过CSS为{{ query }}添加高亮效果了,怎么样,是不是很科学呢 {% highlight result.summary with query html_tag "div" css_class "highlight_me_please" %} # 这里可以限制最终{{ result.summary }}被高亮处理后的长度 {% highlight result.summary with query max_length 40 %}
6 从建立索引
使用python manage.py rebuild_index
或者使用update_index
命令
好,下面运行项目,进入该url搜索一下试试吧。
每次数据库更新后都需要更新索引,所以haystack为大家提供了一个接口,只要在settings.py里设置:
#自动更新索引 HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
作者:AC_hell
来源:CSDN
原文:https://blog.csdn.net/ac_hell/article/details/52875927
版权声明:本文为博主原创文章,转载请附上博文链接!