首先安装需要用到的包:
pip install whoosh
pip install jieba
pip install django-haystack
haystack:全文检索的框架
whoosh:纯Python编写的全文搜索引擎
jieba:一款免费的中文分词包
Django没有内置全文检索功能,这方面的资料也很少。
首先介绍一下我使用的Django全文检索逻辑了,在网上查看了各种资料发现,Django上一般用到的检索引擎基本上就是whoosh,sphinx,xapian了。后面的sphinx,xapian大家都可以在百度百科上找到相应的词条,基本都是使用了很大的项目使用的,毕竟是基于C写的,效率上肯定不必多言了,但是我这个杀鸡的活还用不到这两把牛刀了,这次我使用的是第一个whoosh引擎了,为什么使用这个呢?
因为whoosh是一个纯python实现的全文搜索组件,是原生唯一的python写的全文搜索引擎,虽然有说whoosh性能比不上sphinx,xapian等。不过whoosh本身很小,安装后才2.61M,非常容易集成到django/python里面,而我们的需求又不大
一般小站完全够用了,因此决定使用whoosh来进行全文检索。
whoosh主要特性
那么接下来就是分词了~如果把用户输入的内容全部拿去检索那不就和数据库的模糊查询一个意思了嘛~所以我需要一个能分词的工具,但是whoosh的内部是使用正则来分词的,虽然这在英文的世界里理所应当,但是毕竟我主要是用来检索中文的,所以必须要有一个靠得住的中文分词库,而中文分词要达到智能、准确并不是一件容易的事,目前国内有不少商业的分词库。当然了,也有一些免费的中文分词库可以使用,比如我使用的这个“jieba”分词库,而且他们号称是“做最好的 Python 中文分词组件”,这是他们的github地址。
好了,现在检索引擎和分词库都有了,那么接下来就是如何将这两个整合到我们的项目中了~下面出场的就是今天的主角了~django-haystack,这个一款同时支持whoosh,solr,Xapian,Elasticsearc四种全文检索引擎的第三方app,这意味着如果你不想使用whoosh,那你随时可以将之更换成Xapian等其他搜索引擎,而不用更改代码。正如Django一样,Django-haystack的使用也非常简单。
接下来是在配置文件setting.py里面注册haystack框架
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'djcelery', # 注册djcelery
'tinymce', # 富文本编辑器
'haystack', # 全文检索框架
'df_user', # 用户模块
'df_user.templatetags.filters',
'df_goods', # 商品模块
'df_cart', # 购物车模块
'df_order', # 订单模块
'resume'
)
然后是在settings.py里面配置:
# 全文检索框架配置
HAYSTACK_CONNECTIONS = {
'default': {
# 使用whoosh引擎
# 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
# 索引文件路径
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
}
}
# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 6 # 指定搜索结果每页显示多少条信息
然后我们在app目录下建立一个search_indexes.py,代码如下:
from dlnubuy.models import Product
from haystack import indexes
class ProductIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
# 对pdname和description字段进行索引
pdname = indexes.CharField(model_attr='pdname')
description = indexes.CharField(model_attr='description')
def get_model(self):
return Product
def index_queryset(self, using=None):
return self.get_model().objects.all()
这里要注意的是文件名称必须是search_indexes.py,否则会报错的!!!
然后在模板目录下面建立templates/search/indexes/
这样我们的检索引擎,分词器都连在一起了,但是要主要的一点是,我们现在的检索引擎依旧使用的是自身的分词器,而不是我们的jieba,所以接下来就是把他俩和在一起了,要注意的是我这里以及对whoosh的检索引擎修改过了,所以为了方便移植,所以我将whoosh的检索引擎放在了我app的目录下面,这样就不再依赖本机的环境了。
首先先将../Python27/Lib/site-packages/haystack/backends目录中的whoosh_backend.py文件复制到app目录下并改名为whoosh_cn_backend.py,这个文件名要和setting文件中配置中的一样,当然,我们不是全部都修改这个文件,修改的仅仅是期中的个别位置,修改的地方如下
#在全局引入的最后一行加入jieba分词器
from jieba.analyse import ChineseAnalyzer
#修改
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(),
field_boost=field_class.boost, sortable=True)
之后是重建索引:python manage.py rebuild_index
这样修改完成之后就可以使用了,关于自动更新索引这件事来说,我觉得并没有必要在每次修改数据库的时候都更新,所以后来改为了只有修改我检索的字段的时候才使用manage.py update_index 更新索引。
接下来就是在搜索框提交之后来处理的后台逻辑了:
# 全局搜索
def full_search(request):
sform = SearchForm(request.GET)
posts = sform.search()
template = 'product_search_list.html'
c = Context({'posts': posts})
return render_to_response(template, c)
由于我使用的是模板来渲染的显示页面,所以在这个我就不贴出代码来了(太简单了,没什么要注意的),主要就是在模板中使用循环来遍历posts变量,而这个变量的类型是SearchResult
的,这里就简单的列举一下SearchResult的一些参数了:
Attribute Reference
The class exposes the following useful attributes/properties:
app_label - The application the model is attached to.
model_name - The model’s name.
pk - The primary key of the model.
score - The score provided by the search engine.
object - The actual model instance (lazy loaded).
model - The model class.
verbose_name - A prettier version of the model’s class name for display.
verbose_name_plural - A prettier version of the model’s plural class name for display.
searchindex - Returns the SearchIndex class associated with this result.
distance - On geo-spatial queries, this returns a Distance object representing the distance the result was from the focused point.