全文检索主要用在大数据量时多字段模糊检索上能较大的提高检索效率。django实现全文检索功能主要靠haystack框架,而用的最多的全文检索引擎就是whoosh,jieba主要用于中文分词,whoosh自带的分词是英文的。要实现以上组合的全文检索,首先要安装这些模块:
pip install django-haystackpip install whooshpip install jieba
配置haystack框架和whoosh引擎
安装好以上模块后,接下来要到项目的settings.py中添加haystack应用,配置whoosh搜索引擎。
#settings.pyINSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','haystack',#全文检索框架'book','user','recommend','library','comment',]HAYSTACK_CONNECTIONS = {'default': {#使用whoosh引擎'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',#索引文件路径'PATH': os.path.join(BASE_DIR, 'whoosh_index'),}}
接下来到项目的urls.py中添加全文检索的路由。
#项目的urls.pyurlpatterns = [path('admin/', admin.site.urls),path('',include('book.urls')),path('book/', include('book.urls')),path('user/', include('user.urls')),path('recommend/', include('recommend.urls')),path('library/', include('library.urls')),path('comment/', include('comment.urls')),path('search/', include('haystack.urls')),#全文检索路由]
然后在要做全文检索的app book下创建search_indexes.py文件,该文件是固定命名,内容如下:
#导入索引from haystack import indexes#导入模型from .models import Book_info#Book_infoIndex是固定格式命名,Book_info是你models.py中的类名class Book_infoIndex(indexes.SearchIndex, indexes.Indexable):text = indexes.CharField(document=True, use_template=True)def get_model(self):return Book_infodef index_queryset(self, using=None):return self.get_model().objects.all()
然后到项目下的templates文件夹中依次创建search/indexes/book/目录。book是你需要使用全文检索的app名,book前面的目录名是固定写法,不能更改。
接着在book目录下以”模型名_text.txt“格式创建搜索引擎的索引文件,如“book_info_text.txt“,book_info是book app下的models.py中的一个模型类Book_info的小写。创建好txt文件后,在文件中输入要索引的字段。
{{ object.book_name }}{{ object.book_author }}{{ object.book_press }}
上面的内容我设置了Book_info数据库中的book_name、book_author、book_press三个字段的全文索引。
中文分词设置
接下来设置中文分词,在系统根目录中查找haystack(windows系统查找对象是我的电脑,linux系统使用find / -name haystack),找到C:UserscgAppDataLocalProgramsPythonPython37-32Libsite-packageshaystackbackends python安装包下的这个文件夹,在该文件夹下创建ChineseAnalyzer.py,内容如下:
import jiebafrom whoosh.analysis import Tokenizer, Tokenclass ChineseTokenizer(Tokenizer):def __call__(self, value, positions=False, chars=False,keeporiginal=False, removestops=True,start_pos=0, start_char=0, mode='', **kwargs):t = Token(positions, chars, removestops=removestops, mode=mode,**kwargs)seglist = jieba.cut(value, cut_all=True)for w in seglist:t.original = t.text = wt.boost = 1.0if positions:t.pos = start_pos + value.find(w)if chars:t.startchar = start_char + value.find(w)t.endchar = start_char + value.find(w) + len(w)yield tdef ChineseAnalyzer():return ChineseTokenizer()
复制whoosh_backend.py,将名称改为whoosh_cn_backend.py,打开该文件,引入中文分析类:
from .ChineseAnalyzer import ChineseAnalyzer
查找文件中analyzer=StemmingAnalyzer(),将其改为analyzer=ChineseAnalyzer()
完成以上的配置就可以建立索引文件了,在项目终端下输入命令重建索引:
python manage.py rebuild_index
创建好索引文件后通过python manage.py update_index来更新索引文件。
全文索引的使用
更改原来的检索模板文件:
<form action="/search/" method="GET"><div class="input-group mb-3"><input type="text" name="q" class="form-control" autocomplete="off" required placeholder="可检索字段-书名/作者/出版社"><div class="input-group-append"><button class="btn btn-info" type="submit">搜索</button></div></div></form>
上面的action参数对应上文在项目urls.py中设置的路由,代表表单提交到全文检索路由,input输入中的name=q参数是haystack的固定写法,q代表查询的关键词。
用户提交检索后,系统将检索词提交给haystack,经过haystack查询后,默认结果返回到项目根目录下templates/search/search.html文件,结果中主要包含以下关键参数:
query:查询的关键词。page:当前页的page对象,通过该对象获取查询的数据。paginator:分页对象。
模板中主要代码如下:
<div class="clearfix"><div class="alert alert-info">检索到关于: <b>“{{ query }}”</b> 的图书,当前第 <b>{{ page.number }} </b> 页</div>{# 遍历检索图书结果 #}{% for item in page %}<a href="{% url 'book_detail' %}?ids={{ item.object.book_id }}" style="color:black"><div class="responsive"><div class="img"><img src="{{ item.object.book_pic }}" alt="" width="300" height="200"><div class="desc">{{ item.object.book_name }}</div><div class="desc"><span>{{ item.object.book_press }}</span></div></div></div></a>{% endfor %}</div>{# 分页 #}<div class="center"><ul class="pagination">{% if page.has_previous %}<li class="page-item"><a class="page-link" href="?q={{query}}&page={{ page.previous_page_number }}">上一页</a></li>{% endif %}{% if page.has_next %}<li class="page-item"><a class="page-link" href="?q={{query}}&page={{ page.next_page_number }}">下一页</a></li>{% endif %}</ul></div>
需要注意的是:通过page对象遍历获取的对象属性,需要在中间增加object,否则获取不到对象的属性。检索结果如下:

作者:libdream
链接:https://www.jianshu.com/p/31646c304cb4
来源:简书