# Demo: GitHub search with Manticore Search

**TL;DR:** 在这篇博客文章中，我们演示了如何使用 Manticore Search 创建一个与 GitHub 用于查找问题的搜索应用非常相似的搜索应用。
* 尝试演示：
  * 爬取你的仓库 - [https://github.manticoresearch.com/](https://github.manticoresearch.com/)。你将需要等待。
  * 在爬取的仓库中搜索 - [https://github.manticoresearch.com/manticoresoftware/manticoresearch](https://github.manticoresearch.com/manticoresoftware/manticoresearch)。
* GitHub 项目 - [https://github.com/manticoresoftware/manticore-github-issue-search](https://github.com/manticoresoftware/manticore-github-issue-search/tree/62b2a3ca166eeed356049e1125e6093739fb4f54)。
* [为自己设置](https://github.com/manticoresoftware/manticore-github-issue-search/tree/62b2a3ca166eeed356049e1125e6093739fb4f54) 以一种全新的方式浏览你的 GitHub 问题、拉取请求和评论。

## 介绍

在我们有效突出 Manticore Search 能力和性能的旅程中，我们意识到选择一个能够作为有说服力展示的真实世界应用的重要性。我们考虑了几个选项——常见的选择包括：
* 电子商务网站
* 目录列表
* 电影数据库等。

虽然这些是熟悉且易于理解的例子，Manticore 与它们完美契合，但它们在提供实际价值方面有所不足。

这时灵感来了：**为什么不为 GitHub 问题创建一个搜索工具？** 不仅这将为我们提供一个强大的演示机会，而且这也为使用 Manticore Search 的高级功能增强搜索体验提供了机会 **这至少对我们 Manticore 核心团队来说是有用的**。

我们接受了这个挑战，并自豪地推出我们的创作——一个专门针对 GitHub 问题的搜索引擎。这不仅仅是一个演示；它是一个实用工具，我们希望它对 GitHub 社区非常有用。

我们邀请您探索并互动我们的 GitHub 问题搜索 [https://github.manticoresearch.com](https://github.manticoresearch.com/)。通过这种动手体验，发现 Manticore Search 的全部潜力。享受我们增强的搜索功能带来的好处，并亲自看看 Manticore Search 如何转变数据探索。

在某些情况下，我们实现了比 GitHub 快 30 倍的搜索速度。好奇它是如何运作以及我们是如何做到的吗？让我们深入探讨我们是如何构建它的。

| GitHub 搜索 - 215 毫秒 | 通过 Manticore 的 GitHub 搜索 - 6 毫秒 |
|---|---|
| ![来自 GitHub 界面的搜索结果](./manticoresearch-github-issue-search-demo/results-of-search-from-the-github-interface.png) | ![来自 Manticore Search 演示项目的搜索结果](./manticoresearch-github-issue-search-demo/results-of-search-fromthe-manticore-search-demo-project.png) |

## **前提条件**

概念很简单——我们的目标是将选定的 GitHub 仓库中的数据提取到 Manticore 搜索数据库中。通过全文索引数据，我们可以启用有效的搜索功能。

我们的决定是保持与 GitHub 非常相似的设计，但在用户界面中进行细微的增强，以适应不仅技术娴熟的用户，还包括那些技术经验较少的用户。

此外，我们还旨在引入其他功能，例如：
* 跨问题和评论的组合搜索
* 高级过滤选项
* 根据反应对结果进行排序的能力
* 无限滚动分页

让我们深入细节，检查当前面临的挑战，并探索 Manticore 如何通过实际示例解决这些问题。

## 为 MVP 选择合适的工具

开发一个演示可能是一个相当大的挑战，但当你在与时间赛跑时，你需要尽可能多的帮助。这就是为什么我们选择了经过验证的后端使用 PHP 和客户端使用 JavaScript 的组合——再加上一点 SEO 友好的混合魔法。你可能会问为什么选择 PHP？嗯，这就像给你的项目装上了喷气背包！它启动迅速，验证简单，测试起来轻而易举。当然，因为我们的团队在 PHP 方面比其他美丽而现代的编程语言更有经验。（顺便说一句，[阅读关于](/blog/manticoresearch-buddy-pluggable-design/) 如何构建一个用 C++ 编写的 Manticore Search 的 PHP 插件。）

Manticore Search 还附带了 [PHP 客户端](https://github.com/manticoresoftware/manticoresearch-php)，我们在演示中使用了它。使用它就像这样简单：

```php
<?php
use Manticoresearch\\Client;
$client = new Client(['host' => 'localhost', 'port' => 9308]);
$index = $client->index('repo');
$docs = $index->search('bug')->get();
foreach ($docs as $doc) {
    var_dump($doc->getId(), $doc->getData());
}

```

就这样，你创建了一个 Manticore 客户端，选择你想要交流的表，发送一个搜索请求，然后——哇！——结果就源源不断地进来了。

我们不会在这里深入探讨 Manticore Search PHP 客户端的深处，但如果你迫不及待想要尝试，可以查看他们的仓库 [Manticore Search PHP 客户端](https://github.com/manticoresoftware/manticoresearch-php)。

演示包括多个组件，因为它：
- 从 GitHub 获取数据，
- 维护一个待处理的仓库队列
- 可以通过电子邮件发送通知
- 等等。等等。等等

为了方便你，所有与 Manticore Search 交互的代码都位于 [Manticore.php](https://github.com/manticoresoftware/manticore-github-issue-search/blob/c52fa522705eb947deaaf487e8dd2cb6534b4156/app/src/lib/Manticore.php)。这可能对将来考虑比较不同存储引擎的任何人也有用。

## 我们必须克服的有趣挑战

在开发演示的过程中，除了实现上述提到的琐碎事项外，我们还遇到了一些有趣的挑战，你可能在自己的项目中也会遇到。

### **在合并两个表时搜索结果的相关性**

任何搜索系统的一个关键方面是其结果的相关性。当使用 Manticore Search 作为后端实现 GitHub 问题演示时，值得注意的是，相关性在开箱即用的情况下得到了有效管理。Manticore Search 采用经典的基于 BM25 的排名方法，根据文档和查询中关键词的频率和重要性以及字段长度归一化（匹配术语所在文本字段的长度）对搜索结果进行排序。这意味着无需复杂的配置或复杂的算法即可开始高效的搜索体验。有关更多详细信息，请参阅文档 – [排名概述](https://manual.manticoresearch.com/Searching/Sorting_and_ranking#Ranking-overview)。

我们面临的挑战涉及在 GitHub 问题和评论中执行组合搜索。从技术上讲，我们在 Manticore 层将其分为两个独立的表：一个用于问题，另一个用于评论。在研究排名机制后，我们决定实现 Rank-Biased Precision (RBP) 算法，这使我们能够合并来自两个不同来源的结果。此外，Manticore Search 提供了一个可以通过 PHP 客户端的 `$doc->getScore()` 方法检索的 'score' 字段。您可以在此处查看代码：[Manticore.php 代码](https://github.com/manticoresoftware/manticore-github-issue-search/blob/539a813a11d210489ab109105703cfc2bec8e598/app/src/lib/Manticore.php#L176-L177)。

因此，我们不仅实现了“开箱即用”的相关性，还利用 RBP 来结合两个来源，最大化搜索结果的有效性！

### 问题和评论的高级过滤

![GitHub 问题搜索的高级过滤和整个界面与 Manticore Search 演示项目](./manticoresearch-github-issue-search-demo/the-advanced-filtering-and-the-entire-interface-of-the-github-issue-search.png)

#### 步骤 1：渲染范围

在搜索功能的领域中，单纯的基本搜索往往不足以满足需求。用户经常需要使用过滤器来细化他们的结果。在 Manticore Search 和许多其他搜索引擎中，实现基于范围或相等的简单过滤器是直接的。然而，当涉及在某些范围内对结果进行分组时，这项任务可能看起来令人生畏——但实际上，使用 Manticore Search 这非常可管理。

我们的目标是使用户能够选择预定义的范围并相应地应用过滤器，同时避免存储或缓存任何额外数据。例如，我们旨在按评论数量过滤问题：≤ 5，介于 5 和 10 之间，以及 ≥ 10。Manticore Search 通过其 [INTERVAL](https://manual.manticoresearch.com/Functions/Arrays_and_conditions_functions#INTERVAL()) 函数简化了此过程。让我们看看它在演示中的实现。

我们设计了一种特殊的方法，生成我们所需的范围以及每个范围内项目的计数。以下是伪代码，以便理解它是多么简单：

```php
$client = static::client();
$index = $client->index('issue');
$search = $index->search('');
$range = implode(',', $values);
$facets = $search
    ->limit(0)
    ->filter('repo_id', $repoId)
    ->expression('range', "INTERVAL(comments, $range)")
    ->facet('range', 'counters', sizeof($values) + 1)
    ->get()
    ->getFacets();
```

您可以在以下 URL 查看完整代码：

[查看完整代码](https://github.com/manticoresoftware/manticore-github-issue-search/blob/539a813a11d210489ab109105703cfc2bec8e598/app/src/lib/Manticore.php#L478-L522)

#### 步骤 2：应用过滤器

下一步涉及过滤结果。这是通过使用 `gt`（大于）过滤器结合 `or` 条件来实现的。以下是代码的简化表示：

```php
$search->filter('comments', 'gt', 0, Search::FILTER_AND);
$search->filter('comments', 'lte', 3, Search::FILTER_OR);

```

您可以通过此链接检查我们的代码片段：

[查看代码片段](https://github.com/manticoresoftware/manticore-github-issue-search/blob/539a813a11d210489ab109105703cfc2bec8e598/app/src/lib/Manticore.php#L624-L639)

### 按反应排序

在 GitHub 上进行搜索时，您可能会注意到它不显示或允许按反应进行过滤。然而，有时识别反应最多的问题可能特别有洞察力——例如，评估最受欢迎的功能或预测即将出现的问题。这就是按反应排序变得无价的地方。

首先，我们需要捕获反应数据。GitHub API 方便地以简单的 JSON 对象形式提供了这些数据：

```json
{
  "url": "https://api.github.com/repos/ClickHouse/ClickHouse/issues/35407/reactions",
  "total_count": 0,
  "+1": 0,
  "-1": 0,
  "laugh": 0,
  "hooray": 0,
  "confused": 0,
  "heart": 0,
  "rocket": 0,
  "eyes": 0
}
```

这是个好消息，因为 Manticore Search 提供了 [原生 JSON 支持](https://manual.manticoresearch.com/Creating_a_table/Data_types#JSON)!

接下来，我们必须考虑排序的需求。我们需要按单个 JSON 字段排序还是按多个字段的总和排序？幸运的是，Manticore Search 使我们能够同时做到这两点。它完全符合我们的需求！我们可以直接将 JSON 存储在表中，并使用以下代码片段来启用排序：

```php
$search->expression(
    'positive_reactions',
    'integer(reactions.`+1`) + integer(reactions.hooray) + integer(reactions.heart) + integer(reactions.rocket)'
);

```

有关排序实现的全面视图，请参阅此处的完整代码片段：[Manticore PHP 客户端排序示例](https://github.com/manticoresoftware/manticore-github-issue-search/blob/539a813a11d210489ab109105703cfc2bec8e598/app/src/lib/Manticore.php#L561-L590)

如上所示，我们利用 Manticore PHP 客户端的 `expression` 函数使用 `.` 符号访问 JSON 字段。这种方法消除了缓存计数器或执行额外计算的需要。您可以创建一个 JSON 字段，使用表达式访问它，保持高速，并避免缓存机制的开销！

## 分面搜索

搜索和过滤能力是任何强大搜索功能的基本组成部分。然而，在获取计数的速度方面常常会出现挑战。众所周知，在 MySQL 中实现快速计数操作需要使用索引。这些索引不仅会扩大数据库的大小，还会增加对负载较重的应用程序的复杂性，这些应用程序通常会诉诸于缓存，并随后根据需要调整这些计数。

好消息是，Manticore Search 完全避免了这些问题！使用 Manticore Search，从数据库中检索计数既简单又快速，消除了对额外缓存层的需求。

为了在页面上显示反映所应用过滤器的实时计数，我们使用了与搜索相同的过滤器。不过，我们引入了一个额外的用于分面的查询，仅需几毫秒。这种方法使我们能够几乎没有任何开销地获取指定组的当前计数。下面是一个简洁的PHP代码片段，演示如何实现这一点：

```php
$facets = $search
  ->limit(0) // We're only interested in counts, hence no results needed
  ->filter('repo_id', $repoId) // Filter by repository ID
  ->expression('open', 'if(closed_at=0,1,0)') // Evaluate whether issues are open
  ->facet('open', 'counters', 2) // Get facet counts for open and closed issues
    ->get() // Execute the search query and retrieve the results
  ->getFacets(); // Extract the facets data from the results

```

让我们分解一下：我们将限制设置为零，因为我们的目标是获取计数器，而不是搜索结果。我们通过仓库ID进行过滤，并应用一个表达式按`closed_at`字段进行分组。这种分组为我们提供了开放和关闭问题的计数器。

对于有兴趣了解完整实现的人，完整的代码片段可在GitHub上找到：[Manticore GitHub Issue Search - Manticore.php](https://github.com/manticoresoftware/manticore-github-issue-search/blob/539a813a11d210489ab109105703cfc2bec8e598/app/src/lib/Manticore.php#L292-L319)

借助Manticore Search，高效获取计数的挑战通过几乎开箱即用的解决方案得到了解决。还有什么比这更高效和用户友好的呢？😊

## 结论和进一步计划

在开发我们的演示项目过程中，我们旨在展示Manticore Search的功能和效率。结果不仅满足了我们的预期，还为我们提供了一个增强浏览GitHub仓库方式的工具。通过这一举措，我们能够展示Manticore Search的潜力，并集成了多项改进和功能，以增强GitHub当前提供的功能：

- 我们实现了明显更快的搜索速度，搜索通常在约5-10毫秒内完成，而GitHub的搜索时间超过200毫秒。
- 我们的演示项目允许在搜索结果中包含评论，提供的信息范围比GitHub当前提供的更广。
- 我们引入了根据反应数量对问题进行排序的功能，为用户提供了一个额外的互动维度。
- 提供了高级过滤选项，允许更精确的搜索，例如显示特定评论范围内的问题或仅在评论中进行搜索。

我们鼓励您通过访问：[https://github.manticoresearch.com](https://github.manticoresearch.com/) 探索这些改进。

此外，对于有兴趣查看开源代码或在本地运行该项目的人，可以在此处获取：[https://github.com/manticoresoftware/manticore-github-issue-search](https://github.com/manticoresoftware/manticore-github-issue-search/tree/62b2a3ca166eeed356049e1125e6093739fb4f54)

我们还兴奋地宣布计划将[向量搜索](https://manual.manticoresearch.com/Searching/KNN#KNN-vector-search)（可在Manticore开发包中使用，即将发布）整合到我们的演示中。这一即将推出的特性旨在进一步优化与全文搜索结合时的结果质量，展示如何利用Manticore的新功能来增强搜索功能，敬请期待并[关注我们的Twitter](https://twitter.com/manticoresearch)。

我们欢迎您对Manticore Search功能和能力的这一实际演示提供反馈，并期待与您分享更多更新。期待您的反馈：[issues](https://github.com/manticoresoftware/manticore-github-issue-search/issues)， [discussions](https://github.com/manticoresoftware/manticore-github-issue-search/discussions)。
