You are currently viewing GoからOpenSearchを利用してみる

GoからOpenSearchを利用してみる

OpenSearchを利用する場合、何かしらのプログラムから利用することにあるかと思います。
今回はGoからOpenSearchを利用してみようと思います。

といっても、OpenSearch公式に一通りのサンプルが用意されているため、記載されている方法にて実装します。

ドキュメントはこちらです
https://opensearch.org/docs/latest/clients/go/

早速コード

公式ドキュメントを流用しています。

package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"strings"

	opensearch "github.com/opensearch-project/opensearch-go"
	opensearchapi "github.com/opensearch-project/opensearch-go/opensearchapi"
)

const IndexName = "go-test-index1"

func main() {
	// Initialize the client with SSL/TLS enabled.
	client, err := opensearch.NewClient(opensearch.Config{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
		Addresses: []string{"https://localhost:9200"},
		Username:  "admin", // For testing only. Don't store credentials in code.
		Password:  "admin",
	})
	if err != nil {
		fmt.Println("cannot initialize", err)
		os.Exit(1)
	}

	// Print OpenSearch version information on console.
	fmt.Println(client.Info())

	// Define index settings.
	settings := strings.NewReader(`{
     'settings': {
       'index': {
            'number_of_shards': 1,
            'number_of_replicas': 2
            }
          }
     }`)

	// Create an index with non-default settings.
	res := opensearchapi.IndicesCreateRequest{
		Index: IndexName,
		Body:  settings,
	}
	fmt.Println("Creating index")
	fmt.Println(res)

	// Add a document to the index.
	document := strings.NewReader(`{
        "title": "Moneyball",
        "director": "Bennett Miller",
        "year": "2011"
    }`)

	docId := "1"
	req := opensearchapi.IndexRequest{
		Index:      IndexName,
		DocumentID: docId,
		Body:       document,
	}
	insertResponse, err := req.Do(context.Background(), client)
	if err != nil {
		fmt.Println("failed to insert document ", err)
		os.Exit(1)
	}
	fmt.Println("Inserting a document")
	fmt.Println(insertResponse)
	defer insertResponse.Body.Close()

	// Perform bulk operations.
	blk, err := client.Bulk(
		strings.NewReader(`
    { "index" : { "_index" : "go-test-index1", "_id" : "2" } }
    { "title" : "Interstellar", "director" : "Christopher Nolan", "year" : "2014"}
    { "create" : { "_index" : "go-test-index1", "_id" : "3" } }
    { "title" : "Star Trek Beyond", "director" : "Justin Lin", "year" : "2015"}
    { "update" : {"_id" : "3", "_index" : "go-test-index1" } }
    { "doc" : {"year" : "2016"} }
`),
	)

	if err != nil {
		fmt.Println("failed to perform bulk operations", err)
		os.Exit(1)
	}
	fmt.Println("Performing bulk operations")
	fmt.Println(blk)

	// Search for the document.
	content := strings.NewReader(`{
       "size": 5,
       "query": {
           "multi_match": {
           "query": "miller",
           "fields": ["title^2", "director"]
           }
      }
    }`)

	search := opensearchapi.SearchRequest{
		Index: []string{IndexName},
		Body:  content,
	}

	searchResponse, err := search.Do(context.Background(), client)
	if err != nil {
		fmt.Println("failed to search document ", err)
		os.Exit(1)
	}
	fmt.Println("Searching for a document")
	fmt.Println(searchResponse)
	defer searchResponse.Body.Close()

	// Delete the document.
	delete := opensearchapi.DeleteRequest{
		Index:      IndexName,
		DocumentID: docId,
	}

	deleteResponse, err := delete.Do(context.Background(), client)
	if err != nil {
		fmt.Println("failed to delete document ", err)
		os.Exit(1)
	}
	fmt.Println("Deleting a document")
	fmt.Println(deleteResponse)
	defer deleteResponse.Body.Close()

	// Delete the previously created index.
	deleteIndex := opensearchapi.IndicesDeleteRequest{
		Index: []string{IndexName},
	}

	deleteIndexResponse, err := deleteIndex.Do(context.Background(), client)
	if err != nil {
		fmt.Println("failed to delete index ", err)
		os.Exit(1)
	}
	fmt.Println("Deleting the index")
	fmt.Println(deleteIndexResponse)
	defer deleteIndexResponse.Body.Close()
}

上記を実行すると、以下のような実行結果が得られます。

インデックス作成からデータの追加、検索、そしてインデックス削除まで一連の流れがgoから行うことができます。
使い方も比較的シンプルですね

サンプルデータに対して検索をかけてみる

次はOpenSearchのサンプルデータ「opensearch_dashboards_sample_data_ecommerce」に対して検索を行ってみます。

package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"strings"

	opensearch "github.com/opensearch-project/opensearch-go"
	opensearchapi "github.com/opensearch-project/opensearch-go/opensearchapi"
)

const IndexName = "opensearch_dashboards_sample_data_ecommerce"

func main() {
	// Initialize the client with SSL/TLS enabled.
	client, err := opensearch.NewClient(opensearch.Config{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
		Addresses: []string{"https://localhost:9200"},
		Username:  "admin", // For testing only. Don't store credentials in code.
		Password:  "admin",
	})
	if err != nil {
		fmt.Println("cannot initialize", err)
		os.Exit(1)
	}

	// Print OpenSearch version information on console.
	fmt.Println(client.Info())

	// Search for the document.
	content := strings.NewReader(`{
       "size": 5,
       "query": {
           "match": {
			"customer_full_name" : "Mary"
           }
      }
    }`)

	search := opensearchapi.SearchRequest{
		Index: []string{IndexName},
		Body:  content,
	}

	searchResponse, err := search.Do(context.Background(), client)
	if err != nil {
		fmt.Println("failed to search document ", err)
		os.Exit(1)
	}
	fmt.Println("Searching for a document")
	fmt.Println(searchResponse)
	defer searchResponse.Body.Close()

}

検索だけならこれだけで実行できます。
サンプルデータに対して、顧客名が「Mary」を含むデータを検索しています。
実行結果は以下の通り。

思ったよりデータがたくさん帰ってきたため(154件)、すべての結果は載せていませんが、JSON形式でデータが返ってきました。
これなら、json.Unmarshalで構造体に変換するもの簡単にできそうです。

ただクエリの部分はJSON形式の文字列で渡す必要があるので、プログラムでクエリを組み立てるのが少し大変そうです。
別途、ヘルパーのような仕組みが無いか、調べてみるつもりです。

コメントを残す