Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapping and Search Template API support #4

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 88 additions & 16 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ import (

// Searcher set the contract to manage indices, synchronize data and request
type Client interface {
CreateIndex(indexName, mapping string) (*Response, error)
CreateIndex(indexName, settings string) (*Response, error)
DeleteIndex(indexName string) (*Response, error)
UpdateIndexSetting(indexName, mapping string) (*Response, error)
UpdateIndexSetting(indexName, settings string) (*Response, error)
IndexSettings(indexName string) (Settings, error)
IndexExists(indexName string) (bool, error)
GetMapping(indexName, datatype string) ([]byte, error)
PutMapping(indexName, datatype, mapping string) (*Response, error)
Status(indices string) (*Settings, error)
InsertDocument(indexName, documentType, identifier string, data []byte) (*InsertDocument, error)
Document(indexName, documentType, identifier string) (*Document, error)
DeleteDocument(indexName, documentType, identifier string) (*Document, error)
Bulk(data []byte) (*Bulk, error)
Search(indexName, documentType, data string, explain bool) (*SearchResult, error)
MSearch(queries []MSearchQuery) (*MSearchResult, error)
CreateSearchTemplate(name, template string) (*Response, error)
SearchTemplate(indexName, data string, explain bool) (*SearchResult, error)
Suggest(indexName, data string) ([]byte, error)
GetIndicesFromAlias(alias string) ([]string, error)
UpdateAlias(remove []string, add []string, alias string) (*Response, error)
Expand Down Expand Up @@ -56,11 +60,11 @@ func NewClientFromUrl(rawurl string) Client {
}

// CreateIndex instantiates an index
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html
func (c *client) CreateIndex(indexName, mapping string) (*Response, error) {
// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-create-index.html
func (c *client) CreateIndex(indexName, settings string) (*Response, error) {
url := c.Host.String() + "/" + indexName
reader := bytes.NewBufferString(mapping)
response, err := sendHTTPRequest("POST", url, reader)
reader := bytes.NewBufferString(settings)
response, err := sendHTTPRequest("PUT", url, reader)
if err != nil {
return &Response{}, err
}
Expand All @@ -75,7 +79,7 @@ func (c *client) CreateIndex(indexName, mapping string) (*Response, error) {
}

// DeleteIndex deletes an existing index.
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-delete-index.html
// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-delete-index.html
func (c *client) DeleteIndex(indexName string) (*Response, error) {
url := c.Host.String() + "/" + indexName
response, err := sendHTTPRequest("DELETE", url, nil)
Expand All @@ -93,10 +97,10 @@ func (c *client) DeleteIndex(indexName string) (*Response, error) {
}

// UpdateIndexSetting changes specific index level settings in real time
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-update-settings.html
func (c *client) UpdateIndexSetting(indexName, mapping string) (*Response, error) {
// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-update-settings.html
func (c *client) UpdateIndexSetting(indexName, settings string) (*Response, error) {
url := c.Host.String() + "/" + indexName + "/_settings"
reader := bytes.NewBufferString(mapping)
reader := bytes.NewBufferString(settings)
response, err := sendHTTPRequest("PUT", url, reader)
if err != nil {
return &Response{}, err
Expand All @@ -112,7 +116,7 @@ func (c *client) UpdateIndexSetting(indexName, mapping string) (*Response, error
}

// IndexSettings allows to retrieve settings of index
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-settings.html
// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-get-settings.html
func (c *client) IndexSettings(indexName string) (Settings, error) {
url := c.Host.String() + "/" + indexName + "/_settings"
response, err := sendHTTPRequest("GET", url, nil)
Expand All @@ -132,7 +136,7 @@ func (c *client) IndexSettings(indexName string) (Settings, error) {
}

// IndexExists allows to check if the index exists or not.
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-exists.html
// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-exists.html
func (c *client) IndexExists(indexName string) (bool, error) {
url := c.Host.String() + "/" + indexName
httpClient := &http.Client{}
Expand All @@ -144,6 +148,33 @@ func (c *client) IndexExists(indexName string) (bool, error) {
return newReq.StatusCode == http.StatusOK, nil
}

// GetMapping allows to retrieve mappings for index
// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-get-mapping.html
func (c *client) GetMapping(indexName, datatype string) ([]byte, error) {
url := c.Host.String() + "/" + indexName + "/_mapping/" + datatype
response, err := sendHTTPRequest("GET", url, nil)
return response, err
}

// PutMapping allows to update mappings for index
// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-put-mapping.html
func (c *client) PutMapping(indexName, datatype, mapping string) (*Response, error) {
url := c.Host.String() + "/" + indexName + "/_mapping/" + datatype
reader := bytes.NewBufferString(mapping)
response, err := sendHTTPRequest("PUT", url, reader)
if err != nil {
return &Response{}, err
}

esResp := &Response{}
err = json.Unmarshal(response, esResp)
if err != nil {
return &Response{}, err
}

return esResp, nil
}

// Status allows to get a comprehensive status information
func (c *client) Status(indices string) (*Settings, error) {
url := c.Host.String() + "/" + indices + "/_status"
Expand Down Expand Up @@ -243,7 +274,7 @@ func (c *client) Search(indexName, documentType, data string, explain bool) (*Se
documentType = documentType + "/"
}

url := c.Host.String() + "/" + indexName + "/" + documentType + "/_search"
url := c.Host.String() + "/" + indexName + "/" + documentType + "_search"
if explain {
url += "?explain"
}
Expand Down Expand Up @@ -289,6 +320,45 @@ func (c *client) MSearch(queries []MSearchQuery) (*MSearchResult, error) {
return esResp, nil
}

// CreateSearchTemplate add new stored search template
func (c *client) CreateSearchTemplate(name, template string) (*Response, error) {
url := c.Host.String() + "/_search/template/" + name
reader := bytes.NewBufferString(template)
response, err := sendHTTPRequest("POST", url, reader)
if err != nil {
return &Response{}, err
}

esResp := &Response{}
err = json.Unmarshal(response, esResp)
if err != nil {
return &Response{}, err
}

return esResp, nil
}

// SearchTemplate allows to execute search with search template
func (c *client) SearchTemplate(indexName, data string, explain bool) (*SearchResult, error) {
url := c.Host.String() + "/" + indexName + "/_search/template"
if explain {
url += "?explain"
}
reader := bytes.NewBufferString(data)
response, err := sendHTTPRequest("POST", url, reader)
if err != nil {
return &SearchResult{}, err
}

esResp := &SearchResult{}
err = json.Unmarshal(response, esResp)
if err != nil {
return &SearchResult{}, err
}

return esResp, nil
}

// Suggest allows basic auto-complete functionality.
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
func (c *client) Suggest(indexName, data string) ([]byte, error) {
Expand Down Expand Up @@ -366,9 +436,11 @@ func sendHTTPRequest(method, url string, body io.Reader) ([]byte, error) {
return nil, err
}

if method == "POST" || method == "PUT" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
// if method == "POST" || method == "PUT" {
// req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
// } else {
// }
req.Header.Set("Content-Type", "application/json")

newReq, err := client.Do(req)
if err != nil {
Expand Down
61 changes: 48 additions & 13 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package elasticsearch_test
import (
"bytes"
"encoding/json"
"strings"
"testing"
"time"

"github.com/maximelamure/elasticsearch"
// "github.com/maximelamure/elasticsearch"
"github.com/walm/elasticsearch"
)

var (
ProductDocumentType = "PRODUCT"
ProductMapping = `{ "properties": { "colors": { "type": "string" } } }`
ESScheme = "http"
ESHost = "localhost"
ESPort = "9200"
Expand Down Expand Up @@ -64,6 +67,21 @@ func TestIndexManagement(t *testing.T) {
helper.OK(t, err)
helper.Assert(t, response, "Index has not been created with the CreateIndex function")

//Get mappings for type
mappings, err := client.GetMapping(IndexName, ProductDocumentType)
helper.OK(t, err)
helper.Assert(t, string(mappings) == "{}", "Mappings is not empty")

//Update mappings for type
mappingsResponse, err := client.PutMapping(IndexName, ProductDocumentType, ProductMapping)
helper.OK(t, err)
helper.Assert(t, mappingsResponse.Acknowledged, "Mappings has not been updated")

//Get updated mappings type
mappings, err = client.GetMapping(IndexName, ProductDocumentType)
helper.OK(t, err)
helper.Assert(t, strings.Contains(string(mappings), `{"colors":{"type":"string"}`), "Mappings has not been updated")

//Delete the index
deleteResponse, err := client.DeleteIndex(IndexName)
helper.OK(t, err)
Expand Down Expand Up @@ -154,8 +172,9 @@ func TestSearch(t *testing.T) {
buffer.WriteByte('\n')
}

_, err := client.Bulk(buffer.Bytes())
bulkResponse, err := client.Bulk(buffer.Bytes())
helper.OK(t, err)
helper.Assert(t, len(bulkResponse.Items) == 3, "Bulk did not index all items")

//We have to wait after a bulk
time.Sleep(1500 * time.Millisecond)
Expand All @@ -165,16 +184,23 @@ func TestSearch(t *testing.T) {
helper.OK(t, err)
helper.Assert(t, search.Hits.Total == 2, "The search doesn't return all matched items")

//MSearch
//SearchTemplate
_, err = client.CreateSearchTemplate("colorSearch", SearchTemplateColorSearch())
helper.Assert(t, err == nil, "Can't create search template colorSearch")

search, err = client.SearchTemplate(IndexName, SearchByColorSearchTemplate(), false)
helper.OK(t, err)
helper.Assert(t, search.Hits.Total == 2, "The search doesn't return all matched items")

//MSearch
mqueries := make([]elasticsearch.MSearchQuery, 2)
mqueries[0] = elasticsearch.MSearchQuery{Header: `{ "index":` + IndexName + `, "type":"` + ProductDocumentType + `" }`, Body: `{ "query": {"match_all" : {}}, "from" : 0, "size" : 1} }`}
mqueries[1] = elasticsearch.MSearchQuery{Header: `{ "index":` + IndexName + `, "type":"` + ProductDocumentType + `" }`, Body: `{"query": {"match_all" : {}}, "from" : 0, "size" : 2}}`}
mqueries[0] = elasticsearch.MSearchQuery{Header: `{ "index": "` + IndexName + `", "type": "` + ProductDocumentType + `" }`, Body: `{"query": {"match_all" : {}}, "from" : 0, "size" : 1}`}
mqueries[1] = elasticsearch.MSearchQuery{Header: `{ "index": "` + IndexName + `", "type": "` + ProductDocumentType + `" }`, Body: `{"query": {"match_all" : {}}, "from" : 0, "size" : 2}`}

msresult, err := client.MSearch(mqueries)
helper.OK(t, err)
helper.Assert(t, msresult.Responses[0].Hits.Total == 1, "The msearch doesn't return all matched items")
helper.Assert(t, msresult.Responses[1].Hits.Total == 2, "The msearch doesn't return all matched items")
helper.Assert(t, len(msresult.Responses[0].Hits.Hits) == 1, "The msearch doesn't return all matched items")
helper.Assert(t, len(msresult.Responses[1].Hits.Hits) == 2, "The msearch doesn't return all matched items")

//Delete the index
deleteResponse, err := client.DeleteIndex(IndexName)
Expand All @@ -184,12 +210,8 @@ func TestSearch(t *testing.T) {

func BulkIndexConstant(indexName, documentType, id string) string {

return `{"index":
{ "_index": "` + indexName + `",
"_type": "` + documentType + `",
"_id": "` + id + `"
}
}`
// no new lines
return `{"index": { "_index": "` + indexName + `", "_type": "` + documentType + `", "_id": "` + id + `" } }`
}

func SearchByColorQuery(color string) string {
Expand All @@ -202,6 +224,19 @@ func SearchByColorQuery(color string) string {
}`
}

func SearchTemplateColorSearch() string {
return `{ "template": { "query": { "match": { "Colors": "{{color}}" } } } }`
}

func SearchByColorSearchTemplate() string {
return `{
"id": "colorSearch",
"params": {
"color": "red"
}
}`
}

func TestSuggestion(t *testing.T) {

type PayLoadSuggester struct {
Expand Down
19 changes: 17 additions & 2 deletions structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,29 @@ type Bulk struct {
Type string `json:"_type"`
ID string `json:"_id"`
Status int `json:"status"`
Error string `json:"error"`
Error struct {
Type string `json:"type"`
Reason string `json:"reason"`
CausedBy struct {
Type string `json:"type"`
Reason string `json:"reason"`
} `json:"caused_by"`
} `json:"error"`
} `json:"create"`
Index struct {
Index string `json:"_index"`
Type string `json:"_type"`
ID string `json:"_id"`
Version int `json:"_version"`
Status int `json:"status"`
Error string `json:"error"`
Error struct {
Type string `json:"type"`
Reason string `json:"reason"`
CausedBy struct {
Type string `json:"type"`
Reason string `json:"reason"`
} `json:"caused_by"`
} `json:"error"`
} `json:"index"`
} `json:"items"`
}
Expand All @@ -83,6 +97,7 @@ type SearchResult struct {
} `json:"_shards"`
Hits ResultHits `json:"hits"`
Aggregations json.RawMessage `json:"aggregations"`
Suggest json.RawMessage `json:"suggest"`
}

// ResultHits represents the result of the search hits
Expand Down