125 lines
3.3 KiB
Go
125 lines
3.3 KiB
Go
// Package index provides index-level operations for OpenSearch.
|
|
package index
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"es-demo/client"
|
|
|
|
"github.com/opensearch-project/opensearch-go/v2/opensearchapi"
|
|
)
|
|
|
|
// FieldMapping represents a field mapping configuration.
|
|
type FieldMapping struct {
|
|
Type string `json:"type"`
|
|
Fields map[string]any `json:"fields,omitempty"`
|
|
// Common field options
|
|
Index *bool `json:"index,omitempty"`
|
|
Store *bool `json:"store,omitempty"`
|
|
Analyzer string `json:"analyzer,omitempty"`
|
|
Format string `json:"format,omitempty"`
|
|
IgnoreAbove int `json:"ignore_above,omitempty"`
|
|
}
|
|
|
|
// PutMapping updates the mapping for an index by adding new fields.
|
|
// Note: Existing field mappings cannot be changed in OpenSearch.
|
|
func PutMapping(ctx context.Context, c *client.Client, indexName string, properties map[string]FieldMapping) error {
|
|
if indexName == "" {
|
|
return ErrInvalidIndexName
|
|
}
|
|
|
|
if len(properties) == 0 {
|
|
return fmt.Errorf("properties cannot be empty")
|
|
}
|
|
|
|
// Build mapping request
|
|
mappingBody := map[string]any{
|
|
"properties": properties,
|
|
}
|
|
|
|
data, err := json.Marshal(mappingBody)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal mapping: %w", err)
|
|
}
|
|
|
|
req := opensearchapi.IndicesPutMappingRequest{
|
|
Index: []string{indexName},
|
|
Body: bytes.NewReader(data),
|
|
}
|
|
|
|
res, err := req.Do(ctx, c.GetClient())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to execute put mapping request: %w", err)
|
|
}
|
|
defer func() {
|
|
if closeErr := res.Body.Close(); closeErr != nil {
|
|
fmt.Fprintf(os.Stderr, "warning: failed to close response body: %v\n", closeErr)
|
|
}
|
|
}()
|
|
|
|
if res.IsError() {
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
return fmt.Errorf("put mapping failed with status %s: %s", res.Status(), string(bodyBytes))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetMapping retrieves the mapping for an index.
|
|
func GetMapping(ctx context.Context, c *client.Client, indexName string) (map[string]any, error) {
|
|
if indexName == "" {
|
|
return nil, ErrInvalidIndexName
|
|
}
|
|
|
|
req := opensearchapi.IndicesGetMappingRequest{
|
|
Index: []string{indexName},
|
|
}
|
|
|
|
res, err := req.Do(ctx, c.GetClient())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to execute get mapping request: %w", err)
|
|
}
|
|
defer func() {
|
|
if closeErr := res.Body.Close(); closeErr != nil {
|
|
fmt.Fprintf(os.Stderr, "warning: failed to close response body: %v\n", closeErr)
|
|
}
|
|
}()
|
|
|
|
if res.StatusCode == 404 {
|
|
return nil, ErrIndexNotFound
|
|
}
|
|
|
|
if res.IsError() {
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
return nil, fmt.Errorf("get mapping failed with status %s: %s", res.Status(), string(bodyBytes))
|
|
}
|
|
|
|
var response map[string]struct {
|
|
Mappings map[string]any `json:"mappings"`
|
|
}
|
|
|
|
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
|
|
return nil, fmt.Errorf("failed to decode mapping response: %w", err)
|
|
}
|
|
|
|
indexData, exists := response[indexName]
|
|
if !exists {
|
|
return nil, ErrIndexNotFound
|
|
}
|
|
|
|
return indexData.Mappings, nil
|
|
}
|
|
|
|
// AddField adds a new field to the index mapping.
|
|
// This is a convenience wrapper around PutMapping for adding a single field.
|
|
func AddField(ctx context.Context, c *client.Client, indexName string, fieldName string, mapping FieldMapping) error {
|
|
return PutMapping(ctx, c, indexName, map[string]FieldMapping{
|
|
fieldName: mapping,
|
|
})
|
|
}
|