如何用CockroachDB和Elasticsearch进行全文搜索

294 阅读4分钟

全文索引和搜索是如今应用程序的一个常见功能。用户希望能够通过在用户界面上输入一些搜索词,快速找到一家餐馆、一个产品、一篇电影评论或其他任何东西。许多这样的应用程序都是使用关系型数据库作为数据存储的,所以这些应用程序一般不是专门用于搜索的,而是将其作为一个附加功能。

对于[使用CockroachDB的开发者]来说,全文搜索选项确实还不存在于数据库本身。尽管[CockroachDB确实支持Levenshtein和Soundex],而且这些可以以新的方式结合起来,支持较短的数据元素的模糊匹配,但建立全文搜索的努力才刚刚开始。

说到这里,[CockroachDB确实支持changefeeds],或者叫Change Data Capture(CDC)。Changefeeds允许你根据DB中表的变化来配置事件流,这些事件可以被发送到消息队列(如Kafka)、S3桶,甚至是HTTP(S)端点。一旦配置好,任何INSERT、UPDATE、DELETE都会产生一个事件,可以由另一个进程来执行。这个进程甚至可以是[Elasticsearch]这样的东西,它将提供全文索引和搜索能力。

这个例子的目的是为了说明CockroachDB与Elasticsearch的整合模式,所以它被简化为只有一个表,而这个表是面向存储取自URL的数据。在现实世界中,我们可能会有多个具有外键关系的表。

解决方案技术栈概述

