1
0
mirror of https://github.com/stevenferrer/multi-select-facet.git synced 2025-11-23 21:54:45 +02:00

Upgrade solr-go to version 0.2

This commit is contained in:
Steven Ferrer
2021-02-10 09:52:07 +08:00
parent fe3169f05f
commit 973d09768b
12 changed files with 193 additions and 218 deletions

2
.gitignore vendored
View File

@@ -13,3 +13,5 @@
# Dependency directories (remove the comment below to include it)
# vendor/
api

View File

@@ -1,11 +1,11 @@
DOCKER ?= docker
SOLR_INST ?="solr-multi-select-facet-demo"
COLLECTION ?= "multi-select-facet-demo"
PODMAN ?= podman
SOLR ?="multi-select-facet-demo"
.PHONY: solr
solr: stop-solr
$(DOCKER) run -d -p 8983:8983 --name $(SOLR_INST) solr:latest solr-precreate $(COLLECTION)
.PHONY: start-solr
start-solr: stop-solr
$(PODMAN) run -d -p 8983:8983 --name $(SOLR) solr:8 solr -c -f
$(PODMAN) exec -it $(SOLR) bash -c 'sleep 5; wait-for-solr.sh --max-attempts 10 --wait-seconds 5'
.PHONY: stop-solr
stop-solr:
$(DOCKER) rm -f $(SOLR_INST) || true
$(PODMAN) rm -f $(SOLR) || true

View File

