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/main.go

315 lines
6.8 KiB
Go
Raw Normal View History

2020-06-09 00:12:27 +08:00
package main
2020-06-09 02:45:17 +08:00
import (
"context"
2020-06-09 19:15:43 +08:00
"flag"
2020-06-09 02:45:17 +08:00
"log"
2020-06-09 19:15:43 +08:00
"net/http"
2021-02-10 09:52:07 +08:00
"os"
2020-06-09 02:45:17 +08:00
2020-06-09 19:15:43 +08:00
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/cors"
2020-06-12 21:38:11 +08:00
"github.com/pkg/errors"
2020-06-29 16:01:17 +08:00
2020-07-24 19:12:31 +08:00
solr "github.com/sf9v/solr-go"
2020-06-09 02:45:17 +08:00
)
2020-06-09 19:15:43 +08:00
const (
2021-02-10 09:52:07 +08:00
dataPath = "data/products.json"
defaultCollection = "multi-select-facet-demo"
2020-06-09 19:15:43 +08:00
)
2020-06-09 02:45:17 +08:00
2020-06-09 19:15:43 +08:00
func main() {
2021-02-10 09:52:07 +08:00
collection := flag.String("collection", defaultCollection, "specify the name of collection")
createCollection := flag.Bool("create-collection", false, "create solr collection")
2020-06-29 16:01:17 +08:00
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")
2020-06-09 19:15:43 +08:00
flag.Parse()
2020-06-09 02:45:17 +08:00
2021-02-10 09:52:07 +08:00
baseURL := "http://localhost:8983"
solrClient := solr.NewJSONClient(baseURL)
2020-06-09 02:45:17 +08:00
2020-06-12 21:38:11 +08:00
ctx := context.Background()
2021-02-10 09:52:07 +08:00
if *createCollection {
log.Println("creating collection...")
err := solrClient.CreateCollection(ctx, solr.NewCollectionParams().
Name(*collection).NumShards(1).ReplicationFactor(1))
if err != nil {
log.Fatal(err)
}
}
2020-06-09 19:15:43 +08:00
if *initSchema {
log.Print("initializing solr schema...")
2020-06-29 16:01:17 +08:00
err := initSolrSchema(ctx, *collection, solrClient)
2020-06-09 19:15:43 +08:00
if err != nil {
log.Fatal(err)
}
}
2020-06-29 16:01:17 +08:00
if *indexData {
2020-06-09 19:15:43 +08:00
log.Println("indexing products...")
2021-02-10 09:52:07 +08:00
err := indexProducts(ctx, *collection, solrClient)
2020-06-09 19:15:43 +08:00
if err != nil {
log.Fatal(err)
}
}
2020-06-29 16:01:17 +08:00
if *initSuggester {
log.Println("initializing suggester component...")
2021-02-10 09:52:07 +08:00
err := initSuggestConfig(ctx, *collection, solrClient)
2020-06-29 16:01:17 +08:00
if err != nil {
log.Fatal(err)
}
}
2020-06-09 19:15:43 +08:00
r := chi.NewRouter()
// basic middlewares
r.Use(middleware.Logger)
r.Use(cors.Handler(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: false,
MaxAge: 300,
}))
// search handler
r.Method(http.MethodGet, "/search", &searchHandler{
2020-06-13 23:21:28 +08:00
collection: *collection,
2020-06-09 19:15:43 +08:00
solrClient: solrClient,
})
2020-06-26 18:26:10 +08:00
r.Method(http.MethodGet, "/suggest", &suggestHandler{
collection: *collection,
solrClient: solrClient,
})
2020-06-09 19:15:43 +08:00
addr := ":8081"
log.Printf("listening on %s\n", addr)
err := http.ListenAndServe(addr, r)
if err != nil {
log.Fatal(err)
}
2020-06-09 02:45:17 +08:00
}
2020-06-29 16:01:17 +08:00
func initSolrSchema(ctx context.Context, collection string, solrClient solr.Client) (err error) {
2020-10-19 18:35:21 +08:00
2021-02-10 09:52:07 +08:00
// 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",
},
},
},
},
2020-06-30 16:14:55 +08:00
// approach #2
2021-02-10 09:52:07 +08:00
// Refer to https://blog.griddynamics.com/implement-autocomplete-search-for-large-e-commerce-catalogs/
2020-06-30 16:14:55 +08:00
{
2020-10-19 18:35:21 +08:00
Name: "text_suggest",
Class: "solr.TextField",
PositionIncrementGap: "100",
2021-02-10 09:52:07 +08:00
IndexAnalyzer: &solr.Analyzer{
Tokenizer: &solr.Tokenizer{
2020-06-30 16:14:55 +08:00
Class: "solr.WhitespaceTokenizerFactory",
},
2021-02-10 09:52:07 +08:00
Filters: []solr.Filter{
2020-06-30 16:14:55 +08:00
{
Class: "solr.LowerCaseFilterFactory",
},
{
Class: "solr.ASCIIFoldingFilterFactory",
},
2020-10-19 18:35:21 +08:00
{
Class: "solr.EdgeNGramFilterFactory",
MinGramSize: 1,
MaxGramSize: 20,
},
2020-06-30 16:14:55 +08:00
},
},
2021-02-10 09:52:07 +08:00
QueryAnalyzer: &solr.Analyzer{
Tokenizer: &solr.Tokenizer{
2020-06-30 16:14:55 +08:00
Class: "solr.WhitespaceTokenizerFactory",
},
2021-02-10 09:52:07 +08:00
Filters: []solr.Filter{
2020-06-30 16:14:55 +08:00
{
Class: "solr.LowerCaseFilterFactory",
},
{
Class: "solr.ASCIIFoldingFilterFactory",
},
{
Class: "solr.SynonymGraphFilterFactory",
Synonyms: "synonyms.txt",
},
},
},
},
2020-06-26 18:26:10 +08:00
}
for _, fieldType := range fieldTypes {
2021-02-10 09:52:07 +08:00
err = solrClient.AddFieldTypes(ctx, collection, fieldType)
2020-06-26 18:26:10 +08:00
if err != nil {
return errors.Wrap(err, "add field type")
}
}
2020-06-12 21:38:11 +08:00
// define the fields
2021-02-10 09:52:07 +08:00
fields := []solr.Field{
2020-06-09 19:15:43 +08:00
{
2020-10-19 18:35:21 +08:00
Name: "docType",
Type: "string",
2020-06-09 02:45:17 +08:00
},
2020-06-09 19:15:43 +08:00
{
2020-10-19 18:35:21 +08:00
Name: "name",
Type: "text_general",
2020-06-09 02:45:17 +08:00
},
2020-06-09 19:15:43 +08:00
{
2020-10-19 18:35:21 +08:00
Name: "category",
Type: "text_gen_sort",
2020-06-09 19:15:43 +08:00
},
{
2020-10-19 18:35:21 +08:00
Name: "brand",
Type: "text_gen_sort",
2020-06-09 19:15:43 +08:00
},
{
2020-10-19 18:35:21 +08:00
Name: "productType",
Type: "string",
2020-06-09 02:45:17 +08:00
},
2020-06-26 18:26:10 +08:00
{
2020-06-28 18:19:16 +08:00
Name: "suggest",
Type: "text_suggest",
2020-10-19 18:35:21 +08:00
Stored: false,
2020-06-28 18:19:16 +08:00
MultiValued: true,
2020-06-26 18:26:10 +08:00
},
2020-06-09 02:45:17 +08:00
}
2021-02-10 09:52:07 +08:00
err = solrClient.AddFields(ctx, collection, fields...)
if err != nil {
return errors.Wrap(err, "add fields")
2020-06-09 19:15:43 +08:00
}
2020-06-09 02:45:17 +08:00
2021-02-10 09:52:07 +08:00
copyFields := []solr.CopyField{
2020-06-26 18:26:10 +08:00
{
Source: "name",
Dest: "suggest",
},
{
Source: "name",
Dest: "_text_",
},
{
Source: "category",
Dest: "_text_",
},
{
Source: "brand",
Dest: "_text_",
},
{
Source: "productType",
Dest: "_text_",
},
{
Source: "*_s",
Dest: "_text_",
},
2020-06-26 18:26:10 +08:00
}
2021-02-10 09:52:07 +08:00
err = solrClient.AddCopyFields(ctx, collection, copyFields...)
if err != nil {
return errors.Wrap(err, "add copy fields")
2020-06-26 18:26:10 +08:00
}
2020-06-09 19:15:43 +08:00
return nil
}
2020-06-09 02:45:17 +08:00
2021-02-10 09:52:07 +08:00
func initSuggestConfig(ctx context.Context, collection string, solrClient solr.Client) error {
2020-06-29 16:01:17 +08:00
// suggester configs
2021-02-10 09:52:07 +08:00
suggestComponent := solr.NewComponent(solr.SearchComponent).
Name("suggest").Class("solr.SuggestComponent").
Config(solr.M{
"suggester": solr.M{
"name": "default",
2020-10-19 18:35:21 +08:00
"lookupImpl": "AnalyzingInfixLookupFactory",
2020-06-29 16:01:17 +08:00
"dictionaryImpl": "DocumentDictionaryFactory",
"field": "suggest",
"suggestAnalyzerFieldType": "text_suggest",
},
2021-02-10 09:52:07 +08:00
})
2020-06-29 16:01:17 +08:00
2021-02-10 09:52:07 +08:00
suggestHandler := solr.NewComponent(solr.RequestHandler).
Name("/suggest").Class("solr.SearchHandler").
Config(solr.M{
2020-06-29 16:01:17 +08:00
"startup": "lazy",
2021-02-10 09:52:07 +08:00
"defaults": solr.M{
2020-06-29 16:01:17 +08:00
"suggest": true,
"suggest.count": 10,
"suggest.dictionary": "default",
2020-06-29 16:01:17 +08:00
},
"components": []string{"suggest"},
2021-02-10 09:52:07 +08:00
})
2020-06-29 16:01:17 +08:00
2021-02-10 09:52:07 +08:00
err := solrClient.AddComponents(ctx, collection,
suggestComponent, suggestHandler)
2020-06-29 16:01:17 +08:00
if err != nil {
return errors.Wrap(err, "add suggester configs")
}
return nil
}
2020-06-13 23:21:28 +08:00
func indexProducts(ctx context.Context, collection string,
2021-02-10 09:52:07 +08:00
solrClient solr.Client) error {
f, err := os.OpenFile(dataPath, os.O_RDONLY, 0644)
2020-06-09 19:15:43 +08:00
if err != nil {
return err
}
2021-02-10 09:52:07 +08:00
_, err = solrClient.Update(ctx, collection, solr.JSON, f)
2020-06-13 23:21:28 +08:00
if err != nil {
return err
}
// commit updates
2021-02-10 09:52:07 +08:00
err = solrClient.Commit(ctx, collection)
2020-06-09 19:15:43 +08:00
if err != nil {
return err
2020-06-09 02:45:17 +08:00
}
2020-06-09 00:12:27 +08:00
2020-06-09 19:15:43 +08:00
return nil
2020-06-09 02:45:17 +08:00
}