【elasticsearch实战】从零开始设计全站搜索引擎,2024年最新阿里P7亲自教你

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)
img

正文

数据传输选型

我们的数据存储在MySQL,文档数据存储在对象存储腾讯云COS中,需要近实时的将文档数据的变更同步到es数据库中,有以下一些同步方案。

同步方案选型
  1. 应用同步双写
    在这里插入图片描述
  2. 应用异步双写
    在这里插入图片描述
  3. 基于MySQL的抽取
    在这里插入图片描述
  4. 基于Binlog实时同步
    在这里插入图片描述
    四种方案原理和对比如下:
方案原理优点缺点
1. 应用同步双写当应用程序对MySQL进行写操作时,同时对Elasticsearch进行写操作。1. 实时性较高。2. 数据同步过程相对简单。1. 对应用程序造成较大压力。2. 需要应用程序维护两个数据源。3. 一旦出现错误,可能导致数据不一致。
2. 应用异步双写当应用程序对MySQL进行写操作时,将写操作记录到消息队列,然后异步地对Elasticsearch进行写操作。1. 对应用程序的压力较小。2. 数据同步过程相对简单。1. 实时性较差。2. 需要应用程序维护两个数据源。3. 一旦出现错误,可能导致数据不一致。
3. 基于MySQL的定时任务抽取定时从MySQL中抽取数据,然后将数据写入到Elasticsearch。1. 对应用程序无影响。2. 可以自定义同步周期。1. 实时性较差。2. 需要额外的定时任务维护。3. 需要对MySQL进行查询操作,可能影响性能。
4. 基于MySQL的Binlog日志同步通过解析MySQL的Binlog日志,实时地将数据变更写入到Elasticsearch。1. 实时性较高。2. 对应用程序无影响。3. 可以保证数据一致性。1. 需要解析Binlog日志,实现较为复杂。2. 需要额外的同步工具或中间件。3. 需要对MySQL的Binlog日志进行维护。

我们考虑综合考虑了实时性要求和对应用的改造影响,选择了方案4: 基于MySQL的Binlog日志同步
那么异步同步工具有又怎么选择呢?

同步工具选型

同步工具开源方案目前最活跃的应该是阿里巴巴开源的canal ,可以看github官网的原理介绍

  1. MySQL主备复制原理:
    • MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志- 事件binary log events,可以通过 show binlog events 进行查看)
    • MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
    • MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据
  2. canal 工作原理
    • canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
    • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
    • canal 解析 binary log 对象(原始为 byte 流)

在这里插入图片描述
我们结合自己的业务场景和系统现状选择了腾讯云DTS做数据传输工具, 另外自研了数据传输的中间件,来解决不同数据表结构的适配问题,统一适配数据格式之后,将数据从新写入kafka,然后通过logstash 读取kafka数据写入binlog

#mermaid-svg-CDPtMmuPvv8JTgZj {font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-CDPtMmuPvv8JTgZj .error-icon{fill:#552222;}#mermaid-svg-CDPtMmuPvv8JTgZj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CDPtMmuPvv8JTgZj .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-CDPtMmuPvv8JTgZj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CDPtMmuPvv8JTgZj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CDPtMmuPvv8JTgZj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CDPtMmuPvv8JTgZj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CDPtMmuPvv8JTgZj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CDPtMmuPvv8JTgZj .marker.cross{stroke:#333333;}#mermaid-svg-CDPtMmuPvv8JTgZj svg{font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CDPtMmuPvv8JTgZj .label{font-family:“trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-CDPtMmuPvv8JTgZj .cluster-label text{fill:#333;}#mermaid-svg-CDPtMmuPvv8JTgZj .cluster-label span{color:#333;}#mermaid-svg-CDPtMmuPvv8JTgZj .label text,#mermaid-svg-CDPtMmuPvv8JTgZj span{fill:#333;color:#333;}#mermaid-svg-CDPtMmuPvv8JTgZj .node rect,#mermaid-svg-CDPtMmuPvv8JTgZj .node circle,#mermaid-svg-CDPtMmuPvv8JTgZj .node ellipse,#mermaid-svg-CDPtMmuPvv8JTgZj .node polygon,#mermaid-svg-CDPtMmuPvv8JTgZj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CDPtMmuPvv8JTgZj .node .label{text-align:center;}#mermaid-svg-CDPtMmuPvv8JTgZj .node.clickable{cursor:pointer;}#mermaid-svg-CDPtMmuPvv8JTgZj .arrowheadPath{fill:#333333;}#mermaid-svg-CDPtMmuPvv8JTgZj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CDPtMmuPvv8JTgZj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CDPtMmuPvv8JTgZj .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-CDPtMmuPvv8JTgZj .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-CDPtMmuPvv8JTgZj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CDPtMmuPvv8JTgZj .cluster text{fill:#333;}#mermaid-svg-CDPtMmuPvv8JTgZj .cluster span{color:#333;}#mermaid-svg-CDPtMmuPvv8JTgZj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CDPtMmuPvv8JTgZj :root{–mermaid-font-family:“trebuchet ms”,verdana,arial,sans-serif;}

