elasticsearch(搜索引擎)提供了自动补全接口

官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html

1、创建搜索自动补全字段suggest

自动补全需要用到一个字段名称为suggest类型为Completion类型的一个字段

所以我们需要用将前面的elasticsearch-dsl操作elasticsearch(搜索引擎)增加suggest类型为Completion

注意:因为elasticsearch-dsl源码问题,设置字段为Completion类型指定分词器时会报错,所以我们需要重写CustomAnalyzer类

只有Completion类型才是,其他类型不用,其他类型直接指定分词器即可

#!/usr/bin/env python

from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \
analyzer, InnerObjectWrapper, Completion, Keyword, Text, Integer # 更多字段类型见第三百六十四节elasticsearch(搜索引擎)的mapping映射管理
from elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzer #导入CustomAnalyzer类 from elasticsearch_dsl.connections import connections # 导入连接elasticsearch(搜索引擎)服务器方法
connections.create_connection(hosts=['127.0.0.1']) class CustomAnalyzer(_CustomAnalyzer): # 自定义CustomAnalyzer类,来重写CustomAnalyzer类
def get_analysis_definition(self):
return {} ik_analyzer = CustomAnalyzer("ik_max_word", filter=["lowercase"]) # 实例化重写的CustomAnalyzer类传入分词器和大小写转,将大写转换成小写 class lagouType(DocType): # 自定义一个类来继承DocType类
suggest = Completion(analyzer=ik_analyzer)
# Text类型需要分词,所以需要知道中文分词器,ik_max_wordwei为中文分词器
title = Text(analyzer="ik_max_word") # 设置,字段名称=字段类型,Text为字符串类型并且可以分词建立倒排索引
description = Text(analyzer="ik_max_word")
keywords = Text(analyzer="ik_max_word")
url = Keyword() # 设置,字段名称=字段类型,Keyword为普通字符串类型,不分词
riqi = Date() # 设置,字段名称=字段类型,Date日期类型 class Meta: # Meta是固定写法
index = "lagou" # 设置索引名称(相当于数据库名称)
doc_type = 'biao' # 设置表名称 if __name__ == "__main__": # 判断在本代码文件执行才执行里面的方法,其他页面调用的则不执行里面的方法
lagouType.init() # 生成elasticsearch(搜索引擎)的索引,表,字段等信息 # 使用方法说明:
# 在要要操作elasticsearch(搜索引擎)的页面,导入此模块
# lagou = lagouType() #实例化类
# lagou.title = '值' #要写入字段=值
# lagou.description = '值'
# lagou.keywords = '值'
# lagou.url = '值'
# lagou.riqi = '值'
# lagou.save() #将数据写入elasticsearch(搜索引擎)

2、搜索自动补全字段suggest写入数据

搜索自动补全字段suggest接收的要搜索的字段分词数据,详情见下面的自定义分词函数

elasticsearch-dsl操作elasticsearch(搜索引擎)

