简单地说,我们现在是Redis

了解更多

用reresearch构建实时全文网站搜索

喝我们自己的香槟:我们如何用RediSearch将实时搜索添加到Redis文档站点。



回到博客

当我们想要添加实时全文搜索到Redis文档站点,我们转向再研究.reresearchch模块中强大的搜索功能帮助我们将平淡无奇的表单转变为令人惊叹的搜索体验。为了展示RediSearch的一些可能性,并帮助启动您的搜索项目,我想谈谈我们项目的架构并分享我们的代码。我们构建的Python应用程序被调用redis-sitesearch.如果你想查看代码或者在你自己的网站上运行它,它是开源,你可以免费试用reresearch.com复述,云的必需品.继续读下去,了解细节!

我们为什么要使用reresearch

我们建立了一个新的搜索体验,因为我们的文档站点已经超越了以前的搜索引擎Lunr.js。具体来说,我们希望从新的搜索体验中获得一些东西:

  • 对查询、索引和结果结构的更多控制
  • 实时搜索
  • 支持分面搜索

我们知道reresearch可以提供我们清单上的所有东西。(如果你不熟悉再研究,这是一个伟大的查询和索引系统的Redis,并包括强大的全文搜索功能。)所以,我们得工作了。几周内,我们在文档站点上有了一个全新的搜索API。让我们从一个较高的水平来看项目的各个部分,然后我们将放大到更近的地方。

高级体系结构

我们的文档搜索有两个主要部分:由HTML输入和搜索结果列表组成的JavaScript前端和查询RediSearch的REST API后端。

当您键入时,前端向后端API发出搜索请求并呈现结果。由于Redis是一个内存数据库,并且部署在多个区域,在俄勒冈州的测试中获得这些结果的速度非常快——平均约为40- 50毫秒。

搜索API的HTTP请求的屏幕截图显示了40ms - 60ms的响应时间。

我们知道,人类将低于100毫秒的反应时间视为瞬间,所以我们很高兴达到40 - 60毫秒的范围。

不过,搜索应用程序内部到底发生了什么,才会出现这种情况呢?以下是涉及的部分:

  • 与RediSearch复述,
  • 一个Python后台任务,抓取文档站点并在Redis中索引数据
  • 提供搜索API的Python web服务

以下是这些碎片如何组合在一起的图表:

此图显示了项目的索引器、重新搜索、搜索API和前端组件,以及索引器和重新搜索、搜索API和重新搜索以及前端和搜索API之间的数据流连接。

我们在谷歌Cloud上的一个容器中运行这些组件,并在一个全局负载均衡器后面使用一个多区域部署将容器的实例分发到全世界。

现在让我们详细看看后端应用程序涉及的四个步骤:

  1. 索引
  2. 解析
  3. 查询
  4. 部署

索引

在处理任何搜索查询之前,我们需要对文档站点建立索引。为此,我们使用一个RediSearch索引定义,该定义包含我们将用于搜索的所有字段。在我们的Python应用程序中,有一个后台作业按进度抓取文档站点,并将其内容添加到reresearch索引中。让我们看看这两件事是如何运作的。

该指数的定义

使用RediSearch,您需要在进行任何查询之前创建索引定义。

RediSearch索引与你的Redis数据库中的hash保持同步。在redis-sitesearch应用程序中,我们为要添加到搜索索引中的每个文档创建一个哈希。

然后我们为想要索引的站点创建一个RediSearch索引。每个索引与匹配前缀的键中的哈希值同步sitesearch:{环境}:{url}:医生:. 目前,我们只为文档站点编制索引,但这种设计允许我们使用同一个应用程序实例为多个站点编制索引。索引定义采用模式参数,该参数定义应该将哪些Hash字段添加到索引中。redis-sitesearch索引以下字段:

  • 标题
  • 节标题
  • 身体
  • URL

使用redisearch-python客户端,架构如下所示:

TextField("title", weight=10), TextField("section_title"), TextField("body", weight=1.5), TextField("url"),

您可以看到,我们在标题和正文字段中添加了“权重”。这意味着搜索查询将考虑这些字段中的命中比其他字段更相关。

索引工作

有了索引定义后,我们需要一个后台任务来抓取文档站点并创建reresearch.com要索引的哈希值。

为此,我们使用复述,队列构建每30分钟运行一次的索引作业。这项工作使用发痒的库,我们使用自定义逻辑对其进行了扩展,以将抓取的页面内容解析为结构化数据。

