feat: 新增index/mapping/document/search接口
This commit is contained in:
343
operations/index/search_test.go
Normal file
343
operations/index/search_test.go
Normal file
@@ -0,0 +1,343 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestSearchIntegration tests search operations.
|
||||
func TestSearchIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test in short mode")
|
||||
}
|
||||
|
||||
c := setupIntegrationTest(t)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
indexName := "test-search-integration"
|
||||
|
||||
// Setup index with mapping
|
||||
config := &IndexConfig{
|
||||
Mappings: map[string]any{
|
||||
"properties": map[string]any{
|
||||
"title": map[string]any{
|
||||
"type": "text",
|
||||
},
|
||||
"category": map[string]any{
|
||||
"type": "keyword",
|
||||
},
|
||||
"price": map[string]any{
|
||||
"type": "integer",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := CreateIndex(ctx, c, indexName, config)
|
||||
if err != nil {
|
||||
t.Fatalf("setup: CreateIndex() error = %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = DeleteIndex(ctx, c, indexName)
|
||||
}()
|
||||
|
||||
// Index test documents
|
||||
docs := []*Document{
|
||||
{
|
||||
ID: "1",
|
||||
Source: map[string]any{
|
||||
"title": "Go Programming Language",
|
||||
"category": "books",
|
||||
"price": 50,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Source: map[string]any{
|
||||
"title": "Python for Beginners",
|
||||
"category": "books",
|
||||
"price": 40,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "3",
|
||||
Source: map[string]any{
|
||||
"title": "JavaScript Guide",
|
||||
"category": "books",
|
||||
"price": 45,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = BulkIndexDocuments(ctx, c, indexName, docs)
|
||||
if err != nil {
|
||||
t.Fatalf("setup: BulkIndexDocuments() error = %v", err)
|
||||
}
|
||||
|
||||
// Give ES a moment to index
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Test 1: Match query
|
||||
t.Run("MatchQuery", func(t *testing.T) {
|
||||
query := &SearchQuery{
|
||||
Query: MatchQuery("title", "Programming"),
|
||||
Size: 10,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if result.Hits.Total.Value == 0 {
|
||||
t.Error("Search() returned no results")
|
||||
}
|
||||
|
||||
t.Logf("Match query found %d results", result.Hits.Total.Value)
|
||||
})
|
||||
|
||||
// Test 2: Term query
|
||||
t.Run("TermQuery", func(t *testing.T) {
|
||||
query := &SearchQuery{
|
||||
Query: TermQuery("category", "books"),
|
||||
Size: 10,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if result.Hits.Total.Value != 3 {
|
||||
t.Errorf("Term query found %d results, want 3", result.Hits.Total.Value)
|
||||
}
|
||||
|
||||
t.Logf("Term query found %d results", result.Hits.Total.Value)
|
||||
})
|
||||
|
||||
// Test 3: Range query
|
||||
t.Run("RangeQuery", func(t *testing.T) {
|
||||
query := &SearchQuery{
|
||||
Query: RangeQuery("price", 40, 50),
|
||||
Size: 10,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if result.Hits.Total.Value == 0 {
|
||||
t.Error("Range query returned no results")
|
||||
}
|
||||
|
||||
t.Logf("Range query found %d results", result.Hits.Total.Value)
|
||||
})
|
||||
|
||||
// Test 4: Bool query
|
||||
t.Run("BoolQuery", func(t *testing.T) {
|
||||
boolQ := &BoolQuery{
|
||||
Must: []map[string]any{
|
||||
TermQuery("category", "books"),
|
||||
},
|
||||
Filter: []map[string]any{
|
||||
RangeQuery("price", nil, 45),
|
||||
},
|
||||
}
|
||||
|
||||
query := &SearchQuery{
|
||||
Query: boolQ.ToBoolQuery(),
|
||||
Size: 10,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if result.Hits.Total.Value == 0 {
|
||||
t.Error("Bool query returned no results")
|
||||
}
|
||||
|
||||
t.Logf("Bool query found %d results", result.Hits.Total.Value)
|
||||
})
|
||||
|
||||
// Test 5: Match all query
|
||||
t.Run("MatchAllQuery", func(t *testing.T) {
|
||||
query := &SearchQuery{
|
||||
Query: MatchAllQuery(),
|
||||
Size: 10,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if result.Hits.Total.Value != 3 {
|
||||
t.Errorf("Match all query found %d results, want 3", result.Hits.Total.Value)
|
||||
}
|
||||
|
||||
t.Logf("Match all query found %d results", result.Hits.Total.Value)
|
||||
})
|
||||
|
||||
// Test 6: Pagination
|
||||
t.Run("Pagination", func(t *testing.T) {
|
||||
query := &SearchQuery{
|
||||
Query: MatchAllQuery(),
|
||||
Size: 1,
|
||||
From: 1,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if len(result.Hits.Hits) != 1 {
|
||||
t.Errorf("Pagination returned %d hits, want 1", len(result.Hits.Hits))
|
||||
}
|
||||
|
||||
t.Log("Pagination test passed")
|
||||
})
|
||||
|
||||
// Test 7: Multi-match query
|
||||
t.Run("MultiMatchQuery", func(t *testing.T) {
|
||||
query := &SearchQuery{
|
||||
Query: MultiMatchQuery("Programming", "title", "category"),
|
||||
Size: 10,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if result.Hits.Total.Value == 0 {
|
||||
t.Error("Multi-match query returned no results")
|
||||
}
|
||||
|
||||
t.Logf("Multi-match query found %d results", result.Hits.Total.Value)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSearch(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test in short mode")
|
||||
}
|
||||
|
||||
c := setupIntegrationTest(t)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
indexName := "test-search"
|
||||
|
||||
// Cleanup any existing index first
|
||||
_ = DeleteIndex(ctx, c, indexName)
|
||||
|
||||
// Setup
|
||||
err := CreateIndex(ctx, c, indexName, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("setup: CreateIndex() error = %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = DeleteIndex(ctx, c, indexName)
|
||||
}()
|
||||
|
||||
// Index a document
|
||||
doc := &Document{
|
||||
Source: map[string]any{
|
||||
"message": "test search",
|
||||
},
|
||||
}
|
||||
|
||||
_, err = IndexDocument(ctx, c, indexName, doc)
|
||||
if err != nil {
|
||||
t.Fatalf("setup: IndexDocument() error = %v", err)
|
||||
}
|
||||
|
||||
// Give ES a moment
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
query := &SearchQuery{
|
||||
Query: MatchAllQuery(),
|
||||
Size: 10,
|
||||
}
|
||||
|
||||
result, err := Search(ctx, c, indexName, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Search() error = %v", err)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
t.Error("Search() returned nil")
|
||||
}
|
||||
|
||||
t.Logf("Search succeeded: found %d results", result.Hits.Total.Value)
|
||||
}
|
||||
|
||||
func TestMatchQuery(t *testing.T) {
|
||||
query := MatchQuery("field", "value")
|
||||
|
||||
if query == nil {
|
||||
t.Error("MatchQuery() returned nil")
|
||||
}
|
||||
|
||||
if _, ok := query["match"]; !ok {
|
||||
t.Error("MatchQuery() missing 'match' key")
|
||||
}
|
||||
|
||||
t.Log("MatchQuery test passed")
|
||||
}
|
||||
|
||||
func TestTermQuery(t *testing.T) {
|
||||
query := TermQuery("field", "value")
|
||||
|
||||
if query == nil {
|
||||
t.Error("TermQuery() returned nil")
|
||||
}
|
||||
|
||||
if _, ok := query["term"]; !ok {
|
||||
t.Error("TermQuery() missing 'term' key")
|
||||
}
|
||||
|
||||
t.Log("TermQuery test passed")
|
||||
}
|
||||
|
||||
func TestRangeQuery(t *testing.T) {
|
||||
query := RangeQuery("age", 18, 65)
|
||||
|
||||
if query == nil {
|
||||
t.Error("RangeQuery() returned nil")
|
||||
}
|
||||
|
||||
if _, ok := query["range"]; !ok {
|
||||
t.Error("RangeQuery() missing 'range' key")
|
||||
}
|
||||
|
||||
t.Log("RangeQuery test passed")
|
||||
}
|
||||
|
||||
func TestBoolQuery(t *testing.T) {
|
||||
boolQ := &BoolQuery{
|
||||
Must: []map[string]any{
|
||||
MatchQuery("field", "value"),
|
||||
},
|
||||
}
|
||||
|
||||
query := boolQ.ToBoolQuery()
|
||||
|
||||
if query == nil {
|
||||
t.Error("ToBoolQuery() returned nil")
|
||||
}
|
||||
|
||||
if _, ok := query["bool"]; !ok {
|
||||
t.Error("ToBoolQuery() missing 'bool' key")
|
||||
}
|
||||
|
||||
t.Log("BoolQuery test passed")
|
||||
}
|
||||
Reference in New Issue
Block a user