From 57e3c6c37d916dab8d58b65e2b4c91ea9e85e0c5 Mon Sep 17 00:00:00 2001 From: Lindsay Burton Date: Mon, 12 Jan 2026 11:58:31 -0800 Subject: [PATCH 1/2] Updated Go files for v4 --- go/README.md | 12 ++ go/backup.go | 171 ++++++++++++++++++++++++++ go/change_index_settings.go | 60 ++++++++++ go/generate_key.go | 66 ++++++----- go/go.mod | 13 +- go/go.sum | 4 + go/indexing.go | 211 +++++++++++++++++---------------- go/rest_api_return_top_hits.go | 52 ++++++++ go/restore.go | 203 +++++++++++++++++++++++++++++++ go/rules.go | 106 +++++++++++++++++ go/simple.go | 75 ++++++------ 11 files changed, 802 insertions(+), 171 deletions(-) create mode 100644 go/backup.go create mode 100644 go/change_index_settings.go create mode 100644 go/rest_api_return_top_hits.go create mode 100644 go/restore.go create mode 100644 go/rules.go diff --git a/go/README.md b/go/README.md index 34629a4..3610f60 100644 --- a/go/README.md +++ b/go/README.md @@ -33,6 +33,13 @@ Install these dependencies using the go build command. ```bash go build ``` + +If you plan to access the Analytics API, please run this command, too. + +```bash +go get github.com/algolia/algoliasearch-client-go +``` + Once setup, you can run each of the script in this folder using the Go command line. Example: to execute the `simple.go` script: @@ -46,4 +53,9 @@ go run simple.go | ------------- | ------------- | | [simple.go](./simple.go) | Index a single object and run a search query | | [indexing.go](./indexing.go) | Showcase of the main indexing methods | +| [change-index-settings.go](./change-index-settings.go) | Change index settings | +| [rules.go](./rules.go) | Export rules and add a new rule to an index | +| [backup.go](./backup.go) | Backup an index | +| [restore.go](./restore.go) | Restore an index | +| [rest_api_return_top_hits.go](./rest_api_return_top_hits.go) | Get top 1000 searches with Analytics REST API | | [generate_key.go](./generate_key.go) | Generate a rate limted search API key | diff --git a/go/backup.go b/go/backup.go new file mode 100644 index 0000000..16ce6be --- /dev/null +++ b/go/backup.go @@ -0,0 +1,171 @@ +package main + +import ( + "fmt" + "log" + "os" + "github.com/algolia/algoliasearch-client-go/v4/algolia/search" + "github.com/joho/godotenv" + "encoding/json" +) + +func PrintErrAndExit(err error) { + fmt.Println(err) + os.Exit(1) +} + + +func PrintCurrentObjects() { + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + resSearch, err := client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(indexName)) + if err != nil { + // handle the eventual error + panic(err) + } + fmt.Println("Current objects: ", resSearch.Hits, "\n") +} + +func main() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + // Algolia client credentials + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + + // Start the API client + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + + // Get all records from an index + // https://www.algolia.com/doc/api-reference/api-methods/browse/#get-all-records-from-an-index + // Use an API key with `browse` ACL + resBrowseObj, err := client.Browse(client.NewApiBrowseRequest( + indexName)) + + if err != nil { + // handle the eventual error + panic(err) + } + + fmt.Println("Current objects") + PrintCurrentObjects() + + // Encode array to json + resEncodeObjJson, err := json.Marshal(resBrowseObj.Hits) + if err != nil { + log.Fatal(err) + } + + // Write json to file + err = os.WriteFile(indexName + "_records.json", resEncodeObjJson, 0644) // 0644 gives read/write permissions for the owner, and read for others + if err != nil { + log.Fatalf("Error writing to file: %v", err) + } + + // Retrieve settings for an index + // https://www.algolia.com/doc/api-reference/api-methods/get-settings/#retrieve-settings-for-an-index + resGetSettings, err := client.GetSettings(client.NewApiGetSettingsRequest( + indexName).WithGetVersion(2)) + if err != nil { + // handle the eventual error + panic(err) + } + + fmt.Println("Current settings") + fmt.Println(resGetSettings) + + // Encode array to json + resEncodeSettingsJson, err := json.Marshal(resGetSettings) + if err != nil { + log.Fatal(err) + } + + // Write json to file + err = os.WriteFile(indexName + "_settings.json", resEncodeSettingsJson, 0644) // 0644 grants read/write permissions for the owner + if err != nil { + log.Fatalf("Error writing to file: %v", err) + } + + // Export rules + // https://www.algolia.com/doc/api-reference/api-methods/export-rules/ + var rules []search.Rule + + err = client.BrowseRules( + indexName, + *search.NewEmptySearchRulesParams(), + search.WithAggregator(func(r any, err error) { + if err != nil { + log.Fatalf("There was an error: %v", err) + } + + rules = append(rules, r.(*search.SearchRulesResponse).Hits...) + }), + ) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Current rules:") + for _, rule := range rules { + fmt.Printf("- Rule: %s\n", rule.ObjectID) + } + + // Encode array to json + resEncodeRulesJson, err := json.Marshal(rules) + if err != nil { + log.Fatal(err) + } + + // Write json to file + err = os.WriteFile(indexName + "_rules.json", resEncodeRulesJson, 0644) // 0644 grants read/write permissions for the owner + if err != nil { + log.Fatalf("Error writing to file: %v", err) + } + + // Export synonyms + // https://www.algolia.com/doc/api-reference/api-methods/export-synonyms/ + var synonyms []search.SynonymHit + + err = client.BrowseSynonyms( + indexName, + *search.NewEmptySearchSynonymsParams(), + search.WithAggregator(func(r any, err error) { + if err != nil { + log.Fatalf("There was an error: %v", err) + } + + synonyms = append(synonyms, r.(*search.SearchSynonymsResponse).Hits...) + }), + ) + if err != nil { + log.Fatal(err) + } + + for _, synonym := range synonyms { + fmt.Printf("- Synonym: %s\n", synonym.ObjectID) + } + + // Encode array to json + resEncodeSynonymsJson, err := json.Marshal(synonyms) + if err != nil { + log.Fatal(err) + } + + // Write json to file + err = os.WriteFile(indexName + "_synonyms.json", resEncodeSynonymsJson, 0644) // 0644 grants read/write permissions for the owner + if err != nil { + log.Fatalf("Error writing to file: %v", err) + } +} \ No newline at end of file diff --git a/go/change_index_settings.go b/go/change_index_settings.go new file mode 100644 index 0000000..50a4b6c --- /dev/null +++ b/go/change_index_settings.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "log" + "os" + "github.com/algolia/algoliasearch-client-go/v4/algolia/search" + "github.com/joho/godotenv" +) + +func PrintErrAndExit(err error) { + fmt.Println(err) + os.Exit(1) +} + +func main() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + // Algolia client credentials + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + + // Start the API client + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + + //Setting settings + //https://www.algolia.com/doc/libraries/sdk/methods/search/set-settings + resSetSettings, err := client.SetSettings(client.NewApiSetSettingsRequest( + indexName, + search.NewEmptyIndexSettings().SetSearchableAttributes( + []string{"actors", "genre"}, + )).WithForwardToReplicas(true), + ) + if err != nil { + PrintErrAndExit(err) + } + _, err = client.WaitForTask(indexName, resSetSettings.TaskID) + if err != nil { + PrintErrAndExit(err) + } + + //Printing settings + //https://www.algolia.com/doc/api-reference/api-methods/get-settings/ + fmt.Println("Index settings:") + resGetSettings, err := client.GetSettings(client.NewApiGetSettingsRequest( + indexName).WithGetVersion(2)) + if err != nil { + // handle the eventual error + panic(err) + } + + fmt.Println(resGetSettings) +} \ No newline at end of file diff --git a/go/generate_key.go b/go/generate_key.go index 4c36f8d..c859ccf 100644 --- a/go/generate_key.go +++ b/go/generate_key.go @@ -10,41 +10,35 @@ import ( "fmt" "log" "os" - - "github.com/algolia/algoliasearch-client-go/v3/algolia/search" + "github.com/algolia/algoliasearch-client-go/v4/algolia/search" "github.com/joho/godotenv" ) func main() { - var err error - - err = godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") + if err := godotenv.Load(); err != nil { + log.Fatalf("godotenv.Load: %v", err) } - // Get your Algolia Application ID and (admin) API key from the dashboard: https://www.algolia.com/account/api-keys - // and choose a name for your index. Add these environment variables to a `.env` file: + + // Algolia client credentials appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") // Start the API client - // https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/ - client := search.NewClient(appID, apiKey) + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } // Create the API key. // https://www.algolia.com/doc/api-reference/api-methods/add-api-key/?client=go fmt.Println("Generating key...") - - keyParams := search.Key{ - ACL: []string{"search"}, - Description: "Restricted search-only API key for algolia.com", - MaxQueriesPerIPPerHour: 100, - } - var key string - var keyRes search.CreateKeyRes - keyRes, err = client.AddAPIKey(keyParams) - err = keyRes.Wait() + keyRes, err := client.AddApiKey(client.NewApiAddApiKeyRequest( + search.NewEmptyApiKey().SetAcl( + []search.Acl{search.Acl("search")}).SetDescription("Restricted search-only API key for algolia.com"))) if err != nil { panic(errors.New("Error generating key.")) } else { @@ -52,24 +46,36 @@ func main() { fmt.Println("Key generated successfully:", key) } + // Wait for API key + // https://www.algolia.com/doc/libraries/sdk/methods/search/wait-for-api-key + resWaitForKey, err := client.WaitForApiKey( + key, search.ApiKeyOperation("add")) + if err != nil { + // handle the eventual error + panic(err) + } else { + fmt.Println("Task is complete.") + fmt.Println(resWaitForKey) + } + // Test the new key fmt.Println("Testing key...") // Initialise a new client with the generated key - client = search.NewClient(appID, key) - - // Create an index (or connect to it, if an index with the name `ALGOLIA_INDEX_NAME` already exists) - // https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/#initialize-an-index - index := client.InitIndex(indexName) + newClient, err := search.NewClient(appID, key) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } // Search the index with an empty string // https://www.algolia.com/doc/api-reference/api-methods/search/ - var indexRes search.QueryRes - - indexRes, err = index.Search("") + indexRes, err := newClient.SearchSingleIndex(newClient.NewApiSearchSingleIndexRequest(indexName)) if err != nil { panic(errors.New("Error testing key.")) + fmt.Println(err) } else { - fmt.Println("Key tested successfully.", indexRes.NbHits, "hits found.") + fmt.Println("Key tested successfully.", len(indexRes.Hits), "hits found.") } } diff --git a/go/go.mod b/go/go.mod index 11cd253..abd61bd 100644 --- a/go/go.mod +++ b/go/go.mod @@ -1,8 +1,17 @@ module github.com/algolia-samples/api-clients-quickstart -go 1.16 +go 1.21.11 + +require github.com/algolia/algoliasearch-client-go/v3 v3.4.0 require ( - github.com/algolia/algoliasearch-client-go/v3 v3.4.0 + github.com/algolia/algoliasearch-client-go v2.25.0+incompatible // indirect + github.com/algolia/algoliasearch-client-go/v4 v4.34.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/joho/godotenv v1.4.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.1.0 // indirect + github.com/stretchr/testify v1.4.0 // indirect + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect ) diff --git a/go/go.sum b/go/go.sum index 07ef16f..0db527d 100644 --- a/go/go.sum +++ b/go/go.sum @@ -1,5 +1,9 @@ +github.com/algolia/algoliasearch-client-go v2.25.0+incompatible h1:FGQr9l++u4uQPDXrW8jM5kNJm3Iw5SxEJJtYXSFmPRY= +github.com/algolia/algoliasearch-client-go v2.25.0+incompatible/go.mod h1:4NR25U+0vkfx/0J5l+kOHJ1iPnqOTTBxfd3aALKU+aw= github.com/algolia/algoliasearch-client-go/v3 v3.4.0 h1:eeVU30L5DkKUK2q/EjXw+8o7reoK4QB1mS+BG0Jbd4Y= github.com/algolia/algoliasearch-client-go/v3 v3.4.0/go.mod h1:d0/D54BCmkwhLxT5VIQBeYLAz2GbZHFX9OptYyohTr0= +github.com/algolia/algoliasearch-client-go/v4 v4.34.1 h1:I7LDIRpyrhYG5FYb5NM7aYbZ/OTUBb6d94NSw2qdEDY= +github.com/algolia/algoliasearch-client-go/v4 v4.34.1/go.mod h1:2bHeze2/5+jvT8IYVq8j2NDLr/4R6erGxgud7ESuXww= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/go/indexing.go b/go/indexing.go index 35b2fa8..1751561 100644 --- a/go/indexing.go +++ b/go/indexing.go @@ -4,27 +4,28 @@ import ( "fmt" "log" "os" - - "github.com/algolia/algoliasearch-client-go/v3/algolia/opt" - "github.com/algolia/algoliasearch-client-go/v3/algolia/search" + "github.com/algolia/algoliasearch-client-go/v4/algolia/search" "github.com/joho/godotenv" + "strconv" ) -type Contact struct { - ObjectID string `json:"objectID,omitempty"` - Name string `json:"name,omitempty"` - Email string `json:"email,omitempty"` -} - func PrintErrAndExit(err error) { fmt.Println(err) os.Exit(1) } -func PrintCurrentObjects(i search.Index) { - resSearch, err := i.Search("") +func PrintCurrentObjects() { + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + client, err := search.NewClient(appID, apiKey) if err != nil { - PrintErrAndExit(err) + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + resSearch, err := client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(indexName)) + if err != nil { + // handle the eventual error + panic(err) } fmt.Println("Current objects: ", resSearch.Hits, "\n") } @@ -37,113 +38,123 @@ func main() { // Algolia client credentials appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") - // Initialize the client - // https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/ - client := search.NewClient(appID, apiKey) - - // Initialize an index - // https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/#initialize-an-index - index := client.InitIndex(indexName) + // Start the API client + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } // Define some objects to add to our index - // https://www.algolia.com/doc/api-client/methods/indexing/#object-and-record - contacts := []Contact{ - { - Name: "Foo", - ObjectID: "1", - }, - { - Name: "Bar", - ObjectID: "2", - }, + contacts := []map[string]any{ + map[string]any{"objectID": "1", "name": "Foo"}, + map[string]any{"objectID": "2", "name": "Bar"}, } // We don't have any objects (yet) in our index - PrintCurrentObjects(*index) + PrintCurrentObjects() // Save Objects: Add mutliple new objects to an index. - // https://www.algolia.com/doc/api-reference/api-methods/add-objects/?client=go + // https://www.algolia.com/doc/libraries/sdk/methods/search/save-objects fmt.Println("Save Objects - Adding multiple objects: ", contacts) - resSaveMultiple, err := index.SaveObjects(contacts) + + resSaveMultiple, err := client.SaveObjects(indexName,contacts) + if err != nil { PrintErrAndExit(err) } - err = resSaveMultiple.Wait() + + _, err = client.WaitForTask(indexName, resSaveMultiple[len(resSaveMultiple)-1].TaskID) + if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() // Save Objects: Replace an existing object with an updated set of attributes. - // https://www.algolia.com/doc/api-reference/api-methods/save-objects/?client=go + // https://www.algolia.com/doc/libraries/sdk/v1/methods/save-objects fmt.Println("Save Objects - Replacing objects’s attributes on:", contacts[0]) - newContact := Contact{ - Name: "FooBar", - ObjectID: "1", + newContact := map[string]any{ + "name": "FooBar", + "objectID": "1", } - resSaveSingle, err := index.SaveObject(newContact) + + resSaveSingle, err := client.SaveObject(client.NewApiSaveObjectRequest( + indexName, + newContact, + )) + if err != nil { PrintErrAndExit(err) } - err = resSaveSingle.Wait() + + _, err = client.WaitForTask(indexName, resSaveSingle.TaskID) + if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() // Partial Update Objects: Update one or more attributes of an existing object. // https://www.algolia.com/doc/api-reference/api-methods/partial-update-objects/?client=go fmt.Println("Partial Update Objects - Updating object’s attributes on:", contacts[0]) - newContact = Contact{ - Email: "foo@bar.com", // New attribute - ObjectID: "1", + + newUpdate := map[string]any{ + "email": "foo@bar.com", } - resPartialUpdate, err := index.PartialUpdateObject(newContact) + + resPartialUpdate, err := client.PartialUpdateObject(client.NewApiPartialUpdateObjectRequest( + indexName, + "1", + newUpdate)) + if err != nil { PrintErrAndExit(err) } - err = resPartialUpdate.Wait() + fmt.Println(resPartialUpdate) if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() // Delete Objects: Remove objects from an index using their objectID. // https://www.algolia.com/doc/api-reference/api-methods/delete-objects/?client=go - objectIDToDelete := contacts[0].ObjectID + objectIDToDelete := 1 fmt.Println("Delete Objects - Deleting object with objectID:", objectIDToDelete) - resDelete, err := index.DeleteObject(objectIDToDelete) + resDelete, err := client.DeleteObject(client.NewApiDeleteObjectRequest( + indexName, strconv.Itoa(objectIDToDelete))) if err != nil { PrintErrAndExit(err) } - err = resDelete.Wait() + _, err = client.WaitForTask(indexName, resDelete.TaskID) if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() // Replace All Objects: Clears all objects from your index and replaces them with a new set of objects. // https://www.algolia.com/doc/api-reference/api-methods/replace-all-objects/?client=go - newContacts := []Contact{ - { - Name: "NewFoo", - ObjectID: "3", - }, - { - Name: "NewBar", - ObjectID: "4", - }, + newContacts := []map[string]any{ + {"objectID": "1", "name": "Adam"}, + {"objectID": "2", "name": "Benoit"}, } fmt.Println("Replace All Objects - Clears all objects and replaces them with:", newContacts) - resReplaceAll, err := index.ReplaceAllObjects(newContacts) + resReplaceAll, err := client.ReplaceAllObjects( + indexName, + newContacts, + search.WithBatchSize(77), + search.WithScopes([]search.ScopeType{search.ScopeType("settings"), search.ScopeType("synonyms")}), + ) if err != nil { PrintErrAndExit(err) } - err = resReplaceAll.Wait() + _, err = client.WaitForTask(indexName, resReplaceAll.MoveOperationResponse.TaskID); if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() // Delete By: Remove all objects matching a filter (including geo filters). // https://www.algolia.com/doc/api-reference/api-methods/delete-by/?client=go @@ -151,34 +162,44 @@ func main() { // Firstly, have an attribute to filter on // https://www.algolia.com/doc/api-client/methods/settings/?client=go - resSetSettings, err := index.SetSettings(search.Settings{ - AttributesForFaceting: opt.AttributesForFaceting("name"), - }) + resSetSettings, err := client.SetSettings(client.NewApiSetSettingsRequest( + indexName, + search.NewEmptyIndexSettings().SetAttributesForFaceting( + []string{"name"}, + )).WithForwardToReplicas(true), + ) if err != nil { PrintErrAndExit(err) } - err = resSetSettings.Wait() + _, err = client.WaitForTask(indexName, resSetSettings.TaskID) if err != nil { PrintErrAndExit(err) } - resDeleteBy, err := index.DeleteBy(opt.Filters("name:NewBar")) // https://www.algolia.com/doc/api-reference/api-parameters/filters/ + // https://www.algolia.com/doc/api-reference/api-parameters/filters/ + resDeleteBy, err := client.DeleteBy(client.NewApiDeleteByRequest( + indexName, + search.NewEmptyDeleteByParams().SetFilters("name:NewBar")), + ) if err != nil { PrintErrAndExit(err) } - err = resDeleteBy.Wait() + _, err = client.WaitForTask(indexName, resDeleteBy.TaskID) if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() // Get Objects: Get one or more objects using their objectIDs. // https://www.algolia.com/doc/api-reference/api-methods/get-objects/?client=go - objectID := newContacts[0].ObjectID + objectID := newContacts[0]["objectID"] + objectIDStr := fmt.Sprint(objectID) fmt.Println("Get Objects - Getting object with objectID:", objectID) - var retrievedContact Contact - err = index.GetObject(objectID, &retrievedContact) + retrievedContact, err := client.GetObject(client.NewApiGetObjectRequest( + indexName, objectIDStr).WithAttributesToRetrieve( + []string{"objectID", objectIDStr}), + ) if err != nil { PrintErrAndExit(err) } @@ -186,48 +207,38 @@ func main() { // Custom Batch: Perform several indexing operations in one API call. // https://www.algolia.com/doc/api-reference/api-methods/batch/?client=go - operations := []search.BatchOperationIndexed{ - { - IndexName: indexName, - BatchOperation: search.BatchOperation{ - Action: search.AddObject, - Body: Contact{ - Name: "BatchedBar", - }, - }, - }, - { - IndexName: indexName, - BatchOperation: search.BatchOperation{ - Action: search.UpdateObject, - Body: Contact{ - ObjectID: objectID, - Name: "NewBatchedBar", - }, - }, - }, - } + operations := search.NewEmptyBatchWriteParams().SetRequests( + []search.BatchRequest{ + *search.NewEmptyBatchRequest().SetAction(search.Action("addObject")).SetBody(map[string]any{"Name": "BatchedBar"}), + *search.NewEmptyBatchRequest().SetAction(search.Action("addObject")).SetBody(map[string]any{"Name": "NewBatchedBar"}), + }) + fmt.Println("Custom Batch - Batching operations:", operations) - resBatch, err := client.MultipleBatch(operations) + resBatch, err := client.Batch(client.NewApiBatchRequest( + indexName, + operations), + ) if err != nil { PrintErrAndExit(err) } - err = resBatch.Wait() + _, err = client.WaitForTask(indexName, resBatch.TaskID) if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() // Clear Objects: Clear the records of an index without affecting its settings. // https://www.algolia.com/doc/api-reference/api-methods/clear-objects/?client=go fmt.Println("Clear Objects: Clear the records of an index without affecting its settings.") - resClear, err := index.ClearObjects() + resClear, err := client.ClearObjects(client.NewApiClearObjectsRequest(indexName)) if err != nil { PrintErrAndExit(err) } - err = resClear.Wait() + + _, err = client.WaitForTask(indexName, resClear.TaskID) + if err != nil { PrintErrAndExit(err) } - PrintCurrentObjects(*index) + PrintCurrentObjects() } diff --git a/go/rest_api_return_top_hits.go b/go/rest_api_return_top_hits.go new file mode 100644 index 0000000..916ad03 --- /dev/null +++ b/go/rest_api_return_top_hits.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "log" + "os" + "github.com/algolia/algoliasearch-client-go/v4/algolia/analytics" + "github.com/joho/godotenv" + "encoding/json" +) + +func PrintErrAndExit(err error) { + fmt.Println(err) + os.Exit(1) +} + +func main() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + // Algolia client credentials + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + + // Start the API client + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + // Initialize the client with your application region, eg. analytics.ALGOLIA_APPLICATION_REGION + client, err := analytics.NewClient(appID, apiKey, analytics.US) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + + resTopSearches, err := client.GetTopSearches(client.NewApiGetTopSearchesRequest(indexName).WithLimit(1000),) + if err != nil { + // handle the eventual error + panic(err) + } + + // Format the resulting json string + resEncodeTopSearchesJson, err := json.Marshal(resTopSearches) + if err != nil { + log.Fatal(err) + } + + // Write json to file + err = os.WriteFile(indexName + "_top_1000_searches.json", resEncodeTopSearchesJson, 0644) // 0644 grants read/write permissions for the owner, and read for others + if err != nil { + log.Fatalf("Error writing to file: %v", err) + } +} \ No newline at end of file diff --git a/go/restore.go b/go/restore.go new file mode 100644 index 0000000..f509a64 --- /dev/null +++ b/go/restore.go @@ -0,0 +1,203 @@ +package main + +import ( + "fmt" + "log" + "os" + "io/ioutil" + "github.com/algolia/algoliasearch-client-go/v4/algolia/search" + "github.com/joho/godotenv" + "encoding/json" +) + +func PrintErrAndExit(err error) { + fmt.Println(err) + os.Exit(1) +} + + +func PrintCurrentObjects() { + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + resSearch, err := client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(indexName)) + if err != nil { + // handle the eventual error + panic(err) + } + fmt.Println("Current objects: ", resSearch.Hits, "\n") +} + +func main() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + // Algolia client credentials + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + + // Start the API client + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + + // Restoring all records with replace all objects method + // https://www.algolia.com/doc/api-reference/api-methods/replace-all-objects/ + + // Read json file + fmt.Println("Records:") + recordsFile := indexName + "_records.json" + jsonFile, err := os.Open(recordsFile) + if err != nil { + fmt.Printf("failed to open json file: %s, error: %v", recordsFile, err) + return + } + defer jsonFile.Close() + + byteValue, _ := ioutil.ReadAll(jsonFile) + + var result []map[string]any + json.Unmarshal([]byte(byteValue), &result) + + fmt.Println(result) + + // Restore Records + resReplaceObj, err := client.ReplaceAllObjects(indexName, result) + if err != nil { + // handle the eventual error + panic(err) + } + + _, err = client.WaitForTask(indexName, resReplaceObj.MoveOperationResponse.TaskID); + if err != nil { + PrintErrAndExit(err) + } + + fmt.Println("Records restored") + + // Restoring settings with set settings method + // https://www.algolia.com/doc/api-reference/api-methods/set-settings/ + + // Read json file + fmt.Println("Index settings") + settingsFileName := indexName + "_settings.json" + settingsFile, err := os.Open(settingsFileName) + if err != nil { + fmt.Printf("failed to open json file: %s, error: %v", settingsFileName, err) + return + } + defer jsonFile.Close() + + settingsJson, _ := ioutil.ReadAll(settingsFile) + + settings := search.NewEmptyIndexSettings() + json.Unmarshal(settingsJson, settings) + + fmt.Println(settings) + + // Restore settings + resSetSettings, err := client.SetSettings( + client.NewApiSetSettingsRequest(indexName, settings). + WithForwardToReplicas(true), + ) + if err != nil { + // handle the eventual error + panic(err) + } + + _, err = client.WaitForTask(indexName, resSetSettings.TaskID) + if err != nil { + PrintErrAndExit(err) + } + + fmt.Println("Settings restored") + + // Restoring Rules with replace all rules method + // https://www.algolia.com/doc/api-reference/api-methods/replace-all-rules/ + + // Read json file + fmt.Println("Rules:") + rulesFileName := indexName + "_rules.json" + rulesFile, err := os.Open(rulesFileName) + if err != nil { + fmt.Printf("failed to open json file: %s, error: %v", rulesFileName, err) + return + } + defer rulesFile.Close() + + rulesJson, _ := ioutil.ReadAll(rulesFile) + + var rules []search.Rule + json.Unmarshal(rulesJson, &rules) + + fmt.Println(rules) + + // Restore Rules + resSaveRules, err := client.SaveRules( + client.NewApiSaveRulesRequest( + indexName, + rules, + ). + WithForwardToReplicas(false). + WithClearExistingRules(true), + ) + if err != nil { + PrintErrAndExit(err) + } + + _, err = client.WaitForTask(indexName, resSaveRules.TaskID) + if err != nil { + PrintErrAndExit(err) + } + + fmt.Println("Rules restored") + + // Restoring Synonyms with replace all synonyms method + // https://www.algolia.com/doc/api-reference/api-methods/replace-all-synonyms/?client=php + + // Read json file + fmt.Println("Synonyms:") + synonymsFileName := indexName + "_synonyms.json" + synonymsFile, err := os.Open(synonymsFileName) + if err != nil { + fmt.Printf("failed to open json file: %s, error: %v", synonymsFileName, err) + return + } + defer synonymsFile.Close() + + synonymsJson, _ := ioutil.ReadAll(synonymsFile) + + var synonyms []search.SynonymHit + json.Unmarshal(synonymsJson, &synonyms) + + fmt.Println(synonyms) + + // Restore Synonyms + resSaveSynonyms, err := client.SaveSynonyms( + client.NewApiSaveSynonymsRequest( + indexName, + synonyms, + ). + WithForwardToReplicas(true). + WithReplaceExistingSynonyms(true), + ) + if err != nil { + PrintErrAndExit(err) + } + + _, err = client.WaitForTask(indexName, resSaveSynonyms.TaskID) + if err != nil { + PrintErrAndExit(err) + } + + fmt.Println("Synonyms restored") + +} \ No newline at end of file diff --git a/go/rules.go b/go/rules.go new file mode 100644 index 0000000..f5af607 --- /dev/null +++ b/go/rules.go @@ -0,0 +1,106 @@ +package main + +import ( + "fmt" + "log" + "os" + "github.com/algolia/algoliasearch-client-go/v4/algolia/search" + "github.com/joho/godotenv" +) + +func PrintErrAndExit(err error) { + fmt.Println(err) + os.Exit(1) +} + +func main() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + // Algolia client credentials + appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") + + // Start the API client + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + client, err := search.NewClient(appID, apiKey) + if err != nil { + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) + } + + // Exporting the rules + // https://www.algolia.com/doc/api-reference/api-methods/export-rules/#examples + fmt.Printf("Original rules:\n") + + var rules []search.Rule + + err = client.BrowseRules( + indexName, + *search.NewEmptySearchRulesParams(), + search.WithAggregator(func(r any, err error) { + if err != nil { + log.Fatalf("There was an error: %v", err) + } + + rules = append(rules, r.(*search.SearchRulesResponse).Hits...) + }), + ) + if err != nil { + log.Fatal(err) + } + + for _, rule := range rules { + fmt.Printf("- Rule: %s\n", rule.ObjectID) + } + + // Adding a new rule + // https://www.algolia.com/doc/api-reference/api-methods/save-rule/#save-a-rule + objectID := "id1" + fmt.Println("Adding a new rule called:", objectID) + resSaveRule, err := client.SaveRule(client.NewApiSaveRuleRequest( + indexName, objectID, + search.NewEmptyRule().SetObjectID(objectID).SetConditions( + []search.Condition{*search.NewEmptyCondition().SetPattern("flower").SetAnchoring(search.Anchoring("contains"))}).SetConsequence( + search.NewEmptyConsequence().SetPromote( + []search.Promote{*search.PromoteObjectIDAsPromote( + search.NewEmptyPromoteObjectID().SetObjectID("439957720").SetPosition(0))})))) + + if err != nil { + PrintErrAndExit(err) + } + _, err = client.WaitForTask(indexName, resSaveRule.TaskID) + if err != nil { + PrintErrAndExit(err) + } + + + // print the response + fmt.Println(resSaveRule) + + // Exporting the modified rules + // https://www.algolia.com/doc/api-reference/api-methods/export-rules/#examples + fmt.Printf("Updated rules:\n") + + var updatedRules []search.Rule + + err = client.BrowseRules( + indexName, + *search.NewEmptySearchRulesParams(), + search.WithAggregator(func(r any, err error) { + if err != nil { + log.Fatalf("There was an error: %v", err) + } + + updatedRules = append(updatedRules, r.(*search.SearchRulesResponse).Hits...) + }), + ) + if err != nil { + log.Fatal(err) + } + + for _, rule := range updatedRules { + fmt.Printf("- Rule: %s\n", rule.ObjectID) + } +} \ No newline at end of file diff --git a/go/simple.go b/go/simple.go index caebc04..b9bc0ea 100644 --- a/go/simple.go +++ b/go/simple.go @@ -4,66 +4,63 @@ package main import ( "fmt" "os" - "github.com/algolia/algoliasearch-client-go/v3/algolia/search" + "github.com/algolia/algoliasearch-client-go/v4/algolia/search" "github.com/joho/godotenv" "log" ) -type Contact struct { - ObjectID string `json:"objectID"` - Name string `json:"name"` -} - func main() { err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } - // Get your Algolia Application ID and (admin) API key from the dashboard: https://www.algolia.com/account/api-keys - // and choose a name for your index. Add these environment variables to a `.env` file: + + // Get your Algolia Application ID and (admin) API key from the dashboard: https://www.algolia.com/account/api-keys + // and choose a name for your index. Add these environment variables to a `.env` file: appID, apiKey, indexName := os.Getenv("ALGOLIA_APP_ID"), os.Getenv("ALGOLIA_API_KEY"), os.Getenv("ALGOLIA_INDEX_NAME") // Start the API client - // https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/ - client := search.NewClient(appID, apiKey) - - // Create an index (or connect to it, if an index with the name `ALGOLIA_INDEX_NAME` already exists) - // https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/#initialize-an-index - index := client.InitIndex(indexName) - - // Add new objects to the index - // https://www.algolia.com/doc/api-reference/api-methods/add-objects/ - resSave, err := index.SaveObjects([]Contact{ - {ObjectID: "1", Name: "Foo"}, - }) + // https://www.algolia.com/doc/libraries/sdk/methods/search#go + client, err := search.NewClient(appID, apiKey) if err != nil { - fmt.Println(err) - os.Exit(1) + // The client can fail to initialize if you pass an invalid parameter. + fmt.Printf("Client error") + panic(err) } - // Wait for the indexing task to complete - // https://www.algolia.com/doc/api-reference/api-methods/wait-task/ - err = resSave.Wait() - if err != nil { - fmt.Println(err) - os.Exit(1) + // Add new objects to the index + // https://www.algolia.com/doc/libraries/sdk/methods/search/save-objects + resSave, saveObjsErr := client.SaveObjects( + indexName, + []map[string]any{ + { + "objectID": "1", + "name": "Foo", + }, + }, + ) + if saveObjsErr != nil { + // handle the eventual error + panic(saveObjsErr) } - // Search the index for "Fo" - // https://www.algolia.com/doc/api-reference/api-methods/search/ - res, err := index.Search("Foo") + _, err = client.WaitForTask(indexName, resSave[len(resSave)-1].TaskID) if err != nil { - fmt.Println(err) - os.Exit(1) + fmt.Print("Error") + log.Fatal(err) } - var contacts []Contact - - err = res.UnmarshalHits(&contacts) + // Search the index for "Foo" + respSearch, err := client.Search(client.NewApiSearchRequest( + search.NewEmptySearchMethodParams().SetRequests( + []search.SearchQuery{*search.SearchForHitsAsSearchQuery( + search.NewEmptySearchForHits().SetIndexName(indexName).SetQuery("Foo").SetHitsPerPage(50))}), + )) if err != nil { - fmt.Println(err) - os.Exit(1) + // handle the eventual error + panic(err) } - fmt.Println("search results: ", contacts) + fmt.Println(respSearch.Results); + } From 430e7edfb1d660110f5a682fef8f85e0dd3fd881 Mon Sep 17 00:00:00 2001 From: Lindsay Burton Date: Fri, 23 Jan 2026 14:08:08 -0800 Subject: [PATCH 2/2] Updating file name for analytics quickstart file --- go/README.md | 2 +- go/{rest_api_return_top_hits.go => return_top_hits.go} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename go/{rest_api_return_top_hits.go => return_top_hits.go} (100%) diff --git a/go/README.md b/go/README.md index 3610f60..43ba600 100644 --- a/go/README.md +++ b/go/README.md @@ -57,5 +57,5 @@ go run simple.go | [rules.go](./rules.go) | Export rules and add a new rule to an index | | [backup.go](./backup.go) | Backup an index | | [restore.go](./restore.go) | Restore an index | -| [rest_api_return_top_hits.go](./rest_api_return_top_hits.go) | Get top 1000 searches with Analytics REST API | +| [return_top_hits.go](./rest_api_return_top_hits.go) | Get top 1000 searches with Analytics REST API | | [generate_key.go](./generate_key.go) | Generate a rate limted search API key | diff --git a/go/rest_api_return_top_hits.go b/go/return_top_hits.go similarity index 100% rename from go/rest_api_return_top_hits.go rename to go/return_top_hits.go