supporting-blog-content/ollama-and-go-for-rag/elasticsearch/elasticsearch.go (52 lines of code) (raw):
package elasticsearch
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/elastic/go-elasticsearch/v8"
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
)
// Initializing elasticsearch client
func EsClient() (*elasticsearch.TypedClient, error) {
var cloudID = "" // your Elastic Cloud ID Here
var apiKey = "" // your Elastic ApiKey Here
es, err := elasticsearch.NewTypedClient(elasticsearch.Config{
CloudID: cloudID,
APIKey: apiKey,
})
if err != nil {
return nil, fmt.Errorf("unable to connect: %w", err)
}
return es, nil
}
// Searching for documents and building the context
func SemanticRetriever(client *elasticsearch.TypedClient, query string, size int) (string, error) {
// Perform the semantic search
res, err := client.Search().
Index("rag-ollama").
Query(&types.Query{
Semantic: &types.SemanticQuery{
Field: "semantic_field",
Query: query,
},
}).
Size(size).
Do(context.Background())
if err != nil {
return "", fmt.Errorf("semantic search failed: %w", err)
}
// Prepare to format the results
var output strings.Builder
output.WriteString("Documents found\n\n")
// Iterate through the search hits
for i, hit := range res.Hits.Hits {
// Define a struct to unmarshal each document
var doc struct {
Title string `json:"title"`
Content string `json:"content"`
}
// Unmarshal the document source into our struct
if err := json.Unmarshal(hit.Source_, &doc); err != nil {
return "", fmt.Errorf("failed to unmarshal document %d: %w", i, err)
}
// Append the formatted document to our output
output.WriteString(fmt.Sprintf("Title\n%s\n\nContent\n%s\n", doc.Title, doc.Content))
// Add a separator between documents, except for the last one
if i < len(res.Hits.Hits)-1 {
output.WriteString("\n-----\n\n")
}
}
// Return the formatted output as a string
return output.String(), nil
}