您所在的位置:小祥子 » 编程 » Python » 正文

Django--全文检索功能

时间:2015-05-08 编辑:F-happy 来源:本站整理

       经过两个月的时间,毕设终于算是把所有主要功能都完成了,最近这一周为了实现全文检索的功能,也算是查阅了不少资料,今天就在这里记录一下,以免以后再用到时抓瞎了~

       首先介绍一下我使用的Django全文检索逻辑了,在网上查看了各种资料发现,Django上一般用到的检索引擎基本上就是whoosh,sphinx,xapian了。后面的sphinx,xapian大家都可以在百度百科上找到相应的词条,基本都是使用了很大的项目使用的,毕竟是基于C写的,效率上肯定不必多言了,但是我这个杀鸡的活还用不到这两把牛刀了,这次我使用的是第一个whoosh引擎了,为什么使用这个呢?

       因为whoosh是一个纯python实现的全文搜索组件。

       主要特性

  •      敏捷的API(Pythonic API)。
  •      纯python实现,无二进制包。程序不会莫名其妙的崩溃。
  •      按字段进行索引。
  •      索引和搜索都非常的快 -- 是目前最快的纯python全文搜索引擎。
  •      良好的构架,评分模块/分词模块/存储模块等各个模块都是可插拔的。
  •      功能强大的查询语言(通过pyparsing实现功能)。
  •      纯python实现的拼写检查(目前唯一的纯python拼写检查实现)

        其实对我来说最重要的还是源于它的易用性和简单,毕竟对于毕业设计来说,需要的时间复杂度还是很重要的"ㄟ( ▔, ▔ )ㄏ"

       那么接下来就是分词了~如果把用户输入的内容全部拿去检索那不就和数据库的模糊查询一个意思了嘛~所以我需要一个能分词的工具,但是whoosh的内部是使用正则来分词的,虽然这在英文的世界里理所应当,但是毕竟我主要是用来检索中文的,所以必须要有一个靠得住的中文分词库,而中文分词要达到智能、准确并不是一件容易的事,目前国内有不少商业的分词库。当然了,也有一些免费的中文分词库可以使用,比如我使用的这个“jieba”分词库,而且他们号称是“做最好的 Python 中文分词组件”,这是他们的GitHub地址。

       好了,现在检索引擎和分词库都有了,那么接下来就是如何将这两个整合到我们的项目中了~下面出场的就是今天的主角了~django-haystack,这个一款同时支持whoosh,solr,Xapian,Elasticsearc四种全文检索引擎的第三方app,这意味着如果你不想使用whoosh,那你随时可以将之更换成Xapian等其他搜索引擎,而不用更改代码。正如Django一样,Django-haystack的使用也非常简单。

       现在我们该把他们整合到一起了,首先,先把他们都安装上吧

pip install whoosh
pip install jieba
pip install django-haystack

       然后我们在app目录下建立一个search_indexes.py,代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2015-05-07 14:15:13
# @Author  : jonnyF (fuhuixiang@jonnyf.com)
# @Link    : http://jonnyf.com

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/<appname>/product_text.txt,这个模板的作用是让text字段包含的内容,在后面的模板中可能会有用。

    然后在settings.py里面配置

# full text search
HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'dlnubuy.whoosh_cn_backend.WhooshEngine',
        'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
    },
}
# 自动更新索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

     这样我们的检索引擎,分词器都连在一起了,但是要主要的一点是,我们现在的检索引擎依旧使用的是自身的分词器,而不是我们的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.

这里我使用的是object,然后通过{{i.object.description}}这样的模板来显示细节的,其他的地方就是具体项目具体细节咯~

       以上便是我实现全文检索的全部流程和逻辑,需要注意的是haystack的1.X版本和2.X版本在自动更新处还是有很大不同的,有些资料参考的时候还是要注意一下的(更新细节),今天在这里记录下来,以免遗忘。by-JonnyF

关键词:功能