Skip to content

Commit

Permalink
Change scripting
Browse files Browse the repository at this point in the history
Scripting changed quite a bit in 6.0. First, we now only have scripting
types "inline" and "stored". For inline scripting code, we need to use
the `"source"` property now instead of `"inline"`, and there is no
shortcut to pass the code. For stored scripts, e.g. those stored in the
configuration, we need to use `"id"`. The `"file"` property has been
removed in 6.0.

For details, see
https://www.elastic.co/guide/en/elasticsearch/reference/6.0/modules-scripting-using.html.
  • Loading branch information
olivere committed Nov 16, 2017
1 parent faf2372 commit fa15f3c
Show file tree
Hide file tree
Showing 14 changed files with 100 additions and 102 deletions.
4 changes: 2 additions & 2 deletions bulk_update_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestBulkUpdateRequestSerialization(t *testing.T) {
}),
Expected: []string{
`{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"doc"}}`,
`{"script":{"inline":"ctx._source.retweets += param1","lang":"javascript","params":{"param1":42}},"upsert":{"counter":42}}`,
`{"script":{"lang":"javascript","params":{"param1":42},"source":"ctx._source.retweets += param1"},"upsert":{"counter":42}}`,
},
},
// #3
Expand Down Expand Up @@ -80,7 +80,7 @@ func TestBulkUpdateRequestSerialization(t *testing.T) {
}),
Expected: []string{
`{"update":{"_id":"1","_index":"index1","_retry_on_conflict":3,"_type":"doc"}}`,
`{"script":{"inline":"ctx._source.retweets += param1","lang":"javascript","params":{"param1":42}},"scripted_upsert":true,"upsert":{"counter":42}}`,
`{"script":{"lang":"javascript","params":{"param1":42},"source":"ctx._source.retweets += param1"},"scripted_upsert":true,"upsert":{"counter":42}}`,
},
},
}
Expand Down
2 changes: 1 addition & 1 deletion reindex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ func TestReindexSourceWithScript(t *testing.T) {
t.Fatal(err)
}
got := string(b)
want := `{"dest":{"index":"new_twitter","version_type":"external"},"script":{"inline":"if (ctx._source.foo == 'bar') {ctx._version++; ctx._source.remove('foo')}"},"source":{"index":"twitter"}}`
want := `{"dest":{"index":"new_twitter","version_type":"external"},"script":{"source":"if (ctx._source.foo == 'bar') {ctx._version++; ctx._source.remove('foo')}"},"source":{"index":"twitter"}}`
if got != want {
t.Fatalf("\ngot %s\nwant %s", got, want)
}
Expand Down
22 changes: 9 additions & 13 deletions script.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,21 @@ type Script struct {
func NewScript(script string) *Script {
return &Script{
script: script,
typ: "", // default type is "inline"
typ: "inline",
params: make(map[string]interface{}),
}
}

// NewScriptInline creates and initializes a new Script of type "inline".
// NewScriptInline creates and initializes a new inline script, i.e. code.
func NewScriptInline(script string) *Script {
return NewScript(script).Type("inline")
}

// NewScriptId creates and initializes a new Script of type "id".
func NewScriptId(script string) *Script {
// NewScriptStored creates and initializes a new stored script.
func NewScriptStored(script string) *Script {
return NewScript(script).Type("id")
}

// NewScriptFile creates and initializes a new Script of type "file".
func NewScriptFile(script string) *Script {
return NewScript(script).Type("file")
}

// Script is either the cache key of the script to be compiled/executed
// or the actual script source code for inline scripts. For indexed
// scripts this is the id used in the request. For file scripts this is
Expand All @@ -51,7 +46,7 @@ func (s *Script) Script(script string) *Script {
return s
}

// Type sets the type of script: "inline", "id", or "file".
// Type sets the type of script: "inline" or "id".
func (s *Script) Type(typ string) *Script {
s.typ = typ
return s
Expand Down Expand Up @@ -88,10 +83,11 @@ func (s *Script) Source() (interface{}, error) {
return s.script, nil
}
source := make(map[string]interface{})
if s.typ == "" {
source["inline"] = s.script
// Beginning with 6.0, the type can only be "source" or "id"
if s.typ == "" || s.typ == "inline" {
source["source"] = s.script
} else {
source[s.typ] = s.script
source["id"] = s.script
}
if s.lang != "" {
source["lang"] = s.lang
Expand Down
25 changes: 4 additions & 21 deletions script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestScriptingDefault(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `"doc['field'].value * 2"`
expected := `{"source":"doc['field'].value * 2"}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand All @@ -37,14 +37,14 @@ func TestScriptingInline(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"inline":"doc['field'].value * factor","params":{"factor":2}}`
expected := `{"params":{"factor":2},"source":"doc['field'].value * factor"}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
}

func TestScriptingId(t *testing.T) {
builder := NewScriptId("script-with-id").Param("factor", 2.0)
func TestScriptingStored(t *testing.T) {
builder := NewScriptStored("script-with-id").Param("factor", 2.0)
src, err := builder.Source()
if err != nil {
t.Fatal(err)
Expand All @@ -59,20 +59,3 @@ func TestScriptingId(t *testing.T) {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
}

func TestScriptingFile(t *testing.T) {
builder := NewScriptFile("script-file").Param("factor", 2.0).Lang("groovy")
src, err := builder.Source()
if err != nil {
t.Fatal(err)
}
data, err := json.Marshal(src)
if err != nil {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"file":"script-file","lang":"groovy","params":{"factor":2}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
}
2 changes: 1 addition & 1 deletion search_aggs_bucket_significant_terms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func TestSignificantTermsAggregationWithScript(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"significant_terms":{"field":"crime_type","script_heuristic":{"script":"_subset_freq/(_superset_freq - _subset_freq + 1)"}}}`
expected := `{"significant_terms":{"field":"crime_type","script_heuristic":{"script":{"source":"_subset_freq/(_superset_freq - _subset_freq + 1)"}}}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down
2 changes: 1 addition & 1 deletion search_aggs_pipeline_bucket_script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestBucketScriptAggregation(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"bucket_script":{"buckets_path":{"tShirtSales":"t-shirts\u003esales","totalSales":"total_sales"},"script":"tShirtSales / totalSales * 100"}}`
expected := `{"bucket_script":{"buckets_path":{"tShirtSales":"t-shirts\u003esales","totalSales":"total_sales"},"script":{"source":"tShirtSales / totalSales * 100"}}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down
2 changes: 1 addition & 1 deletion search_aggs_pipeline_bucket_selector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestBucketSelectorAggregation(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"bucket_selector":{"buckets_path":{"totalSales":"total_sales"},"script":"totalSales \u003e= 1000"}}`
expected := `{"bucket_selector":{"buckets_path":{"totalSales":"total_sales"},"script":{"source":"totalSales \u003e= 1000"}}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down
2 changes: 1 addition & 1 deletion search_queries_fsq_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestFieldValueFactorWithMultipleScoreFuncsAndWeights(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"function_score":{"boost":2,"boost_mode":"multiply","functions":[{"field_value_factor":{"factor":2,"field":"income","modifier":"sqrt"},"weight":2.5},{"script_score":{"script":"_score * doc['my_numeric_field'].value"},"weight":1.25},{"weight":0.5}],"max_boost":12,"query":{"term":{"name.last":"banon"}},"score_mode":"max"}}`
expected := `{"function_score":{"boost":2,"boost_mode":"multiply","functions":[{"field_value_factor":{"factor":2,"field":"income","modifier":"sqrt"},"weight":2.5},{"script_score":{"script":{"source":"_score * doc['my_numeric_field'].value"}},"weight":1.25},{"weight":0.5}],"max_boost":12,"query":{"term":{"name.last":"banon"}},"score_mode":"max"}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down
4 changes: 2 additions & 2 deletions search_queries_script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestScriptQuery(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"script":{"script":"doc['num1'.value \u003e 1"}}`
expected := `{"script":{"script":{"source":"doc['num1'.value \u003e 1"}}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand All @@ -38,7 +38,7 @@ func TestScriptQueryWithParams(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"script":{"_name":"MyQueryName","script":"doc['num1'.value \u003e 1"}}`
expected := `{"script":{"_name":"MyQueryName","script":{"source":"doc['num1'.value \u003e 1"}}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down
4 changes: 2 additions & 2 deletions search_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func TestSearchSourceScriptFields(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"query":{"match_all":{}},"script_fields":{"test1":{"script":"doc['my_field_name'].value * 2"},"test2":{"script":{"inline":"doc['my_field_name'].value * factor","params":{"factor":3.1415927}}}}}`
expected := `{"query":{"match_all":{}},"script_fields":{"test1":{"script":{"source":"doc['my_field_name'].value * 2"}},"test2":{"script":{"params":{"factor":3.1415927},"source":"doc['my_field_name'].value * factor"}}}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down Expand Up @@ -232,7 +232,7 @@ func TestSearchSourceMixDifferentSorters(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"query":{"match_all":{}},"sort":[{"a":{"order":"desc"}},{"b":{"order":"asc"}},{"_script":{"order":"asc","script":{"inline":"doc['field_name'].value * factor","params":{"factor":1.1}},"type":"number"}}]}`
expected := `{"query":{"match_all":{}},"sort":[{"a":{"order":"desc"}},{"b":{"order":"asc"}},{"_script":{"order":"asc","script":{"params":{"factor":1.1},"source":"doc['field_name'].value * factor"},"type":"number"}}]}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down
4 changes: 2 additions & 2 deletions sort_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func TestScriptSort(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"_script":{"order":"asc","script":{"inline":"doc['field_name'].value * factor","params":{"factor":1.1}},"type":"number"}}`
expected := `{"_script":{"order":"asc","script":{"params":{"factor":1.1},"source":"doc['field_name'].value * factor"},"type":"number"}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand All @@ -231,7 +231,7 @@ func TestScriptSortOrderDesc(t *testing.T) {
t.Fatalf("marshaling to JSON failed: %v", err)
}
got := string(data)
expected := `{"_script":{"order":"desc","script":{"inline":"doc['field_name'].value * factor","params":{"factor":1.1}},"type":"number"}}`
expected := `{"_script":{"order":"desc","script":{"params":{"factor":1.1},"source":"doc['field_name'].value * factor"},"type":"number"}}`
if got != expected {
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
}
Expand Down
2 changes: 1 addition & 1 deletion update_by_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func TestUpdateByQueryBodyWithQueryAndScript(t *testing.T) {
t.Fatal(err)
}
got := string(b)
want := `{"query":{"term":{"user":"olivere"}},"script":{"inline":"ctx._source.likes++"}}`
want := `{"query":{"term":{"user":"olivere"}},"script":{"source":"ctx._source.likes++"}}`
if got != want {
t.Fatalf("\ngot %s\nwant %s", got, want)
}
Expand Down
58 changes: 58 additions & 0 deletions update_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
"context"
"encoding/json"
"testing"
)

func TestUpdateWithScript(t *testing.T) {
client := setupTestClientAndCreateIndexAndAddDocs(t) // , SetTraceLog(log.New(os.Stdout, "", 0)))

// Get original
getRes, err := client.Get().Index(testIndexName).Type("doc").Id("1").Do(context.TODO())
if err != nil {
t.Fatal(err)
}
var original tweet
if err := json.Unmarshal(*getRes.Source, &original); err != nil {
t.Fatal(err)
}

// Update with script
updRes, err := client.Update().Index(testIndexName).Type("doc").Id("1").
Script(
NewScript(`ctx._source.message = "Updated message text."`).Lang("painless"),
).
Do(context.TODO())
if err != nil {
t.Fatal(err)
}
if updRes == nil {
t.Fatal("response is nil")
}
if want, have := "updated", updRes.Result; want != have {
t.Fatalf("want Result = %q, have %v", want, have)
}

// Get new version
getRes, err = client.Get().Index(testIndexName).Type("doc").Id("1").Do(context.TODO())
if err != nil {
t.Fatal(err)
}
var updated tweet
if err := json.Unmarshal(*getRes.Source, &updated); err != nil {
t.Fatal(err)
}

if want, have := original.User, updated.User; want != have {
t.Fatalf("want User = %q, have %v", want, have)
}
if want, have := "Updated message text.", updated.Message; want != have {
t.Fatalf("want Message = %q, have %v", want, have)
}
}
Loading

0 comments on commit fa15f3c

Please sign in to comment.