337 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			337 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# 🔍 Meilisearch Setup Guide
 | 
						|
 | 
						|
Complete guide for testing and using the Meilisearch integration in ObsiViewer.
 | 
						|
 | 
						|
## Quick Start (5 minutes)
 | 
						|
 | 
						|
### 1. Start Meilisearch
 | 
						|
 | 
						|
```bash
 | 
						|
npm run meili:up
 | 
						|
```
 | 
						|
 | 
						|
This launches Meilisearch in Docker on port 7700.
 | 
						|
 | 
						|
### 2. Index Your Vault
 | 
						|
 | 
						|
```bash
 | 
						|
npm run meili:reindex
 | 
						|
```
 | 
						|
 | 
						|
This indexes all `.md` files from your vault. Progress will be logged to console.
 | 
						|
 | 
						|
### 3. Test the API
 | 
						|
 | 
						|
```bash
 | 
						|
# Simple search
 | 
						|
curl "http://localhost:4000/api/search?q=obsidian"
 | 
						|
 | 
						|
# With operators
 | 
						|
curl "http://localhost:4000/api/search?q=tag:work path:Projects"
 | 
						|
 | 
						|
# All notes
 | 
						|
curl "http://localhost:4000/api/search?q=*&limit=5"
 | 
						|
```
 | 
						|
 | 
						|
### 4. Enable in Angular (Optional)
 | 
						|
 | 
						|
Edit `src/core/logging/environment.ts`:
 | 
						|
 | 
						|
```typescript
 | 
						|
export const environment = {
 | 
						|
  USE_MEILI: true,  // ← Change this to true
 | 
						|
  // ...
 | 
						|
};
 | 
						|
```
 | 
						|
 | 
						|
Then restart your Angular dev server: `npm run dev`
 | 
						|
 | 
						|
## Testing Checklist
 | 
						|
 | 
						|
### ✅ Backend Tests
 | 
						|
 | 
						|
- [ ] **Docker started**: `docker ps` shows `obsiviewer-meilisearch` running
 | 
						|
- [ ] **Indexing works**: `npm run meili:reindex` completes without errors
 | 
						|
- [ ] **Basic search**: `curl "http://localhost:4000/api/search?q=*"` returns hits
 | 
						|
- [ ] **Tag filter**: `curl "http://localhost:4000/api/search?q=tag:yourTag"` works
 | 
						|
- [ ] **Path filter**: `curl "http://localhost:4000/api/search?q=path:YourFolder"` works
 | 
						|
- [ ] **File filter**: `curl "http://localhost:4000/api/search?q=file:readme"` works
 | 
						|
- [ ] **Highlights**: Response includes `_formatted` with `<mark>` tags
 | 
						|
- [ ] **Facets**: Response includes `facetDistribution` with tags, parentDirs
 | 
						|
- [ ] **Performance**: `npm run bench:search` shows P95 < 150ms
 | 
						|
 | 
						|
### ✅ Incremental Updates
 | 
						|
 | 
						|
Test that Chokidar automatically updates Meilisearch:
 | 
						|
 | 
						|
1. Start server: `node server/index.mjs`
 | 
						|
2. Create a new `.md` file in vault with tag `#test-meilisearch`
 | 
						|
3. Search: `curl "http://localhost:4000/api/search?q=tag:test-meilisearch"`
 | 
						|
4. Verify the new file appears in results
 | 
						|
5. Edit the file, search again - changes should be reflected
 | 
						|
6. Delete the file, search again - should no longer appear
 | 
						|
 | 
						|
### ✅ Angular Integration
 | 
						|
 | 
						|
With `USE_MEILI: true`:
 | 
						|
 | 
						|
1. Open app in browser: `http://localhost:4200`
 | 
						|
2. Use search bar
 | 
						|
3. Open browser DevTools Network tab
 | 
						|
4. Verify requests go to `/api/search` instead of local search
 | 
						|
5. Results should show server-side highlights
 | 
						|
 | 
						|
## Query Examples
 | 
						|
 | 
						|
### Basic Searches
 | 
						|
 | 
						|
```bash
 | 
						|
# Find all notes
 | 
						|
curl "http://localhost:4000/api/search?q=*"
 | 
						|
 | 
						|
# Simple text search
 | 
						|
curl "http://localhost:4000/api/search?q=obsidian"
 | 
						|
 | 
						|
# Phrase search
 | 
						|
curl "http://localhost:4000/api/search?q=search%20engine"
 | 
						|
```
 | 
						|
 | 
						|
### Operators
 | 
						|
 | 
						|
