Problem
Your system needs to help users find the data they want. For example, a movie website allows users to search for movies by name, author, actor, etc.
The first thing that comes to mind is using SQL's LIKE. It is a good and fast approach to problem solving. But overall it's not really good. We want more than that. Such as full-text search support, search query suggestions, etc., it is time to implement a search engine system.
There are many famous engine support: ElasticSearch, Solr, ... And there's a new guy who's also quite strong.
That is RedisSearch. even though it just appeared recently but he is good choice to consider by those things:
- simple syntax, easy to approach.
- does not require a heavy infrastructure to maintain (like ElasticSearch for example)
- the search speed is quite fast
- especially if you are using Redis for other features like Cache, Queue, ... Then implementing more search using Redis is great
Let's start exploring RedisSearch
RedisSearch ?
For ease of understanding, RedisSearch is an extension module of Redis. It's support full-text search, suggest keywords, so on.
Flow implement RedisSearch
Above is simple schema of RedisSearch integration. There are a few points to note:
- It is related to the fields you need to search in the future. As the name of the video, actors,...
- Need to build pusher and querier:
pusher: supports pushing data from the current database to Redis.
querier: current API support that interacts with RedisSearch
Practice
For example, there is a movie website. And need to integrate the search feature.
-
Setup RedisSearch
For quickly, we will use docker to build environmentdocker run -p 6377:6379 redislabs/redisearch:latest
-
Create index document
// createIndexDocument.ts const createVideoIndexDocument = async () => { const redis = await useRedisClient(); await redis.ft.create(movieIndex, { name: { type: SchemaFieldTypes.TEXT, SORTABLE: true, }, description: { type: SchemaFieldTypes.TEXT, SORTABLE: true, }, duration: { type: SchemaFieldTypes.NUMERIC, SORTABLE: true, }, }); }; createVideoIndexDocument();
ts-node createIndexDocument.ts # the script will generate video index document
-
Import sample data
To make your life easier, I have created a json file which contains over 300 movies[ { "name": "[Star Talk] Which Penang hill is a must visit for Singapore leading male idol Li Nanxing?", "description": "[star talk] which penang hill is a must visit for singapore leading male idol li nanxing?", "duration": 716 }, { "name": "[Lu Lu Land] Jackson Wang Sends JJ Lin Birthday Greetings for His Birthday", "description": "[lu lu land] jackson wang sends jj lin birthday greetings for his birthday", "duration": 983 }, { "name": "[Test Me If You Can] Great Gadgets for Mopping and Sweeping! | EP 2/8", "description": "[test me if you can] great gadgets for mopping and sweeping! | ep 2/8", "duration": 202 }, { "name": "[Ah Boys No Limit] Challenge starts! Team PVP mode on! | EP 41/45", "description": "[ah boys no limit] challenge starts! team pvp mode on! | ep 41/45", "duration": 296 }, { "name": "[Ah Boys No Limit] ABNL Cheerleading captain is here! The prophecy of Hafiz came true? | EP 42/45", "description": "[ah boys no limit] abnl cheerleading captain is here! the prophecy of hafiz came true? | ep 42/45", "duration": 676 }, ... ]
Run the script to import above info info into Redis
// pusher.ts import { createClient } from "redis"; import fs from "fs"; import path from "path"; const videos = JSON.parse( fs.readFileSync(path.resolve(__dirname, "./data/videos.json"), "utf-8") ); const importMoviesData = async function () { const client = createClient({ url: "redis://localhost:6380", }); console.info("connecting redis"); await client.connect(); console.info("inserted item"); let idx = 0; for (const item of videos) { await client.hSet("video:" + idx, item); idx++; } }; importMoviesData();
ts-node pusher.ts
-
Implement RedisSearch
// search.ts const fullTextSearch = async function () { const client = await redisClient(); const readline = rl.createInterface({ input: process.stdin, output: process.stdout, }); while (true) { const obtainAnswerResult = () => { return new Promise((res) => { readline.question("input your text: ", (t) => { res(t); }); }); }; const text = await obtainAnswerResult(); console.info("searching for", text); const rs = await client.ft.search(movieIndex, `*${text}*`); console.info(rs.documents); } }; fullTextSearch();
ts-node search.ts
Result
Advanced Features
There are still many features on RedisSearch. You can explore here
Thank for reading the post.