#!/usr/bin/env python
# -*- coding:utf8 -*-
#!/usr/bin/env python from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \
analyzer, InnerObjectWrapper, Completion, Keyword, Text, Integer
from elasticsearch_dsl.connections import connections # 导入连接elasticsearch(搜索引擎)服务器方法
# 更多字段类型见第三百六十四节elasticsearch(搜索引擎)的mapping映射管理
from elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzer #导入CustomAnalyzer类 connections.create_connection(hosts=['127.0.0.1']) class CustomAnalyzer(_CustomAnalyzer): # 自定义CustomAnalyzer类,来重写CustomAnalyzer类
def get_analysis_definition(self):
return {} ik_analyzer = CustomAnalyzer("ik_max_word", filter=["lowercase"]) # 实例化重写的CustomAnalyzer类传入分词器和大小写转,将大写转换成小写 class lagouType(DocType): # 自定义一个类来继承DocType类
suggest = Completion(analyzer=ik_analyzer)
# Text类型需要分词,所以需要知道中文分词器,ik_max_wordwei为中文分词器
title = Text(analyzer="ik_max_word") # 设置,字段名称=字段类型,Text为字符串类型并且可以分词建立倒排索引
description = Text(analyzer="ik_max_word")
keywords = Text(analyzer="ik_max_word")
url = Keyword() # 设置,字段名称=字段类型,Keyword为普通字符串类型,不分词
riqi = Date() # 设置,字段名称=字段类型,Date日期类型 class Meta: # Meta是固定写法
index = "lagou" # 设置索引名称(相当于数据库名称)
doc_type = 'biao' # 设置表名称 def gen_suggest(index, info_tuple):
# 根据字符串生成搜索建议数组
"""
此函数主要用于,连接elasticsearch(搜索引擎),使用ik_max_word分词器,将传入的字符串进行分词,返回分词后的结果
此函数需要两个参数:
第一个参数:要调用elasticsearch(搜索引擎)分词的索引index,一般是(索引操作类._doc_type.index)
第二个参数:是一个元组,元祖的元素也是元组,元素元祖里有两个值一个是要分词的字符串,第二个是分词的权重,多个分词传多个元祖如下
书写格式:
gen_suggest(lagouType._doc_type.index, (('字符串', 10),('字符串', 8)))
"""
es = connections.create_connection(lagouType._doc_type.using) # 连接elasticsearch(搜索引擎),使用操作搜索引擎的类下面的_doc_type.using连接
used_words = set()
suggests = []
for text, weight in info_tuple:
if text:
# 调用es的analyze接口分析字符串,
words = es.indices.analyze(index=index, analyzer="ik_max_word", params={'filter':["lowercase"]}, body=text)
anylyzed_words = set([r["token"] for r in words["tokens"] if len(r["token"])>1])
new_words = anylyzed_words - used_words
else:
new_words = set() if new_words:
suggests.append({"input":list(new_words), "weight":weight}) # 返回分词后的列表,里面是字典,
# 如:[{'input': ['录音', '广告'], 'weight': 10}, {'input': ['新能源', '汽车',], 'weight': 8}]
return suggests if __name__ == "__main__": # 判断在本代码文件执行才执行里面的方法,其他页面调用的则不执行里面的方法
lagouType.init() # 生成elasticsearch(搜索引擎)的索引,表,字段等信息
# 使用方法说明:
# 在要要操作elasticsearch(搜索引擎)的页面,导入此模块
# lagou = lagouType() #实例化类
# lagou.title = '值' #要写入字段=值
# lagou.description = '值'
# lagou.keywords = '值'
# lagou.url = '值'
# lagou.riqi = '值'
# lagou.save() #将数据写入elasticsearch(搜索引擎)

suggest字段写入数据

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
# items.py,文件是专门用于,接收爬虫获取到的数据信息的,就相当于是容器文件 import scrapy
from scrapy.loader.processors import MapCompose, TakeFirst
from scrapy.loader import ItemLoader # 导入ItemLoader类也就加载items容器类填充数据
from adc.models.elasticsearch_orm import lagouType, gen_suggest # 导入elasticsearch操作模块 class LagouItemLoader(ItemLoader): # 自定义Loader继承ItemLoader类,在爬虫页面调用这个类填充数据到Item类
default_output_processor = TakeFirst() # 默认利用ItemLoader类,加载items容器类填充数据,是列表类型,可以通过TakeFirst()方法,获取到列表里的内容 def tianjia(value): # 自定义数据预处理函数
return value # 将处理后的数据返给Item class LagouItem(scrapy.Item): # 设置爬虫获取到的信息容器类
title = scrapy.Field( # 接收爬虫获取到的title信息
input_processor=MapCompose(tianjia), # 将数据预处理函数名称传入MapCompose方法里处理,数据预处理函数的形式参数value会自动接收字段title
)
description = scrapy.Field()
keywords = scrapy.Field()
url = scrapy.Field()
riqi = scrapy.Field() def save_to_es(self):
lagou = lagouType() # 实例化elasticsearch(搜索引擎对象)
lagou.title = self['title'] # 字段名称=值
lagou.description = self['description']
lagou.keywords = self['keywords']
lagou.url = self['url']
lagou.riqi = self['riqi']
# 将title和keywords数据传入分词函数,进行分词组合后返回写入搜索建议字段suggest
lagou.suggest = gen_suggest(lagouType._doc_type.index, ((lagou.title, 10),(lagou.keywords, 8)))
lagou.save() # 将数据写入elasticsearch(搜索引擎对象)
return

