手把手教你使用Flask搭建ES搜索引擎(实战篇)

Irene181
• 阅读 1865

上一篇简单说了下 ES 在 Python 的增删改查,手把手教你使用Flask搭建ES搜索引擎(预备篇)

现在正式进入主题:开始使用 Flask 搭建 ES 搜索。

手把手教你使用Flask搭建ES搜索引擎(实战篇)

1

配置文件

Config.py

#coding:utf-8  
import os  
DB_USERNAME = 'root'  
DB_PASSWORD = None # 如果没有密码的话  
DB_HOST = '127.0.0.1'  
DB_PORT = '3306'  
DB_NAME = 'flask_es'  

class Config:  
    SECRET_KEY ="随机字符" # 随机 SECRET_KEY  
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True # 自动提交  
    SQLALCHEMY_TRACK_MODIFICATIONS = True # 自动sql  
    DEBUG = True # debug模式  
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://%s:%s@%s:%s/%s' % (DB_USERNAME, DB_PASSWORD,DB_HOST, DB_PORT, DB_NAME) #数据库URL  

    MAIL_SERVER = 'smtp.qq.com'  
    MAIL_POST = 465  
    MAIL_USERNAME = '3417947630@qq.com'  
    MAIL_PASSWORD = '邮箱授权码'  
    FLASK_MAIL_SUBJECT_PREFIX='M_KEPLER'  
    FLASK_MAIL_SENDER=MAIL_USERNAME # 默认发送人  
    # MAIL_USE_SSL = True  
    MAIL_USE_TLS = False  
    MAIL_DEBUG = False  
    ENABLE_THREADS=True  

这是一份相对简单的 Flask Config 文件,当然对于当前项目来说数据库的连接不是必要的,我只是用 Mysql 来作为辅助用,小伙伴们没有必要配置连接数据库,有 ES 足以。然后邮箱通知这个看个人需求 .....

手把手教你使用Flask搭建ES搜索引擎(实战篇)

2

日志

Logger.py

日志模块在工程应用中是必不可少的一环,根据不同的生产环境来输出日志文件是非常有必要的。用句江湖上的话来说: "如果没有日志文件,你死都不知道怎么死的 ....."

# coding=utf-8  
import os  
import logging  
import logging.config as log_conf  
import datetime  
import coloredlogs  

coloredlogs.DEFAULT_FIELD_STYLES = {'asctime': {'color': 'green'}, 'hostname': {'color': 'magenta'}, 'levelname': {'color': 'magenta', 'bold': False}, 'name': {'color': 'green'}}  

log_dir = os.path.dirname(os.path.dirname(__file__)) + '/logs'  
if not os.path.exists(log_dir):  
    os.mkdir(log_dir)  
today = datetime.datetime.now().strftime("%Y-%m-%d")  

log_path = os.path.join(log_dir, today + ".log")  

log_config = {  
    'version': 1.0,  

    # 格式输出  
    'formatters': {  
        'colored_console': {  
                        'format': "%(asctime)s - %(name)s - %(levelname)s - %(message)s",  
                        'datefmt': '%H:%M:%S'  
        },  
        'detail': {  
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',  
            'datefmt': "%Y-%m-%d %H:%M:%S"  #时间格式  
        },  
    },  

    'handlers': {  
        'console': {  
            'class': 'logging.StreamHandler',   
            'level': 'DEBUG',  
            'formatter': 'colored_console'  
        },  
        'file': {  
            'class': 'logging.handlers.RotatingFileHandler',    
            'maxBytes': 1024 * 1024 * 1024,    
            'backupCount': 1,   
            'filename': log_path,   
            'level': 'INFO',    
            'formatter': 'detail',  #   
            'encoding': 'utf-8',  # utf8 编码  防止出现编码错误  
        },  
    },  

    'loggers': {  
        'logger': {  
            'handlers': ['console'],    
            'level': 'DEBUG',   
        },  

    }  
}  

