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/api/search_handler.go
Steven Ferrer a1fd241063 minor updates
2020-06-12 21:38:11 +08:00

277 lines
6.1 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/stevenferrer/solr-go"
)
type facet struct {
Name string `json:"name"`
Buckets []bucket `json:"buckets"`
}
type bucket struct {
Val string `json:"val"`
SkuCount int `json:"skuCount"`
ProductCount int `json:"productCount"`
}
type product struct {
ID string `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
ProductType string `json:"productType"`
Brand string `json:"brand"`
}
type facetConfig struct {
field, facet string
vals []string
}
type searchHandler struct {
solrClient solr.Client
}
func (h *searchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
categories := strings.Split(r.URL.Query().Get("categories"), ",")
productTypes := strings.Split(r.URL.Query().Get("productTypes"), ",")
brands := strings.Split(r.URL.Query().Get("brands"), ",")
colorFamilies := strings.Split(r.URL.Query().Get("colorFamilies"), ",")
simCardSlots := strings.Split(r.URL.Query().Get("simCardSlots"), ",")
operatingSystems := strings.Split(r.URL.Query().Get("operatingSystems"), ",")
storageCapacities := strings.Split(r.URL.Query().Get("storageCapacities"), ",")
facetsMap := M{}
catsFacetCfg := facetConfig{
facet: "categories",
field: "category",
vals: categories,
}
productTypsFacetCfg := facetConfig{
facet: "productTypes",
field: "productType",
vals: productTypes,
}
brandsFacetCfg := facetConfig{
facet: "brands",
field: "brand",
vals: brands,
}
filters := []string{}
for _, facetCfg := range []facetConfig{catsFacetCfg, productTypsFacetCfg, brandsFacetCfg} {
tagVals := []string{}
for _, val := range facetCfg.vals {
if val == "" {
continue
}
tagVals = append(tagVals, facetCfg.field+":"+val)
}
if len(tagVals) == 0 {
filters = append(filters, fmt.Sprintf("{!tag=top}%s:*", facetCfg.field))
} else {
filters = append(filters, fmt.Sprintf("{!tag=top}%s", strings.Join(tagVals, " OR ")))
}
facetsMap[facetCfg.facet] = M{
"facet": M{
"productCount": "uniqueBlock(_root_)",
},
"field": facetCfg.field,
"limit": -1,
"type": "terms",
}
}
colorFamiliesFctCfg := facetConfig{
facet: "colorFamilies",
field: "colorFamily_s",
vals: colorFamilies,
}
simCardSlotsFctCfg := facetConfig{
facet: "simCardSlots",
field: "simCardSlots_s",
vals: simCardSlots,
}
operatingSystemsFctCfg := facetConfig{
facet: "operatingSystems",
field: "operatingSystem_s",
vals: operatingSystems,
}
storageCapacitiesFctCfg := facetConfig{
facet: "storageCapacities",
field: "storageCapacity_s",
vals: storageCapacities,
}
childFqs := []string{}
for _, fctCfg := range []facetConfig{colorFamiliesFctCfg, simCardSlotsFctCfg, operatingSystemsFctCfg, storageCapacitiesFctCfg} {
tagVals := []string{}
for _, val := range fctCfg.vals {
if val == "" {
continue
}
tagVals = append(tagVals, fctCfg.field+":"+val)
}
if len(tagVals) == 0 {
childFqs = append(childFqs, fmt.Sprintf("{!tag=%s}%s:*", fctCfg.field, fctCfg.field))
} else {
childFqs = append(childFqs, fmt.Sprintf("{!tag=%s}%s", fctCfg.field, strings.Join(tagVals, " OR ")))
}
facetsMap[fctCfg.facet] = M{
"domain": M{
"excludeTags": "top",
"filter": []string{
fmt.Sprintf("{!filters param=$child.fq excludeTags=%s v=$child.query}", fctCfg.field),
"{!child of=$parent.fq filters=$fq v=$parent.fq}",
},
},
"type": "terms",
"field": fctCfg.field,
"limit": -1,
"facet": M{
"productCount": "uniqueBlock(_root_)",
},
}
}
query := M{
"query": "{!parent tag=top filters=$child.fq which=$parent.fq score=total v=$child.query}",
"queries": M{
"parent.fq": "docType:product",
"child.query": "docType:sku",
"child.fq": childFqs,
},
"filter": filters,
"fields": "*",
"facet": facetsMap,
}
// b, err := json.MarshalIndent(query, "", " ")
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(string(b))
queryRespone, err := h.solrClient.Query().Query(r.Context(), collection, query)
if err != nil {
http.Error(w, err.Error(), 500)
}
var facets = []facet{}
for k, v := range queryRespone.Facets {
if k == "count" {
continue
}
vv, ok := v.(map[string]interface{})
if !ok {
http.Error(w, "buckets is not map[string]interface{}", 500)
}
bucks, ok := vv["buckets"].([]interface{})
if !ok {
http.Error(w, "buckets not found", 500)
}
buckets := []bucket{}
for _, bk := range bucks {
buck, ok := bk.(map[string]interface{})
if !ok {
http.Error(w, "buck not map[string]interface{}", 500)
}
productCount, ok := buck["productCount"].(float64)
if !ok {
http.Error(w, "product count not found", 500)
}
skuCount, ok := buck["count"].(float64)
if !ok {
http.Error(w, "sku count not found", 500)
}
val, ok := buck["val"].(string)
if !ok {
http.Error(w, "val not found", 500)
}
buckets = append(buckets, bucket{
Val: val,
SkuCount: int(skuCount),
ProductCount: int(productCount),
})
}
facets = append(facets, facet{
Name: k,
Buckets: buckets,
})
}
var products = []product{}
for _, doc := range queryRespone.Response.Docs {
id, ok := doc["id"].(string)
if !ok {
http.Error(w, "id not found", 500)
}
name, ok := doc["name"].([]interface{})
if !ok {
http.Error(w, "name not found", 500)
}
category, ok := doc["category"].([]interface{})
if !ok {
http.Error(w, "category not found", 500)
}
brand, ok := doc["brand"].([]interface{})
if !ok {
http.Error(w, "brand not found", 500)
}
productType, ok := doc["productType"].(string)
if !ok {
http.Error(w, "productType not found", 500)
}
products = append(products, product{
ID: id,
Name: name[0].(string),
Category: category[0].(string),
Brand: brand[0].(string),
ProductType: productType,
})
}
resp := M{
"products": products,
"facets": facets,
"queryResponse": queryRespone,
}
w.Header().Add("content-type", "application/json")
err = json.NewEncoder(w).Encode(resp)
if err != nil {
http.Error(w, http.StatusText(500), 500)
}
}