写入elasticsearch(搜索引擎)后的情况

{
"_index": "lagou",
"_type": "biao",
"_id": "AV5MDu0NXJs9MkF5tFxW",
"_version": 1,
"_score": 1,
"_source": {
"title": "LED光催化灭蚊灯广告录音_广告录音网-火红广告录音_叫卖录音下载_语音广告制作",
"keywords": "各类小商品,广告录音,叫卖录音,火红广告录音",
"url": "http://www.luyin.org/post/2486.html",
"suggest": [
{
"input": [
"广告"
,
"火红"
,
"制作"
,
"叫卖"
,
"灭蚊灯"
,
"语音"
,
"下载"
,
"led"
,
"录音"
,
"灭蚊"
,
"光催化"
,
"催化"
],
"weight": 10
}
,
{
"input": [
"小商品"
,
"广告"
,
"各类"
,
"火红"
,
"叫卖"
,
"商品"
,
"小商"
,
"录音"
],
"weight": 8
}
],
"riqi": "2017-09-04T16:43:20",
"description": "LED光催化灭蚊灯广告录音 是广告录音网-火红广告录音中一篇关于 各类小商品 的文章,欢迎您阅读和评论,专业叫卖录音-广告录音-语音广告制作"
}
}

用Django实现搜索的自动补全功能说明

1.将搜索框绑定一个事件,每输入一个字触发这个事件,获取到输入框里的内容,用ajax将输入的词请求到Django的逻辑处理函数。

2.在逻辑处理函数里,将请求词用elasticsearch(搜索引擎)的fuzzy模糊查询,查询suggest字段里存在请求词的数据,将查询到的数据添加到自动补全

html代码:

