Redis
 Computer >> コンピューター >  >> プログラミング >> Redis

Upstash Redis Search 登場へ:Redis データを高速かつスケーラブルに検索する新機能

Upstashでは、1〜2週間後に「Upstash Redis Search」をローンチする予定です。本記事では、私たちが何を構築しているのか、そしてなぜこの機能に期待しているのかについて、その先行きを少しだけお披露目したいと思います。

なぜこの機能を作るのか

私たちが検索分野に足を踏み入れたのは2024年のことです。まず「Upstash Vector」によってセマンティック(意味ベース)検索を可能にし、その後さらにこの領域へ注力して「Upstash Search」を展開してきました。

たとえば、これは2025年にUpstash Searchを発表した際のローンチツイートです。Upstash Searchは、ベクトルベースのセマンティック検索ソリューションです👇

Upstash Redis Search 登場へ:Redis データを高速かつスケーラブルに検索する新機能

そして私たちは、これまでのSearchでの学びを活かしながら、さらに先へ進めるだと考えています。

実のところ、既存の検索プロバイダーの多くには不満がありました。個人的な意見として、どれもサーバーレス環境にうまくフィットしないのです。それほど不満があったため、2023年にはAWS CloudSearchをベースに自前の検索アプリを構築したことさえあります💀

私たちが求めていたのは、次のようなものです。

  • Redisの中で動作すること。Redisはとにかく速い
  • Upstash Redis SDKでそのまま使えること
  • 100%型安全であること
  • 入力しながら結果を返すリアルタイム検索(search-as-you-type)に耐えうる速度を持つこと

だから、私たち自身の手で作ることにしました。

Redis APIを超えた初めての拡張

これは私たちにとって大きな一歩です。これまで@upstash/redisは、Redisコマンドとほぼ1対1で対応する設計でした。今回のSearchは、その枠を超えた最初の拡張機能となります。

内部では「Tantivy」という全文検索エンジンを採用しています。TantivyはApache LuceneにインスパイアされたRust製の検索エンジンで、とにかく高速です。トークナイズ、ステミング、ファジーマッチング、フレーズ検索、BM25スコアリングなど、検索に必要なプリミティブがすべて揃っています。

目標は、この機能がSDKやUpstash Redis本体の一部のように自然に感じられることです。現在@upstash/redisを使っている方にとっては、検索の追加が別製品の導入ではなく、ごく自然な拡張として受け取れるはずです。

型安全なスキーマビルダー

個人的に特に気に入っているのが、新しいスキーマビルダーです。zodライクなAPIで、検索対象のフィールドを定義できます。

import { Redis, s } from "@upstash/redis";
 
const redis = Redis.fromEnv();
 
const schema = s.object({
 name: s.string(),
 description: s.string(),
 sku: s.string().noTokenize(),
 brand: s.string().noStem(),
 price: s.number(),
 inStock: s.boolean(),
});
 
const products = await redis.search.createIndex({
 name: "products",
 dataType: "json",
 prefix: "product:",
 schema,
});

.noTokenize().noStem()メソッドを使うことで、テキストの処理方法を細かく制御できます。

  • トークナイズ(Tokenization):テキストを検索可能な単語に分割します。自然言語には最適ですが、SKUのようなコードは壊れてしまいます(SKU-12345-BLK["SKU", "12345", "BLK"]に分割されるなど)。商品コード、メールアドレス、UUIDなどには無効化しましょう。
  • ステミング(Stemming):単語を語根の形に変換し、「running」と「run」が一致するようにします。ブランド名や固有名詞など、完全一致させたい場合には無効化するのがおすすめです。

スキーマを定義しておけば、クエリに対して完全な型推論が効きます。存在しないフィールドをクエリしようとすれば、TypeScriptがエラーを検出してくれます。スキーマの構文はzodに寄せているので、違和感なく使い始められるはずです。

クエリのプリミティブ

ローンチ時点では、ほとんどの検索ユースケースをカバーできる5つの主要オペレーターを提供します。

$smart — スマートマッチング

$smartオペレーターを使うと、スマートマッチングが自動的に適用されます。「とりあえずこれを使っておけば動く™」を目指した、初心者にとっての最良の入り口となるオペレーターです。

await products.query({
 filter: {
 name: { $smart: "wirless headphones" },
 },
});

