Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

แนะนำ Upstash Redis Search: การค้นหาทรงพลังและ Scalable สำหรับข้อมูล Redis ของคุณ

เรากำลัง launch Upstash Redis Search ในอีก 1-2 สัปดาห์ แตผมอยาก share early thoughts บนสิ่งที่เรากำลังสร้าง และทำไมผมตื่นเต้น

ทำไมเราถึงสร้างนี้

เราอยู่ใน search space ตั้งแต่ 2024 เริ่มจาก Upstash Vector Vector อนุญาตให้คน implement semantic search และต่อมาเรา double down เข้าสู่ product space นี้ด้วย Upstash Search

เช่น นี่คือ launch tweet ของเรา 2025 ประกาศ Upstash Search โซลูชัน semantic search แบบ vector-based 👇

แนะนำ Upstash Redis Search: การค้นหาทรงพลังและ Scalable สำหรับข้อมูล Redis ของคุณ

และผมคิดว่าเราทำได้ดีกว่านี้ และ build on learnings จาก Search

เรา pretty unhappy กับ existing search providers ส่วนใหญ่ สำหรับผมส่วนตัว ไม่มีตัวไหน fit เข้ากับ serverless space 好好 มากจนผมสร้าง search app ของตัวเองจาก AWS Cloudsearch ในปี 2023 💀

สิ่งที่เราอยากได้คือ:

  • อยู่ใน Redis เพราะ Redis เร็วมาก
  • ทำงานกับ Upstash Redis SDK
  • 100% type-safe
  • เร็วพอสำหรับ real-time search-as-you-type

ดังนั้นเรากำลังสร้างมัน

Extension แรกของเราเกิน Redis API

นี่เป็น big deal สำหรับเรา จนตอนนี้ @upstash/redis เป็น near 1:1 mapping ของ Redis commands Search เป็น extension แรกของเราเกินนั้น

เราใช้ Tantivy ใต้หลังคา full-text search engine ที่เขียนใน Rust inspired by Apache Lucene มันเร็ว มากจริงๆ และให้ primitives ทั้งหมดที่เราต้องการ เช่น tokenization, stemming, fuzzy matching, phrase queries และ BM25 scoring

เป้าหมายคือทำให้มันรู้สึก native กับ SDK และ Upstash Redis เอง ถ้าคุณใช้ @upstash/redis วันนี้ การเพิ่ม search ควรรู้สึกเหมือน natural extension ไม่ใช่ separate product

Type-safe Schema Builder

หนึ่งอย่างที่ผมพอใจมากคือ schema builder ใหม่ เรา define searchable fields ด้วย zod-like 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() methods ให้เราควบคุมการประมวลผล text:

  • Tokenization แยก text เป็นคำที่ค้นหาได้ ดีสำหรับ natural language แต่ทำลายอย่าง SKUs (SKU-12345-BLK กลายเป็น ["SKU", "12345", "BLK"]) ปิดมันสำหรับ codes, emails และ UUIDs
  • Stemming ลดคำให้เป็น root form ทำให้ "running" match "run" ปิดมันสำหรับ brand names และ proper nouns ที่เราอยาก exact matching

Schema ให้เรา full type inference บน queries ถ้าเราพยายาม query field ที่ไม่มี TypeScript จะจับได้ เราเก็บ schema syntax ใกล้เคียง zod syntax เพื่อให้ familiar

The Query Primitives (Query Primitives)

เรา launch ด้วย 5 operators หลักที่เราคิดว่า cover most search use cases:

$smart สำหรับ smart matching

ด้วย $smart operator เรา apply smart matching อัตโนมัติ Operator นี้ควร just work™ และเป็นวิธีที่ดีที่สุดสำหรับ beginners เริ่มต้น

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

ใต้หลังคา นี่รัน:

  1. Exact phrase match (highest boost) - Documents ที่มี "wireless headphones" ติดกันและลำดับถูกต้อง
  2. Phrase with slop (medium boost) - Documents ที่คำปรากฏตามลำดับแตไม่ติดกัน (เช่น wireless bose headphones)
  3. Terms match (medium boost) - Documents ที่มีทุก terms, ใดๆ order
  4. Fuzzy matching (no boost) - Documents ที่มี typo อย่าง "wireles headphone"
  5. Fuzzy prefix on last word (no boost) - สำหรับ search-as-you-type scenarios

Scores รวมกันเพื่อได้ most relevant results สำหรับ search boxes ส่วนใหญ่ นี่คือ literally ทั้งหมดที่คุณต้องการ 當然 คุณ implement operator นี้เองและเล่นกับ settings ได้ เพราะมัน built on primitive operators ด้านล่าง

$eq สำหรับ exact equality

สำหรับ fields ที่เราอยาก exact matching:

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

$phrase สำหรับ phrase matching

เมื่อเราต้องการคำปรากฏติดกันและลำดับถูกต้อง:

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

เราสามารถเพิ่ม slop ให้อนุญาตคำระหว่างได้:

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

$fuzzy สำหรับ typo tolerance

สำหรับ fuzzy matching ด้วย configurable typo tolerance (เช่น 2 typos):

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

$regex สำหรับ pattern matching

เมื่อเราต้องการ regular expression patterns:

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

สิ่งหนึ่งที่ต้องจด: regex ทำงานดีที่สุดบน fields ที่มี .noStem() เนื่องจาก stemmed text จะไม่ match expected patterns

Boosting Specific Fields (Boosting ฟิลด์เฉพาะ)

เราสามารถ apply boosts เพื่อให้ weight บาง matches สูงกว่า:

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

นี่ทำให้ name matches วार्थสองเท่า description matches 有用เมื่อเราอยาก title matches rank สูงกว่า body matches

What's Next (ต่อไปอะไร)

ทุกอย่างที่ผมใส่ในบทความนี้ยังเปลี่ยนแปลงได้ เรากำลัง polish edges และเขียน docs Official launch ใน 1-2 สัปดาห์

แตผมคิดว่ามันเก๋ที่เราได้ first look ร่วมกัน 👀

几个สิ่งที่เราอาจ explore หลัง launch:

  • Vector search integration (semantic + keyword hybrid search)
  • Autocomplete และ suggestions

ถ้าอยาก early access หรือมีคำถาม ติดต่อ @joshtriedcoding

Thanks for reading 🙌