Skip to content

Commit 4a1e540

Browse files
committed
first iteration
1 parent 9b818de commit 4a1e540

File tree

16 files changed

+5264
-0
lines changed

16 files changed

+5264
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
dist/
6+
cdk.out/
7+
*.js
8+
*.d.ts
9+
10+
# Keep TypeScript source
11+
!jest.config.js
12+
13+
# IDE
14+
.idea/
15+
.vscode/
16+
*.swp
17+
*.swo
18+
19+
# OS
20+
.DS_Store
21+
Thumbs.db
22+
23+
# Logs
24+
*.log
25+
npm-debug.log*
26+
27+
# Local env
28+
.env
29+
.env.local
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
.PHONY: install deploy init seed destroy clean help web-ui test-search get-api-url
2+
3+
help:
4+
@echo "ParadeDB Movie Search Sample App"
5+
@echo ""
6+
@echo "Usage:"
7+
@echo " make install - Install all dependencies"
8+
@echo " make deploy - Deploy CDK stack to LocalStack"
9+
@echo " make init - Initialize database schema and BM25 index"
10+
@echo " make seed - Load movie data from S3 into ParadeDB"
11+
@echo " make web-ui - Run the Web UI on localhost port 3000"
12+
@echo " make destroy - Tear down the stack"
13+
@echo " make clean - Remove build artifacts"
14+
@echo ""
15+
@echo "Quick start:"
16+
@echo " make install && make deploy && make init && make seed && make web-ui"
17+
18+
install:
19+
@echo "Installing CDK dependencies..."
20+
npm install
21+
@echo "Installing Lambda dependencies..."
22+
cd lambda && npm install
23+
@echo "Done!"
24+
25+
deploy:
26+
@echo "Deploying MovieSearchStack to LocalStack..."
27+
cdklocal bootstrap
28+
cdklocal deploy --require-approval never
29+
@echo ""
30+
@echo "Deployment complete!"
31+
32+
init:
33+
@echo "Initializing database schema and BM25 index..."
34+
@API_URL=$$(awslocal cloudformation describe-stacks \
35+
--stack-name MovieSearchStack \
36+
--query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
37+
--output text 2>/dev/null); \
38+
if [ -z "$$API_URL" ]; then \
39+
echo "Error: Stack not deployed. Run 'make deploy' first."; \
40+
exit 1; \
41+
fi; \
42+
curl -s -X POST "$${API_URL}admin/init" | jq .
43+
@echo "Database initialized!"
44+
45+
seed:
46+
@echo "Seeding movie data from S3..."
47+
@API_URL=$$(awslocal cloudformation describe-stacks \
48+
--stack-name MovieSearchStack \
49+
--query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
50+
--output text 2>/dev/null); \
51+
if [ -z "$$API_URL" ]; then \
52+
echo "Error: Stack not deployed. Run 'make deploy' first."; \
53+
exit 1; \
54+
fi; \
55+
curl -s -X POST "$${API_URL}admin/seed" | jq .
56+
@echo "Data seeded!"
57+
58+
test-search:
59+
@echo "Testing search endpoint..."
60+
@API_URL=$$(awslocal cloudformation describe-stacks \
61+
--stack-name MovieSearchStack \
62+
--query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
63+
--output text 2>/dev/null); \
64+
if [ -z "$$API_URL" ]; then \
65+
echo "Error: Stack not deployed. Run 'make deploy' first."; \
66+
exit 1; \
67+
fi; \
68+
echo "Searching for 'redemption'..."; \
69+
curl -s "$${API_URL}search?q=redemption" | jq .
70+
71+
destroy:
72+
@echo "Destroying MovieSearchStack..."
73+
cdklocal destroy --force
74+
@echo "Stack destroyed!"
75+
76+
clean:
77+
rm -rf node_modules lambda/node_modules cdk.out dist
78+
@echo "Cleaned!"
79+
80+
get-api-url:
81+
@awslocal cloudformation describe-stacks \
82+
--stack-name MovieSearchStack \
83+
--query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
84+
--output text
85+
86+
web-ui:
87+
@echo "Starting Movie Search Web UI..."
88+
@echo "API endpoint: http://movie-search-api.execute-api.localhost.localstack.cloud:4566/dev"
89+
@echo ""
90+
@which serve > /dev/null 2>&1 || (echo "Installing serve..." && npm i -g serve)
91+
serve -s ./web -l 3000
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# ParadeDB Movie Search Sample App
2+
3+
A CDK application demonstrating ParadeDB's full-text search capabilities with LocalStack.
4+
5+
## Overview
6+
7+
This sample app deploys a serverless movie search application using:
8+
9+
- **AWS Lambda** - Handles search and data operations
10+
- **Amazon API Gateway** - REST API endpoints
11+
- **Amazon S3** - Stores movie dataset
12+
- **ParadeDB** - Full-text search engine (runs as LocalStack extension)
13+
14+
### Features Demonstrated
15+
16+
| Feature | Description |
17+
|---------|-------------|
18+
| **BM25 Ranking** | Industry-standard relevance scoring |
19+
| **Fuzzy Matching** | Handles typos (e.g., "Godfater" finds "Godfather") |
20+
| **Highlighting** | Returns matched text with highlighted terms |
21+
22+
### API Endpoints
23+
24+
| Method | Endpoint | Description |
25+
|--------|----------|-------------|
26+
| GET | `/search?q=<query>` | Search movies with BM25 ranking |
27+
| GET | `/movies/{id}` | Get movie details by ID |
28+
| POST | `/admin/init` | Initialize database schema |
29+
| POST | `/admin/seed` | Load movie data from S3 |
30+
31+
## Prerequisites
32+
33+
- [LocalStack](https://localstack.cloud/) installed and running
34+
- [Node.js](https://nodejs.org/) 18+ installed
35+
- [AWS CDK Local](https://github.com/localstack/aws-cdk-local) (`npm install -g aws-cdk-local`)
36+
- [AWS CLI](https://aws.amazon.com/cli/) configured
37+
- ParadeDB extension installed in LocalStack
38+
39+
## Setup
40+
41+
### 1. Start LocalStack with ParadeDB Extension
42+
43+
```bash
44+
# Install the ParadeDB extension
45+
localstack extensions install localstack-extension-paradedb
46+
47+
# Start LocalStack
48+
localstack start
49+
```
50+
51+
### 2. Install Dependencies
52+
53+
```bash
54+
cd paradedb/sample-movie-search
55+
make install
56+
```
57+
58+
Or manually:
59+
60+
```bash
61+
npm install
62+
cd lambda && npm install
63+
```
64+
65+
### 3. Deploy the Stack
66+
67+
```bash
68+
make deploy
69+
```
70+
71+
Or manually:
72+
73+
```bash
74+
cdklocal bootstrap
75+
cdklocal deploy
76+
```
77+
78+
After deployment, you'll see output similar to:
79+
80+
```
81+
Outputs:
82+
MovieSearchStack.ApiEndpoint = https://movie-search-api.execute-api.localhost.localstack.cloud:4566/dev/
83+
MovieSearchStack.DataBucketName = movie-search-data
84+
MovieSearchStack.InitEndpoint = https://movie-search-api.execute-api.localhost.localstack.cloud:4566/dev/admin/init
85+
MovieSearchStack.MovieSearchApiEndpointB25066EC = https://movie-search-api.execute-api.localhost.localstack.cloud:4566/dev/
86+
MovieSearchStack.MoviesEndpoint = https://movie-search-api.execute-api.localhost.localstack.cloud:4566/dev/movies/{id}
87+
MovieSearchStack.SearchEndpoint = https://movie-search-api.execute-api.localhost.localstack.cloud:4566/dev/search
88+
MovieSearchStack.SeedEndpoint = https://movie-search-api.execute-api.localhost.localstack.cloud:4566/dev/admin/seed
89+
```
90+
91+
### 4. Initialize Database
92+
93+
Create the movies table and BM25 search index:
94+
95+
```bash
96+
make init
97+
```
98+
99+
### 5. Seed Data
100+
101+
Load movie data from S3 into ParadeDB:
102+
103+
```bash
104+
make seed
105+
```
106+
107+
## Usage
108+
109+
### Search Movies
110+
111+
```bash
112+
# Basic search
113+
curl "https://<api-id>.execute-api.localhost.localstack.cloud:4566/dev/search?q=redemption"
114+
115+
# With pagination
116+
curl "https://<api-id>.execute-api.localhost.localstack.cloud:4566/dev/search?q=dark%20knight&limit=5&offset=0"
117+
118+
# Fuzzy search (handles typos)
119+
curl "https://<api-id>.execute-api.localhost.localstack.cloud:4566/dev/search?q=godfater"
120+
```
121+
122+
### Get Movie Details
123+
124+
```bash
125+
curl "https://<api-id>.execute-api.localhost.localstack.cloud:4566/dev/movies/tt0111161"
126+
```
127+
128+
### Example Response
129+
130+
```json
131+
{
132+
"success": true,
133+
"data": {
134+
"results": [
135+
{
136+
"id": "tt0111161",
137+
"title": "The Shawshank Redemption",
138+
"year": 1994,
139+
"genres": ["Drama"],
140+
"rating": 9.3,
141+
"directors": ["Frank Darabont"],
142+
"actors": ["Tim Robbins", "Morgan Freeman", "Bob Gunton"],
143+
"highlight": "...finding solace and eventual <mark>redemption</mark> through acts of common decency."
144+
}
145+
],
146+
"total": 1,
147+
"limit": 10,
148+
"offset": 0
149+
}
150+
}
151+
```
152+
153+
## Web UI
154+
155+
A minimal web UI is included in the `web/` directory. To use it:
156+
157+
1. Open `web/index.html` in a browser
158+
2. Set the API URL by opening the browser console and running:
159+
160+
```javascript
161+
setApiUrl('https://<api-id>.execute-api.localhost.localstack.cloud:4566/dev')
162+
```
163+
164+
3. Start searching!
165+
166+
## How It Works
167+
168+
1. **Deployment**: CDK creates Lambda functions, API Gateway, and S3 bucket with movie data
169+
170+
2. **Initialization**: The init Lambda creates the movies table and ParadeDB BM25 index:
171+
```sql
172+
CALL paradedb.create_bm25(
173+
index_name => 'movies_search_idx',
174+
table_name => 'movies',
175+
key_field => 'id',
176+
text_fields => paradedb.field('title') || paradedb.field('plot')
177+
);
178+
```
179+
180+
3. **Data Loading**: The seed Lambda reads `movies.json` from S3 and inserts into ParadeDB
181+
182+
4. **Search**: Queries use ParadeDB's BM25 search with fuzzy matching:
183+
```sql
184+
SELECT *, paradedb.snippet(plot) as highlight
185+
FROM movies
186+
WHERE id @@@ paradedb.parse('title:query~1 OR plot:query~1')
187+
ORDER BY paradedb.score(id) DESC
188+
```
189+
190+
## References
191+
192+
- [ParadeDB Documentation](https://docs.paradedb.com/)
193+
- [LocalStack Extensions](https://docs.localstack.cloud/aws/tooling/extensions/)
194+
- [AWS CDK Local](https://github.com/localstack/aws-cdk-local)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env node
2+
import "source-map-support/register";
3+
import * as cdk from "aws-cdk-lib";
4+
import { MovieSearchStack } from "../lib/movie-search-stack";
5+
6+
const app = new cdk.App();
7+
new MovieSearchStack(app, "MovieSearchStack", {});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"app": "npx ts-node --prefer-ts-exts bin/app.ts",
3+
"watch": {
4+
"include": ["**"],
5+
"exclude": [
6+
"README.md",
7+
"cdk*.json",
8+
"**/*.d.ts",
9+
"**/*.js",
10+
"tsconfig.json",
11+
"package*.json",
12+
"node_modules",
13+
"lambda/node_modules"
14+
]
15+
},
16+
"context": {
17+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
18+
"@aws-cdk/core:checkSecretUsage": true,
19+
"@aws-cdk/core:target-partitions": ["aws", "aws-cn"]
20+
}
21+
}

0 commit comments

Comments
 (0)