汇总:网站搜索大优化!
优采云 发布时间: 2022-09-24 00:09汇总:网站搜索大优化!
使用ES+云开发实用优化网站搜索
大家好,我是玉皮。今天,我将进行一场技术战,以提高 网站search 的灵活性。
ES+云开发搜索优化实践
本文大纲:
鱼皮 - 网站搜索优化背景
我开发的编程导航网站已经上线6个月了,但是自上线以来,网站一直存在一个严重的问题,就是搜索功能不好用。
之前为了追求快速上线,搜索功能只是简单的使用数据库模糊查询(含)实现,方便开发,但是这种方式很不灵活。
例如,网站上有一个名为“Java Design Patterns”的资源,但是用户搜索“Java Design Patterns”却找不到任何东西。原因是资源名称中收录空格,用户搜索“Java Design Patterns”。 关键词 输入时没有空格。
空格只是一个特例,类似的情况还有很多。比如网站上有一个资源叫做“Java并发编程实践”,但是当用户搜索“Java实践”时,前者收录“Java”和“Java”。 “实战”这两个字,却一无所获。
你要知道搜索功能对于一个信息聚合网站来说是非常重要的,它直接影响着用户的体验。如果您在 网站 上找不到资源,谁会使用它们?
所以我也收到了一些朋友的礼貌建议,比如这个秃头汤姆:
我之前没有优化搜索,主要是两个原因:穷+怕麻烦。但是随着网站用户的增多,是时候补上这个坑了!
技术选择
为了提高网站搜索的灵活性,在前端和后端都使用全文搜索技术。
前端全文搜索
有时,我们要检索的数据是有限的,所有数据都存储在客户端。
比如个人博客网站,我们通常将每个文章作为文件存储在某个目录下,而不是后台数据库中。在这种情况下,不需要从服务器上去。如果请求动态数据,可以直接在前端搜索数据。
有一些现成的搜索库,比如Lunr.js(GitHub 7k+star),先添加你要检索的内容:
var idx = lunr(function () {<br /> this.field('title')<br /> this.field('body')<br /> // 内容<br /> this.add({<br /> "title": "yupi",<br /> "body": "wx搜程序员鱼皮,阅读我的原创文章",<br /> "id": "1"<br /> })<br />})<br />
然后只需搜索:
idx.search("鱼皮")<br />
纯前端全文搜索的优点是不需要后端,简单方便,可以节省服务器压力;无需连接互联网,也没有额外的网络开销,检索速度更快。
后端全文搜索
与前端不同的是,后端全文搜索是在服务器上做的,从远程数据库中搜索出符合要求的数据,然后直接返回给前端。
目前主流的后端全文搜索技术是Elasticsearch,一个分布式的、RESTful风格的搜索和数据分析引擎。
它功能强大且灵活,但需要构建、定义数据、管理字典、上传和维护数据等,操作性强,需要一定的技巧。菜鸟大佬设计的ES搜索系统,神奇不一样。
所以,对于Elasticsearch不熟悉的同学,可以直接使用现成的全文搜索服务。比如Algolia,直接通过它提供的API上传要检索的数据,然后使用它提供的API进行检索。提供了一定的空闲空间,足够小网站和学习使用。
阿尔及利亚搜索服务选择
那么我应该为我的编程导航选择哪种实现方式网站?
首先,这个网站的资源数量不是固定的,不定期动态更新,所以不适合前端全文搜索。
其次,考虑到未来网站的数据量会比较大,可能需要根据用户的搜索动态优化检索系统(比如自定义编程词典),考虑使用 Elasticsearch 技术自己构建搜索引擎,而不是现成的全文搜索服务,让你以后可以按照自己的意愿定制系统。另外,不需要将网站数据发送到其他平台,可以保证数据的安全性。
ES 安装
决定使用 Elasticsearch 后,首先要设置环境。
你可以自己购买服务器,然后按照官方文档一步一步手动安装。对于有一定规模的个人网站,虽然搭建过程不难,但后期维护成本巨大,比如性能分析、监控、告警、安全等,都需要自己配置。尤其是后期网站数据量会比较大,所以需要考虑搭建集群、横向扩展等。
因此,我选择直接使用云服务商提供的 Elasticsearch 服务。这里我选择腾讯云,它为你自动搭建现成的ES集群服务,同时提供可视化架构管理、集群监控、日志、高级插件、智能巡检等功能。
Cloud ES 集群架构
虽然 ES 服务很贵,但节省的时间对我来说是值得的。
还有一个非常方便的自定义搜索服务Elastic App Search,有兴趣的可以试试。
ES 公共服务
我们的目标是优化网站resources的搜索功能,但是接下来要做的不是直接写具体的业务逻辑,而是先开发一个公共的ES服务。
其实ES的操作还是比较简单的。可以简单理解为数据库。那么公共ES服务应该有基本的增删改查功能,供其他函数调用。
实施
由于编程导航后端使用腾讯云开发技术,使用Node.js编写服务,所以使用官方推荐的@elastic/elasticsearch库来操作ES。
没用过云开发也没关系,可以先把它理解为后端,欢迎阅读我之前的文章:.
代码很简单。首先,与 ES 建立连接。为了保证数据安全,请使用内网地址:
const client = new Client({<br /> // 内网地址<br /> node: 'http://10.0.61.1:9200',<br /> // 用户名和密码<br /> auth: {<br /> username: esConfig.username,<br /> password: esConfig.password,<br /> },<br />});<br />
然后写 CRUD。这里是一个抽象的步骤,通过switch等分支语句,根据请求参数来区分操作、要操作的数据等,这样每个操作就不需要单独写成一个接口了。
// 接受请求参数<br />const { op, index, id, params } = event;<br />// 根据操作执行增删改查<br />switch (op) {<br /> case 'add':<br /> return doAdd(index, id, params);<br /> case 'delete':<br /> return doDelete(index, id);<br /> case 'search':<br /> return doSearch(index, params);<br /> case 'update':<br /> return doUpdate(index, id, params);<br />}<br />
在云开发中,如果一个函数太久没有被调用,资源就会被释放。下次请求时,会执行冷启动重新创建资源,导致接口返回慢。因此,将多个操作封装到同一个函数中也可以减少冷启动的机会。
对代码的具体增删改查不再赘述,阅读ES Node官方文档即可,代码会开源到编程导航仓库()。
本地调试
编写代码后,可以使用云开发自带的tcb命令行工具在本地执行功能。
记得先改ES到公网的连接地址,然后输入一行命令。比如我们要在ES中插入一条数据,传入要执行的函数名,请求参数,代码路径:
tcb fn run <br /> --name <br /> --params "{\"op\": \"add\"}"<br /> --path <br />
执行成功后,可以在ES中看到新插入的数据(通过Kibana面板或curl查看):
远程测试
在本地测试公共服务代码后,将ES连接地址改为内网IP,然后发布到云端。
然后尝试编写另一个函数来访问公共ES服务,例如将资源插入ES并通过callFunction进行请求:
// 添加资源到 ES<br />function addData() {<br /> // 请求公共服务<br /> app.callFunction({<br /> name: 'esService',<br /> data: {<br /> op: 'add',<br /> index: 'resource',<br /> id,<br /> params: data,<br /> }<br /> });<br />}<br />
但是数据没有插入成功,却返回了接口超时,为什么?
内网配置
从日志得知ES无法连接。会不会是发布ES公共服务的机器和ES不在同一个内网的原因?
所以需要在云开发控制台中更改ES公共服务的私网配置,选择和购买ES时一样的子网即可:
配置ES云功能专网
修改后再次远程请求ES公共服务,数据插入成功~
数据索引
开发完ES公共服务后,可以编写具体的业务逻辑。
首先,ES中必须建立索引(类似于数据库的表),以约定数据类型、分词等信息,而不是允许任意插入数据。
例如,为了更灵活的搜索,资源名称应指定为“文本”类型以启用分词,并指定ik中文分词器:
"name": {<br /> "type": "text",<br /> "analyzer": "ik_max_word",<br /> "search_analyzer": "ik_smart",<br /> "fields": {<br /> "keyword": {<br /> "type": "keyword",<br /> "ignore_above": 256<br /> }<br /> }<br />}<br />
点赞数应设置为“long”类型,只允许数字:
"likeNum": {<br /> "type": "long"<br />}<br />
最好也给索引分配一个别名,以便以后修改字段时可以重建索引:
"aliases" : { <br /> "resource": {}<br />}<br />
写好索引的json配置后,通过curl或Kibana调用ES新索引接口即可。
数据同步
以前,编程导航网站的资源数据都存储在数据库中,用户可以从数据库中查询。但是现在我们想从 ES 中查询,ES 是不够的,我们必须想办法将数据库中的资源数据同步到 ES 中。
有几种同步策略。
双写
过去,用户推荐的资源只会插入到数据库中。双写是指资源插入数据库时,要同时插入到ES中。
听起来很简单,但这种方法存在一些问题:
之前的代码会改,每个写数据库的地方都要加ES。
会出现一边写失败,另一边写成功的情况,导致数据库和ES的数据不一致。
有没有对现有代码干扰较少的方法?
定时器同步
如果对数据的实时性要求不高,可以选择定时同步,定时将数据库中新插入或修改的数据复制到ES。
实现方式有很多种,比如使用Logstash数据传输管道,或者自己编写定时任务程序,这样就完全不需要改动现有的代码了。
实时同步
如果对数据的实时性要求很高,刚插入数据库的数据必须能够立即被搜索到,所以需要实时同步。除了双写,还可以监控数据库的binlog,我们可以感知数据库的任何变化。
阿里有一个开源项目叫Canal,可以实时监控MySQL数据库,向下游推送通知。有兴趣的朋友可以看看。
运河工程实施
由于搜索编程资源对实时性要求不高,所以定时同步即可。
云开发默认提供了定时功能,所以我直接写了一个云函数,每1分钟执行一次,每次读取数据库中最近5分钟发生变化的数据,防止最后一次执行失败。 另外,必须配置超时时间,防止函数执行时间过长导致执行失败。
在云端开发-云端功能控制台可视化配置,需要指定定时任务的crontab表达式:
配置云功能计时和超时
开启定时同步后,别忘了编写并执行第一个同步函数,将全量历史数据同步到ES。
数据检索
现在ES上有数据了,只剩下最后一步了,也就是如何搜索数据?
首先要学习ES的搜索DSL(语法),包括如何取列、搜索、过滤、分页、排序等。对于新手来说还是有点麻烦,尤其是布尔表达式的组合查询条件,一不小心就会查不到数据。因此,建议您先在 Kibana 提供的调试工具中编写查询语法:
Kibana 调试
找到期望的数据后,编写后端搜索函数,接受的请求参数要与原接口保持一致,减少改动。
查询语法可以根据前端的请求动态拼接,例如按资源名搜索:
// 传了资源名<br />if (name) {<br /> // 拼接查询语句<br /> query.bool.should = [<br /> {<br /> match: {<br /> name<br /> }<br /> }<br /> ];<br />}<br />
这样就完成了整个网站的搜索优化。
让我们再试试效果,现在即使我输入一些带有更多“鱼”的单词,我也能找到它!
ES如何实现灵活搜索?欢迎阅读。
新的ES搜索接口的发布并不意味着旧的数据库查询接口已经过时,可以同时保留。按名称搜索资源时,使用了新的接口,更加灵活;根据审核状态查找用户发布的资源时,可以使用旧界面从数据库中查找。这样,负载分担,职责分离,对的技术才能做对的事!
最新信息:网站内容该怎么去更新,更新多少合适呢?
<p>网站SEO 是否需要每日更新文章?首先,当涉及到搜索引擎对网站的爬取和更新时,搜索引擎在不断读取网站的爬取的同时,也会判断一个网站的更新程度@>。网站如果长期无人维护,那么搜索引擎对你的网站的爬取也会逐渐减少,慢慢的,排名也会慢慢的下降,所以更新一下