log_conf.dictConfig(log_config)  
log_v = logging.getLogger('log')  

coloredlogs.install(level='DEBUG', logger=log_v)  


# # Some examples.  
# logger.debug("this is a debugging message")  
# logger.info("this is an informational message")  
# logger.warning("this is a warning message")  
# logger.error("this is an error message")  
# logger.critical("this is a critical message")  

这里准备好了一份我常用的日志配置文件,可作为常用的日志格式,直接调用即可,根据不同的等级来输出到终端或 .log 文件,拿走不谢。

手把手教你使用Flask搭建ES搜索引擎(实战篇)

3

路由

对于 Flask 项目而言, 蓝图和路由会让整个项目更具观赏性(当然指的是代码的阅读)。

这里我采用两个分支来作为数据支撑,一个是 Math 入口,另一个是 Baike 入口,数据的来源是基于上一篇的百度百科爬虫所得,根据 深度优先 的爬取方式抓取后放入 ES 中。

# coding:utf8  
from flask import Flask  
from flask_sqlalchemy import SQLAlchemy  
from app.config.config import Config  
from flask_mail import Mail  
from flask_wtf.csrf import CSRFProtect  

app = Flask(__name__,template_folder='templates',static_folder='static')  
app.config.from_object(Config)  

db = SQLAlchemy(app)  
db.init_app(app)  

csrf = CSRFProtect(app)  
mail = Mail(app)  
# 不要在生成db之前导入注册蓝图。  
from app.home.baike import baike as baike_blueprint  
from app.home.math import math as math_blueprint  
from app.home.home import home as home_blueprint  

app.register_blueprint(home_blueprint)  
app.register_blueprint(math_blueprint,url_prefix="/math")  
app.register_blueprint(baike_blueprint,url_prefix="/baike")  
# -*- coding:utf-8 -*-  
from flask import Blueprint  
baike = Blueprint("baike", __name__)  
from app.home.baike import views  
# -*- coding:utf-8 -*-  
from flask import Blueprint  
math = Blueprint("math", __name__)  

from app.home.math import views  

声明路由并在 __init__ 文件中初始化

下面来看看路由的实现(以Baike为例)

# -*- coding:utf-8 -*-  
import os  
from flask_paginate import Pagination, get_page_parameter  
from app.Logger.logger import log_v  
from app.elasticsearchClass import elasticSearch  

from app.home.forms import SearchForm  

from app.home.baike import baike  
from flask import request, jsonify, render_template, redirect  

baike_es = elasticSearch(index_type="baike_data",index_name="baike")  

@baike.route("/")  
def index():  
    searchForm = SearchForm()  
    return render_template('baike/index.html', searchForm=searchForm)  

@baike.route("/search", methods=['GET', 'POST'])  
def baikeSearch():  
    search_key = request.args.get("b", default=None)  
    if search_key:  
        searchForm = SearchForm()  
        log_v.error("[+] Search Keyword: " + search_key)  
        match_data = baike_es.search(search_key,count=30)  

        # 翻页  
        PER_PAGE = 10  
        page = request.args.get(get_page_parameter(), type=int, default=1)  
        start = (page - 1) * PER_PAGE  
        end = start + PER_PAGE  
        total = 30  
        print("最大数据总量:", total)  
        pagination = Pagination(page=page, start=start, end=end, total=total)  
        context = {  
            'match_data': match_data["hits"]["hits"][start:end],  
            'pagination': pagination,  
            'uid_link': "/baike/"  
        }  
        return render_template('data.html', q=search_key, searchForm=searchForm, **context)  
    return redirect('home.index')  