订阅binlog

读取kafka

写入kafka2

input来源于kafka2

输出到kafka1

腾讯云 DTS-kafka1

MySQL

dts适配

kafka2

logstash

Elasticsearch

整体设计

架构图

架构图如下

  • 搜索服务:基础的关键词检索能力、权限控制、热词/联想词、搜索结果混排、查询第三方数据
  • 数据转换服务:读取kafkabinlog转换成满足es索引结构的json对象,再写入kafka,通过logstash写入es中。
    在这里插入图片描述

详细设计

该服务包括:搜索门户api、权限控制、搜索能力、搜索混排、搜索热词、联想关键词。

搜索混排

由于自主维护的数据和第三方数据源数据都存储在es中,因此可以直接使用评分进行合并,如下图所示。
在这里插入图片描述

注意:

  1. 可以配置不同数据源的评分权重(或者评分算法)以便优先要展示的结果;
  2. 需要记录不同数据源的偏移量和不同数据的查询结果,以便实现下次查询分页处理;
  3. 查询ES和查询私有云数据使用协程并行操作,等待2个结果共同返回处理。

另外你的第三方数据源没有存储在es数据库中,不能直接给出文档评分的,可以考虑以下混排方案:

方案原理优点缺点
es临时建索引做混排将来自不同数据源的数据在Elasticsearch中创建一个临时索引,然后在该索引上进行搜索和排序。1. 利用Elasticsearch强大的搜索功能。2. 支持复杂的查询和排序。1. 需要创建临时索引,可能影响性能。2. 需要处理索引的创建和删除。3. 可能需要处理数据源之间的数据差异。
Lucene内存混排将来自不同数据源的数据加载到Lucene内存索引中,然后在内存索引上进行搜索和排序。1. 高性能,因为数据存储在内存中。2. 支持复杂的查询和排序。1. 内存占用较高。2. 需要处理Lucene内存索引的创建和维护。3. 可能需要处理数据源之间的数据差异。
分词词频内存混排根据分词和词频对来自不同数据源的数据进行内存中的排序,然后返回排序后的结果。1. 实现相对简单。2. 内存占用相对较低。1. 只支持基于分词和词频的排序。2. 对于复杂的查询和排序需求,可能不够灵活。3. 可能需要处理数据源之间的数据差异。

翻页方案

由于要对2个数据源进行混排,要支持搜索跳页比较困难,因此在功能实现上目前只能支持上下翻页来实现

翻页计算公式

前端需要保存每一页es 和 api 两个数据源的偏移量:EsOffset 和 ApiOffset,可以使用对象数组保存pageArrays[0] = {EsOffset: 0, ApiOffset: 0 } , 翻页计算公式如下:

  • 当前页码计算公式:PageNo =(EsOffset+ApiOffset) /PageSize
  • 上一页:将当前页码减1 :pageArrays[(EsOffset+ApiOffset)/ PageSize - 1 ] , 获取上一页页面缓存的上一页 EsOffset 和 ApiOffset
  • 下一页: EsOffset = EsOffset + EsUsedItemCountApiOffset = ApiOffset + ApiUsedItemCount, 获取下一页的EsOffset 和 ApiOffset

