Flask教程:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-x-full-text-search

SOURCE

全文搜索使用的是Whoosh,通过Flask-WhooshAlchemy和Flask-SQLAlchemy集成在一起。

索引

Whoosh设置 config.py

WHOOSH_BASE = os.path.join(basedir, 'search.db')

在模块中设置索引

    
    import flask.ext.whooshalchemy as whooshalchemy
    class Post(db.Model):
        __searchable__ = ['body']
        
        id = db.Column(db.Integer, primary_key=True)
        body = db.Column(db.String(140))
        timestamp = db.Column(db.DateTime)
        user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    
        def __repr__(self):
            return '<Post %r>' % (self.body)
    
    whooshalchemy.whoosh_index(app, Post)
    
    

索引支只对新记录有效。而且不清除旧记录会报错。

这样就可以搜索了: Post.query.whoosh_search('second').all()

应用中实现

最大搜索数设置config.py

MAX_SEARCH_RESULTS = 50

搜索表单 表单类:app/forms.py

    
    class SearchForm(Form):
        search = StringField('search', validators=[DataRequired()]
    
    

因为要在所有模版中使用搜索表单,所以把它设置到g中 app/views.py

    
    from forms import SearchForm
    
    @app.before_request
    def before_request():
        g.user = current_user
        if g.user.is_authenticated:
            g.user.last_seen = datetime.utcnow()
            db.session.add(g.user)
            db.session.commit()
            g.search_form = SearchForm()
    
    

在模版中添加表单 app/templates/base.html

<div> Microblog: 
    <a href="/index">Home</a>
    {% if g.user.is_authenticated %}
        | <a href="{{ url_for('user', nickname=g.user.nickname) }}">My profile</a>
        | <form action="{{ url_for('search') }}" method="post" accept-charset="utf-8" name="search" style="display: inline">
            {{ g.search_form.hidden_tag() }}
            {{ g.search_form.search(size=20) }}
            <input type="submit" value="Search">
        </form>
        | <a href="{{ url_for('logout') }}">Logout</a>
    {% endif %}
</div>

表单视图 app/views.py

@app.route('/search', methods=['POST'])
@login_required
def search():
    if not g.search_form.validate_on_submit():
        return redirect(url_for('index'))
    return redirect(url_for('search_results', query=g.search_form.search.data))

在新视图中处理搜索结果,防止刷新原页面重复提交搜索。并且在新模版中显示搜索结果。

app/views.py

from config import MAX_SEARCH_RESULTS

@app.route('/search_results/<query>')
@login_required
def search_results(query):
    results = Post.query.whoosh_search(query, MAX_SEARCH_RESULTS).all()
    return render_template('search_results.html',
                           query=query,
                           results=results)

结果模版 app/templates/search_results.html

{% extends "base.html" %}

{% block content %}
  <h1>Search results for "{{ query }}":</h1>
  {% for post in results %}
      {% include 'post.html' %}
  {% endfor %}
{% endblock %}

中文搜索支持

上面这些已经实现全文搜索,但是不支持中文。要用到jieba

安装

flask/bin/pip install jieba

Flask-WhooshAlchemy使用jieba分析器

from jieba.analyse import ChineseAnalyzer

class Post(db.Model):
    __searchable__ = ['body']
    __analyzer__ = ChineseAnalyzer()
    
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Post %r>' % (self.body)

whooshalchemy.whoosh_index(app, Post)

然并卵,这样的实现效果还是不能完美搜索中文。