```bash
 | 
						|
# Single tag
 | 
						|
curl "http://localhost:4000/api/search?q=tag:dev"
 | 
						|
 | 
						|
# Multiple tags (both must match)
 | 
						|
curl "http://localhost:4000/api/search?q=tag:dev tag:angular"
 | 
						|
 | 
						|
# Path filter
 | 
						|
curl "http://localhost:4000/api/search?q=path:Projects/Angular"
 | 
						|
 | 
						|
# File name search
 | 
						|
curl "http://localhost:4000/api/search?q=file:readme"
 | 
						|
 | 
						|
# Combined: tag + path + text
 | 
						|
curl "http://localhost:4000/api/search?q=tag:dev path:Projects typescript"
 | 
						|
```
 | 
						|
 | 
						|
### Typo Tolerance
 | 
						|
 | 
						|
```bash
 | 
						|
# Intentional typos (should still match)
 | 
						|
curl "http://localhost:4000/api/search?q=obsever"  # → "observer"
 | 
						|
curl "http://localhost:4000/api/search?q=searh"    # → "search"
 | 
						|
```
 | 
						|
 | 
						|
### Pagination & Sorting
 | 
						|
 | 
						|
```bash
 | 
						|
# Limit results
 | 
						|
curl "http://localhost:4000/api/search?q=*&limit=10"
 | 
						|
 | 
						|
# Offset (page 2)
 | 
						|
curl "http://localhost:4000/api/search?q=*&limit=10&offset=10"
 | 
						|
 | 
						|
# Sort by date (newest first)
 | 
						|
curl "http://localhost:4000/api/search?q=*&sort=updatedAt:desc"
 | 
						|
 | 
						|
# Sort by title
 | 
						|
curl "http://localhost:4000/api/search?q=*&sort=title:asc"
 | 
						|
```
 | 
						|
 | 
						|
## Performance Benchmarking
 | 
						|
 | 
						|
Run the benchmark suite:
 | 
						|
 | 
						|
```bash
 | 
						|
npm run bench:search
 | 
						|
```
 | 
						|
 | 
						|
This tests 5 different queries with 20 concurrent connections for 10 seconds each.
 | 
						|
 | 
						|
**Expected Results** (on modern dev machine with 1000 notes):
 | 
						|
- P95: < 150ms ✅
 | 
						|
- Average: 50-100ms
 | 
						|
- Throughput: 200+ req/sec
 | 
						|
 | 
						|
If P95 exceeds 150ms, check:
 | 
						|
1. Is Meilisearch running? `docker ps`
 | 
						|
2. Is the index populated? Check `/health` endpoint
 | 
						|
3. System resources (CPU/RAM)
 | 
						|
4. Adjust `typoTolerance` or `searchableAttributes` in `meilisearch.client.mjs`
 | 
						|
 | 
						|
## Troubleshooting
 | 
						|
 | 
						|
### Meilisearch won't start
 | 
						|
 | 
						|
```bash
 | 
						|
# Check if port 7700 is already in use
 | 
						|
netstat -an | findstr 7700  # Windows
 | 
						|
lsof -i :7700               # macOS/Linux
 | 
						|
 | 
						|
# View Meilisearch logs
 | 
						|
docker logs obsiviewer-meilisearch
 | 
						|
 | 
						|
# Restart Meilisearch
 | 
						|
npm run meili:down
 | 
						|
npm run meili:up
 | 
						|
```
 | 
						|
 | 
						|
### Search returns empty results
 | 
						|
 | 
						|
```bash
 | 
						|
# Check if index exists and has documents
 | 
						|
curl http://localhost:7700/indexes/notes_vault/stats \
 | 
						|
  -H "Authorization: Bearer dev_meili_master_key_change_me"
 | 
						|
 | 
						|
# Reindex if needed
 | 
						|
npm run meili:reindex
 | 
						|
```
 | 
						|
 | 
						|
### "Connection refused" errors
 | 
						|
 | 
						|
Ensure Meilisearch is running:
 | 
						|
 | 
						|
```bash
 | 
						|
docker ps | grep meilisearch
 | 
						|
# Should show: obsiviewer-meilisearch ... Up ... 0.0.0.0:7700->7700/tcp
 | 
						|
```
 | 
						|
 | 
						|
### Changes not reflected immediately
 | 
						|
 | 
						|
Wait 1-2 seconds after file changes for Chokidar to process. Check server logs:
 | 
						|
 | 
						|
```
 | 
						|
[Meili] Upserted: Projects/MyNote.md
 | 
						|
```
 | 
						|
 | 
						|
### Performance issues
 | 
						|
 | 
						|
1. **Reduce typo tolerance**: Edit `server/meilisearch.client.mjs`
 | 
						|
   ```javascript
 | 
						|
   typoTolerance: {
 | 
						|
     enabled: true,
 | 
						|
     minWordSizeForTypos: {
 | 
						|
       oneTypo: 5,    // Was 3
 | 
						|
       twoTypos: 9    // Was 6
 | 
						|
     }
 | 
						|
   }
 | 
						|
   ```
 | 
						|
 | 
						|
