feat: 新增index/mapping/document/search接口
This commit is contained in:
246
operations/index/index.go
Normal file
246
operations/index/index.go
Normal file
@@ -0,0 +1,246 @@
|
||||
// Package index provides index-level operations for OpenSearch.
|
||||
package index
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"es-demo/client"
|
||||
|
||||
"github.com/opensearch-project/opensearch-go/v2/opensearchapi"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrIndexNotFound is returned when the specified index does not exist.
|
||||
ErrIndexNotFound = errors.New("index not found")
|
||||
|
||||
// ErrIndexAlreadyExists is returned when trying to create an index that already exists.
|
||||
ErrIndexAlreadyExists = errors.New("index already exists")
|
||||
|
||||
// ErrInvalidIndexName is returned when the index name is invalid.
|
||||
ErrInvalidIndexName = errors.New("invalid index name")
|
||||
)
|
||||
|
||||
// IndexSettings represents the settings for an index.
|
||||
type IndexSettings struct {
|
||||
NumberOfShards int `json:"number_of_shards,omitempty"`
|
||||
NumberOfReplicas int `json:"number_of_replicas,omitempty"`
|
||||
}
|
||||
|
||||
// IndexConfig represents the complete configuration for creating an index.
|
||||
type IndexConfig struct {
|
||||
Settings *IndexSettings `json:"settings,omitempty"`
|
||||
Mappings map[string]any `json:"mappings,omitempty"`
|
||||
Aliases map[string]any `json:"aliases,omitempty"`
|
||||
}
|
||||
|
||||
// IndexInfo represents information about an index.
|
||||
type IndexInfo struct {
|
||||
Name string
|
||||
Settings *IndexSettings
|
||||
Mappings map[string]any
|
||||
Aliases map[string]any
|
||||
}
|
||||
|
||||
// CreateIndex creates a new index with the specified configuration.
|
||||
func CreateIndex(ctx context.Context, c *client.Client, name string, config *IndexConfig) error {
|
||||
if name == "" {
|
||||
return ErrInvalidIndexName
|
||||
}
|
||||
|
||||
// Build request body
|
||||
var body io.Reader
|
||||
if config != nil {
|
||||
data, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal index config: %w", err)
|
||||
}
|
||||
body = bytes.NewReader(data)
|
||||
}
|
||||
|
||||
req := opensearchapi.IndicesCreateRequest{
|
||||
Index: name,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
res, err := req.Do(ctx, c.GetClient())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute create index 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)
|
||||
if res.StatusCode == 400 {
|
||||
return fmt.Errorf("%w: %s", ErrIndexAlreadyExists, string(bodyBytes))
|
||||
}
|
||||
return fmt.Errorf("create index failed with status %s: %s", res.Status(), string(bodyBytes))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetIndex retrieves information about an index.
|
||||
func GetIndex(ctx context.Context, c *client.Client, name string) (*IndexInfo, error) {
|
||||
if name == "" {
|
||||
return nil, ErrInvalidIndexName
|
||||
}
|
||||
|
||||
req := opensearchapi.IndicesGetRequest{
|
||||
Index: []string{name},
|
||||
}
|
||||
|
||||
res, err := req.Do(ctx, c.GetClient())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute get index 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 index failed with status %s: %s", res.Status(), string(bodyBytes))
|
||||
}
|
||||
|
||||
// Parse response
|
||||
var response map[string]struct {
|
||||
Settings struct {
|
||||
Index struct {
|
||||
NumberOfShards string `json:"number_of_shards"`
|
||||
NumberOfReplicas string `json:"number_of_replicas"`
|
||||
} `json:"index"`
|
||||
} `json:"settings"`
|
||||
Mappings map[string]any `json:"mappings"`
|
||||
Aliases map[string]any `json:"aliases"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode index info: %w", err)
|
||||
}
|
||||
|
||||
indexData, exists := response[name]
|
||||
if !exists {
|
||||
return nil, ErrIndexNotFound
|
||||
}
|
||||
|
||||
info := &IndexInfo{
|
||||
Name: name,
|
||||
Mappings: indexData.Mappings,
|
||||
Aliases: indexData.Aliases,
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// DeleteIndex deletes an index.
|
||||
func DeleteIndex(ctx context.Context, c *client.Client, name string) error {
|
||||
if name == "" {
|
||||
return ErrInvalidIndexName
|
||||
}
|
||||
|
||||
req := opensearchapi.IndicesDeleteRequest{
|
||||
Index: []string{name},
|
||||
}
|
||||
|
||||
res, err := req.Do(ctx, c.GetClient())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute delete index 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 ErrIndexNotFound
|
||||
}
|
||||
|
||||
if res.IsError() {
|
||||
bodyBytes, _ := io.ReadAll(res.Body)
|
||||
return fmt.Errorf("delete index failed with status %s: %s", res.Status(), string(bodyBytes))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IndexExists checks if an index exists.
|
||||
func IndexExists(ctx context.Context, c *client.Client, name string) (bool, error) {
|
||||
if name == "" {
|
||||
return false, ErrInvalidIndexName
|
||||
}
|
||||
|
||||
req := opensearchapi.IndicesExistsRequest{
|
||||
Index: []string{name},
|
||||
}
|
||||
|
||||
res, err := req.Do(ctx, c.GetClient())
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to execute exists 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)
|
||||
}
|
||||
}()
|
||||
|
||||
return res.StatusCode == 200, nil
|
||||
}
|
||||
|
||||
// ListIndices lists all indices matching a pattern (use "*" for all).
|
||||
func ListIndices(ctx context.Context, c *client.Client, pattern string) ([]string, error) {
|
||||
if pattern == "" {
|
||||
pattern = "*"
|
||||
}
|
||||
|
||||
req := opensearchapi.CatIndicesRequest{
|
||||
Index: []string{pattern},
|
||||
Format: "json",
|
||||
}
|
||||
|
||||
res, err := req.Do(ctx, c.GetClient())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute list indices 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 nil, fmt.Errorf("list indices failed with status %s: %s", res.Status(), string(bodyBytes))
|
||||
}
|
||||
|
||||
var indices []struct {
|
||||
Index string `json:"index"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(res.Body).Decode(&indices); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode indices list: %w", err)
|
||||
}
|
||||
|
||||
result := make([]string, len(indices))
|
||||
for i, idx := range indices {
|
||||
result[i] = idx.Index
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user