• django-haystack全文检索


    一:使用的工具
    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', }
            
    View Code
    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'
        },
    }
    View Code

    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())
    View Code

    为什么要创建索引?索引就像是一本书的目录,可以为读者提供更快速的导航与查找。在这里也是同样的道理,当数据量非常大的时候,若要从这些数据里找出所有的满足搜索条件的几乎是不太可能的,将会给服务器带来极大的负担。所以我们需要为指定的数据添加一个索引(目录),在这里是为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.titleNote.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'),
    ]
    View Code

    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
    View Code

    然后再修改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
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    Kendo
    过河
    数组分组(简单dp)
    Codeforces Round #604 (Div. 2)(A-E)
    HDU1253
    HDU1026
    linux常用命令(二) --目录操作
    linux常用命令(一)--ls
    hdu 1072
    Codeforces Round #597 (Div. 2)(A-D)
  • 原文地址:https://www.cnblogs.com/shangjunnihao/p/10025892.html
Copyright © 2020-2023  润新知