使用 GraphQL 和 Elasticsearch 构建搜索引擎

阅读时长 7 分钟读完

搜索引擎是现代 Web 应用中的重要部分。针对不同的需求,例如在线商店、社交媒体或者大型网站,开发人员需要构建不同规模和复杂度的搜索引擎。在这篇文章中,我们将介绍使用 GraphQL 和 Elasticsearch 构建搜索引擎的方法和技巧。

GraphQL 简介

GraphQL 是一种查询语言和运行时环境,由 Facebook 在 2012 年开发,并在 2015 年对外发布。GraphQL 旨在简化客户端和服务器之间的数据交互,将客户端的数据需要传递给服务器的请求和服务器返回数据的响应,变成一种类似于关系型数据库查询语言的格式。GraphQL 可以大幅度降低增量数据需求以及为纷繁复杂的客户端恶心的 RESTful 设计提供优雅的解决方案。

GraphQL 核心特性:

  • 自描述性:可以搜索模式并按照模型的方式来生产新的查询。
  • 精确性:开发人员可以精确指定所需的字段,避免了 RESTful 开发中查询遇到的数据其他不需要的情况。
  • 强大的类型系统:GraphQL 使用类似关系型数据库的类型系统的设计,可以明确数据模型并自动生成相关的文档。
  • 使用单端点 API:开发人员只需要专注数据模型和查询的描述,而不是 URL、HTTP 方法和 JSON 结构等。
  • 带有可重用的组件:开发人员可以创建和维护一个为 API 设计的组件库或者输出部分。

Elasticsearch 简介

Elasticsearch 是一个开源分布式搜索引擎,它使用专门的存储、索引和分析技术,方便快速并且容易地存储、搜索和分析大量文档。它提供了一个广泛的 API,可以处理千万级别的数据并支持实时查询。Elasticsearch 还提供插件机制,允许用户扩展和自定义搜索引擎。

Elasticsearch 核心特性:

  • 分布式存储和查询
  • 支持全文检索和聚合查询
  • 开箱即用的 RESTful API 接口
  • 可定制和可扩展
  • 实时查询和数据更新

构建搜索引擎

结合 GraphQL 和 Elasticsearch,可以构建出高效,易用的搜索引擎。类似于 GraphQL,Elasticsearch 也采用了类似 RESTful 的 API 设计,接口实现了相关的请求、查询语言等。构建一个基于 GraphQL 和 Elasticsearch 的搜索引擎,首要任务是设计 DOM 的数据模型。

下面,我们假设需要搜索的文档具有如下格式:

-- -------------------- ---- -------
-
    ----- --
    -------- ------ -------
    ------- ------ ------ --- ----- ---------
    ------- -
        ----- --
        ------- -------
    --
    -------- ---
    ------- --------- ---------
    ------- --------------------------
-

以上数据表示一个文档,包含一个 ID、一些元数据、一些文本内容和其他数据 (可设置可售前),这是代表一图片文档的包含。因为 Elasticsearch 是基于 JSON 处理的,可以轻松将其转化为 Elasticsearch 支持的数据格式,即 index (索引)、type(文档),同时在 Elasticsearch 中使用 Mapping 定义字段、类型和其它设置。

首先,我们需要将上面的文档映射到 Elasticsearch 中的索引。这个过程需要定义模型的映射,定义索引名称以及索引的数据类型,具体代码如下:

-- -------------------- ---- -------
--- ---------
-
   ----------- -
        ------------------- --
        --------------------- -
   --
   ----------- -
        ------------- -
            ----- - ------- --------- --
            -------- - ------- ------ --
            ------- - ------- ------ --
            ------- -
                ------- ---------
                ------------- -
                    ----- - ------- --------- --
                    ------- - ------- ------ -
                -
            --
            -------- - ------- --------- --
            ------- - ------- --------- --
            ------- - ------- ------ -
        -
   -
-

以上代码定义了一个名为 my_index 的索引,同时设定了 3 个分片和 2 个副本。其次,定义了索引里的字段类型以及包含的字段。

接下来,我们可以使用 GraphQL 来构建查询语言。GraphQL 核心是创建一个 schema,该 schema 定义了所有可以访问的查询,其中就包含了一些 Elasticsearch 查询。例如,以下代码显示了可以执行的查询类型:

-- -------------------- ---- -------
---- ----- -
    --------------------- -------- ----- --- - -- ------ --- - ---- -----------
    ------------------ -------- ----- --- - -- ------ --- - ---- --------
-

---- ------- -
    --- ---
    ------ -------
    ------ ----
    ----- ----------
-

---- ---- -
    --- ---
    ----- -------
-

这个 schema 定义了两个查询类型 searchArticlessearchUsers,它们都是返回指定类型的数组。其中,searchArticles 查询接受一个查询字符串、用于跳过的条数和用于返回的最大项目数量。这个查询需要返回匹配查询字符串的所有文章,这些文章都包含 idtitlelikestags 字段。

searchUsers 查询与 searchArticles 类似,它需要匹配查询字符串并返回所有匹配的用户,这些用户包含 idname 字段。

GraphQL 执行查询是一种两个不同模式的查询:查询模式和变更模式(Update、Delete、Insert)。与 REST API 不同,GraphQL 可以执行多个查询同时返回多个结果。

最后,我们需要将 GraphQL 和 Elasticsearch 集成在一起。为了执行 Elasticsearch 查询,需要使用类似于 Elasticsearch-js 和 apollo-link-resolve-fetch 的库。这些库将 GraphQL 查询结果直接转换为 Elasticsearch 查询,轻松地与 Elasticsearch 集成。第三方库和插件能在 apollo-link 和 Elasticsearch-js 上构建 GraphQL 和 Elasticsearch 集成所需的组件。

以下是一个使用 node.js 和 Elasticsearch-js 的示例代码:

-- -------------------- ---- -------
----- - ------ - - ---------------------------------
----- ------ - --- -------- ----- ----------------------- --

----- -------- ------------- -
  ----- ------- - ----- ---------------
    -- -----
  --

  ------ --------------------------- -- ------------
-

我们使用 Elasticsearch-js 开始了一个 Elasticsearch 客户端,向 Elasticsearch 发出一个查询请求。查询采用 JSON 示范样式来指定查询参数,或者直接输入查询字符串。

结论

使用 GraphQL 和 Elasticsearch 构建搜索引擎,可以实现高效、易用、可扩展的搜索引擎。GraphQL 提供了一个强大的查询语言,Elasticsearch 提供了强大的搜索引擎。这两个技术的结合可以将搜索引擎的复杂度降至最低,使其成为现代 Web 应用中必不可少的一部分。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/676e22fb2a18d78edd902f0e

纠错
反馈