注意:查询到第一页时,可清空页面分页缓存数组对象,重新存储。

翻页举例说明
  1. 查询首页,假设没页显示20条数据

    • 请求参数:EsOffset = 0,ApiOffset=0, PageSize=20
    • 返回结果:EsOffset = 0,ApiOffset=0,EsUsedItemCount=7,ApiUsedItemCount=13, EsHasNextPage=true,ApiHasNextPage=true

前端需要需要页面需要保存当前第一页页面的 EsOffset=0ApiOffset=0PageNo = (0 + 0) / 20 = 0 ,页面缓存数据: pageArrays=[{EsOffset: 0, ApiOffset: 0 }]

  1. 继续查询下一页

    • 请求参数:EsOffset = EsOffset + EsUsedItemCount=> 0 + 7 = 7,ApiOffset=ApiOffset+ApiUsedItemCount = 0 + 13 = 13, PageSize=20
    • 返回结果:EsOffset = 7,ApiOffset=13, EsUsedItemCount = 12,ApiUsedItemCount = 8, EsHasNextPage=true,ApiHasNextPage=true
    • 前端继续缓存当前分页数据:EsOffset=7 和 ApiOffset=13,PageNo = (7 + 13) / 20 = 1, pageArrays=[{EsOffset: 0, ApiOffset: 0 },{EsOffset: 7, ApiOffset: 13}]
  2. 查询上一页

  • 请求参数:当前页码减1 (EsOffset+ApiOffset)/ PageSize - 1 => (7 + 13)/20 - 1 = 0 EsOffset = pageArrays[0].EsOffset = 0,ApiOffset=pageArrays[0].ApiOffset = 0, PageSize = 20
  • 返回结果:与第一页一致
    如果是查询第一数据,清空缓存数组,重新缓存当前分页数据。

权限处理

搜索权限需要满足根据用户权限过滤部分无权限的文档,以下是召回前处理和召回后处理权限的方案对比。

方案实现优点缺点
召回前过滤在查询时,根据用户的权限对文档进行过滤,只返回有权限查看的文档。1. 查询结果直接满足权限要求。2. 减少了无关文档的返回,提高了性能。1. 需要在查询时处理权限信息。2. 对于复杂的权限体系,实现可能较为复杂。
召回后过滤先查询所有文档,然后根据用户的权限对查询结果进行过滤。1. 查询过程简单,不需要处理权限信息。2. 适用于简单的权限体系。1. 可能返回大量无关文档,影响性能。2. 需要在查询后处理权限信息,增加了实现复杂度。

根据我的需求和场景,对性能要求较高,我们使用召回前过滤。如果希望简化查询过程,页可以考虑使用召回后过滤。
下面是在文档的权限格式,包含文档有权限的用户ID和部门ID

"privilege": {
     "data": [
         {
             "type": "staff",
             "id": "xxxx"
         },
         {
             "type": "department",
             "id": 1
         }
     ]
 }

我们在设计索引mapping时

{
  "mappings": {
    "properties": {
      "privilege": {
        "properties": {
          "data": {
            "type": "nested",
            "properties": {
              "type": {
                "type": "keyword"
              },
              "id": {
                "type": "keyword"
              }
            }
          }
        }
      }
    }
  }
}

查询权限过滤参数:

