docs: remove old implementation docs and setup guides
This commit is contained in:
@@ -0,0 +1,336 @@
|
||||
# 🔍 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
|
||||
@@ -0,0 +1,364 @@
|
||||
# Guide de Débogage de la Recherche Meilisearch
|
||||
|
||||
## 🔍 Problème Actuel
|
||||
|
||||
La recherche Meilisearch est activée mais les résultats ne s'affichent pas dans l'interface.
|
||||
|
||||
## ✅ Ce qui Fonctionne
|
||||
|
||||
### Backend API
|
||||
- ✅ Meilisearch est actif (port 7700)
|
||||
- ✅ Backend Express est actif (port 4000)
|
||||
- ✅ Index Meilisearch contient 642 documents
|
||||
- ✅ API `/api/search` retourne des résultats valides
|
||||
|
||||
**Test backend :**
|
||||
```bash
|
||||
curl "http://localhost:4000/api/search?q=test&limit=2"
|
||||
# Retourne: {"hits":[...], "estimatedTotalHits":..., "processingTimeMs":...}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
- ✅ `USE_MEILI: true` dans `environment.ts`
|
||||
- ✅ Proxy Angular configuré (`/api` → `localhost:4000`)
|
||||
- ✅ HttpClient configuré dans `index.tsx`
|
||||
|
||||
### Autres Fonctionnalités
|
||||
- ✅ **Bookmarks** : Utilise `/api/vault/bookmarks` (backend)
|
||||
- ✅ **Calendrier** : Utilise `/api/files/metadata` (backend)
|
||||
- ✅ **Vault** : Utilise `/api/vault` (backend)
|
||||
|
||||
## 🐛 Logs de Débogage Ajoutés
|
||||
|
||||
### Frontend
|
||||
|
||||
#### 1. SearchMeilisearchService
|
||||
```typescript
|
||||
// src/core/search/search-meilisearch.service.ts
|
||||
console.log('[SearchMeilisearchService] Sending request:', url);
|
||||
console.log('[SearchMeilisearchService] Request completed');
|
||||
```
|
||||
|
||||
#### 2. SearchOrchestratorService
|
||||
```typescript
|
||||
// src/core/search/search-orchestrator.service.ts
|
||||
console.log('[SearchOrchestrator] Calling Meilisearch with query:', query);
|
||||
console.log('[SearchOrchestrator] Raw Meilisearch response:', response);
|
||||
console.log('[SearchOrchestrator] Transformed hit:', { id, matchCount, result });
|
||||
```
|
||||
|
||||
#### 3. SearchPanelComponent
|
||||
```typescript
|
||||
// src/components/search-panel/search-panel.component.ts
|
||||
console.log('[SearchPanel] Results received:', arr);
|
||||
console.error('[SearchPanel] Search error:', e);
|
||||
```
|
||||
|
||||
## 🧪 Tests à Effectuer
|
||||
|
||||
### 1. Vérifier les Logs Console
|
||||
|
||||
1. **Ouvrir DevTools** (F12)
|
||||
2. **Aller dans Console**
|
||||
3. **Taper une recherche** (ex: "test")
|
||||
4. **Observer les logs** dans l'ordre :
|
||||
|
||||
```
|
||||
[SearchOrchestrator] Calling Meilisearch with query: test
|
||||
[SearchMeilisearchService] Sending request: /api/search?q=test&limit=20&highlight=true
|
||||
[SearchMeilisearchService] Request completed
|
||||
[SearchOrchestrator] Raw Meilisearch response: {hits: [...], ...}
|
||||
[SearchOrchestrator] Transformed hit: {id: "...", matchCount: 1, result: {...}}
|
||||
[SearchPanel] Results received: [{noteId: "...", matches: [...], ...}]
|
||||
```
|
||||
|
||||
### 2. Vérifier l'Onglet Network
|
||||
|
||||
1. **Ouvrir DevTools** → **Network**
|
||||
2. **Filtrer** : `search`
|
||||
3. **Taper une recherche**
|
||||
4. **Vérifier** :
|
||||
- ✅ Requête GET `/api/search?q=...`
|
||||
- ✅ Status: 200 OK
|
||||
- ✅ Response contient `hits` avec des données
|
||||
|
||||
### 3. Vérifier les Résultats Transformés
|
||||
|
||||
Dans la console, après une recherche :
|
||||
```javascript
|
||||
// Inspecter le signal results
|
||||
// (nécessite Angular DevTools ou breakpoint)
|
||||
```
|
||||
|
||||
## 🔧 Points de Vérification
|
||||
|
||||
### 1. Proxy Angular
|
||||
|
||||
**Fichier :** `proxy.conf.json`
|
||||
```json
|
||||
{
|
||||
"/api": {
|
||||
"target": "http://localhost:4000",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
"logLevel": "warn"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Vérifier :**
|
||||
```bash
|
||||
# Depuis le navigateur (port 3000)
|
||||
curl http://localhost:3000/api/search?q=test
|
||||
|
||||
# Doit retourner les mêmes résultats que :
|
||||
curl http://localhost:4000/api/search?q=test
|
||||
```
|
||||
|
||||
### 2. Transformation des Résultats
|
||||
|
||||
**Code :** `src/core/search/search-orchestrator.service.ts`
|
||||
|
||||
Le mapping Meilisearch → SearchResult doit produire :
|
||||
```typescript
|
||||
{
|
||||
noteId: string, // ID du document
|
||||
matches: [ // Au moins 1 match
|
||||
{
|
||||
type: 'content',
|
||||
text: string,
|
||||
context: string, // Contenu avec <mark> ou texte brut
|
||||
ranges: []
|
||||
}
|
||||
],
|
||||
score: 100,
|
||||
allRanges: []
|
||||
}
|
||||
```
|
||||
|
||||
**Problème potentiel :** Si `matches` est vide, rien ne s'affiche.
|
||||
|
||||
**Solution :** Le code a été modifié pour toujours créer au moins un match avec `excerpt` ou `content`.
|
||||
|
||||
### 3. Affichage des Résultats
|
||||
|
||||
**Composant :** `SearchResultsComponent`
|
||||
|
||||
**Vérifier dans le template :**
|
||||
```html
|
||||
@if (sortedGroups().length === 0) {
|
||||
<!-- Message "No results" -->
|
||||
} @else {
|
||||
<!-- Liste des résultats -->
|
||||
@for (group of sortedGroups(); track group.noteId) {
|
||||
<!-- Affichage du groupe -->
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Signal à inspecter :**
|
||||
- `results()` : Doit contenir les SearchResult[]
|
||||
- `sortedGroups()` : Doit contenir les ResultGroup[]
|
||||
|
||||
## 🚨 Problèmes Possibles
|
||||
|
||||
### Problème 1 : Requête HTTP ne part pas
|
||||
|
||||
**Symptômes :**
|
||||
- Aucun log `[SearchMeilisearchService] Sending request`
|
||||
- Aucune requête dans Network tab
|
||||
|
||||
**Causes possibles :**
|
||||
- `USE_MEILI` n'est pas à `true`
|
||||
- Service non injecté correctement
|
||||
- Observable non souscrit
|
||||
|
||||
**Solution :**
|
||||
```typescript
|
||||
// Vérifier dans environment.ts
|
||||
export const environment = {
|
||||
USE_MEILI: true, // ← Doit être true
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
### Problème 2 : Requête part mais pas de réponse
|
||||
|
||||
**Symptômes :**
|
||||
- Log `[SearchMeilisearchService] Sending request` présent
|
||||
- Pas de log `Request completed`
|
||||
- Erreur dans Network tab
|
||||
|
||||
**Causes possibles :**
|
||||
- Backend non démarré
|
||||
- Proxy mal configuré
|
||||
- CORS
|
||||
|
||||
**Solution :**
|
||||
```bash
|
||||
# Vérifier backend
|
||||
curl http://localhost:4000/api/search?q=test
|
||||
|
||||
# Vérifier proxy
|
||||
# Redémarrer ng serve si nécessaire
|
||||
```
|
||||
|
||||
### Problème 3 : Réponse reçue mais pas de résultats
|
||||
|
||||
**Symptômes :**
|
||||
- Log `[SearchOrchestrator] Raw Meilisearch response` présent
|
||||
- `hits.length > 0`
|
||||
- Mais `matches.length === 0` dans transformed hit
|
||||
|
||||
**Causes possibles :**
|
||||
- `_formatted` absent dans la réponse Meilisearch
|
||||
- `excerpt` absent
|
||||
- Mapping incorrect
|
||||
|
||||
**Solution :**
|
||||
Le code a été modifié pour créer un match de fallback avec `excerpt` ou un extrait de `content`.
|
||||
|
||||
### Problème 4 : Résultats transformés mais pas affichés
|
||||
|
||||
**Symptômes :**
|
||||
- Log `[SearchPanel] Results received` avec `arr.length > 0`
|
||||
- Mais rien ne s'affiche dans l'UI
|
||||
|
||||
**Causes possibles :**
|
||||
- Signal `results` non mis à jour
|
||||
- Composant SearchResults ne reçoit pas les données
|
||||
- Change detection non déclenchée
|
||||
|
||||
**Solution :**
|
||||
```typescript
|
||||
// Vérifier que results.set() est appelé
|
||||
this.results.set(arr);
|
||||
this.hasSearched.set(true);
|
||||
```
|
||||
|
||||
### Problème 5 : Highlighting ne fonctionne pas
|
||||
|
||||
**Symptômes :**
|
||||
- Résultats affichés
|
||||
- Mais pas de surlignage (balises `<mark>`)
|
||||
|
||||
**Causes possibles :**
|
||||
- `_formatted` absent
|
||||
- HTML échappé
|
||||
- Balises `<mark>` non rendues
|
||||
|
||||
**Solution :**
|
||||
Le code a été modifié pour :
|
||||
1. Détecter les balises `<mark>` dans `match.context`
|
||||
2. Retourner le HTML tel quel (sans échappement) si présent
|
||||
3. Sinon, utiliser le highlighter local
|
||||
|
||||
## 📋 Checklist de Débogage
|
||||
|
||||
- [ ] Backend démarré (`node server/index.mjs`)
|
||||
- [ ] Frontend démarré (`npm run dev`)
|
||||
- [ ] Meilisearch actif (`docker ps | grep meilisearch`)
|
||||
- [ ] `USE_MEILI: true` dans `environment.ts`
|
||||
- [ ] Hard refresh du navigateur (Ctrl+Shift+R)
|
||||
- [ ] DevTools Console ouverte
|
||||
- [ ] DevTools Network tab ouverte
|
||||
- [ ] Taper une recherche (2+ caractères)
|
||||
- [ ] Vérifier logs console (ordre attendu)
|
||||
- [ ] Vérifier requête HTTP dans Network
|
||||
- [ ] Vérifier réponse JSON (hits présents)
|
||||
- [ ] Vérifier transformation (matches non vide)
|
||||
- [ ] Vérifier affichage (liste de résultats visible)
|
||||
|
||||
## 🔄 Workflow de Test Complet
|
||||
|
||||
```bash
|
||||
# 1. Vérifier Meilisearch
|
||||
docker ps | grep meilisearch
|
||||
curl http://127.0.0.1:7700/health
|
||||
|
||||
# 2. Vérifier Backend
|
||||
curl "http://localhost:4000/api/search?q=test&limit=1"
|
||||
# Doit retourner JSON avec hits
|
||||
|
||||
# 3. Démarrer Frontend (si pas déjà fait)
|
||||
npm run dev
|
||||
|
||||
# 4. Ouvrir navigateur
|
||||
# http://localhost:3000
|
||||
|
||||
# 5. Ouvrir DevTools (F12)
|
||||
# - Console tab
|
||||
# - Network tab
|
||||
|
||||
# 6. Taper recherche
|
||||
# - Minimum 2 caractères
|
||||
# - Observer logs console
|
||||
# - Observer requête Network
|
||||
|
||||
# 7. Vérifier affichage
|
||||
# - Liste de résultats doit apparaître
|
||||
# - Cliquer sur un groupe pour voir les matches
|
||||
# - Vérifier highlighting (balises <mark>)
|
||||
```
|
||||
|
||||
## 🆘 Si Rien Ne Fonctionne
|
||||
|
||||
### Étape 1 : Vérifier Backend Isolé
|
||||
|
||||
```bash
|
||||
curl -v "http://localhost:4000/api/search?q=test&limit=1"
|
||||
```
|
||||
|
||||
**Attendu :**
|
||||
- Status: 200 OK
|
||||
- Content-Type: application/json
|
||||
- Body: `{"hits":[...], ...}`
|
||||
|
||||
### Étape 2 : Vérifier Proxy
|
||||
|
||||
```bash
|
||||
# Depuis un autre terminal
|
||||
curl "http://localhost:3000/api/search?q=test&limit=1"
|
||||
```
|
||||
|
||||
**Attendu :** Même réponse que backend direct
|
||||
|
||||
### Étape 3 : Vérifier Logs Backend
|
||||
|
||||
Dans le terminal où `node server/index.mjs` tourne :
|
||||
```
|
||||
[Meili] Search query: test
|
||||
[Meili] Results: 1 hits in 15ms
|
||||
```
|
||||
|
||||
### Étape 4 : Vérifier Logs Frontend
|
||||
|
||||
Dans la console du navigateur :
|
||||
```
|
||||
[SearchOrchestrator] Calling Meilisearch with query: test
|
||||
[SearchMeilisearchService] Sending request: /api/search?q=test&limit=20&highlight=true
|
||||
```
|
||||
|
||||
### Étape 5 : Breakpoint Debugging
|
||||
|
||||
1. Ouvrir DevTools → Sources
|
||||
2. Trouver `search-panel.component.ts`
|
||||
3. Mettre un breakpoint sur `this.results.set(arr)`
|
||||
4. Taper une recherche
|
||||
5. Inspecter `arr` quand le breakpoint est atteint
|
||||
|
||||
## 📊 Métriques de Performance
|
||||
|
||||
Une fois fonctionnel, vérifier :
|
||||
- **Temps de recherche** : < 100ms (Meili + réseau)
|
||||
- **Nombre de résultats** : Dépend de la requête
|
||||
- **Highlighting** : Balises `<mark>` présentes
|
||||
- **Pas de gel UI** : Interface reste réactive
|
||||
|
||||
## 🎯 Prochaines Étapes
|
||||
|
||||
Une fois la recherche fonctionnelle :
|
||||
1. Retirer les `console.log` de débogage
|
||||
2. Optimiser le mapping si nécessaire
|
||||
3. Ajouter tests E2E
|
||||
4. Documenter le comportement final
|
||||
@@ -0,0 +1,330 @@
|
||||
# Guide d'Optimisation de la Recherche
|
||||
|
||||
## 🚀 Problème Résolu
|
||||
|
||||
### Avant (Recherche Locale)
|
||||
- ❌ Le frontend chargeait **toutes les notes** en mémoire
|
||||
- ❌ Chaque recherche parcourait **tous les contextes** en JavaScript
|
||||
- ❌ **Gels de l'interface** lors de la saisie avec de gros vaults
|
||||
- ❌ Performances dégradées avec > 1000 notes
|
||||
|
||||
### Après (Meilisearch Backend)
|
||||
- ✅ Le frontend envoie les requêtes au **backend via API**
|
||||
- ✅ Meilisearch indexe et recherche **côté serveur**
|
||||
- ✅ **Aucun gel** - recherche asynchrone avec debounce
|
||||
- ✅ Performances optimales même avec 10,000+ notes
|
||||
- ✅ **Recherche en temps réel** pendant la saisie (debounce 300ms)
|
||||
|
||||
## 📋 Configuration
|
||||
|
||||
### 1. Activer Meilisearch
|
||||
|
||||
Le fichier `src/core/logging/environment.ts` contrôle le mode de recherche :
|
||||
|
||||
```typescript
|
||||
export const environment = {
|
||||
production: false,
|
||||
appVersion: '0.1.0',
|
||||
USE_MEILI: true, // ✅ Activé pour utiliser Meilisearch
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Démarrer Meilisearch
|
||||
|
||||
```bash
|
||||
# Démarrer le conteneur Meilisearch
|
||||
npm run meili:up
|
||||
|
||||
# Vérifier que Meilisearch est actif
|
||||
curl http://127.0.0.1:7700/health
|
||||
```
|
||||
|
||||
### 3. Indexer le Vault
|
||||
|
||||
```bash
|
||||
# Indexation initiale
|
||||
npm run meili:reindex
|
||||
|
||||
# Ou rebuild complet (up + reindex)
|
||||
npm run meili:rebuild
|
||||
```
|
||||
|
||||
### 4. Démarrer le Backend
|
||||
|
||||
```bash
|
||||
# Avec les variables d'environnement du .env
|
||||
node server/index.mjs
|
||||
|
||||
# Ou avec variables explicites
|
||||
VAULT_PATH=/path/to/vault MEILI_MASTER_KEY=devMeiliKey123 node server/index.mjs
|
||||
```
|
||||
|
||||
### 5. Démarrer le Frontend
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 🔄 Flux de Recherche Optimisé
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Frontend │
|
||||
│ (Angular) │
|
||||
└──────┬──────┘
|
||||
│ 1. Saisie utilisateur (debounce 300ms)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────┐
|
||||
│ SearchPanelComponent │
|
||||
│ - Debounce avec RxJS │
|
||||
│ - Subject pour recherches │
|
||||
└──────┬──────────────────────┘
|
||||
│ 2. Appel orchestrateur
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────┐
|
||||
│ SearchOrchestratorService │
|
||||
│ - Détecte USE_MEILI=true │
|
||||
│ - Délègue à Meilisearch │
|
||||
└──────┬──────────────────────┘
|
||||
│ 3. HTTP GET /api/search?q=...
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────┐
|
||||
│ Backend Express │
|
||||
│ - Parse query Obsidian │
|
||||
│ - Construit params Meili │
|
||||
└──────┬──────────────────────┘
|
||||
│ 4. Recherche dans index
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────┐
|
||||
│ Meilisearch │
|
||||
│ - Index optimisé │
|
||||
│ - Recherche ultra-rapide │
|
||||
│ - Highlighting │
|
||||
└──────┬──────────────────────┘
|
||||
│ 5. Résultats JSON
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────┐
|
||||
│ Frontend │
|
||||
│ - Affichage des résultats │
|
||||
│ - Highlighting │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
### Optimisations Implémentées
|
||||
|
||||
#### 1. **Debounce Intelligent** (`SearchPanelComponent`)
|
||||
```typescript
|
||||
// Recherche en temps réel avec debounce 300ms
|
||||
this.searchSubject.pipe(
|
||||
debounceTime(300),
|
||||
distinctUntilChanged((prev, curr) => prev.query === curr.query)
|
||||
).subscribe(({ query, options }) => {
|
||||
this.executeSearch(query, options);
|
||||
});
|
||||
```
|
||||
|
||||
#### 2. **Index Local Désactivé** (quand Meilisearch actif)
|
||||
```typescript
|
||||
private syncIndexEffect = effect(() => {
|
||||
// Only rebuild index if not using Meilisearch
|
||||
if (!environment.USE_MEILI) {
|
||||
const notes = this.vaultService.allNotes();
|
||||
this.searchIndex.rebuildIndex(notes);
|
||||
}
|
||||
}, { allowSignalWrites: true });
|
||||
```
|
||||
|
||||
#### 3. **Exécution Asynchrone**
|
||||
```typescript
|
||||
if (environment.USE_MEILI) {
|
||||
// Execute immediately with Meilisearch (backend handles it)
|
||||
executeNow();
|
||||
} else {
|
||||
// Use setTimeout to avoid blocking UI with local search
|
||||
setTimeout(executeNow, 0);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. **Recherche Live** (pendant la saisie)
|
||||
```typescript
|
||||
onQueryChange(query: string): void {
|
||||
this.currentQuery.set(query);
|
||||
|
||||
// With Meilisearch, enable live search with debounce
|
||||
if (environment.USE_MEILI && query.trim().length >= 2) {
|
||||
this.searchSubject.next({ query, options: this.lastOptions });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔍 Opérateurs de Recherche Supportés
|
||||
|
||||
Tous les opérateurs Obsidian sont mappés vers Meilisearch :
|
||||
|
||||
| Opérateur | Exemple | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `tag:` | `tag:projet` | Recherche par tag |
|
||||
| `path:` | `path:docs/` | Recherche dans un chemin |
|
||||
| `file:` | `file:readme` | Recherche par nom de fichier |
|
||||
| `content:` | `content:angular` | Recherche dans le contenu |
|
||||
| `section:` | `section:intro` | Recherche dans les sections |
|
||||
| `-` | `-tag:archive` | Exclusion |
|
||||
| `OR` | `angular OR react` | OU logique |
|
||||
| `AND` | `angular AND typescript` | ET logique |
|
||||
|
||||
## 📊 Performances
|
||||
|
||||
### Benchmarks (vault de 5000 notes)
|
||||
|
||||
| Méthode | Temps de recherche | Gel UI | Mémoire |
|
||||
|---------|-------------------|--------|---------|
|
||||
| **Local (avant)** | 800-1200ms | ❌ Oui (500ms+) | ~150MB |
|
||||
| **Meilisearch (après)** | 15-50ms | ✅ Non | ~20MB |
|
||||
|
||||
### Métriques Clés
|
||||
|
||||
- **Latence réseau** : ~5-10ms (localhost)
|
||||
- **Temps de recherche Meilisearch** : 10-30ms
|
||||
- **Debounce** : 300ms (évite recherches inutiles)
|
||||
- **Taille index** : ~50MB pour 10,000 notes
|
||||
|
||||
## 🛠️ Maintenance
|
||||
|
||||
### Réindexation
|
||||
|
||||
L'index Meilisearch est mis à jour automatiquement via Chokidar :
|
||||
|
||||
```javascript
|
||||
// server/index.mjs
|
||||
vaultWatcher.on('add', (filePath) => {
|
||||
if (filePath.toLowerCase().endsWith('.md')) {
|
||||
upsertFile(filePath).catch(err => console.error('[Meili] Upsert failed:', err));
|
||||
}
|
||||
});
|
||||
|
||||
vaultWatcher.on('change', (filePath) => {
|
||||
if (filePath.toLowerCase().endsWith('.md')) {
|
||||
upsertFile(filePath).catch(err => console.error('[Meili] Upsert failed:', err));
|
||||
}
|
||||
});
|
||||
|
||||
vaultWatcher.on('unlink', (filePath) => {
|
||||
if (filePath.toLowerCase().endsWith('.md')) {
|
||||
deleteFile(relativePath).catch(err => console.error('[Meili] Delete failed:', err));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Réindexation Manuelle
|
||||
|
||||
```bash
|
||||
# Via API
|
||||
curl -X POST http://localhost:4000/api/reindex
|
||||
|
||||
# Via script npm
|
||||
npm run meili:reindex
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
|
||||
```bash
|
||||
# Statistiques de l'index
|
||||
curl http://127.0.0.1:7700/indexes/vault-{hash}/stats
|
||||
|
||||
# Santé Meilisearch
|
||||
curl http://127.0.0.1:7700/health
|
||||
```
|
||||
|
||||
## 🐛 Dépannage
|
||||
|
||||
### Problème : Recherche ne fonctionne pas
|
||||
|
||||
**Solution 1 : Vérifier Meilisearch**
|
||||
```bash
|
||||
# Vérifier si Meilisearch est actif
|
||||
docker ps | grep meilisearch
|
||||
|
||||
# Redémarrer si nécessaire
|
||||
npm run meili:down
|
||||
npm run meili:up
|
||||
```
|
||||
|
||||
**Solution 2 : Vérifier l'index**
|
||||
```bash
|
||||
# Lister les index
|
||||
curl http://127.0.0.1:7700/indexes
|
||||
|
||||
# Réindexer
|
||||
npm run meili:reindex
|
||||
```
|
||||
|
||||
**Solution 3 : Vérifier les logs**
|
||||
```bash
|
||||
# Logs Meilisearch
|
||||
docker logs obsidian-meilisearch
|
||||
|
||||
# Logs backend
|
||||
# Visible dans la console où node server/index.mjs tourne
|
||||
```
|
||||
|
||||
### Problème : Recherche lente
|
||||
|
||||
**Causes possibles :**
|
||||
1. Index non créé → `npm run meili:reindex`
|
||||
2. Meilisearch non démarré → `npm run meili:up`
|
||||
3. `USE_MEILI=false` → Vérifier `environment.ts`
|
||||
|
||||
### Problème : Résultats incomplets
|
||||
|
||||
**Solution :**
|
||||
```bash
|
||||
# Rebuild complet de l'index
|
||||
npm run meili:down
|
||||
npm run meili:up
|
||||
npm run meili:reindex
|
||||
```
|
||||
|
||||
## 🔐 Sécurité
|
||||
|
||||
### Clé Master
|
||||
|
||||
La clé master Meilisearch est définie dans `.env` :
|
||||
|
||||
```env
|
||||
MEILI_MASTER_KEY=devMeiliKey123
|
||||
```
|
||||
|
||||
⚠️ **Important :** En production, utilisez une clé forte et sécurisée !
|
||||
|
||||
### CORS
|
||||
|
||||
Le backend Express est configuré pour accepter les requêtes du frontend :
|
||||
|
||||
```javascript
|
||||
// Pas de CORS nécessaire car frontend et backend sur même origine
|
||||
// En production, configurer CORS si nécessaire
|
||||
```
|
||||
|
||||
## 📚 Ressources
|
||||
|
||||
- [Documentation Meilisearch](https://www.meilisearch.com/docs)
|
||||
- [API Meilisearch](https://www.meilisearch.com/docs/reference/api/overview)
|
||||
- [Obsidian Search Syntax](https://help.obsidian.md/Plugins/Search)
|
||||
- [RxJS Debounce](https://rxjs.dev/api/operators/debounceTime)
|
||||
|
||||
## 🎯 Prochaines Améliorations
|
||||
|
||||
- [ ] Recherche fuzzy (tolérance aux fautes)
|
||||
- [ ] Facettes pour filtrage avancé
|
||||
- [ ] Recherche géographique (si coordonnées dans frontmatter)
|
||||
- [ ] Synonymes et stop words personnalisés
|
||||
- [ ] Cache des résultats côté frontend
|
||||
- [ ] Pagination des résultats (actuellement limité à 20)
|
||||
Reference in New Issue
Block a user