From a595a0dc40c268f6f2513226c501ef0762bbda9f Mon Sep 17 00:00:00 2001 From: filipe oliveira Date: Tue, 7 Apr 2020 09:32:11 +0100 Subject: [PATCH] Shared pool among clients and fixed pool resources release (#51) * [add] added option to create clients with shared pool. added option to releases the resources used by the pool ( single, and multihost ) * [add] added Close() test on multi-host pool * [add] extended test for Close on multihost pool * [add] swapped deprecated redis.NewPool to redis.Pool constructor. preserving all errors on multihost pool CLose() * [fix] fixed CI invalid memory address or nil pointer dereference on TestNewMultiHostPool/multi-host_single_address --- redisearch/aggregate_test.go | 70 ++++++++++-- redisearch/autocomplete_test.go | 35 ++---- redisearch/client.go | 9 ++ redisearch/client_test.go | 81 +++----------- redisearch/document_test.go | 9 +- redisearch/pool.go | 30 ++++- redisearch/pool_test.go | 89 ++++++++++++--- redisearch/redisearch_test.go | 192 +++++++++++++++++++------------- 8 files changed, 321 insertions(+), 194 deletions(-) diff --git a/redisearch/aggregate_test.go b/redisearch/aggregate_test.go index 823cb8b..278257d 100644 --- a/redisearch/aggregate_test.go +++ b/redisearch/aggregate_test.go @@ -16,14 +16,6 @@ import ( "testing" ) -func createClient(indexName string) *Client { - value, exists := os.LookupEnv("REDISEARCH_TEST_HOST") - host := "localhost:6379" - if exists && value != "" { - host = value - } - return NewClient(host, indexName) -} // Game struct which contains a Asin, a Description, a Title, a Price, and a list of categories // a type and a list of social links @@ -38,6 +30,68 @@ type Game struct { Categories []string `json:"categories"` } + +func init() { + /* load test data */ + value, exists := os.LookupEnv("REDISEARCH_RDB_LOADED") + requiresDatagen := true + if exists && value != "" { + requiresDatagen = false + } + if requiresDatagen { + c := createClient("bench.ft.aggregate") + + sc := NewSchema(DefaultOptions). + AddField(NewTextField("foo")) + c.Drop() + if err := c.CreateIndex(sc); err != nil { + log.Fatal(err) + } + ndocs := 10000 + docs := make([]Document, ndocs) + for i := 0; i < ndocs; i++ { + docs[i] = NewDocument(fmt.Sprintf("doc%d", i), 1).Set("foo", "hello world") + } + + if err := c.IndexOptions(DefaultIndexingOptions, docs...); err != nil { + log.Fatal(err) + } + } + +} + +func benchmarkAggregate(c *Client, q *AggregateQuery, b *testing.B) { + for n := 0; n < b.N; n++ { + c.Aggregate(q) + } +} + +func benchmarkAggregateCursor(c *Client, q *AggregateQuery, b *testing.B) { + for n := 0; n < b.N; n++ { + c.Aggregate(q) + for q.CursorHasResults() { + c.Aggregate(q) + } + } +} + +func BenchmarkAgg_1(b *testing.B) { + c := createClient("bench.ft.aggregate") + q := NewAggregateQuery(). + SetQuery(NewQuery("*")) + b.ResetTimer() + benchmarkAggregate(c, q, b) +} + +func BenchmarkAggCursor_1(b *testing.B) { + c := createClient("bench.ft.aggregate") + q := NewAggregateQuery(). + SetQuery(NewQuery("*")). + SetCursor(NewCursor()) + b.ResetTimer() + benchmarkAggregateCursor(c, q, b) +} + func AddValues(c *Client) { // Open our jsonFile bzipfile := "../tests/games.json.bz2" diff --git a/redisearch/autocomplete_test.go b/redisearch/autocomplete_test.go index e2b4ba4..8ce8cba 100644 --- a/redisearch/autocomplete_test.go +++ b/redisearch/autocomplete_test.go @@ -1,32 +1,21 @@ -package redisearch_test +package redisearch import ( "fmt" - "github.com/RediSearch/redisearch-go/redisearch" "github.com/gomodule/redigo/redis" "github.com/stretchr/testify/assert" - "os" "reflect" "testing" ) -func createAutocompleter(dictName string) *redisearch.Autocompleter { - value, exists := os.LookupEnv("REDISEARCH_TEST_HOST") - host := "localhost:6379" - if exists && value != "" { - host = value - } - return redisearch.NewAutocompleter(host, dictName) -} - func TestAutocompleter_Serialize(t *testing.T) { - fuzzy := redisearch.DefaultSuggestOptions + fuzzy := DefaultSuggestOptions fuzzy.Fuzzy = true - withscores := redisearch.DefaultSuggestOptions + withscores := DefaultSuggestOptions withscores.WithScores = true - withpayloads := redisearch.DefaultSuggestOptions + withpayloads := DefaultSuggestOptions withpayloads.WithPayloads = true - all := redisearch.DefaultSuggestOptions + all := DefaultSuggestOptions all.Fuzzy = true all.WithScores = true all.WithPayloads = true @@ -36,7 +25,7 @@ func TestAutocompleter_Serialize(t *testing.T) { } type args struct { prefix string - opts redisearch.SuggestOptions + opts SuggestOptions } tests := []struct { name string @@ -45,7 +34,7 @@ func TestAutocompleter_Serialize(t *testing.T) { want redis.Args want1 int }{ - {"default options", fields{"key1"}, args{"ab", redisearch.DefaultSuggestOptions,}, redis.Args{"key1", "ab", "MAX", 5}, 1}, + {"default options", fields{"key1"}, args{"ab", DefaultSuggestOptions,}, redis.Args{"key1", "ab", "MAX", 5}, 1}, {"FUZZY", fields{"key1"}, args{"ab", fuzzy,}, redis.Args{"key1", "ab", "MAX", 5, "FUZZY"}, 1}, {"WITHSCORES", fields{"key1"}, args{"ab", withscores,}, redis.Args{"key1", "ab", "MAX", 5, "WITHSCORES"}, 2}, {"WITHPAYLOADS", fields{"key1"}, args{"ab", withpayloads,}, redis.Args{"key1", "ab", "MAX", 5, "WITHPAYLOADS"}, 2}, @@ -53,7 +42,7 @@ func TestAutocompleter_Serialize(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a := redisearch.NewAutocompleterFromPool(nil, tt.fields.name) + a := NewAutocompleterFromPool(nil, tt.fields.name) got, got1 := a.Serialize(tt.args.prefix, tt.args.opts) if !reflect.DeepEqual(got, tt.want) { t.Errorf("serialize() got = %v, want %v", got, tt.want) @@ -69,9 +58,9 @@ func TestSuggest(t *testing.T) { a := createAutocompleter("testing") // Add Terms to the Autocompleter - terms := make([]redisearch.Suggestion, 10) + terms := make([]Suggestion, 10) for i := 0; i < 10; i++ { - terms[i] = redisearch.Suggestion{Term: fmt.Sprintf("foo %d", i), + terms[i] = Suggestion{Term: fmt.Sprintf("foo %d", i), Score: 1.0, Payload: fmt.Sprintf("bar %d", i)} } err := a.AddTerms(terms...) @@ -80,7 +69,7 @@ func TestSuggest(t *testing.T) { assert.Nil(t, err) assert.Equal(t, int64(10), suglen) // Retrieve Terms From Autocompleter - Without Payloads / Scores - suggestions, err := a.SuggestOpts("f", redisearch.SuggestOptions{Num: 10}) + suggestions, err := a.SuggestOpts("f", SuggestOptions{Num: 10}) assert.Nil(t, err) assert.Equal(t, 10, len(suggestions)) for _, suggestion := range suggestions { @@ -90,7 +79,7 @@ func TestSuggest(t *testing.T) { } // Retrieve Terms From Autocompleter - With Payloads & Scores - suggestions, err = a.SuggestOpts("f", redisearch.SuggestOptions{Num: 10, WithScores: true, WithPayloads: true}) + suggestions, err = a.SuggestOpts("f", SuggestOptions{Num: 10, WithScores: true, WithPayloads: true}) assert.Nil(t, err) assert.Equal(t, 10, len(suggestions)) for _, suggestion := range suggestions { diff --git a/redisearch/client.go b/redisearch/client.go index d9dfae0..0d67b75 100644 --- a/redisearch/client.go +++ b/redisearch/client.go @@ -38,6 +38,15 @@ func NewClient(addr, name string) *Client { return ret } +// NewAutocompleter creates a new Autocompleter with the given pool and index name +func NewClientFromPool(pool *redis.Pool, name string) *Client { + ret := &Client{ + pool: pool, + name: name, + } + return ret +} + // CreateIndex configues the index and creates it on redis func (i *Client) CreateIndex(s *Schema) (err error) { args := redis.Args{i.name} diff --git a/redisearch/client_test.go b/redisearch/client_test.go index 762ffe6..fe7cfc7 100644 --- a/redisearch/client_test.go +++ b/redisearch/client_test.go @@ -2,73 +2,12 @@ package redisearch import ( "fmt" - "github.com/stretchr/testify/assert" - "log" - "os" "reflect" "testing" -) - -func init() { - /* load test data */ - value, exists := os.LookupEnv("REDISEARCH_RDB_LOADED") - requiresDatagen := true - if exists && value != "" { - requiresDatagen = false - } - if requiresDatagen { - c := createClient("bench.ft.aggregate") - - sc := NewSchema(DefaultOptions). - AddField(NewTextField("foo")) - c.Drop() - if err := c.CreateIndex(sc); err != nil { - log.Fatal(err) - } - ndocs := 10000 - docs := make([]Document, ndocs) - for i := 0; i < ndocs; i++ { - docs[i] = NewDocument(fmt.Sprintf("doc%d", i), 1).Set("foo", "hello world") - } - - if err := c.IndexOptions(DefaultIndexingOptions, docs...); err != nil { - log.Fatal(err) - } - } - -} -func benchmarkAggregate(c *Client, q *AggregateQuery, b *testing.B) { - for n := 0; n < b.N; n++ { - c.Aggregate(q) - } -} - -func benchmarkAggregateCursor(c *Client, q *AggregateQuery, b *testing.B) { - for n := 0; n < b.N; n++ { - c.Aggregate(q) - for q.CursorHasResults() { - c.Aggregate(q) - } - } -} - -func BenchmarkAgg_1(b *testing.B) { - c := createClient("bench.ft.aggregate") - q := NewAggregateQuery(). - SetQuery(NewQuery("*")) - b.ResetTimer() - benchmarkAggregate(c, q, b) -} - -func BenchmarkAggCursor_1(b *testing.B) { - c := createClient("bench.ft.aggregate") - q := NewAggregateQuery(). - SetQuery(NewQuery("*")). - SetCursor(NewCursor()) - b.ResetTimer() - benchmarkAggregateCursor(c, q, b) -} + "github.com/gomodule/redigo/redis" + "github.com/stretchr/testify/assert" +) func TestClient_Get(t *testing.T) { @@ -492,6 +431,20 @@ func TestClient_Config(t *testing.T) { assert.Equal(t, "100", kvs["TIMEOUT"]) } +func TestNewClientFromPool(t *testing.T) { + host, password := getTestConnectionDetails() + pool := &redis.Pool{Dial: func() (redis.Conn, error) { + return redis.Dial("tcp", host, redis.DialPassword(password)) + }, MaxIdle: maxConns} + client1 := NewClientFromPool(pool, "index1") + client2 := NewClientFromPool(pool, "index2") + assert.Equal(t, client1.pool, client2.pool) + err1 := client1.pool.Close() + err2 := client2.pool.Close() + assert.Nil(t, err1) + assert.Nil(t, err2) +} + func TestClient_GetTagVals(t *testing.T) { c := createClient("testgettagvals") diff --git a/redisearch/document_test.go b/redisearch/document_test.go index 94d2d37..614a20a 100644 --- a/redisearch/document_test.go +++ b/redisearch/document_test.go @@ -1,7 +1,6 @@ -package redisearch_test +package redisearch import ( - "github.com/RediSearch/redisearch-go/redisearch" "reflect" "testing" ) @@ -24,7 +23,7 @@ func TestEscapeTextFileString(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := redisearch.EscapeTextFileString(tt.args.value); got != tt.want { + if got := EscapeTextFileString(tt.args.value); got != tt.want { t.Errorf("EscapeTextFileString() = %v, want %v", got, tt.want) } }) @@ -55,7 +54,7 @@ func TestDocument_EstimateSize(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - d := &redisearch.Document{ + d := &Document{ Id: tt.fields.Id, Score: tt.fields.Score, Payload: tt.fields.Payload, @@ -90,7 +89,7 @@ func TestDocument_SetPayload(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - d := &redisearch.Document{ + d := &Document{ Id: tt.fields.Id, Score: tt.fields.Score, Payload: tt.fields.Payload, diff --git a/redisearch/pool.go b/redisearch/pool.go index e2cfb66..c1524ac 100644 --- a/redisearch/pool.go +++ b/redisearch/pool.go @@ -1,14 +1,16 @@ package redisearch import ( + "fmt" + "github.com/gomodule/redigo/redis" "math/rand" "sync" "time" - "github.com/gomodule/redigo/redis" ) type ConnPool interface { Get() redis.Conn + Close() error } type SingleHostPool struct { @@ -16,17 +18,16 @@ type SingleHostPool struct { } func NewSingleHostPool(host string) *SingleHostPool { - ret := redis.NewPool(func() (redis.Conn, error) { - // TODO: Add timeouts. and 2 separate pools for indexing and querying, with different timeouts + pool := &redis.Pool{Dial: func() (redis.Conn, error) { return redis.Dial("tcp", host) - }, maxConns) - ret.TestOnBorrow = func(c redis.Conn, t time.Time) (err error) { + }, MaxIdle: maxConns} + pool.TestOnBorrow = func(c redis.Conn, t time.Time) (err error) { if time.Since(t) > time.Second { _, err = c.Do("PING") } return err } - return &SingleHostPool{ret} + return &SingleHostPool{pool} } type MultiHostPool struct { @@ -65,3 +66,20 @@ func (p *MultiHostPool) Get() redis.Conn { return pool.Get() } + +func (p *MultiHostPool) Close() (err error) { + p.Lock() + defer p.Unlock() + for host, pool := range p.pools { + poolErr := pool.Close() + //preserve pool error if not nil but continue + if poolErr != nil { + if err == nil { + err = fmt.Errorf("Error closing pool for host %s. Got %v.", host, poolErr) + } else { + err = fmt.Errorf("%v Error closing pool for host %s. Got %v.", err, host, poolErr) + } + } + } + return +} diff --git a/redisearch/pool_test.go b/redisearch/pool_test.go index 12fb46a..71a1796 100644 --- a/redisearch/pool_test.go +++ b/redisearch/pool_test.go @@ -1,17 +1,13 @@ -package redisearch_test +package redisearch import ( - "github.com/RediSearch/redisearch-go/redisearch" - "os" + "github.com/gomodule/redigo/redis" + "github.com/stretchr/testify/assert" "testing" ) func TestNewMultiHostPool(t *testing.T) { - value, exists := os.LookupEnv("REDISEARCH_TEST_HOST") - host := "localhost:6379" - if exists && value != "" { - host = value - } + host, password := getTestConnectionDetails() type args struct { hosts []string } @@ -19,14 +15,81 @@ func TestNewMultiHostPool(t *testing.T) { name string args args }{ - {"multihost same address", args{[]string{host,},},}, + {"multi-host single address", args{[]string{host,},},}, + {"multi-host several addresses", args{[]string{host, host,},},}, + } + if password == "" { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewMultiHostPool(tt.args.hosts) + conn := got.Get() + if conn == nil { + t.Errorf("NewMultiHostPool() = got nil connection") + } + err := got.Close() + assert.Nil(t, err) + }) + } + } +} + +func TestMultiHostPool_Close(t *testing.T) { + host, password := getTestConnectionDetails() + // Test a simple flow + if password == "" { + oneMulti := NewMultiHostPool([]string{host,}) + conn := oneMulti.Get() + assert.NotNil(t, conn) + err := oneMulti.Close() + assert.Nil(t, err) + err = oneMulti.Close() + assert.NotNil(t, conn) + severalMulti := NewMultiHostPool([]string{host, host,}) + connMulti := severalMulti.Get() + assert.NotNil(t, connMulti) + err = severalMulti.Close() + assert.Nil(t, err) + } + // Exhaustive test + dial := func() (redis.Conn, error) { + return redis.Dial("tcp", host, redis.DialPassword(password)) + } + pool1 := &redis.Pool{Dial: dial, MaxIdle: maxConns} + pool2 := &redis.Pool{Dial: dial, MaxIdle: maxConns} + pool3 := &redis.Pool{Dial: dial, MaxIdle: maxConns} + //Close pull3 prior to enforce error + pool3.Close() + pool4 := &redis.Pool{Dial: dial, MaxIdle: maxConns} + + type fields struct { + pools map[string]*redis.Pool + hosts []string + } + tests := []struct { + name string + fields fields + wantErr bool + }{ + {"empty", fields{map[string]*redis.Pool{}, []string{}}, false,}, + {"normal", fields{map[string]*redis.Pool{"hostpool1": pool1}, []string{"hostpool1"}}, false,}, + {"pool3-already-close", fields{map[string]*redis.Pool{"hostpool2": pool2, "hostpool3": pool3, "hostpool4": pool4,}, []string{"hostpool2", "hostpool3", "hostpool3"}}, false,}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := redisearch.NewMultiHostPool(tt.args.hosts) - conn := got.Get() - if conn == nil { - t.Errorf("NewMultiHostPool() = got nil connection") + p := &MultiHostPool{ + pools: tt.fields.pools, + hosts: tt.fields.hosts, + } + if err := p.Close(); (err != nil) != tt.wantErr { + t.Errorf("Close() error = %v, wantErr %v", err, tt.wantErr) + } + // ensure all connections are really closed + if !tt.wantErr { + for _, pool := range p.pools { + if _, err := pool.Get().Do("PING"); err == nil { + t.Errorf("expected error after connection closed. Got %v", err) + } + } } }) } diff --git a/redisearch/redisearch_test.go b/redisearch/redisearch_test.go index 199c38d..c60612e 100644 --- a/redisearch/redisearch_test.go +++ b/redisearch/redisearch_test.go @@ -1,51 +1,93 @@ -package redisearch_test +package redisearch import ( "fmt" + "github.com/gomodule/redigo/redis" "log" "os" "testing" "time" - "github.com/RediSearch/redisearch-go/redisearch" "github.com/stretchr/testify/assert" ) -func createClient(indexName string) *redisearch.Client { +func getTestConnectionDetails() (string, string) { value, exists := os.LookupEnv("REDISEARCH_TEST_HOST") host := "localhost:6379" + password := "" + valuePassword, existsPassword := os.LookupEnv("REDISEARCH_TEST_PASSWORD") if exists && value != "" { host = value } - return redisearch.NewClient(host, indexName) + if existsPassword && valuePassword != "" { + password = valuePassword + } + return host, password +} + + +func createClient(indexName string) *Client { + host, password := getTestConnectionDetails() + if password != "" { + pool := &redis.Pool{Dial: func() (redis.Conn, error) { + return redis.Dial("tcp", host, redis.DialPassword(password)) + }, MaxIdle: maxConns} + pool.TestOnBorrow = func(c redis.Conn, t time.Time) (err error) { + if time.Since(t) > time.Second { + _, err = c.Do("PING") + } + return err + } + return NewClientFromPool(pool, indexName) + }else{ + return NewClient(host, indexName) + } } +func createAutocompleter(dictName string) *Autocompleter { + host, password := getTestConnectionDetails() + if password != "" { + pool := &redis.Pool{Dial: func() (redis.Conn, error) { + return redis.Dial("tcp", host, redis.DialPassword(password)) + }, MaxIdle: maxConns} + pool.TestOnBorrow = func(c redis.Conn, t time.Time) (err error) { + if time.Since(t) > time.Second { + _, err = c.Do("PING") + } + return err + } + return NewAutocompleterFromPool(pool, dictName) + } else { + return NewAutocompleter(host, dictName) + } +} + func TestClient(t *testing.T) { c := createClient("testung") - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("foo")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("foo")) c.Drop() if err := c.CreateIndex(sc); err != nil { t.Fatal(err) } - docs := make([]redisearch.Document, 100) + docs := make([]Document, 100) for i := 0; i < 100; i++ { - docs[i] = redisearch.NewDocument(fmt.Sprintf("doc%d", i), float32(i)/float32(100)).Set("foo", "hello world") + docs[i] = NewDocument(fmt.Sprintf("doc%d", i), float32(i)/float32(100)).Set("foo", "hello world") } - if err := c.IndexOptions(redisearch.DefaultIndexingOptions, docs...); err != nil { + if err := c.IndexOptions(DefaultIndexingOptions, docs...); err != nil { t.Fatal(err) } // Test it again - if err := c.IndexOptions(redisearch.DefaultIndexingOptions, docs...); err == nil { + if err := c.IndexOptions(DefaultIndexingOptions, docs...); err == nil { t.Fatal("Expected error for duplicate document") } else { - if merr, ok := err.(redisearch.MultiError); !ok { + if merr, ok := err.(MultiError); !ok { t.Fatal("error not a multi error") } else { assert.Equal(t, 100, len(merr)) @@ -54,7 +96,7 @@ func TestClient(t *testing.T) { } } - docs, total, err := c.Search(redisearch.NewQuery("hello world")) + docs, total, err := c.Search(NewQuery("hello world")) assert.Nil(t, err) assert.Equal(t, 100, total) @@ -65,9 +107,9 @@ func TestClient(t *testing.T) { func TestInfo(t *testing.T) { c := createClient("testung") - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("foo")). - AddField(redisearch.NewSortableNumericField("bar")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("foo")). + AddField(NewSortableNumericField("bar")) c.Drop() assert.Nil(t, c.CreateIndex(sc)) @@ -78,25 +120,25 @@ func TestInfo(t *testing.T) { func TestNumeric(t *testing.T) { c := createClient("testung") - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("foo")). - AddField(redisearch.NewSortableNumericField("bar")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("foo")). + AddField(NewSortableNumericField("bar")) c.Drop() assert.Nil(t, c.CreateIndex(sc)) - docs := make([]redisearch.Document, 100) + docs := make([]Document, 100) for i := 0; i < 100; i++ { - docs[i] = redisearch.NewDocument(fmt.Sprintf("doc%d", i), 1).Set("foo", "hello world").Set("bar", i) + docs[i] = NewDocument(fmt.Sprintf("doc%d", i), 1).Set("foo", "hello world").Set("bar", i) } assert.Nil(t, c.Index(docs...)) - docs, total, err := c.Search(redisearch.NewQuery("hello world @bar:[50 100]").SetFlags(redisearch.QueryNoContent | redisearch.QueryWithScores)) + docs, total, err := c.Search(NewQuery("hello world @bar:[50 100]").SetFlags(QueryNoContent | QueryWithScores)) assert.Nil(t, err) assert.Equal(t, 10, len(docs)) assert.Equal(t, 50, total) - docs, total, err = c.Search(redisearch.NewQuery("hello world @bar:[40 90]").SetSortBy("bar", false)) + docs, total, err = c.Search(NewQuery("hello world @bar:[40 90]").SetSortBy("bar", false)) assert.Nil(t, err) assert.Equal(t, 10, len(docs)) assert.Equal(t, 51, total) @@ -104,7 +146,7 @@ func TestNumeric(t *testing.T) { assert.Equal(t, "doc89", docs[1].Id) assert.Equal(t, "doc81", docs[9].Id) - docs, total, err = c.Search(redisearch.NewQuery("hello world @bar:[40 90]"). + docs, total, err = c.Search(NewQuery("hello world @bar:[40 90]"). SetSortBy("bar", true). SetReturnFields("foo")) assert.Nil(t, err) @@ -117,7 +159,7 @@ func TestNumeric(t *testing.T) { assert.Equal(t, "doc49", docs[9].Id) // Try "Explain" - explain, err := c.Explain(redisearch.NewQuery("hello world @bar:[40 90]")) + explain, err := c.Explain(NewQuery("hello world @bar:[40 90]")) assert.Nil(t, err) assert.NotNil(t, explain) } @@ -126,9 +168,9 @@ func TestNoIndex(t *testing.T) { c := createClient("testung") c.Drop() - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextFieldOptions("f1", redisearch.TextFieldOptions{Sortable: true, NoIndex: true, Weight: 1.0})). - AddField(redisearch.NewTextField("f2")) + sc := NewSchema(DefaultOptions). + AddField(NewTextFieldOptions("f1", TextFieldOptions{Sortable: true, NoIndex: true, Weight: 1.0})). + AddField(NewTextField("f2")) err := c.CreateIndex(sc) assert.Nil(t, err) @@ -137,26 +179,26 @@ func TestNoIndex(t *testing.T) { props["f1"] = "MarkZZ" props["f2"] = "MarkZZ" - err = c.Index(redisearch.Document{Id: "doc1", Properties: props}) + err = c.Index(Document{Id: "doc1", Properties: props}) assert.Nil(t, err) props["f1"] = "MarkAA" props["f2"] = "MarkAA" - err = c.Index(redisearch.Document{Id: "doc2", Properties: props}) + err = c.Index(Document{Id: "doc2", Properties: props}) assert.Nil(t, err) - _, total, err := c.Search(redisearch.NewQuery("@f1:Mark*")) + _, total, err := c.Search(NewQuery("@f1:Mark*")) assert.Nil(t, err) assert.Equal(t, 0, total) - _, total, err = c.Search(redisearch.NewQuery("@f2:Mark*")) + _, total, err = c.Search(NewQuery("@f2:Mark*")) assert.Equal(t, 2, total) - docs, total, err := c.Search(redisearch.NewQuery("@f2:Mark*").SetSortBy("f1", false)) + docs, total, err := c.Search(NewQuery("@f2:Mark*").SetSortBy("f1", false)) assert.Equal(t, 2, total) assert.Equal(t, "doc1", docs[0].Id) - docs, total, err = c.Search(redisearch.NewQuery("@f2:Mark*").SetSortBy("f1", true)) + docs, total, err = c.Search(NewQuery("@f2:Mark*").SetSortBy("f1", true)) assert.Equal(t, 2, total) assert.Equal(t, "doc2", docs[0].Id) } @@ -164,19 +206,19 @@ func TestNoIndex(t *testing.T) { func TestHighlight(t *testing.T) { c := createClient("testung") - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("foo")). - AddField(redisearch.NewTextField("bar")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("foo")). + AddField(NewTextField("bar")) c.Drop() assert.Nil(t, c.CreateIndex(sc)) - docs := make([]redisearch.Document, 100) + docs := make([]Document, 100) for i := 0; i < 100; i++ { - docs[i] = redisearch.NewDocument(fmt.Sprintf("doc%d", i), 1).Set("foo", "hello world").Set("bar", "hello world foo bar baz") + docs[i] = NewDocument(fmt.Sprintf("doc%d", i), 1).Set("foo", "hello world").Set("bar", "hello world foo bar baz") } c.Index(docs...) - q := redisearch.NewQuery("hello").Highlight([]string{"foo"}, "[", "]") + q := NewQuery("hello").Highlight([]string{"foo"}, "[", "]") docs, _, err := c.Search(q) assert.Nil(t, err) @@ -186,7 +228,7 @@ func TestHighlight(t *testing.T) { assert.Equal(t, "hello world foo bar baz", d.Properties["bar"]) } - q = redisearch.NewQuery("hello world baz").Highlight([]string{"foo", "bar"}, "{", "}") + q = NewQuery("hello world baz").Highlight([]string{"foo", "bar"}, "{", "}") docs, _, err = c.Search(q) assert.Nil(t, err) @@ -197,7 +239,7 @@ func TestHighlight(t *testing.T) { } // test RETURN contradicting HIGHLIGHT - q = redisearch.NewQuery("hello").Highlight([]string{"foo"}, "[", "]").SetReturnFields("bar") + q = NewQuery("hello").Highlight([]string{"foo"}, "[", "]").SetReturnFields("bar") docs, _, err = c.Search(q) assert.Nil(t, err) @@ -213,20 +255,20 @@ func TestHighlight(t *testing.T) { func TestSummarize(t *testing.T) { c := createClient("testung") - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("foo")). - AddField(redisearch.NewTextField("bar")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("foo")). + AddField(NewTextField("bar")) c.Drop() assert.Nil(t, c.CreateIndex(sc)) - docs := make([]redisearch.Document, 10) + docs := make([]Document, 10) for i := 0; i < 10; i++ { - docs[i] = redisearch.NewDocument(fmt.Sprintf("doc%d", i), 1). + docs[i] = NewDocument(fmt.Sprintf("doc%d", i), 1). Set("foo", "There are two sub-commands commands used for highlighting. One is HIGHLIGHT which surrounds matching text with an open and/or close tag; and the other is SUMMARIZE which splits a field into contextual fragments surrounding the found terms. It is possible to summarize a field, highlight a field, or perform both actions in the same query.").Set("bar", "hello world foo bar baz") } c.Index(docs...) - q := redisearch.NewQuery("commands fragments fields").Summarize("foo") + q := NewQuery("commands fragments fields").Summarize("foo") docs, _, err := c.Search(q) assert.Nil(t, err) @@ -236,9 +278,9 @@ func TestSummarize(t *testing.T) { assert.Equal(t, "hello world foo bar baz", d.Properties["bar"]) } - q = redisearch.NewQuery("commands fragments fields"). + q = NewQuery("commands fragments fields"). Highlight([]string{"foo"}, "[", "]"). - SummarizeOptions(redisearch.SummaryOptions{ + SummarizeOptions(SummaryOptions{ Fields: []string{"foo"}, Separator: "\r\n", FragmentLen: 10, @@ -258,10 +300,10 @@ func TestTags(t *testing.T) { c := createClient("myIndex") // Create a schema - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("title")). - AddField(redisearch.NewTagFieldOptions("tags", redisearch.TagFieldOptions{Separator: ';'})). - AddField(redisearch.NewTagField("tags2")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("title")). + AddField(NewTagFieldOptions("tags", TagFieldOptions{Separator: ';'})). + AddField(NewTagField("tags2")) // Drop an existing index. If the index does not exist an error is returned c.Drop() @@ -272,19 +314,19 @@ func TestTags(t *testing.T) { } // Create a document with an id and given score - doc := redisearch.NewDocument("doc1", 1.0) + doc := NewDocument("doc1", 1.0) doc.Set("title", "Hello world"). Set("tags", "foo bar;bar,baz; hello world"). Set("tags2", "foo bar;bar,baz; hello world") // Index the document. The API accepts multiple documents at a time - if err := c.IndexOptions(redisearch.DefaultIndexingOptions, doc); err != nil { + if err := c.IndexOptions(DefaultIndexingOptions, doc); err != nil { log.Fatal(err) } assertNumResults := func(q string, n int) { // Searching with limit and sorting - _, total, err := c.Search(redisearch.NewQuery(q)) + _, total, err := c.Search(NewQuery(q)) assert.Nil(t, err) assert.Equal(t, n, total) @@ -306,24 +348,24 @@ func TestTags(t *testing.T) { func TestDelete(t *testing.T) { c := createClient("testung") - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("foo")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("foo")) err := c.Drop() assert.Nil(t, err) assert.Nil(t, c.CreateIndex(sc)) - var info *redisearch.IndexInfo + var info *IndexInfo // validate that the index is empty info, err = c.Info() assert.Nil(t, err) assert.Equal(t, uint64(0), info.DocCount) - doc := redisearch.NewDocument("doc1", 1.0) + doc := NewDocument("doc1", 1.0) doc.Set("foo", "Hello world") - err = c.IndexOptions(redisearch.DefaultIndexingOptions, doc) + err = c.IndexOptions(DefaultIndexingOptions, doc) assert.Nil(t, err) // now we should have 1 document (id = doc1) @@ -344,20 +386,20 @@ func TestDelete(t *testing.T) { func TestSpellCheck(t *testing.T) { c := createClient("testung") countries := []string{"Spain", "Israel", "Portugal", "France", "England", "Angola"} - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("country")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("country")) c.Drop() assert.Nil(t, c.CreateIndex(sc)) - docs := make([]redisearch.Document, len(countries)) + docs := make([]Document, len(countries)) for i := 0; i < len(countries); i++ { - docs[i] = redisearch.NewDocument(fmt.Sprintf("doc%d", i), 1).Set("country", countries[i]) + docs[i] = NewDocument(fmt.Sprintf("doc%d", i), 1).Set("country", countries[i]) } assert.Nil(t, c.Index(docs...)) - query := redisearch.NewQuery("Anla Portuga" ) - opts := redisearch.NewSpellCheckOptions(2 ) + query := NewQuery("Anla Portuga" ) + opts := NewSpellCheckOptions(2 ) sugs, total, err := c.SpellCheck(query,opts ) assert.Nil(t, err) assert.Equal(t, 2, len(sugs)) @@ -367,7 +409,7 @@ func TestSpellCheck(t *testing.T) { // 1) 1) "TERM" // 2) "an" // 3) (empty list or set) - queryEmpty := redisearch.NewQuery("An" ) + queryEmpty := NewQuery("An" ) sugs, total, err = c.SpellCheck(queryEmpty,opts ) assert.Nil(t, err) assert.Equal(t, 1, len(sugs)) @@ -389,10 +431,10 @@ func ExampleClient() { c := createClient("myIndex") // Create a schema - sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("body")). - AddField(redisearch.NewTextFieldOptions("title", redisearch.TextFieldOptions{Weight: 5.0, Sortable: true})). - AddField(redisearch.NewNumericField("date")) + sc := NewSchema(DefaultOptions). + AddField(NewTextField("body")). + AddField(NewTextFieldOptions("title", TextFieldOptions{Weight: 5.0, Sortable: true})). + AddField(NewNumericField("date")) // Drop an existing index. If the index does not exist an error is returned c.Drop() @@ -403,18 +445,18 @@ func ExampleClient() { } // Create a document with an id and given score - doc := redisearch.NewDocument("doc1", 1.0) + doc := NewDocument("doc1", 1.0) doc.Set("title", "Hello world"). Set("body", "foo bar"). Set("date", time.Now().Unix()) // Index the document. The API accepts multiple documents at a time - if err := c.IndexOptions(redisearch.DefaultIndexingOptions, doc); err != nil { + if err := c.IndexOptions(DefaultIndexingOptions, doc); err != nil { log.Fatal(err) } // Searching with limit and sorting - docs, total, err := c.Search(redisearch.NewQuery("hello world"). + docs, total, err := c.Search(NewQuery("hello world"). Limit(0, 2). SetReturnFields("title"))