veza/veza-backend-api/internal/elasticsearch/indices.go
senke ba88086f20 feat(v0.10.2): Recherche fulltext Elasticsearch - F361-F365
- Elasticsearch 8.x dans docker-compose.dev
- Package internal/elasticsearch: client, config, mappings, indices
- Sync PG→ES: reindex tracks/users/playlists, IndexTrack/DeleteTrack
- SearchService ES: multi_match + fuzziness (typo tolerance), highlighting
- Fallback gracieux: PostgreSQL si ELASTICSEARCH_URL absent
- Routes: GET /search, GET /search/suggestions, POST /admin/search/reindex
- Frontend: searchApi cursor/limit params (extensibilité)
- docs/ENV_VARIABLES: ELASTICSEARCH_URL, ELASTICSEARCH_INDEX, ELASTICSEARCH_AUTO_INDEX
- Roadmap v0.10.2 → DONE
2026-03-09 10:13:18 +01:00

69 lines
1.6 KiB
Go

package elasticsearch
import (
"bytes"
"context"
"fmt"
"strings"
"github.com/elastic/go-elasticsearch/v8/esapi"
"go.uber.org/zap"
)
// EnsureIndices creates indices if they don't exist (F361, F362)
func (c *Client) EnsureIndices(ctx context.Context) error {
if c == nil {
return nil
}
indices := []struct {
name string
mapping string
}{
{indexName(c.Config.Index, IdxTracks), tracksMapping},
{indexName(c.Config.Index, IdxUsers), usersMapping},
{indexName(c.Config.Index, IdxPlaylists), playlistsMapping},
}
for _, idx := range indices {
exists, err := c.Indices.Exists([]string{idx.name}, c.Indices.Exists.WithContext(ctx))
if err != nil {
return err
}
if exists.StatusCode == 200 {
if c.Logger != nil {
c.Logger.Debug("Elasticsearch index exists", zap.String("index", idx.name))
}
continue
}
res, err := c.Indices.Create(
idx.name,
c.Indices.Create.WithContext(ctx),
c.Indices.Create.WithBody(strings.NewReader(idx.mapping)),
)
if err != nil {
return err
}
defer res.Body.Close()
if res.IsError() {
return fmtErr(res)
}
if c.Logger != nil {
c.Logger.Info("Elasticsearch index created", zap.String("index", idx.name))
}
}
return nil
}
func indexName(prefix, name string) string {
if prefix != "" {
return prefix + "-" + name
}
return "veza-" + name
}
func fmtErr(res *esapi.Response) error {
var buf bytes.Buffer
if _, err := buf.ReadFrom(res.Body); err == nil {
return fmt.Errorf("elasticsearch error: %s", buf.String())
}
return fmt.Errorf("elasticsearch error: status %d", res.StatusCode)
}