@baike.route('/<uid>')  
def baikeSd(uid):  
    base_path = os.path.abspath('app/templates/s_d/')  
    old_file = os.listdir(base_path)[0]  
    old_path = os.path.join(base_path, old_file)  
    file_path = os.path.abspath('app/templates/s_d/{}.html'.format(uid))  
    if not os.path.exists(file_path):  
        log_v.debug("[-] File does not exist, renaming !!!")  
        os.rename(old_path, file_path)  
    match_data = baike_es.id_get_doc(uid=uid)  
    return render_template('s_d/{}.html'.format(uid), match_data=match_data)  

可以看到我们成功的将 elasticSearch 类初始化并且进行了数据搜索。

我们使用了 Flask 的分页插件进行分页并进行了单页数量的限制,根据 Uid 来跳转到详情页中。

细心的小伙伴会发现我这里用了个小技巧

@baike.route('/<uid>')  
def baikeSd(uid):  
    base_path = os.path.abspath('app/templates/s_d/')  
    old_file = os.listdir(base_path)[0]  
    old_path = os.path.join(base_path, old_file)  
    file_path = os.path.abspath('app/templates/s_d/{}.html'.format(uid))  
    if not os.path.exists(file_path):  
        log_v.debug("[-] File does not exist, renaming !!!")  
        os.rename(old_path, file_path)  
    match_data = baike_es.id_get_doc(uid=uid)  
    return render_template('s_d/{}.html'.format(uid), match_data=match_data)  

以此来保证存放详情页面的模板中始终只保留一个 html 文件。

手把手教你使用Flask搭建ES搜索引擎(实战篇)

4

项目启动

一如既往的采用 flask_script 作为项目的启动方案,确实方便。

# coding:utf8  
from app import app  
from flask_script import Manager, Server  

manage = Manager(app)  

# 启动命令  
manage.add_command("runserver", Server(use_debugger=True))  


if __name__ == "__main__":  
    manage.run()  

黑窗口键入

python manage.py runserver  

就可以启动项目,默认端口 5000,访问 http://127.0.0.1:5000

手把手教你使用Flask搭建ES搜索引擎(实战篇)

使用gunicorn启动

pip install gunicorn  
#encoding:utf-8  
import multiprocessing  

from gevent import monkey  
monkey.patch_all()  

# 并行工作进程数  
workers = multiprocessing.cpu_count() * 2 + 1  

debug = True  

reload = True # 自动重新加载  

loglevel = 'debug'  

# 指定每个工作者的线程数  
threads = 2  

# 转发为监听端口8000  
bind = '0.0.0.0:5001'  

# 设置守护进程,将进程交给supervisor管理  
daemon = 'false'  

# 工作模式协程  
worker_class = 'gevent'  

# 设置最大并发量  
worker_connections = 2000  

# 设置进程文件目录  
pidfile = 'log/gunicorn.pid'  
logfile = 'log/debug.log'  

# 设置访问日志和错误信息日志路径  
accesslog = 'log/gunicorn_acess.log'  
errorlog = 'log/gunicorn_error.log'  

利用配置文件来启动 gunicorn 服务器

gunicorn -c gconfig.py manage:app  

项目截图

手把手教你使用Flask搭建ES搜索引擎(实战篇)

手把手教你使用Flask搭建ES搜索引擎(实战篇)

手把手教你使用Flask搭建ES搜索引擎(实战篇)

项目 Github 地址

https://github.com/GZKY-PY/Flask-ES

**-----**------**-----**---**** End **-----**--------**-----**-****

往期精彩文章推荐:

手把手教你使用Flask搭建ES搜索引擎(实战篇)

欢迎各位大佬点击链接加入群聊【helloworld开发者社区】:https://jq.qq.com/?_wv=1027&k=mBlk6nzX进群交流IT技术热点。

本文转自 https://mp.weixin.qq.com/s/OF2QTseXpAw_3GCnrF2A3w,如有侵权,请联系删除。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
4cast
4castpackageloadcsv.KumarAwanish发布:2020122117:43:04.501348作者:KumarAwanish作者邮箱:awanish00@gmail.com首页:
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这