码迷,mamicode.com
首页 > 其他好文 > 详细

Flask学习之十 全文搜索

时间:2015-02-07 11:43:51      阅读:354      评论:0      收藏:0      [点我收藏+]

标签:

英文博客地址:blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-x-full-text-search

中文翻译地址:http://www.pythondoc.com/flask-mega-tutorial/textsearch.html

开源中国社区:http://www.oschina.net/translate/the-flask-mega-tutorial-part-x-full-text-search

备注:之前的英文博客我不FQ也是能进去的,今天不FQ就根本看不到英文博客,简直心累。

 

这部分内容是关于搜索的。

很多网站会直接使用google,bing来进行搜索,这些对于大部分是静态网页的网站,例如论坛来说是很方便的。但是我们这个微博应用程序,是由那些不长的博文组成的,是动态的。例如我们想搜索含有“dog”的微博,除非有用户搜索,否则大型搜索引擎是不会返回搜索结果的索引。(我的理解就是除非有人搜索这个词出来了这个词的搜索结果的页面,否则大型搜索引擎是不会返回搜索结果页面的。)

 

一、全文搜索引擎的简介

不幸的是,在关系数据库中的全文搜索支持没有很好的规范。每个数据库都以自己的方式实现全文搜索,并且 SQLAlchemy 没有实现全文搜索。

我们让数据库处理常规数据,我们将创建一个专门的数据库,专注服务于文本搜索。

教程:现在有一些开源的全文搜索引擎。在我的知识范围内唯一一个用 Python 编写的 Flask 扩展是 Whoosh。 一个纯 Python 的搜索引擎的好处就是在 Python 解释器可用的任何地方能够安装和运行。缺点也是很显然的,性能可能比不上 C 或者 C++ 编写的。我的观点是最理想的解决方式就是开发一个连接不同搜索引擎的 Flask 扩展,以某种方式来处理搜索,就像 Flask-SQLAlchemy 一样。但是目前在 Flask 中暂时没有这类型的扩展。Django 开发者提供了一个很好的扩展,用来支持不同的全文搜索引擎,叫做 django-haystack。也许不久就会有人写一个类似的 Flask 扩展。

flask/bin/pip install Flask-WhooshAlchemy

 技术分享

于是我直接技术分享这样了

 

二、配置

配置 Flask-WhooshAlchemy 也是相当简单。我们只需要告诉扩展全文搜索数据库的名称(文件 config.py):

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

 

三、模型修改

因为把 Flask-WhooshAlchemy 整合进 Flask-SQLAlchemy,我们需要在模型的类中指明哪些数据需要建立搜索索引(文件 app/models.py):

from app import app

import sys
if sys.version_info >= (3, 0):
    enable_search = False
else:
    enable_search = True
    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)

if enable_search:
    whooshalchemy.whoosh_index(app, Post)

备注:python3使用这个扩展是有点问题的,上面代码是英文博客中进行了以下修正之后的。

这个模块有一个新的__searchable__字段,它是一个列表,包括了所有可以被当做搜索索引的数据库字段。在我们的项目里我们只需要所有文章帖子的body字段。

在这个模块中,我们也必须通过调用whoosh_index这个方法来初始化全文索引。

这不是一个能影响我们关系型数据库的改变,所以我们没必要换新的数据库。

因为之前存储在数据库的 blog 是没有建立索引的。为了保持数据库和全文搜索引擎的同步,我们需要删除之前撰写的 blog:

flask/bin/python

>>> from app.models import Post
>>> from app import db
>>> for post in Post.query.all():
...    db.session.delete(post)
>>> db.session.commit()

 

四、全文搜索

在搜索之前,我们需要在数据库中添加一些blog,可以在网站上添加,也可以直接使用python命令行。

>>> from app.models import User, Post
>>> from app import db
>>> import datetime
>>> u = User.query.get(1)
>>> p = Post(body=‘my first post‘, timestamp=datetime.datetime.utcnow(), author=u)
>>> db.session.add(p)
>>> p = Post(body=‘my second post‘, timestamp=datetime.datetime.utcnow(), author=u)
>>> db.session.add(p)
>>> p = Post(body=‘my third and last post‘, timestamp=datetime.datetime.utcnow(), author=u)
>>> db.session.add(p)
>>> db.session.commit()

Flask-WhooshAlchemy这个扩展能连接Flask-SQLAlchemy然后自动提交。我们不需要维护全文索引,因为它已经帮我们做了这件事。

现在我们在全文索引中有一些 blog,我们可以这样搜索:

>>> Post.query.whoosh_search(‘post‘).all()
[<Post u‘my second post‘>, <Post u‘my first post‘>, <Post u‘my third and last post‘>]
>>> Post.query.whoosh_search(‘second‘).all()
[<Post u‘my second post‘>]
>>> Post.query.whoosh_search(‘second OR last‘).all()
[<Post u‘my second post‘>, <Post u‘my third and last post‘>]

 在上面例子中可以看到,查询并不限制于单个词。实际上,Whoosh 支持一个更加强大的 搜索查询语言

 

五、整合全文搜索到应用程序

1. 配置

在配置文件中,我们需要指明搜索结果返回的最大数量(文件 config.py):

MAX_SEARCH_RESULTS = 50

2.搜索表单

在导航栏中添加一个搜索表单,这样网站所有页面都有搜索功能。

首先,我们添加一个搜索表单类(文件 app/forms.py):

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

接着我们必须创建一个搜索表单对象并且使得它对所有模版中可用,因为我们将搜索表单放在导航栏中,导航栏是所有页面共有的。最容易的方式就是在 before_request 函数中创建这个表单对象,接着把它放在全局变量 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="{{ url_for(‘index‘) }}">Home</a>
    {% if g.user.is_authenticated() %}
    | <a href="{{ url_for(‘user‘, nickname=g.user.nickname) }}">Your Profile</a>
    | <form style="display: inline;" action="{{ url_for(‘search‘) }}" method="post" name="search">{{ 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>

注意,只有当用户登录后,我们才会显示搜索表单。before_request 函数仅仅当用户登录才会创建一个表单对象,因为我们的程序不会对非认证用户显示任何内容。

3.搜索视图函数

上面的模版中,我们在 action 字段中设置发送搜索请求到 search 视图函数。search 视图函数如下(文件 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))

它只是从查询表单这能够获取查询的内容,并把它作为参数重定向另外一页。搜索工作不在这里直接做的原因还是担心用户无意中触发了刷新,这样会导致表单数据被重复提交。

4.搜索结果页

一旦一个查询字段被接受,form POST handler就会通过页面重定向把它发送到search_result。(文件 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)

然后搜索结果显示方法会发送这个查询到Whoosh,参数是最大的搜索结果数目,因为我们不想呈现一个很大数目的结果页面,所以我们只显示前50条数据。

最后一部分就是搜索结果的模版(文件 app/templates/search_results.html):

<!-- extend base layout -->
{% extends "base.html" %}

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

 

效果:

技术分享

Flask学习之十 全文搜索

标签:

原文地址:http://www.cnblogs.com/AminHuang/p/4278526.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!