用Scrapy解析结构化页面数据

我们的新搜索体验的目标之一是显示页面中我们找到搜索结果的部分。例如,如果查询“gcp”在“帐户和团队设置”页面的“团队管理”部分发现了一个点击,我们希望在搜索结果中同时显示该页面和部分。以下截图显示了一个搜索结果示例:

在这张截图中,“GCP”是最受欢迎的,所以这个术语以粗体显示,这是reresearch的一个例子突出了特性。“帐户和团队设置”是我们发现点击的页面的标题,“团队管理”是包含点击的部分的名称。

我们通过分解每一页来实现这一点SearchDocument对象。SearchDocument是我们的应用程序用来表示我们想要搜索的网页部分的域模型。

在Scrapy完成爬行网站后,我们转换SearchDocument对象到Redis哈希。然后reresearch在后台对哈希进行索引。

文档打分

当您使用RediSearch配置为索引的键创建Hash时,您可以选择提供一个“__score”字段。如果这样做,RediSearch将在搜索查询中将该文档的最终相关性值乘以__score.这意味着您可以在索引时对数据的一些相关事实进行建模。让我们回顾几个例子redis-sitesearch

我们创建了得分函数文档评分调整原则如下:

  1. “section”文档(从页面上的H2标记创建)的得分应始终低于“page”文档。这是因为我们想浮出水面页面对于主题,如果在显示部分在这个页面。
  2. 在所有条件相同的情况下,位于网站URL层次结构较深的页面得分应该低于位于URL层次结构较高的页面。例如,给定查询“kubernetes”,我们希望在特定kubernetes部署选项的页面之前显示一个Getting Started页面。

这种细粒度的控制是我们转向reresearchch的主要原因。

验证文件

基于规则对文档进行不同的权重有助于提高搜索结果的相关性,但有些文档类型我们希望完全避免索引。我们的验证器是决定是否索引a的简单函数吗SearchDocument基于任意逻辑的。我们使用这些来跳过发行说明和任何看起来像404页面的文档。

使用搜索API进行查询

通过在RediSearch中定期索引文档站点的后台工作,我们终于可以构建我们的搜索API了!我们使用了猎鹰web框架的API,因为它的快速性能。

一个有效的搜索API将前端用户查询转换为reresearch查询。RediSearch支持数字范围、标签、地理位置过滤器和更多类型的查询。对于这个应用程序来说,最适合的是前缀匹配.通过前缀匹配,RediSearch将索引中的所有术语与给定的前缀进行比较。如果用户在搜索表单中输入“red”,API将发出前缀查询“red*”。

通过前缀匹配," red* "将找到许多命中,包括:

  • 复述,
  • 再研究
  • redisgears
  • redistimeseries

当用户键入时,搜索表单将开始显示所有这些术语的点击结果。当用户完成他们正在键入的短语时,结果将开始聚焦。如果最终搜索是“RedSearch”,应用程序会向Redis发出最后一个查询“RedSearch*”,结果将特定于RedSearch。

在谷歌云上部署

谷歌云使部署redis-sitesearch变得容易。我们将后端应用程序构建为单个容器关于谷歌云的计算引擎,运行以下进程:

  • 与RediSearch复述,
  • 搜索API
  • 索引工作的Redis Queue任务worker

我们将该容器部署到谷歌Cloud上的US-West、US-East、Zurich和Mumbai区域的实例组。

请注意:计算引擎每个节点只能运行一个容器,这就是为什么我们在Redis旁边运行Python应用程序。然而,这有减少延迟的好处!

一个全球负载均衡器根据请求的地理来源和实例组中的当前负载将流量路由到这些实例。

你也可以使用reresearch

我们希望为用户提供最好的文档搜索体验。做到这一点的方法,reresearch,就在我们面前。

如果你正在构建一个全文网站搜索功能,可以看看RediSearch。它将您的整个搜索索引保存在内存中,因此查询运行非常快。reresearch还可以通过数值范围、地理半径等进行过滤。你甚至可以启动你的项目使用我们的开源redis-sitesearch代码库.如果你不想自己托管reresearchch,你可以免费使用复述,云的必需品

想了解更多关于reresearch的信息吗?观看我们最新的YouTube视频:在Redis中查询,索引和全文搜索

Baidu