搜索
自己最近总结了一下项目中实现过的搜索功能,接下来就通过具体的python项目来进行说明。
一.单表搜索
实现对于特定表中的某些字段的模糊搜索匹配,比如需要根据关键字搜索教师表中的授课教师或者所教课程的信息:
可以通过数据库查询语句直接实现:
# 根据搜索词search_data查询结果
Teacher.objects.filter(Q(teacher__contains=search_data) | Q(course__contains=search_data))
优点: 使用简单方便
缺点: 模糊查询效率低,数据量较大时会变得异常吃力
二.全文搜索
既然数据库模糊匹配在数据量庞大时不能高效实现全文搜索,那我们就要需要选择合适的搜索引擎来实现,现在主流的搜索引擎大概就是:Lucene,Solr,ElasticSearch。python项目中还会经常用到一个纯python实现的全文搜索引擎whoosh,更加小巧简单。
在django项目中实现全文搜索,可以使用搜索框架haystack来实现,
haystack可以方便地在django中直接添加搜索功能,无需关注索引建立、搜索解析等细节问题。
下面就分别使用whoosh和ElasticSearch来实现项目中的全文搜索。
1.haystack+whoosh+Jieba
1.1 配置
- 安装依赖包
pip install whoosh/django-haystack/jieba
由于Whoosh自带的是英文分词,对中文的分词支持不是太好,故用Jieba替换whoosh的分词组件
- 注册haystack 到Django的 INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# haystack注册
'haystack',
]
- settings中增加搜索引擎配置
import os
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
# PATH为Whoosh 索引文件的存放文件夹
'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'),
},
}
1.2 创建索引
- 如果你想针对某个app例如courses做全文检索,则必须在blog的目录下面建立search_indexes.py文件,文件名不能修改
from haystack import indexes
from .models import Course
class CourseIndex(indexes.SearchIndex, indexes.Indexable):
# 这字段必须这么写,用来告诉haystack和搜索引擎要索引哪些字段
text = indexes.CharField(document=True, use_template=True)
# 模型字段,打包数据
id = indexes.CharField(model_attr='id')
course = indexes.CharField(model_attr='course ')
teacher = indexes.CharField(model_attr='teacher')
content = indexes.CharField(model_attr='content')
image_url = indexes.CharField(model_attr='image_url')
def get_model(self):
# 重载get_model方法,必须要有!
return Course
def index_queryset(self, using=None):
return self.get_model().objects.all()
创建索引会提供更快速的导航与查找。索引的实现细节是我们不需要关心的,每个索引里面必须有且只能有一个字段为 document=True,这代表haystack 和搜索引擎将使用此字段的内容作为索引进行检索(primary field)。其他的字段只是附属的属性,方便调用,并不作为检索数据
- 然后在template下面建立 search/indexes/course
前两个目录都是固定的,第三层是应用的名称,一一对应上,然后建立course_text.txt,名字是刚刚指定的类名的小写加_text.txt ,这里面就是对应哪个字段建立索引。例如:
{
{
object.course}}
{
{
object.teacher}}
1.3 搜索模板
在templates/search/下面,建立一个search.html页面
<!DOCTYPE html>
<html>
<head>
<title></title>
<style> span.highlighted {
color: red; } </style>
</head>
<body>
{% load highlight %}
{% if query %}
<h3>搜索结果如下:</h3>
{% for result in page.object_list %}
{# <a href="/{
{ result.object.id }}/">{
{ result.object.teacher }}</a><br/>#}
<a href="/{
{ result.object.id }}/">{% highlight result.object.teacher with query max_length 2%}</a><br/>
<p>{
{ result.object.course|safe }}</p>
<p>{% highlight result.course with query %}</p>
{% empty %}
<p>啥也没找到</p>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}
<a href="?q={
{ query }}&page={
{ page.previous_page_number }}">{% endif %}« 上一页
{% if page.has_previous %}</a>{% endif %}
|
{% if page.has_next %}<a href="?q={
{ query }}&page={
{ page.next_page_number }}">{% endif %}下一页 »
{% if page.has_next %}</a>{% endif %}
</div>
{% endif %}
{% endif %}
</body>
</html>
需要注意的是page.object_list实际上是SearchResult对象的列表。这些对象返回索引的所有数据。它们可以通过{
{result.object}}来访问。所以{
{ result.object.teacher}}实际使用的是数据库中course对象来访问teacher字段的
1.4 配置URL
添加SearchView到URLconf,在URLconf中添加下面一行:
# 前后端不分离url
url(r'^search/', include('haystack.urls')),
# 前后端分离url
path('search/', MySearchView(), name='haystack_search'),
1.5 视图函数
前后端分离后台需要重写SearchView中的create_response方法,用到的时候可以根据需要重写即可。
1.6 使用jieba分词
建立ChineseAnalyzer.py文件
保存在haystack的安装文件夹下,路径如“D:\python3\Lib\site-packages\haystack\backends”
import jieba
from whoosh.analysis import Tokenizer, Token
class ChineseTokenizer(Tokenizer):
def __call__(self, value, positions=False, chars=False,
keeporiginal=False, removestops=True,
start_pos=0, start_char=0, mode='', **kwargs):
t = Token(positions, chars, removestops=removestops, mode=mode,
**kwargs)
seglist = jieba.cut(value, cut_all=True)
for w in seglist:
t.original = t.text = w
t.boost = 1.0
if positions:
t.pos = start_pos + value.find(w)
if chars:
t.startchar = start_char + value.find(w)
t.endchar = start_char + value.find(w) + len(w)
yield t
def ChineseAnalyzer():
return ChineseTokenizer()
复制whoosh_backend.py文件,改名为whoosh_cn_backend.py
from .ChineseAnalyzer import ChineseAnalyzer
# 查找
analyzer=StemmingAnalyzer()
# 改为
analyzer=ChineseAnalyzer()
2.haystack+ES
2.1 环境配置
下载elasticsearch和其依赖包
pip install django-haystack/elasticsearch
然后在settings中增加搜索引擎配置
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
'URL': 'http://127.0.0.1:9200/', # 此处为elasticsearch运行的服务器ip地址和端口
'INDEX_NAME': 'course', # 指定elasticserach建立的索引库名称
},
}
# 搜索结果每页显示数量
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 5
# 实时更新index
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
2.2 创建索引
和whoosh的步骤一样
2.3 创建索引数据模板
和whoosh的步骤一样
3.4 配置URL
在course/urls.py中添加如下路由
path('course/search/', views.CourseSearchView.as_view(), name='course_search')
3.5 视图函数
from haystack.generic_views import SearchView
from .models import Course
class CourseSearchView(SearchView):
""" 新闻搜索视图 """
# 设置搜索模板文件
template_name = 'course/search.html'
# 否则根据参数q搜索相关数据
def get(self, request, *args, **kwargs):
# 1. 获取查询参数
query = request.GET.get('q')
# 2. 如果没有查询参数
if not query:
# 获取课程对象
course_datas = Course.objects.all()
# 分页, 从配置文件中拿到haystack参数
paginator = Paginator(course_datas, settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)
try:
# 拿到前端传递的page,
page = paginator.get_page(int(request.GET.get('page')))
except Exception as e:
# 如果出错则返回第一页,保证容错性
page = paginator.get_page(1)
return render(request, self.template_name, context={
'page': page,
# 'paginator': paginator,
'query': query
})
# 3. 如果有查询参数
else:
# 则执行搜索
return super().get(request, *args, **kwargs)
def get_context_data(self, *args, **kwargs):
""" 在context中添加page变量 """
context = super().get_context_data(*args, **kwargs)
if context['page_obj']:
# 捕获page_obj,将其赋值到page
context['page'] = context['page_obj']
return context
总结
使用sql语句的模糊搜索效率较低,但是使用非常简单,在数据量较小、搜索精准度要求不高的情况下可以使用。
ES和whoosh搜索引擎在项目的配置步骤是相差不多的,ES的性能还是会比whoosh要高一些的,同时也因为whoosh是纯python实现的搜索引擎,在功能和性能上远不如ES。个人更推荐在项目中使用ES+haystack的方式去实现搜索功能。
今天的文章ElasticSearch和whoosh实现项目中搜索功能分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/32300.html