我选择在谷歌云平台上部署的虚拟机中运行,在us-central1地区,因为CockroachDB无服务器在该地区可用。在目前可用于[CREATE CHANGEFEED]的各种类型的终端中,没有一个能直接与Elasticsearch期望的输入相一致,所以我需要创建一个[Python Flask应用],作为CockroachDB和Elasticsearch之间的适配器。我还决定在虚拟机上直接运行Elasticsearch实例。由于加密所有这些通信似乎是一个好主意,我运行了一个[Nginx]实例,作为Flask应用和Elasticsearch的代理。[Let's Encrypt]负责处理SSL证书。我使用[Google Domains]做DNS,这样我的Let's Encrypt设置就能正常工作。最后,我把这个虚拟机作为一个 "大本营",在那里运行[HTML索引器]。

设置。基础设施

  • Ubuntu 22.04 LTS运行在e2-standard-2 VM上,配有64GB SSD。
  • 网络,子网是default ,其中443端口为HTTPS流量开放。
  • 在虚拟机上。sudo apt update然后sudo apt install postgresql-client
  • 使用默认配置启动ES,并记录下 "弹性用户的密码 "以备后用。
  • 将GitHub repo的内容转移到虚拟机上(例如:git clone https://github.com/mgoddard/crdb-cdc-elastic.git )。
  • 安装了pip。sudo apt install python3-pip
  • 安装了Python依赖项。sudo pip3 install -r requirements.txt
  • 安装了Nginx。sudo apt install -y nginx
  • 在DNS中为虚拟机设置一个 "A "记录,使用其外部IP地址(在我的例子中,它被解析为 "cdc.la-cucaracha.net")。
  • 按照这个程序,为我的Nginx安装获得Let's Encrypt SSL证书。
  • 这个文件的编辑版本替换生成的/etc/nginx/nginx.conf ,然后重新启动Nginx
  • 通过这个用户界面在与虚拟机相同的区域设置了一个CockroachDB无服务器实例。
  • 创建一个CockroachDB用户,并使用同一用户界面获取证书。我将其存储在一个文件中,CC_cred.txt
  • 按照Serverless用户界面上的 "Download CA Cert (Required only once) "指示下载了CA证书。
  • 创建了一个名为defaultdb 的Elasticsearch索引(CockroachDB数据库映射到Elasticsearch索引)。
$ export ES_PASSWD="that password recorded earlier"
$ curl -XPUT -s -k -u elastic:$ES_PASSWD https://localhost:9200/defaultdb | jq
  • 启动了Flask CDC端点。
$ export ES_PASSWD="that password recorded earlier"
$ nohup ./cdc_http.py > cdc.log 2>&1 

设置:蟑螂数据库

登录 CockroachDB 无服务器实例(我习惯使用 psql CLI):

$ psql $( cat ./CC_cred.txt )
psql (14.4 (Ubuntu 14.4-0ubuntu0.22.04.1), server 13.0.0)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_128_GCM_SHA256, bits: 128, compression: off)
Type "help" for help

创建简单表以存储在 Web 上找到的文档:

defaultdb=> CREATE TABLE docs
(
  uri STRING PRIMARY KEY
  , content STRING NOT NULL
  , ts TIMESTAMP DEFAULT NOW()
);
CREATE TABLE

启用范围源(这可能已在无服务器中设置):

defaultdb=> SET CLUSTER SETTING kv.rangefeed.enabled = true;
SET CLUSTER SETTING

将 HTTP 更改源创建到 Python Flask 端点:

defaultdb=> CREATE CHANGEFEED FOR TABLE docs
INTO 'https://cdc.la-cucaracha.net/cdc/'
WITH full_table_name, updated;
       job_id
--------------------
 777046877208477698
(1 row)

将 Elasticsearch 与 CockroachDB 结合使用

我正在从 VM 运行以下内容。

  • 为 HTML 索引器安装额外的依赖项:sudo pip3 install beautifulsoup4
  • 为数据库连接设置环境变量:export DB_CONN_STR=$( cat ../CC_cred.txt )
  • 索引一些网址:
$ ./html_indexer.py https://www.cockroachlabs.com/blog/admission-control-in-cockroachdb/ https://www.cockroachlabs.com/blog/how-to-choose-db-index-keys/ https://www.cockroachlabs.com/docs/v21.1/example-apps.html https://www.cockroachlabs.com/docs/v22.1/multiregion-overview.html https://www.cockroachlabs.com/blog/can-i-scale/ https://www.cockroachlabs.com/blog/sigmod-2022-cockroachdb-multi-region-paper/ https://www.cockroachlabs.com/blog/living-without-atomic-clocks/ https://github.com/cockroachdb/pebble https://www.cockroachlabs.com/blog/netflix-media-infrastructure/ https://www.cockroachlabs.com/blog/full-text-indexing-search/
Indexing uri https://www.cockroachlabs.com/blog/admission-control-in-cockroachdb/ now ...
Indexing uri https://www.cockroachlabs.com/blog/how-to-choose-db-index-keys/ now ...
Indexing uri https://www.cockroachlabs.com/docs/v21.1/example-apps.html now ...
Indexing uri https://www.cockroachlabs.com/docs/v22.1/multiregion-overview.html now ...
Indexing uri https://www.cockroachlabs.com/blog/can-i-scale/ now ...
Indexing uri https://www.cockroachlabs.com/blog/sigmod-2022-cockroachdb-multi-region-paper/ now ...
Indexing uri https://www.cockroachlabs.com/blog/living-without-atomic-clocks/ now ...
Indexing uri https://github.com/cockroachdb/pebble now ...
Indexing uri https://www.cockroachlabs.com/blog/netflix-media-infrastructure/ now ...
Indexing uri https://www.cockroachlabs.com/blog/full-text-indexing-search/ now ...
Total time: 5.30757999420166 s
  • 返回 SQL CLI,检查它们是否已插入:
defaultdb=> select uri, length(content), ts from docs order by 2 desc;
                                      uri                                       | length |             ts
--------------------------------------------------------------------------------+--------+----------------------------
 https://www.cockroachlabs.com/blog/admission-control-in-cockroachdb/           |  24985 | 2022-07-07 15:33:32.685422
 https://www.cockroachlabs.com/docs/v22.1/multiregion-overview.html             |  21300 | 2022-07-07 15:33:33.672853
 https://www.cockroachlabs.com/blog/living-without-atomic-clocks/               |  20184 | 2022-07-07 15:33:35.000319
 https://www.cockroachlabs.com/blog/how-to-choose-db-index-keys/                |  16958 | 2022-07-07 15:33:32.970703
 https://www.cockroachlabs.com/blog/can-i-scale/                                |  14654 | 2022-07-07 15:33:34.196958
 https://www.cockroachlabs.com/blog/full-text-indexing-search/                  |  13387 | 2022-07-07 15:33:36.789336
 https://www.cockroachlabs.com/blog/netflix-media-infrastructure/               |  12859 | 2022-07-07 15:33:36.247931
 https://github.com/cockroachdb/pebble                                          |  12504 | 2022-07-07 15:33:35.708953
 https://www.cockroachlabs.com/blog/sigmod-2022-cockroachdb-multi-region-paper/ |   9454 | 2022-07-07 15:33:34.70964
 https://www.cockroachlabs.com/docs/v21.1/example-apps.html                     |   9373 | 2022-07-07 15:33:33.307314
(10 rows)
  • 尝试 ES 搜索: 搜索脚本根据通过命令行参数提供给它的术语运行“短语查询”。如果有任何搜索命中,则返回的值包括有关搜索的元数据以及表中字段的值,以及最多四个突出显示的匹配片段,长度不超过 80 个字符。请随意调整脚本以满足您的需求。
$ export ES_PASSWD="ad7yMq3nrg+2bGz-QWe*"
$ ./es_search.py database region
{
  "_shards": {
    "failed": 0,
    "skipped": 0,
    "successful": 1,
    "total": 1
  },
  "hits": {
    "hits": [
      {
        "_id": "public-docs-https://www.cockroachlabs.com/docs/v22.1/multiregionoverview.html",
        "_ignored": [
          "content.keyword"
        ],
        "_index": "defaultdb",
        "_score": 1.8865218,
        "highlight": {
          "content": [
            "<em>Database</em> <em>region</em> is a geographic region in which a database operates.",
            "You must choose a <em>database</em> <em>region</em> from the list of available cluster regions.",
            "To add another <em>database</em> <em>region</em>, use the ALTER DATABASE ...",
            "Each <em>database</em> <em>region</em> can only belong to one super region."
          ]
        }
      }
    ],
    "max_score": 1.8865218,
    "total": {
      "relation": "eq",
      "value": 1
    }
  },
  "timed_out": false,
  "took": 16
}
  • 删除数据库中的此行:
defaultdb=> delete from docs where uri = 'https://www.cockroachlabs.com/docs/v22.1/multiregion-overview.html';
DELETE 1
  • 再次尝试该 ES 搜索:
$ ./es_search.py database region
{
  "_shards": {
    "failed": 0,
    "skipped": 0,
    "successful": 1,
    "total": 1
  },
  "hits": {
    "hits": [],
    "max_score": null,
    "total": {
      "relation": "eq",
      "value": 0
    }
  },
  "timed_out": false,
  "took": 4
}

正如预期的那样,搜索没有返回任何结果。

结论

CDC从CockroachDB到Elasticsearch的小旅程到此结束。回顾上面提到的那篇原始博客文章,我有点漫不经心地说你可以使用 CDC 来搜索 Elasticsearch,所以现在我感觉好多了。自从我在Lucene,Solr或Elasticsearch上做了很多工作以来已经有一段时间了,而且它一直在变化,所以很可能我在这里的例子是非常基本的。无论如何,我希望它能激励您在需要时探索这种类型的集成。

感谢您抽出宝贵时间阅读本文!