2. **Limit searchable attributes**: Remove `headings` or `properties.*` if not needed
 | 
						|
 | 
						|
3. **Increase batch size**: Edit `server/meilisearch-indexer.mjs`
 | 
						|
   ```javascript
 | 
						|
   const batchSize = 1000;  // Was 750
 | 
						|
   ```
 | 
						|
 | 
						|
## Environment Variables
 | 
						|
 | 
						|
### Development (local)
 | 
						|
 | 
						|
`.env` or shell:
 | 
						|
```bash
 | 
						|
VAULT_PATH=./vault
 | 
						|
MEILI_HOST=http://127.0.0.1:7700
 | 
						|
MEILI_API_KEY=dev_meili_master_key_change_me
 | 
						|
```
 | 
						|
 | 
						|
### Docker Compose
 | 
						|
 | 
						|
`docker-compose/.env`:
 | 
						|
```env
 | 
						|
MEILI_MASTER_KEY=dev_meili_master_key_change_me
 | 
						|
MEILI_ENV=development
 | 
						|
```
 | 
						|
 | 
						|
### Production
 | 
						|
 | 
						|
**Important**: Change the master key in production!
 | 
						|
 | 
						|
```bash
 | 
						|
MEILI_MASTER_KEY=$(openssl rand -base64 32)
 | 
						|
MEILI_ENV=production
 | 
						|
```
 | 
						|
 | 
						|
## API Reference
 | 
						|
 | 
						|
### GET /api/search
 | 
						|
 | 
						|
**Query Parameters**:
 | 
						|
- `q` (string, required): Search query with optional operators
 | 
						|
- `limit` (number, default: 20): Max results to return
 | 
						|
- `offset` (number, default: 0): Pagination offset
 | 
						|
- `sort` (string): Sort field and direction, e.g., `updatedAt:desc`
 | 
						|
- `highlight` (boolean, default: true): Include `<mark>` highlights
 | 
						|
 | 
						|
**Response**:
 | 
						|
```json
 | 
						|
{
 | 
						|
  "hits": [
 | 
						|
    {
 | 
						|
      "id": "Projects/MyNote.md",
 | 
						|
      "title": "My Note",
 | 
						|
      "path": "Projects/MyNote.md",
 | 
						|
      "file": "MyNote.md",
 | 
						|
      "tags": ["dev", "typescript"],
 | 
						|
      "excerpt": "First 500 chars...",
 | 
						|
      "_formatted": {
 | 
						|
        "title": "My <mark>Note</mark>",
 | 
						|
        "content": "...search <mark>term</mark>..."
 | 
						|
      }
 | 
						|
    }
 | 
						|
  ],
 | 
						|
  "estimatedTotalHits": 42,
 | 
						|
  "facetDistribution": {
 | 
						|
    "tags": { "dev": 15, "typescript": 8 },
 | 
						|
    "parentDirs": { "Projects": 42 }
 | 
						|
  },
 | 
						|
  "processingTimeMs": 12,
 | 
						|
  "query": "note"
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
### POST /api/reindex
 | 
						|
 | 
						|
Triggers a full reindex of all markdown files in the vault.
 | 
						|
 | 
						|
**Response**:
 | 
						|
```json
 | 
						|
{
 | 
						|
  "ok": true,
 | 
						|
  "indexed": true,
 | 
						|
  "count": 1247,
 | 
						|
  "elapsedMs": 3421
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
## Next Steps
 | 
						|
 | 
						|
### P1 Features (Future)
 | 
						|
 | 
						|
- [ ] Multi-language support (configure `locale` in Meilisearch)
 | 
						|
- [ ] Synonyms configuration
 | 
						|
- [ ] Stop words for common terms
 | 
						|
- [ ] Advanced operators: `line:`, `section:`, `[property]:value`
 | 
						|
- [ ] Faceted search UI (tag/folder selectors)
 | 
						|
- [ ] Search result pagination in Angular
 | 
						|
- [ ] Search analytics and logging
 | 
						|
- [ ] Incremental indexing optimization (delta updates)
 | 
						|
 | 
						|
### Performance Optimization
 | 
						|
 | 
						|
- [ ] Redis cache layer for frequent queries
 | 
						|
- [ ] CDN for static assets
 | 
						|
- [ ] Index sharding for very large vaults (10k+ notes)
 | 
						|
- [ ] Lazy loading of highlights (fetch on demand)
 | 
						|
 | 
						|
## Support
 | 
						|
 | 
						|
If you encounter issues:
 | 
						|
 | 
						|
1. Check server logs: `node server/index.mjs` (console output)
 | 
						|
2. Check Meilisearch logs: `docker logs obsiviewer-meilisearch`
 | 
						|
3. Verify environment variables are set correctly
 | 
						|
4. Ensure vault path is correct and contains `.md` files
 | 
						|
5. Test with curl before testing in Angular
 |