@@ -7,32 +7,25 @@ Blog post: [Multi-Select Facet with Solr, Vue and Go](https://sf9v.github.io/pos
## Running the example
1. Run Solr in `docker`.
1. Run Solr using [podman](https://podman.io/).
```console
$ make solr
$ make start-solr
```
Or using [podman](https://podman.io/).
Or using `docker`.
```console
$ DOCKER=podman make solr
$ PODMAN=docker make start-solr
```
The above commands starts Solr container and pre-creates `multi-select-facet-demo` collection.
Wait for a few seconds until Solr has completed loading.
2. Run the API
```console
// cd to api
$ cd cmd/api
// build the api
$ go build -v
$ go build -v -o api
// start the api
$ ./api -init-schema -index-data -init-suggester
// start the api with the initialization options
$ ./api -create-collection -init-schema -index-data -init-suggester
```
3. Run the web app (open a new terminal tab)
@@ -51,7 +44,7 @@ $ yarn serve // or npm run serve
## Contributing
Please feel free to improve this by [sending a PR](https://github.com/sf9v/multi-select-facet/pulls) or [opening an issue](https://github.com/sf9v/multi-select-facet/issues).
Feel free to improve this project by [make a pull-request](https://github.com/sf9v/multi-select-facet/pulls) or [opening an issue](https://github.com/sf9v/multi-select-facet/issues).
## License

7
go.mod
View File

@@ -1,11 +1,10 @@
module github.com/sf9v/multi-select-facet
go 1.14
go 1.15
require (
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/chi v1.5.1
github.com/go-chi/cors v1.1.1
github.com/pkg/errors v0.9.1
github.com/sf9v/solr-go v0.1.3
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
github.com/sf9v/solr-go v0.2.0
)

28
go.sum
View File

@@ -1,33 +1,21 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v1.5.1 h1:kfTK3Cxd/dkMu/rKs5ZceWYp+t5CtiE7vmaTv3LjC6w=
github.com/go-chi/chi v1.5.1/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k=
github.com/go-chi/cors v1.1.1 h1:eHuqxsIw89iXcWnWUN8R72JMibABJTN/4IOYI5WERvw=
github.com/go-chi/cors v1.1.1/go.mod h1:K2Yje0VW/SJzxiyMYu6iPQYa7hMjQX2i/F491VChg1I=
github.com/jarcoal/httpmock v1.0.7 h1:d1a2VFpSdm5gtjhCPWsQHSnx8+5V3ms5431YwvmkuNk=
github.com/jarcoal/httpmock v1.0.7/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sf9v/solr-go v0.1.3 h1:ldgScD/jhZG5haSAOqjuMMXZAImz6dNkNT9XBUAIDDU=
github.com/sf9v/solr-go v0.1.3/go.mod h1:JhdkNLuAOmKTj3TcZ6URW+SCQjoxEKkwLcI6EIEQkHE=
github.com/sf9v/solr-go v0.2.0 h1:fCzDh7knvWtDPAhCdGLpB1GliB7sw1BjMa82HAxHO94=
github.com/sf9v/solr-go v0.2.0/go.mod h1:cSkq8rJSD20L8LkUSLBvzw5H8DGEu8W0OggweUpuMfo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -2,11 +2,10 @@ package main
import (
"context"
"encoding/json"
"flag"
"io/ioutil"
"log"
"net/http"
"os"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
@@ -14,32 +13,35 @@ import (
"github.com/pkg/errors"
solr "github.com/sf9v/solr-go"
solrconfig "github.com/sf9v/solr-go/config"
solrindex "github.com/sf9v/solr-go/index"
solrschema "github.com/sf9v/solr-go/schema"
)
// Any is a convenience type for interface{}
type Any = interface{}
// Map is a convenience type for map[string]interface{}
type Map = map[string]Any
const (
dataPath = "products.json"
coll = "multi-select-facet-demo"
dataPath = "data/products.json"
defaultCollection = "multi-select-facet-demo"
)
func main() {
collection := flag.String("collection", coll, "specify the name of collection")
collection := flag.String("collection", defaultCollection, "specify the name of collection")
createCollection := flag.Bool("create-collection", false, "create solr collection")
initSchema := flag.Bool("init-schema", false, "initialize solr schema")
initSuggester := flag.Bool("init-suggester", false, "initialize suggester component")
indexData := flag.Bool("index-data", false, "index the products data")
flag.Parse()
solrClient := solr.NewClient("localhost", 8983)
baseURL := "http://localhost:8983"
solrClient := solr.NewJSONClient(baseURL)
ctx := context.Background()
if *createCollection {
log.Println("creating collection...")
err := solrClient.CreateCollection(ctx, solr.NewCollectionParams().
Name(*collection).NumShards(1).ReplicationFactor(1))
if err != nil {
log.Fatal(err)
}
}
if *initSchema {
log.Print("initializing solr schema...")
err := initSolrSchema(ctx, *collection, solrClient)
@@ -50,7 +52,7 @@ func main() {
if *indexData {
log.Println("indexing products...")
err := indexProducts(ctx, *collection, solrClient.Index())
err := indexProducts(ctx, *collection, solrClient)
if err != nil {
log.Fatal(err)
}
@@ -58,7 +60,7 @@ func main() {
if *initSuggester {
log.Println("initializing suggester component...")
err := initSuggestConfig(ctx, *collection, solrClient.Config())
err := initSuggestConfig(ctx, *collection, solrClient)
if err != nil {
log.Fatal(err)
}
@@ -98,52 +100,52 @@ func main() {
func initSolrSchema(ctx context.Context, collection string, solrClient solr.Client) (err error) {
// auto-suggest field type
fieldTypes := []solrschema.FieldType{
// // approach #1
// // see: https://blog.griddynamics.com/implementing-autocomplete-with-solr/
// {
// Name: "text_suggest",
// Class: "solr.TextField",
// PositionIncrementGap: "100",
// IndexAnalyzer: &solrschema.Analyzer{
// Tokenizer: &solrschema.Tokenizer{
// Class: "solr.StandardTokenizerFactory",
// },
// Filters: []solrschema.Filter{
// {
// Class: "solr.LowerCaseFilterFactory",
// },
// {
// Class: "solr.EdgeNGramFilterFactory",
// MinGramSize: 1,
// MaxGramSize: 100,
// },
// },
// },
// QueryAnalyzer: &solrschema.Analyzer{
// Tokenizer: &solrschema.Tokenizer{
// Class: "solr.KeywordTokenizerFactory",
// },
// Filters: []solrschema.Filter{
// {
// Class: "solr.LowerCaseFilterFactory",
// },
// },
// },
// },
// Auto-suggest field type
fieldTypes := []solr.FieldType{
// approach #1
// Refer to https://blog.griddynamics.com/implementing-autocomplete-with-solr/
{
Name: "text_suggest_1",
Class: "solr.TextField",
PositionIncrementGap: "100",
IndexAnalyzer: &solr.Analyzer{
Tokenizer: &solr.Tokenizer{
Class: "solr.StandardTokenizerFactory",
},
Filters: []solr.Filter{
{
Class: "solr.LowerCaseFilterFactory",
},
{
Class: "solr.EdgeNGramFilterFactory",
MinGramSize: 1,
MaxGramSize: 100,
},
},
},
QueryAnalyzer: &solr.Analyzer{
Tokenizer: &solr.Tokenizer{
Class: "solr.KeywordTokenizerFactory",
},
Filters: []solr.Filter{
{
Class: "solr.LowerCaseFilterFactory",
},
},
},
},
// approach #2
// see: https://blog.griddynamics.com/implement-autocomplete-search-for-large-e-commerce-catalogs/
// Refer to https://blog.griddynamics.com/implement-autocomplete-search-for-large-e-commerce-catalogs/
{
Name: "text_suggest",
Class: "solr.TextField",
PositionIncrementGap: "100",
IndexAnalyzer: &solrschema.Analyzer{
Tokenizer: &solrschema.Tokenizer{
IndexAnalyzer: &solr.Analyzer{
Tokenizer: &solr.Tokenizer{
Class: "solr.WhitespaceTokenizerFactory",
},
Filters: []solrschema.Filter{
Filters: []solr.Filter{
{
Class: "solr.LowerCaseFilterFactory",
},
@@ -157,11 +159,11 @@ func initSolrSchema(ctx context.Context, collection string, solrClient solr.Clie
},
},
},
QueryAnalyzer: &solrschema.Analyzer{
Tokenizer: &solrschema.Tokenizer{
QueryAnalyzer: &solr.Analyzer{
Tokenizer: &solr.Tokenizer{
Class: "solr.WhitespaceTokenizerFactory",
},
Filters: []solrschema.Filter{
Filters: []solr.Filter{
{
Class: "solr.LowerCaseFilterFactory",
},
@@ -178,14 +180,14 @@ func initSolrSchema(ctx context.Context, collection string, solrClient solr.Clie
}
for _, fieldType := range fieldTypes {
err = solrClient.Schema().AddFieldType(ctx, collection, fieldType)
err = solrClient.AddFieldTypes(ctx, collection, fieldType)
if err != nil {
return errors.Wrap(err, "add field type")
}
}
// define the fields
fields := []solrschema.Field{
fields := []solr.Field{
{
Name: "docType",
Type: "string",
@@ -214,14 +216,12 @@ func initSolrSchema(ctx context.Context, collection string, solrClient solr.Clie
},
}
for _, field := range fields {
err = solrClient.Schema().AddField(ctx, collection, field)
err = solrClient.AddFields(ctx, collection, fields...)
if err != nil {
return errors.Wrap(err, "add field")
}
return errors.Wrap(err, "add fields")
}
copyFields := []solrschema.CopyField{
copyFields := []solr.CopyField{
{
Source: "name",
Dest: "suggest",
@@ -249,48 +249,42 @@ func initSolrSchema(ctx context.Context, collection string, solrClient solr.Clie
},
}
for _, copyField := range copyFields {
err = solrClient.Schema().AddCopyField(ctx, collection, copyField)
err = solrClient.AddCopyFields(ctx, collection, copyFields...)
if err != nil {
return errors.Wrap(err, "add copy field")
}
return errors.Wrap(err, "add copy fields")
}
return nil
}
func initSuggestConfig(ctx context.Context, collection string, configClient solrconfig.Client) error {
func initSuggestConfig(ctx context.Context, collection string, solrClient solr.Client) error {
// suggester configs
addSuggestComponent := solrconfig.NewComponentCommand(
solrconfig.AddSearchComponent, Map{
"name": "suggest",
"class": "solr.SuggestComponent",
"suggester": Map{
suggestComponent := solr.NewComponent(solr.SearchComponent).
Name("suggest").Class("solr.SuggestComponent").
Config(solr.M{
"suggester": solr.M{
"name": "default",
"lookupImpl": "AnalyzingInfixLookupFactory",
"dictionaryImpl": "DocumentDictionaryFactory",
"field": "suggest",
"suggestAnalyzerFieldType": "text_suggest",
},
},
)
})
addSuggestHandler := solrconfig.NewComponentCommand(
solrconfig.AddRequestHandler, Map{
"name": "/suggest",
"class": "solr.SearchHandler",
suggestHandler := solr.NewComponent(solr.RequestHandler).
Name("/suggest").Class("solr.SearchHandler").
Config(solr.M{
"startup": "lazy",
"defaults": Map{
"defaults": solr.M{
"suggest": true,
"suggest.count": 10,
"suggest.dictionary": "default",
},
"components": []string{"suggest"},
},
)
})
err := configClient.SendCommands(ctx, collection,
addSuggestComponent, addSuggestHandler)
err := solrClient.AddComponents(ctx, collection,
suggestComponent, suggestHandler)
if err != nil {
return errors.Wrap(err, "add suggester configs")
}
@@ -299,30 +293,19 @@ func initSuggestConfig(ctx context.Context, collection string, configClient solr
}
func indexProducts(ctx context.Context, collection string,
indexClient solrindex.Client) error {
b, err := ioutil.ReadFile(dataPath)
solrClient solr.Client) error {
f, err := os.OpenFile(dataPath, os.O_RDONLY, 0644)
if err != nil {
return err
}
var products []Map
err = json.Unmarshal(b, &products)
if err != nil {
return err
}
docs := solrindex.NewDocs()
for _, product := range products {
docs.AddDoc(product)
}
err = indexClient.AddDocuments(ctx, collection, docs)
_, err = solrClient.Update(ctx, collection, solr.JSON, f)
if err != nil {
return err
}
// commit updates
err = indexClient.Commit(ctx, collection)
err = solrClient.Commit(ctx, collection)
if err != nil {
return err
}

View File

@@ -8,7 +8,6 @@ import (
"strings"
"github.com/sf9v/solr-go"
"github.com/sf9v/solr-go/query"
)
// searchHandler is the search handler
@@ -72,7 +71,7 @@ var facetConfigs = []facetConfig{
}
func (h *searchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
facetsMap := Map{}
facets := []solr.Faceter{}
productFilters, skuFilters := []string{}, []string{}
for _, fctCfg := range facetConfigs {
tagVals := []string{}
@@ -87,45 +86,52 @@ func (h *searchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !fctCfg.isChild {
// product filters
if len(tagVals) > 0 {
productFilters = append(productFilters, fmt.Sprintf("{!tag=top}%s", strings.Join(tagVals, " OR ")))
filterQuery := solr.NewStandardQueryParser().Tag("top").
Query("'" + strings.Join(tagVals, " OR ") + "'").
BuildParser()
productFilters = append(productFilters, filterQuery)
} else {
productFilters = append(productFilters, fmt.Sprintf("{!tag=top}%s:*", fctCfg.field))
filterQuery := solr.NewStandardQueryParser().Tag("top").
Query(fctCfg.field + ":*").BuildParser()
productFilters = append(productFilters, filterQuery)
}
facetsMap[fctCfg.facet] = Map{
"facet": Map{
"productCount": "uniqueBlock(_root_)",
},
"field": fctCfg.field,
"limit": -1,
"type": "terms",
}
termsFacet := solr.NewTermsFacet(fctCfg.facet).
Field(fctCfg.field).Limit(-1).
AddToFacet("productCount", "uniqueBlock(_root_)")
facets = append(facets, termsFacet)
continue
}
// sku filters
if len(tagVals) > 0 {
skuFilters = append(skuFilters, fmt.Sprintf("{!tag=%s}%s", fctCfg.field, strings.Join(tagVals, " OR ")))
filterQuery := solr.NewStandardQueryParser().Tag(fctCfg.field).
Query("'" + strings.Join(tagVals, " OR ") + "'").BuildParser()
skuFilters = append(skuFilters, filterQuery)
} else {
skuFilters = append(skuFilters, fmt.Sprintf("{!tag=%s}%s:*", fctCfg.field, fctCfg.field))
filterQuery := solr.NewStandardQueryParser().Tag(fctCfg.field).
Query(fctCfg.field + ":*").BuildParser()
skuFilters = append(skuFilters, filterQuery)
}
facetsMap[fctCfg.facet] = Map{
"domain": Map{
"excludeTags": "top",
"filter": []string{
fmt.Sprintf("{!filters param=$skuFilters excludeTags=%s v=$sku}", fctCfg.field),
"{!child of=$product filters=$filter v=$product}",
},
},
"type": "terms",
"field": fctCfg.field,
"limit": -1,
"facet": Map{
"productCount": "uniqueBlock(_root_)",
},
}
facet := solr.NewTermsFacet(fctCfg.facet).
Field(fctCfg.field).Limit(-1).
AddToDomain("excludeTags", "top").
AddToDomain("filter", []string{
solr.NewFiltersQueryParser().
Param("$skuFilters").
ExcludeTags(fctCfg.field).
Query("$sku").BuildParser(),
solr.NewChildrenQueryParser().
Of("$product").
Filters("$filter").
Query("$product").
BuildParser(),
}).
AddToFacet("productCount", "uniqueBlock(_root_)")
facets = append(facets, facet)
}
q := r.URL.Query().Get("q")
@@ -135,20 +141,27 @@ func (h *searchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
q = fmt.Sprintf("%q", q)
}
productFilters = append(productFilters, fmt.Sprintf("{!tag=top}_text_:%s", q))
productFilters = append(productFilters, solr.NewStandardQueryParser().
Tag("top").Query("_text_:"+q).BuildParser())
query := Map{
"query": "{!parent tag=top filters=$skuFilters which=$product score=total v=$sku}",
"queries": Map{
query := solr.NewQuery().
QueryParser(
solr.NewParentQueryParser().
Tag("top").
Filters("$skuFilters").
Which("$product").
Score("total").
Query("$sku"),
).
Queries(solr.M{
"product": "docType:product",
"sku": "docType:sku",
"skuFilters": skuFilters,
},
"filter": productFilters,
"facet": facetsMap,
}
}).
Filters(productFilters...).
Facets(facets...)
queryResp, err := h.solrClient.Query().Query(r.Context(), h.collection, query)
queryResp, err := h.solrClient.Query(r.Context(), h.collection, query)
if err != nil {
http.Error(w, err.Error(), 500)
return
@@ -166,33 +179,32 @@ func (h *searchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
resp["query"] = query
}
w.Header().Add("content-type", "application/json")
err = json.NewEncoder(w).Encode(resp)
if err != nil {
http.Error(w, err.Error(), 500)
}
}
func buildResp(queryResp *query.Response) (Map, error) {
var facets = []Map{}
func buildResp(queryResp *solr.QueryResponse) (solr.M, error) {
var facets = []solr.M{}
for name, v := range queryResp.Facets {
if name == "count" {
continue
}
vv, ok := v.(Map)
vv, ok := v.(map[string]interface{})
if !ok {
return nil, errors.New("v is not M")
}
bucks, ok := vv["buckets"].([]Any)
bucks, ok := vv["buckets"].([]interface{})
if !ok {
return nil, errors.New("vv is not []Any")
}
buckets := []Map{}
buckets := []solr.M{}
for _, bk := range bucks {
buck, ok := bk.(Map)
buck, ok := bk.(map[string]interface{})
if !ok {
return nil, errors.New("bucket is not M")
}
@@ -212,7 +224,7 @@ func buildResp(queryResp *query.Response) (Map, error) {
return nil, errors.New("val is not string")
}
buckets = append(buckets, Map{
buckets = append(buckets, solr.M{
"val": val,
"skuCount": int(skuCount),
"productCount": int(productCount),
@@ -227,31 +239,31 @@ func buildResp(queryResp *query.Response) (Map, error) {
}
}
facets = append(facets, Map{
facets = append(facets, solr.M{
"name": name,
"param": param,
"buckets": buckets,
})
}
var products = []Map{}
for _, doc := range queryResp.Response.Docs {
var products = []solr.M{}
for _, doc := range queryResp.Response.Documents {
id, ok := doc["id"].(string)
if !ok {
return nil, errors.New("id not found or is not string")
}
name, ok := doc["name"].([]Any)
name, ok := doc["name"].([]interface{})
if !ok {
return nil, errors.New("name not found or is not []Any")
}
category, ok := doc["category"].([]Any)
category, ok := doc["category"].([]interface{})
if !ok {
return nil, errors.New("category not found or is not []Any")
}
brand, ok := doc["brand"].([]Any)
brand, ok := doc["brand"].([]interface{})
if !ok {
return nil, errors.New("brand not found or is not []Any")
}
@@ -261,7 +273,7 @@ func buildResp(queryResp *query.Response) (Map, error) {
return nil, errors.New("productType not found or is not string")
}
products = append(products, Map{
products = append(products, solr.M{
"id": id,
"name": name[0].(string),
"category": category[0].(string),
@@ -270,7 +282,7 @@ func buildResp(queryResp *query.Response) (Map, error) {
})
}
return Map{
return solr.M{
"products": products,
"facets": facets,
}, nil

View File

@@ -5,7 +5,6 @@ import (
"net/http"
"github.com/sf9v/solr-go"
"github.com/sf9v/solr-go/suggester"
)
type suggestHandler struct {
@@ -13,6 +12,10 @@ type suggestHandler struct {
solrClient solr.Client
}
type suggestion struct {
Term string `json:"term"`
}
func (h *suggestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query().Get("q")
@@ -21,8 +24,9 @@ func (h *suggestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
dict := "default"
suggestResp, err := h.solrClient.Suggester().Suggest(r.Context(), h.collection,
suggester.Params{Query: q, Dictionaries: []string{dict}})
suggestParams := solr.NewSuggesterParams("suggest").
Build().Query(q).Dictionaries(dict)
suggestResp, err := h.solrClient.Suggest(r.Context(), h.collection, suggestParams)
if err != nil {
http.Error(w, err.Error(), 500)
return
@@ -31,23 +35,17 @@ func (h *suggestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
suggest := *suggestResp.Suggest
termBody := suggest[dict][q]
suggestions := []struct {
Term string `json:"term"`
}{}
suggestions := []suggestion{}
for _, suggest := range termBody.Suggestions {
suggestions = append(suggestions, struct {
Term string `json:"term"`
}{Term: suggest.Term})
suggestions = append(suggestions, suggestion{
Term: suggest.Term,
})
}
resp := Map{
err = json.NewEncoder(w).Encode(solr.M{
"numFound": termBody.NumFound,
"suggestions": suggestions,
}
w.Header().Add("content-type", "application/json")
err = json.NewEncoder(w).Encode(resp)
})
if err != nil {
http.Error(w, err.Error(), 500)
}