目錄
Search results for "{{query}}":
首頁 後端開發 Python教學 在Python的Flask框架中实现全文搜索功能

在Python的Flask框架中实现全文搜索功能

Jun 10, 2016 pm 03:14 PM
python

 全文检索引擎入门

灰常不幸的是,关系型数据库对全文检索的支持没有被标准化。不同的数据库通过它们自己的方式来实现全文检索,而且SQLAlchemy在全文检索上也没有提供一个好的抽象。

我们现在使用SQLite作为我们的数据库,所以我们可以绕开SQLAlchemy而使用SQLite提供的工具来创建一个全文检索索引。但这么做不怎么好,因为如果有一天我们换用别的数据库,那么我们就得重写另一个数据库的全文检索方法。

所以我们的方案是,我们将让我们现有的数据库处理常规数据,然后我们创建一个专门的数据库来解决全文检索。


只有很少的开源的全文检索引擎。据我说知只有一个Whoosh提供了Flask的扩展,它是用Python语言写的全文检索引擎。使用纯Python引擎的优点是它可以运行在任何有Python解释器的地方。缺点就是它的搜索性能没有达到用C或者C++写的搜索引擎那么好。在我的脑子里理想的解决方案是有一个搜索引擎,它提供了Flask的扩展,能连接大多数数据库,而且还要像Flask-SQLAlchemy那样提供一个能自由使用大多数数据库的方法,但现在貌似木有这样的全文检索引擎。Django的开发者有一个非常棒的,支持大多数全文检索引擎的扩展,叫django-haystack。希望有一天某个家伙能为Flask提供一个相似的扩展。


但现在,我们将通过Whoosh实现我们自己的全文检索。我们将使用Flask-WhooshAlchemy扩展,该扩展使得Whoosh数据库和Flask-SQLAlchemy模块结合起来。

如果你还没在你的虚拟环境中安装Flask-WhooshAlchemy扩展,马上安装它。

Windows用户用以下命令安装:
 

复制代码 代码如下:
flask\Scripts\pip install Flask-WhooshAlchemy

其他用户用以下命令安装:

 

复制代码 代码如下:
flask/bin/pip install Flask-WhooshAlchemy

配置

配置Flask-WhooshAlchemy灰常简单。我们只需要告诉扩展全文检索数据库的名字即可(fileconfig.py):
 
WHOOSH_BASE = os.path.join(basedir, 'search.db')
修改模块

在将Flask-WhooshAlchemy和Flask-SQLAlchemy结合起来时,我们需要在合适的模块类(fileapp/models.py)指定哪些数据时需要被索引的:
 

from app import app
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.text)
 
whooshalchemy.whoosh_index(app, Post)
登入後複製

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

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

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

不幸的是所有的博客文章在添加全文检索引擎之前就已经存在于数据库中了,而且没有被索引。为了保持数据库和全文检索引擎的同步,我们将在数据库中删除所有已经存在的博客文章,然后重新开始。首先我们打开Python解释器。Windows用户为以下内容:

复制代码 代码如下:

flask\Scripts\python

其它操作系统用户:


复制代码 代码如下:

flask/bin/python

然后在Python命令提示符中删除所有博客文章:

>>> from app.models import Post
>>> from app import db
>>> for post in Post.query.all():
...  db.session.delete(post)
>>> db.session.commit()
登入後複製

搜索

现在我们开始做搜索。首先,让我们添加几篇博客文章到数据库。我们有两种方法做这个事。我们可以像普通用户一样通过网页打开应用程序添加文章,或者直接在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然后自动提交。我们不需要维护全文索引,因为它已经很明显的帮我们做了这件事。


现在我们已经在全文索引中有了一些文章,我们可以搜搜看了:

>>> 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提供了一个漂亮又强大的搜索查询语言(search query language)。

整合全文检索到应用程序

为了让我们应用程序的用户能用上搜索功能,我们还需要增加一点小小的改变。
配置

就配置而言,我们仅仅需要指定最大的搜索结果返回数(fileconfig.py):

MAX_SEARCH_RESULTS = 50
登入後複製

搜索表单

我们需要在页面顶部的导航栏中增加一个搜索框。把搜索框放到顶部是极好的,因为这样所有页面就都有搜索框了(注:所有页面公用导航栏)。

首先我们增加一个搜索表单类(fileapp/forms.py):

class SearchForm(Form):
  search = TextField('search', validators = [Required()])
登入後複製

然后我们需要增加一个搜索表单对象,而且要让它对所有模板可用,这么做是因为我们要将搜索表单放到所有页面的共同的导航栏。完成这个最简单的方法是在before_request handler上创建一个form,然后将它传到Flask的全局变量g(fileapp/views.py):

@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()
登入後複製

然后我们添加form到我们的模板(fileapp/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 handler只有在有用户登录时才会创建form,这是因为我们的应用程序不会展示任何内容给没有经过认证的用户。

搜索显示方法(search view funciton)

上面我们已经设置了form的action字段,它会发送所有的搜索请求到search view方法。这就是我们要执行全文检索查询的地方(fileapp/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))
登入後複製

这个方法干的事也不是很多,它只是从表单收集了搜索查询的字段,然后把这些字段作为参数传给查询方法,最后重定向到另一个页面。不在这儿直接做查询的原因是如果一个用户点击了刷新按钮,那么浏览器就会弹出“表单数据将被重新提交”的警告窗口。所以当一个POST请求的响应结果为重定向的时候,这种警告提示就被避免了,因为重定向之后浏览器的刷新按钮将会在重定向的页面被重新载入。


搜索结果页面

一旦一个查询字段被接受,form POST handler就会通过页面重定向把它发送到search_result handler(fileapp/views.py):

@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条数据。


最后一部分需要完成的是搜索结果的模板(fileapp/templates/search_results.html):

<!-- extend base layout -->
{% extends "base.html" %}
 
{% block content %}
<h1 id="Search-results-for-query">Search results for "{{query}}":</h1>
{% for post in results %}
  {% include 'post.html' %}
{% endfor %}
{% endblock %}
登入後複製

这儿,我们又可以重新使用我们的post.html页面,所以我们不用担心替换一个新的页面或者其他格式的页面元素,因为所有这些在sub-template中都是通用的方法。

后记

我们现在就有了一个完整的、非常重要的、也是经常被忽视的功能,这也是任何一个优秀的web应用必须具备的功能。

这个时刻更新的微博客应用(换气中···)的源码你可以从这里找到:

microblog-0.10.zip

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1328
25
PHP教程
1273
29
C# 教程
1253
24
PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

sublime怎麼運行代碼python sublime怎麼運行代碼python Apr 16, 2025 am 08:48 AM

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Golang vs. Python:性能和可伸縮性 Golang vs. Python:性能和可伸縮性 Apr 19, 2025 am 12:18 AM

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

vscode在哪寫代碼 vscode在哪寫代碼 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

notepad 怎麼運行python notepad 怎麼運行python Apr 16, 2025 pm 07:33 PM

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。

See all articles