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

273 lines
6.3 KiB
Go
Raw Normal View History

2020-06-13 23:21:28 +08:00
package main
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
2020-07-24 19:12:31 +08:00
"github.com/sf9v/solr-go"
2020-06-13 23:21:28 +08:00
)
// searchHandler is the search handler
type searchHandler struct {
collection string
solrClient solr.Client
}
// facetConfig is a facet configuration
type facetConfig struct {
// field is the field name
field,
// facet is the facet name
facet,
// param is the url query param to be used for retrieving filter values
urlParam string
// isChild set to true to indicate that this is a child facet
isChild bool
}
var facetConfigs = []facetConfig{
// {
// facet: "Category",
// field: "category",
// urlParam: "categories",
// },
{
facet: "Product Type",
field: "productType",
urlParam: "productTypes",
},
{
facet: "Brand",
field: "brand",
urlParam: "brands",
},
{
facet: "Color Family",
field: "colorFamily_s",
urlParam: "colorFamilies",
isChild: true,
},
// {
// facet: "Sim Card Slots",
// field: "simCardSlots_s",
// urlParam: "simCardSlots",
// isChild: true,
// },
{
facet: "Operating System",
field: "operatingSystem_s",
urlParam: "operatingSystems",
isChild: true,
},
{
facet: "Storage Capacity",
field: "storageCapacity_s",
urlParam: "storageCapacities",
isChild: true,
},
}
func (h *searchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
2021-02-10 09:52:07 +08:00
facets := []solr.Faceter{}
2020-06-13 23:21:28 +08:00
productFilters, skuFilters := []string{}, []string{}
2021-02-10 23:38:41 +08:00
for _, fc := range facetConfigs {
filterVals := strings.Split(r.URL.Query().Get(fc.urlParam), ",")
2020-06-13 23:21:28 +08:00
tagVals := []string{}
for _, val := range filterVals {
if val == "" {
continue
}
2021-02-10 23:38:41 +08:00
tagVals = append(tagVals, fc.field+":"+val)
2020-06-13 23:21:28 +08:00
}
2021-02-10 23:38:41 +08:00
if !fc.isChild {
2020-06-13 23:21:28 +08:00
// product filters
if len(tagVals) > 0 {
2021-02-10 23:38:41 +08:00
productFilters = append(productFilters, solr.NewStandardQueryParser().
Tag("top").Query("'"+strings.Join(tagVals, " OR ")+"'").BuildParser())
2020-06-13 23:21:28 +08:00
} else {
2021-02-10 23:38:41 +08:00
productFilters = append(productFilters, solr.NewStandardQueryParser().
Tag("top").Query(fc.field+":*").BuildParser())
2020-06-13 23:21:28 +08:00
}
2021-02-10 23:38:41 +08:00
termsFacet := solr.NewTermsFacet(fc.facet).Field(fc.field).
Limit(-1).AddToFacet("productCount", "uniqueBlock(_root_)")
2021-02-10 09:52:07 +08:00
facets = append(facets, termsFacet)
2020-06-13 23:21:28 +08:00
continue
}
// sku filters
if len(tagVals) > 0 {
2021-02-10 23:38:41 +08:00
skuFilters = append(skuFilters, solr.NewStandardQueryParser().Tag(fc.field).
Query("'"+strings.Join(tagVals, " OR ")+"'").BuildParser())
2020-06-13 23:21:28 +08:00
} else {
2021-02-10 23:38:41 +08:00
skuFilters = append(skuFilters, solr.NewStandardQueryParser().Tag(fc.field).
Query(fc.field+":*").BuildParser())
2020-06-13 23:21:28 +08:00
}
2021-02-10 23:38:41 +08:00
termsFacet := solr.NewTermsFacet(fc.facet).
Field(fc.field).Limit(-1).
2021-02-10 09:52:07 +08:00
AddToDomain("excludeTags", "top").
AddToDomain("filter", []string{
2021-02-10 23:38:41 +08:00
solr.NewFiltersQueryParser().Param("$skuFilters").
ExcludeTags(fc.field).Query("$sku").BuildParser(),
solr.NewChildrenQueryParser().Of("$product").Filters("$filter").
Query("$product").BuildParser(),
2021-02-10 09:52:07 +08:00
}).
AddToFacet("productCount", "uniqueBlock(_root_)")
2021-02-10 23:38:41 +08:00
facets = append(facets, termsFacet)
2020-06-13 23:21:28 +08:00
}
2021-02-10 23:38:41 +08:00
queryStr := r.URL.Query().Get("q")
if len(queryStr) == 0 {
queryStr = "*"
} else {
2021-02-10 23:38:41 +08:00
queryStr = fmt.Sprintf("%q", queryStr)
}
2021-02-10 09:52:07 +08:00
productFilters = append(productFilters, solr.NewStandardQueryParser().
2021-02-10 23:38:41 +08:00
Tag("top").Query("_text_:"+queryStr).BuildParser())
queryParser := solr.NewParentQueryParser().Tag("top").Filters("$skuFilters").
Which("$product").Score("total").Query("$sku")
2021-09-06 12:46:27 +08:00
query := solr.NewQuery(queryParser.BuildParser()).
2021-02-10 23:38:41 +08:00
Filters(productFilters...).
Facets(facets...).
2021-02-10 09:52:07 +08:00
Queries(solr.M{
2020-06-13 23:21:28 +08:00
"product": "docType:product",
"sku": "docType:sku",
"skuFilters": skuFilters,
2021-02-10 23:38:41 +08:00
})
2020-06-13 23:21:28 +08:00
2021-02-10 09:52:07 +08:00
queryResp, err := h.solrClient.Query(r.Context(), h.collection, query)
2020-06-13 23:21:28 +08:00
if err != nil {
http.Error(w, err.Error(), 500)
return
}
// extract products and facets from query response
2021-02-10 23:38:41 +08:00
resp, err := buildResponse(queryResp)
2020-06-13 23:21:28 +08:00
if err != nil {
http.Error(w, err.Error(), 500)
return
}
2020-06-30 17:13:00 +08:00
debug := r.URL.Query().Get("debug") == "true"
if debug {
resp["query"] = query
}
2020-06-13 23:21:28 +08:00
err = json.NewEncoder(w).Encode(resp)
if err != nil {
http.Error(w, err.Error(), 500)
}
}
2021-02-10 23:38:41 +08:00
func buildResponse(response *solr.QueryResponse) (solr.M, error) {
2021-02-10 09:52:07 +08:00
var facets = []solr.M{}
2021-02-10 23:38:41 +08:00
for name, v := range response.Facets {
2020-06-13 23:21:28 +08:00
if name == "count" {
continue
}
2021-02-10 09:52:07 +08:00
vv, ok := v.(map[string]interface{})
2020-06-13 23:21:28 +08:00
if !ok {
2021-02-10 23:38:41 +08:00
return nil, errors.New("v is not map[string]interface{}")
2020-06-13 23:21:28 +08:00
}
2021-02-10 09:52:07 +08:00
bucks, ok := vv["buckets"].([]interface{})
2020-06-13 23:21:28 +08:00
if !ok {
2021-02-10 23:38:41 +08:00
return nil, errors.New("vv is not []interface{}")
2020-06-13 23:21:28 +08:00
}
2021-02-10 09:52:07 +08:00
buckets := []solr.M{}
2020-06-13 23:21:28 +08:00
for _, bk := range bucks {
2021-02-10 09:52:07 +08:00
buck, ok := bk.(map[string]interface{})
2020-06-13 23:21:28 +08:00
if !ok {
2021-02-10 23:38:41 +08:00
return nil, errors.New("bucket is not map[string]interface{}")
2020-06-13 23:21:28 +08:00
}
productCount, ok := buck["productCount"].(float64)
if !ok {
return nil, errors.New("productCount is not float64")
}
skuCount, ok := buck["count"].(float64)
if !ok {
return nil, errors.New("count is not float64")
}
val, ok := buck["val"].(string)
if !ok {
return nil, errors.New("val is not string")
}
2021-02-10 09:52:07 +08:00
buckets = append(buckets, solr.M{
2020-06-13 23:21:28 +08:00
"val": val,
"skuCount": int(skuCount),
"productCount": int(productCount),
})
}
var param string
2021-02-10 23:38:41 +08:00
for _, fc := range facetConfigs {
if fc.facet == name {
param = fc.urlParam
2020-06-13 23:21:28 +08:00
}
}
2021-02-10 09:52:07 +08:00
facets = append(facets, solr.M{
2020-06-13 23:21:28 +08:00
"name": name,
"param": param,
"buckets": buckets,
})
}
2021-02-10 09:52:07 +08:00
var products = []solr.M{}
2021-02-10 23:38:41 +08:00
for _, doc := range response.Response.Documents {
2020-06-13 23:21:28 +08:00
id, ok := doc["id"].(string)
if !ok {
return nil, errors.New("id not found or is not string")
}
2021-02-10 09:52:07 +08:00
name, ok := doc["name"].([]interface{})
2020-06-13 23:21:28 +08:00
if !ok {
2021-02-10 23:38:41 +08:00
return nil, errors.New("name not found or is not []interface{}")
2020-06-13 23:21:28 +08:00
}
2021-02-10 09:52:07 +08:00
category, ok := doc["category"].([]interface{})
2020-06-13 23:21:28 +08:00
if !ok {
2021-02-10 23:38:41 +08:00
return nil, errors.New("category not found or is not []interface{}")
2020-06-13 23:21:28 +08:00
}
2021-02-10 09:52:07 +08:00
brand, ok := doc["brand"].([]interface{})
2020-06-13 23:21:28 +08:00
if !ok {
2021-02-10 23:38:41 +08:00
return nil, errors.New("brand not found or is not []interface{}")
2020-06-13 23:21:28 +08:00
}
productType, ok := doc["productType"].(string)
if !ok {
return nil, errors.New("productType not found or is not string")
}
2021-02-10 09:52:07 +08:00
products = append(products, solr.M{
2020-06-13 23:21:28 +08:00
"id": id,
"name": name[0].(string),
"category": category[0].(string),
"brand": brand[0].(string),
"productType": productType,
})
}
2021-02-10 09:52:07 +08:00
return solr.M{
2020-06-13 23:21:28 +08:00
"products": products,
"facets": facets,
}, nil
}