<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml">
{#引入静态文件路径#}
{% load staticfiles %}
<head>
<meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>lcv-search 搜索引擎</title>
<link href="{% static 'css/style.css'%}" rel="stylesheet" type="text/css" />
<link href="{% static 'css/index.css'%}" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="container">
<div id="bd">
<div id="main">
<h1 class="title">
<div class="logo large"></div>
</h1>
<div class="nav ue-clear">
<ul class="searchList">
<li class="searchItem current" data-type="article">文章</li>
<li class="searchItem" data-type="question">问答</li>
<li class="searchItem" data-type="job">职位</li>
</ul>
</div>
<div class="inputArea">
{% csrf_token %}
<input type="text" class="searchInput" />
<input type="button" class="searchButton" onclick="add_search()" />
<ul class="dataList">
<li>如何学好设计</li>
<li>界面设计</li>
<li>UI设计培训要多少钱</li>
<li>设计师学习</li>
<li>哪里有好的网站</li>
</ul>
</div> <div class="historyArea">
<p class="history">
<label>热门搜索:</label> </p>
<p class="history mysearch">
<label>我的搜索:</label>
<span class="all-search">
<a href="javascript:;">专注界面设计网站</a>
<a href="javascript:;">用户体验</a>
<a href="javascript:;">互联网</a>
<a href="javascript:;">资费套餐</a>
</span> </p>
</div>
</div><!-- End of main -->
</div><!--End of bd--> <div class="foot">
<div class="wrap">
<div class="copyright">Copyright &copy;uimaker.com 版权所有 E-mail:admin@uimaker.com</div>
</div>
</div>
</div>
</body>
<script type="text/javascript" src="{% static 'js/jquery.js'%}"></script>
<script type="text/javascript" src="{% static 'js/global.js'%}"></script>
<script type="text/javascript">
var suggest_url = "/suggest/"
var search_url = "/search/" $('.searchList').on('click', '.searchItem', function(){
$('.searchList .searchItem').removeClass('current');
$(this).addClass('current');
}); function removeByValue(arr, val) {
for(var i=0; i<arr.length; i++) {
if(arr[i] == val) {
arr.splice(i, 1);
break;
}
}
} // 搜索建议
$(function(){
$('.searchInput').bind(' input propertychange ',function(){
var searchText = $(this).val();
var tmpHtml = ""
$.ajax({
cache: false,
type: 'get',
dataType:'json',
url:suggest_url+"?s="+searchText+"&s_type="+$(".searchItem.current").attr('data-type'),
async: true,
success: function(data) {
for (var i=0;i<data.length;i++){
tmpHtml += '<li><a href="'+search_url+'?q='+data[i]+'">'+data[i]+'</a></li>'
}
$(".dataList").html("")
$(".dataList").append(tmpHtml);
if (data.length == 0){
$('.dataList').hide()
}else {
$('.dataList').show()
}
}
});
} );
}) hideElement($('.dataList'), $('.searchInput')); </script>
<script>
var searchArr;
//定义一个search的,判断浏览器有无数据存储(搜索历史)
if(localStorage.search){
//如果有,转换成 数组的形式存放到searchArr的数组里(localStorage以字符串的形式存储,所以要把它转换成数组的形式)
searchArr= localStorage.search.split(",")
}else{
//如果没有,则定义searchArr为一个空的数组
searchArr = [];
}
//把存储的数据显示出来作为搜索历史
MapSearchArr(); function add_search(){
var val = $(".searchInput").val();
if (val.length>=2){
//点击搜索按钮时,去重
KillRepeat(val);
//去重后把数组存储到浏览器localStorage
localStorage.search = searchArr;
//然后再把搜索内容显示出来
MapSearchArr();
} window.location.href=search_url+'?q='+val+"&s_type="+$(".searchItem.current").attr('data-type') } function MapSearchArr(){
var tmpHtml = "";
var arrLen = 0
if (searchArr.length >= 5){
arrLen = 5
}else {
arrLen = searchArr.length
}
for (var i=0;i<arrLen;i++){
tmpHtml += '<a href="'+search_url+'?q='+searchArr[i]+'">'+searchArr[i]+'</a>'
}
$(".mysearch .all-search").html(tmpHtml);
}
//去重
function KillRepeat(val){
var kill = 0;
for (var i=0;i<searchArr.length;i++){
if(val===searchArr[i]){
kill ++;
}
}
if(kill<1){
searchArr.unshift(val);
}else {
removeByValue(searchArr, val)
searchArr.unshift(val)
}
} </script>
</html>

Django路由映射

"""pachong URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app1 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.indexluoji),
url(r'^index/', views.indexluoji),
url(r'^suggest/$', views.suggestluoji,name="suggest"), # 搜索字段补全请求 ]

Django静态文件配置

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
#配置静态文件前缀
STATIC_URL = '/static/'
#配置静态文件目录
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]

备注:搜索自动补全fuzzy查询

#搜索自动补全fuzzy查询
POST lagou/biao/_search?pretty
{
"suggest":{          #字段名称
"my_suggest":{       #自定义变量
"text":"广告",      #搜索词
"completion":{
"field":"suggest",  #搜索字段
"fuzzy":{
"fuzziness":1    #编辑距离
}
}
}
},
"_source":"title"
}

Django逻辑处理文件

from django.shortcuts import render

# Create your views here.
from django.shortcuts import render,HttpResponse
from django.views.generic.base import View
from app1.models import lagouType #导入操作elasticsearch(搜索引擎)类
import json def indexluoji(request):
print(request.method) # 获取用户请求的路径
return render(request, 'index.html') def suggestluoji(request): # 搜索自动补全逻辑处理
key_words = request.GET.get('s', '') # 获取到请求词
re_datas = []
if key_words:
s = lagouType.search() # 实例化elasticsearch(搜索引擎)类的search查询
s = s.suggest('my_suggest', key_words, completion={
"field": "suggest", "fuzzy": {
"fuzziness": 2
},
"size": 5
})
suggestions = s.execute_suggest()
for match in suggestions.my_suggest[0].options:
source = match._source
re_datas.append(source["title"])
return HttpResponse(json.dumps(re_datas), content_type="application/json")

最终完成

四十七 Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能的更多相关文章

  1. 第三百六十七节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)scrapy写入数据到elasticsearch中

    第三百六十七节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)scrapy写入数据到elasticsearch中 前面我们讲到的elasticsearch( ...

  2. 第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理

    第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理 1.映射(mapping)介绍 映射:创建索引的时候,可以预先定义字 ...

  3. 第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

    第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—用Django实现搜索的自动补全功能 elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.e ...

  4. 第三百七十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现我的搜索以及热门搜索

    第三百七十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现我的搜索以及热门 我的搜素简单实现原理我们可以用js来实现,首先用js获取到 ...

  5. 第三百七十节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索结果分页

    第三百七十节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索结果分页 逻辑处理函数 计算搜索耗时 在开始搜索前:start_time ...

  6. 第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能

    第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能 Django实现搜索功能 1.在Django配置搜索结果页的路由映 ...

  7. 第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询

    第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询 bool查询说明 filter:[],字段的过滤,不参与打分must:[] ...

  8. 第三百六十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的基本查询

    第三百六十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的基本查询 1.elasticsearch(搜索引擎)的查询 elasticsearch是功能 ...

  9. 第三百六十三节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mget和bulk批量操作

    第三百六十三节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mget和bulk批量操作 注意:前面讲到的各种操作都是一次http请求操作一条数据,如果想 ...

随机推荐

  1. 原!tomcat启动超时(打印了几行日志,后面没了。也不报错,处于启动状态,直到超时)

    项目框架:spring+struts2+mybatis 今天优化代码,改了一堆mybatis dao和xml文件,启动项目时,就出现如标题描述的状况:打印了几行日志,后面就不打印了,也不报错,处于启动 ...

  2. Python爬虫之-Requests

    Requests模块 Python标准库中提供了:urllib.urllib2.httplib等模块以供Http请求,但是,它的 API 太渣了. 它是为另一个时代.另一个互联网所创建的.它需要巨量的 ...

  3. pycharm断点调试

    step over 执行下一步 蓝色高亮的那一行表示准备执行的代码

  4. python中的闭包是什么

    当一个嵌套函数在其外部区域引用了一个值时,该嵌套函数就是一个闭包,其意义就是会记录这个值 def A(x): def B(): print(x) return B A(7)() #7

  5. 第四课 Makefile文件的制作(下)

    1序言: 前面一节课讲解了Makefile的基础知识包括原理.预定义以及命令格式,这样是可以完成一个自动编译的文件,这些知识可以帮你完成.想想mak真是强大啊,可能有些同志发现了如果项目文件太多每个目 ...

  6. HTML5之概述

    HTML5是万维网的核心语言.标准通用标记语言下的一个应用超文本标记语言(HTML)的第五次重大修改,是继HTML4.01和XHTML1.0之后的超文本标记语言的最新版本.它是由一群自由思想者组成的团 ...

  7. HDU 6351 (Beautiful Now) 2018 Multi-University Training Contest 5

    题意:给定数N(1<=N<=1e9),k(1<=k<=1e9),求对N的任意两位数交换至多k次能得到的最小与最大的数,每一次交换之后不能出现前导零. 因为N最多只有10位,且给 ...

  8. [国家集训队] Crash 的文明世界(第二类斯特林数)

    题目 [国家集训队] Crash 的文明世界 前置 斯特林数\(\Longrightarrow\)斯特林数及反演总结 做法 \[\begin{aligned} ans_x&=\sum\limi ...

  9. 机器学习中的numpy库

            日常学习中总是遇到数据需要处理等问题,这时候我们就可以借助numpy这个工具来做一些有意思的事. 1.生成随机数的几种方式 x=np.random.random(12) ###生成12 ...

  10. linux中的信号简介和trap命令

    1.信号 linux通过信号来在运行在系统上的进程之间通信,也可以通过信号来控制shell脚本的运行 主要有一下信号 1 ##进程重新加载配置 2 ##删除进程在内存中的数据 3 ##删除鼠标在内存中 ...