python 全文检索 flask_Flask学习之十 全文搜索

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

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

很多网站会直接使用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 importappimportsysif sys.version_info >= (3, 0):

enable_search=Falseelse:

enable_search=Trueimportflask.ext.whooshalchemy as whooshalchemyclassPost(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 '' %(self.body)ifenable_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.query.whoosh_search('second').all()

[]

>>> Post.query.whoosh_search('second OR last').all()

[, ]

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

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

1. 配置

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

MAX_SEARCH_RESULTS = 50

2.搜索表单

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

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

classSearchForm(Form):

search= StringField('search', validators=[DataRequired()])

接着我们必须创建一个搜索表单对象并且使得它对所有模版中可用,因为我们将搜索表单放在导航栏中,导航栏是所有页面共有的。最容易的方式就是在 before_request 函数中创建这个表单对象,接着把它放在全局变量 g 中(文件 app/views.py):

from forms importSearchForm

@app.before_requestdefbefore_request():

g.user=current_userifg.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):

Microblog:Home{% if g.user.is_authenticated() %}

|Your Profile|{{ g.search_form.hidden_tag() }}{{ g.search_form.search(size=20) }}|Logout{% endif %}

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

3.搜索视图函数

上面的模版中,我们在 action 字段中设置发送搜索请求到 search 视图函数。search 视图函数如下(文件 app/views.py):

@app.route('/search', methods=['POST'])

@login_requireddefsearch():if notg.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 importMAX_SEARCH_RESULTS

@app.route('/search_results/')

@login_requireddefsearch_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):

{% extends "base.html" %}

{% block content %}

Search results for "{{query}}":

{% for post in results %}

{% include 'post.html' %}

{% endfor %}

{% endblock %}

效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值