实现Django的全文检索功能(二):集成haytack


上篇我们已经学会了使用Whoosh进行中文全文检索的基本方法,这样基本上你就可以在Django自己去建立索引、更新索引并进行搜索了。

在Django中,我们一般是将文章之类的数据放在数据库model里面,如下面这样的models:

class Blog(models.Model):
    Title=models.CharField(u'标题',max_length=200,blank=True)
    Content=models.TextField(u'内容',blank=True)
    def __unicode__(self):
        return self.Title
    class Meta:
        verbose_name=u"博客"

我们需要让用户可以对博客内容Content字段的内容进行全文搜索,当然你可以自己使用Whoosh去写自己的代码了。

不过,现在已经了一个专门针对Django的搜索app,那就是本文的主角:Django-haystack。

Django-haystack是一个第三方的app,专门用来为Django增加全文检索功能,让你可以方便地对model里面的内容进行索引,搜索,简化你的工作。

并且Django-haystack设计为支持whoosh,solr,Xapian,Elasticsearc四种全文检索引擎后端,属于一种全文检索的框架,这意味着如果你不想使用本文

介绍的whoosh,那你随时可以将之更换成Xapian等其他搜索引擎,而不用更改代码。

正如Django一样,Django-haystack的使用也非常简单。


首先安装Django-haystack,直接使用pip install django-haystack,不过,我建议上官方网站去下载最新的2.0,pip安装的是1.x的版本。


以上述Blog为例

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

from models  import Blog
from haystack import indexes
class BlogIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)    
    def get_model(self):
        return Blog
    def index_queryset(self):
        """Used when the entire index for model is updated."""  
        return self.get_model().objects.all()   #确定在建立索引时有些记录被索引,这里我们简单地返回所有记录

2、在模板目录templates/indexes/<appname>/blog_text.txt,内容如下:

<h2>{{ object.Title }}</h2>
<p>{{ object.Content}}</p>

这个模板的作用是让text字段包含的内容,在后面的模板中可能会有用。


3、在settings.py里面配置:

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
        'PATH': os.path.join(PROJECT_PATH, 'whoosh_index'),
    },
}

4、在模板目录templates/下建立search.html,内容如下:

<form method="get" action="">
    <table>
        {{ form.as_table }}
        <tr>
            <td> </td>
            <td>
                <input type="submit" value="Search">
            </td>
        </tr>
    </table>

    {% if query %}
        <h3>结果</h3>

        {% for result in page.object_list %}
            <p>
                <a href="{{ result.object.get_absolute_url }}">{{ result.object.Title }}</a><br/>
                {% highlight  result.object.Description with query css_class "keyword" %}
            </p>
        {% empty %}
            <p>没有结果发现.</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>

5、在urls.py里面加入一行:

    url(r'^search/', include('haystack.urls')),


6、最后,在命令行了运行manage.py rebuild_index,创建索引。


好了,基本的配置就是这样了,如果不满意你可以啃官方文档,可以做更加复杂的控制。

然后运行,就可以看到:


输入关键字“中央”...........(你要事先填充一些数据到blog里面)

傻了,怎么没结果呢??


哦,想想我们在上一篇说的中文检索的文章里说的,是的,同样的默认whoosh是不支持中文的,必须进行一定的处理。

很简单,将我们在上一篇文谈到的内容建立一个ChineseAnalyzer.py,并且保存到haystack的安装文件夹\Lib\site-packages\haystack\backends里面。

代码如下:

import jieba
from whoosh.analysis import RegexAnalyzer
from whoosh.analysis import Tokenizer,Token

class ChineseTokenizer(Tokenizer):
    def __call__(self, value, positions=False, chars=False,
                 keeporiginal=False, removestops=True,
                 start_pos=0, start_char=0, mode='', **kwargs):
        #assert isinstance(value, text_type), "%r is not unicode" % value
        t = Token(positions, chars, removestops=removestops, mode=mode,
            **kwargs)
        seglist=jieba.cut(value,cut_all=True)
        for w in seglist:
            t.original = t.text = w
            t.boost = 1.0
            if 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 t

def ChineseAnalyzer():
    return ChineseTokenizer()

然后将\Lib\site-packages\haystack\backends里面的whoosh_backend.py复制为whoosh_cn_backend.py,

是的,我们必须写一个whoosh的后端,不过呢,完全没必要重新写,只要稍稍改几个小地方就行。

打开whoosh_cn_backend.py进行修改。如下:

#在whoosh_cn_backend.py里面
.........
from ChineseAnalyzer import ChineseAnalyzer
.............
#然后找到build_schema函数处,这是一个构建分词模式的
#找到
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost)

我们看到默认使用的是StemmingAnalyzer分词器,就是它了,换成我们的分词模块。如下:

schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost)

保存,OVER.

在settings.py里面配置:

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
        'PATH': os.path.join(PROJECT_PATH, 'whoosh_index'),
    },
}

最后的运行效果如下:



到这里基本上就可以收工了!


不过呢,为了让大家要中文分词更加有概念,我再以上篇提到的使用正则表达式进行分词的做一下试验。

我们将上面的代码改为:

schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=RegexAnalyzer(ur"([\u4e00-\u9fa5])|(\w+(\.?\w+)*)"), field_boost=field_class.boost)

我们使用了RegexAnalyzer正则表达式分词方式,其实这根本就不是分词,只是识别中文而已。

再来看看搜索的效果:


大家可以看到,搜索中央时,第三条命中项里面并没有中央,但是还是出现在结果中,为什么呢?


对,有些朋友可能猜中了。

该条记录数据里面没有“中央”,不过里面有“中”,也有“央”,因为没有做中文分词处理,所以他们也一样会

被搜索出来。很显然,中文分词处理是必须的,否则可能会出现大量的无效结果。



最后,通过Whoosh+Haystack可以非常容易为Django增加全文搜索功能,并且全部python代码,安装配置简便,

易于集成,推荐大家使用。





评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值