GET /your_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match\_all": {}
        }
      ],
      "filter": [
        {
          "nested": {
            "path": "privilege.data",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "privilege.data.type": "staff"
                    }
                  },
                  {
                    "term": {
                      "privilege.data.id": "xxxx"
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "privilege.data",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "privilege.data.type": "department"
                    }
                  },
                  {
                    "term": {
                      "privilege.data.id": "1"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

搜索行为日志收集

需要满足用户搜索历史记录,首先需要收集用户搜索行为日志。

#mermaid-svg-RGDIHV3yG6IIeTHR {font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-RGDIHV3yG6IIeTHR .error-icon{fill:#552222;}#mermaid-svg-RGDIHV3yG6IIeTHR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RGDIHV3yG6IIeTHR .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-RGDIHV3yG6IIeTHR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RGDIHV3yG6IIeTHR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RGDIHV3yG6IIeTHR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RGDIHV3yG6IIeTHR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RGDIHV3yG6IIeTHR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RGDIHV3yG6IIeTHR .marker.cross{stroke:#333333;}#mermaid-svg-RGDIHV3yG6IIeTHR svg{font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RGDIHV3yG6IIeTHR .label{font-family:“trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-RGDIHV3yG6IIeTHR .cluster-label text{fill:#333;}#mermaid-svg-RGDIHV3yG6IIeTHR .cluster-label span{color:#333;}#mermaid-svg-RGDIHV3yG6IIeTHR .label text,#mermaid-svg-RGDIHV3yG6IIeTHR span{fill:#333;color:#333;}#mermaid-svg-RGDIHV3yG6IIeTHR .node rect,#mermaid-svg-RGDIHV3yG6IIeTHR .node circle,#mermaid-svg-RGDIHV3yG6IIeTHR .node ellipse,#mermaid-svg-RGDIHV3yG6IIeTHR .node polygon,#mermaid-svg-RGDIHV3yG6IIeTHR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RGDIHV3yG6IIeTHR .node .label{text-align:center;}#mermaid-svg-RGDIHV3yG6IIeTHR .node.clickable{cursor:pointer;}#mermaid-svg-RGDIHV3yG6IIeTHR .arrowheadPath{fill:#333333;}#mermaid-svg-RGDIHV3yG6IIeTHR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RGDIHV3yG6IIeTHR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RGDIHV3yG6IIeTHR .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-RGDIHV3yG6IIeTHR .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-RGDIHV3yG6IIeTHR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RGDIHV3yG6IIeTHR .cluster text{fill:#333;}#mermaid-svg-RGDIHV3yG6IIeTHR .cluster span{color:#333;}#mermaid-svg-RGDIHV3yG6IIeTHR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RGDIHV3yG6IIeTHR :root{–mermaid-font-family:“trebuchet ms”,verdana,arial,sans-serif;}

输入关键词

写入日志

用户

服务端

Mysql

通过收集用户搜索关键词存储在MySQL,每日定时任务统计热词和联想词来实现热门搜索榜和搜索联想词。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

oot{–mermaid-font-family:“trebuchet ms”,verdana,arial,sans-serif;}

输入关键词

写入日志

用户

服务端

Mysql

通过收集用户搜索关键词存储在MySQL,每日定时任务统计热词和联想词来实现热门搜索榜和搜索联想词。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
[外链图片转存中…(img-of4U61HJ-1713161987399)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Elasticsearch 是一种开源的全文搜索引擎,它可以帮助用户快速、准确地对网站中的所有内容进行搜索。作为一个全站搜索引擎Elasticsearch 可以处理大量的数据,并提供高性能的搜索功能。它支持通过倒排索引技术来高效地搜索文本内容,并且可以实时更新索引以保持数据的实时性。使用 Elasticsearch 可以实现对网站内容的全文搜索,包括文章、博客、产品信息、用户评论等等。它提供了丰富的搜索功能,包括全文搜索、模糊匹配、聚合搜索、过滤器搜索等,能够帮助用户快速地找到他们感兴趣的内容。 利用 Elasticsearch全站搜索功能,用户可以轻松地在网站中进行全文搜索,无论是在桌面端还是移动端都能够得到良好的搜索体验。而且,Elasticsearch 还支持多语言搜索,可以处理不同语言的文本内容,并提供相关性排名功能,帮助用户找到最相关的搜索结果。另外,Elasticsearch 还可以通过配置不同的分片和复制策略来实现可伸缩性和高可用性,确保搜索服务的稳定性和可靠性。 总的来说,Elasticsearch 全站搜索功能强大而灵活,可以满足不同网站的搜索需求,帮助用户快速找到他们需要的信息,提升网站的用户体验,并且可以通过定制化的配置来满足不同场景的需求。因此,Elasticsearch 全站搜索成为了许多网站和应用的首选搜索引擎

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值