diff --git a/bin/schema.xml b/bin/schema.xml index 0cf0bc7..4267f4c 100644 --- a/bin/schema.xml +++ b/bin/schema.xml @@ -10,6 +10,9 @@ + + + id diff --git a/solrHttp.go b/solrHttp.go index 24cff89..75df470 100644 --- a/solrHttp.go +++ b/solrHttp.go @@ -35,6 +35,9 @@ type solrHttp struct { router Router } +// M is a shortcut for map[string]interface{} +type M map[string]interface{} + func NewSolrHTTP(useHTTPS bool, collection string, options ...func(*solrHttp)) (SolrHTTP, error) { solrCli := solrHttp{collection: collection, minRf: 1, insecureSkipVerify: false, readTimeoutSeconds: 20, writeTimeoutSeconds: 30, connectTimeoutSeconds: 5} logger := log.New(os.Stdout, "[SolrClient] ", log.LstdFlags) @@ -303,6 +306,16 @@ func Cursor(c string) func(url.Values) { } } +// JSONFacet helper function for defining JSON Facets. +func JSONFacet(opts M) func(url.Values) { + jsonFacet, err := json.Marshal(opts) + return func(p url.Values) { + if err == nil { + p["json.facet"] = []string{string(jsonFacet)} + } + } +} + func UrlVals(urlVals url.Values) func(url.Values) { return func(p url.Values) { for key := range urlVals { diff --git a/solrResponse.go b/solrResponse.go index ccacc94..5f74cc8 100644 --- a/solrResponse.go +++ b/solrResponse.go @@ -8,9 +8,10 @@ type SolrResponse struct { Indent string `json:"indent"` Wt string `json:"wt"` } `json:"params"` - Response Response `json:"response"` - NextCursorMark string `json:"nextCursorMark"` - Adds Adds `json:"adds"` + Response Response `json:"response"` + NextCursorMark string `json:"nextCursorMark"` + Adds Adds `json:"adds"` + Facets map[string]interface{} `json:"facets"` } type Response struct { diff --git a/solr_query_test.go b/solr_query_test.go new file mode 100644 index 0000000..2ba41c9 --- /dev/null +++ b/solr_query_test.go @@ -0,0 +1,89 @@ +package solr_test + +import ( + "net/url" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/sendgrid/go-solr" +) + +var _ = Describe("Solr Client", func() { + var solrClient solr.SolrZK + var solrHttp solr.SolrHTTP + var solrHttpRetrier solr.SolrHTTP + var locator solr.SolrLocator + solrClient = solr.NewSolrZK("zk:2181", "solr", "solrtest") + locator = solrClient.GetSolrLocator() + const limit int = 100 + uuid, _ := newUUID() + shardKey := "mycrazysha" + uuid + + err := solrClient.Listen() + BeforeEach(func() { + Expect(err).To(BeNil()) + https, _ := solrClient.UseHTTPS() + solrHttp, err = solr.NewSolrHTTP(https, "solrtest", solr.User("solr"), solr.Password("admin"), solr.MinRF(2)) + Expect(err).To(BeNil()) + solrHttpRetrier = solr.NewSolrHttpRetrier(solrHttp, 5, 100*time.Millisecond) + + var salaries = []float32{40000, 60000, 80000, 100000, 120000} + var firstNames = []string{"john", "jane", "alice", "bob", "ashley", "gordon", "peter", "cindy", "brie", "alex"} + for i := 0; i < limit; i++ { + iterationId, _ := newUUID() + lastId := shardKey + "!rando" + iterationId + doc := map[string]interface{}{ + "id": lastId, + "email": "rando" + iterationId + "@sendgrid.com", + "first_name": firstNames[i%len(firstNames)], + "last_name": uuid, + "salary": salaries[i%len(salaries)], + } + leader, err := locator.GetLeaders(doc["id"].(string)) + Expect(err).To(BeNil()) + + if i < limit-1 { + err := solrHttp.Update(leader, true, doc, solr.Commit(false)) + Expect(err).To(BeNil()) + } else { + err := solrHttp.Update(leader, true, doc, solr.Commit(true)) + Expect(err).To(BeNil()) + } + } + }) + + AfterEach(func() { + replicas, err := locator.GetReplicasFromRoute(shardKey + "!") + Expect(err).To(BeNil()) + err = solrHttp.Update(replicas, false, nil, solr.Commit(true), solr.DeleteStreamBody("last_name:*")) + Expect(err).To(BeNil()) + }) + + Describe("Test Faceting", func() { + It("can return facets", func() { + replicas, err := locator.GetReplicaUris() + Expect(err).To(BeNil()) + + query := []func(url.Values){ + solr.Query("*:*"), + solr.JSONFacet( + solr.M{ + "max_salary": "max(salary)", + "salary": solr.M{ + "type": "terms", + "field": "salary", + }, + }, + ), + } + + r, err := solrHttp.Select(replicas, query...) + Expect(err).To(BeNil()) + Expect(r).To(Not(BeNil())) + Expect(r.Response.NumFound).To(BeEquivalentTo(limit)) + Expect(r.Facets["max_salary"].(float64)).To(BeEquivalentTo(120000)) + Expect(len(r.Facets["salary"].(map[string]interface{})["buckets"].([]interface{}))).To(BeEquivalentTo(5)) + }) + }) +})