内部では、以下のような処理が順に行われます。

  1. 完全なフレーズ一致(最も高いブースト)—— 「wireless headphones」が隣接しかつ順序通り含まれるドキュメント
  2. slop付きフレーズ一致(中程度のブースト)—— 単語が順序通り出現するが隣接していないドキュメント(例:wireless bose headphones)
  3. ターム一致(中程度のブースト)—— すべての単語を含むドキュメント(順序は問わない)
  4. ファジーマッチング(ブーストなし)—— 「wireles headphone」のようなタイポを含むドキュメント
  5. 最後の単語へのファジー前方一致(ブーストなし)—— 入力補完型の検索シナリオ向け

これらのスコアが組み合わさり、最も関連性の高い結果が返されます。多くの検索ボックスなら、実はこれだけで十分です。もちろん、このオペレーターは後述のプリミティブなオペレーターの組み合わせでできているので、自分で実装して設定を調整することも可能です。

$eq — 完全一致

完全一致させたいフィールドにはこちらを使います。

await products.query({
 filter: {
 name: { $eq: "wireless headphones" },
 price: { $eq: 200 },
 },
});

$phrase — フレーズ一致

単語が隣接し、かつ順序どおりに出現する必要がある場合に使います。

await products.query({
 filter: { description: { $phrase: "noise cancelling" } },
});

slopを指定すると、単語の間に他の単語が挟まることを許容できます。

await products.query({
 filter: {
 description: {
 $phrase: { value: "wireless headphones", slop: 2 },
 },
 },
});

$fuzzy — タイプミスへの許容

タイプミスの許容度を設定できるファジーマッチングです(例:2文字までの誤りを許容)。

await products.query({
 filter: { name: { $fuzzy: "headphonse", distance: 2 } },
});

$regex — 正規表現パターンマッチング

正規表現パターンが必要なケースに対応します。

await products.query({
 filter: { sku: { $regex: "SKU-[0-9]{5}-.*" } },
});

注意点として、正規表現は.noStem()を指定したフィールドで最も効果を発揮します。ステミング済みのテキストは期待通りのパターンに一致しないことがあるためです。

特定フィールドへのブースト

ブーストを適用することで、特定のフィールドでの一致を優先的に評価できます。

await products.query({
 filter: {
 $and: [
 { name: { $smart: "wireless", $boost: 2 } },
 { description: { $smart: "wireless" } },
 ],
 },
});

この例では、nameフィールドでの一致がdescriptionフィールドでの一致の2倍の重みを持ちます。タイトルでの一致を本文での一致より上位にランク付けしたい場合などに便利です。

今後の展望

本記事で紹介した内容は、まだ変更される可能性があります。現在は仕上げの調整とドキュメント執筆を進めており、正式リリースは1〜2週間後の予定です。

とはいえ、こうして皆さんと一緒に最初の一歩を覗けるのは本当に嬉しいことです👀

リリース後に検討したいテーマはいくつかあります。

  • ベクトル検索との統合(セマンティック+キーワードのハイブリッド検索)
  • オートコンプリートとサジェスト機能

早期アクセスをご希望の方や質問がある方は、@joshtriedcoding までご連絡ください。

ここまでお読みいただきありがとうございました🙌

  1. Upstash・Redis・QStashで実現するリアルタイム緊急対応システムの構築

    本記事では、Upstashを活用して国の避難所マップに関する情報をRedisで安全に保存・アクセスする方法と、QStashを使ってデータベースをリアルタイムに更新する方法について解説します。 はじめに 今日の世界では、自然災害や軍事的な脅威がますます深刻化しており、それに伴い社会サービス分野におけるデジタル化のニーズも高まっています。 AMBERアラートのような緊急放送システムから、COVID-19の追跡アプリ、SOSシステムまで、国に影響を及ぼすあらゆる危機的状況に対して、幅広いテクノロジーが活用されてきました。 本記事では、Redisとサーバーレスワークロードがどのようにリアルタイム緊急対

  2. Vercel EdgeとUpstash RedisでNext.jsにレート制限を実装する方法

    Vercel Edge Middlewareと@upstash/ratelimitライブラリを活用して、Webアプリケーションにレート制限(レートリミット)を実装する方法を解説します。@upstash/ratelimitは、バックエンドでRedisを使用してレート制限データの保存・管理を行うライブラリです。 Vercel Edgeを使うメリット Vercel Edgeは、ユーザーに最も近いロケーションで計算処理を実行するコンピューティングプラットフォームです。本記事では、リクエストがバックエンドに到達する前に処理を割り込ませるVercel Edge Middlewareを使用します。レート制限