222 lines
6.5 KiB
Go
222 lines
6.5 KiB
Go
package meiliService
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.ma-al.com/goc_daniel/b2b/app/config"
|
|
"git.ma-al.com/goc_daniel/b2b/app/repos/productDescriptionRepo"
|
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
|
"github.com/meilisearch/meilisearch-go"
|
|
)
|
|
|
|
type MeiliService struct {
|
|
productDescriptionRepo productDescriptionRepo.UIProductDescriptionRepo
|
|
meiliClient meilisearch.ServiceManager
|
|
}
|
|
|
|
func New() *MeiliService {
|
|
|
|
client := meilisearch.New(
|
|
config.Get().MailiSearch.ServerURL,
|
|
meilisearch.WithAPIKey(config.Get().MailiSearch.ApiKey),
|
|
)
|
|
|
|
return &MeiliService{
|
|
meiliClient: client,
|
|
productDescriptionRepo: productDescriptionRepo.New(),
|
|
}
|
|
}
|
|
|
|
// ==================================== FOR TESTING ONLY ====================================
|
|
func (s *MeiliService) CreateIndex(id_lang uint) error {
|
|
indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10)
|
|
|
|
products, err := s.productDescriptionRepo.GetMeiliProducts(id_lang)
|
|
for i := 0; i < len(products); i++ {
|
|
products[i].Description = cleanHTML(products[i].Description)
|
|
products[i].DescriptionShort = cleanHTML(products[i].DescriptionShort)
|
|
products[i].Usage = cleanHTML(products[i].Usage)
|
|
}
|
|
|
|
primaryKey := "ProductID"
|
|
docOptions := &meilisearch.DocumentOptions{
|
|
PrimaryKey: &primaryKey,
|
|
SkipCreation: false,
|
|
}
|
|
task, err := s.meiliClient.Index(indexName).AddDocuments(products, docOptions)
|
|
if err != nil {
|
|
return fmt.Errorf("meili AddDocuments error: %w", err)
|
|
}
|
|
finishedTask, err := s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond)
|
|
fmt.Printf("Task status: %s\n", finishedTask.Status)
|
|
fmt.Printf("Task error: %s\n", finishedTask.Error)
|
|
|
|
filterableAttributes := []interface{}{
|
|
"CategoryID",
|
|
"CategoryIDs",
|
|
}
|
|
task, err = s.meiliClient.Index(indexName).UpdateFilterableAttributes(&filterableAttributes)
|
|
if err != nil {
|
|
return fmt.Errorf("meili AddDocuments error: %w", err)
|
|
}
|
|
finishedTask, err = s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond)
|
|
fmt.Printf("Task status: %s\n", finishedTask.Status)
|
|
fmt.Printf("Task error: %s\n", finishedTask.Error)
|
|
|
|
displayedAttributes := []string{
|
|
"ProductID",
|
|
"Name",
|
|
"EAN13",
|
|
"Reference",
|
|
"Variations",
|
|
"CoverImage",
|
|
}
|
|
task, err = s.meiliClient.Index(indexName).UpdateDisplayedAttributes(&displayedAttributes)
|
|
if err != nil {
|
|
return fmt.Errorf("meili AddDocuments error: %w", err)
|
|
}
|
|
finishedTask, err = s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond)
|
|
fmt.Printf("Task status: %s\n", finishedTask.Status)
|
|
fmt.Printf("Task error: %s\n", finishedTask.Error)
|
|
|
|
searchableAttributes := []string{
|
|
"Name",
|
|
"DescriptionShort",
|
|
"Reference",
|
|
"EAN13",
|
|
"CategoryName",
|
|
"Description",
|
|
"Usage",
|
|
}
|
|
task, err = s.meiliClient.Index(indexName).UpdateSearchableAttributes(&searchableAttributes)
|
|
if err != nil {
|
|
return fmt.Errorf("meili AddDocuments error: %w", err)
|
|
}
|
|
finishedTask, err = s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond)
|
|
fmt.Printf("Task status: %s\n", finishedTask.Status)
|
|
fmt.Printf("Task error: %s\n", finishedTask.Error)
|
|
|
|
return err
|
|
}
|
|
|
|
// ==================================== FOR TESTING ONLY ====================================
|
|
func (s *MeiliService) Test(id_lang uint) (meilisearch.SearchResponse, error) {
|
|
indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10)
|
|
|
|
searchReq := &meilisearch.SearchRequest{
|
|
Limit: 4,
|
|
Facets: []string{
|
|
"CategoryID",
|
|
},
|
|
}
|
|
|
|
// Perform search
|
|
results, err := s.meiliClient.Index(indexName).Search("mat", searchReq)
|
|
if err != nil {
|
|
fmt.Printf("Meilisearch error: %v\n", err)
|
|
return meilisearch.SearchResponse{}, err
|
|
}
|
|
|
|
fmt.Printf("Search results for query 'mat' in %s: %d hits\n", indexName, len(results.Hits))
|
|
|
|
return *results, nil
|
|
}
|
|
|
|
// Search performs a full-text search on the specified index
|
|
func (s *MeiliService) Search(id_lang uint, query string, id_category uint) (meilisearch.SearchResponse, error) {
|
|
indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10)
|
|
|
|
filter_query := "Active = 1"
|
|
if id_category != 0 {
|
|
// Use CategoryIDs to include products from child categories
|
|
filter_query += fmt.Sprintf(" AND CategoryIDs = %d", id_category)
|
|
}
|
|
|
|
searchReq := &meilisearch.SearchRequest{
|
|
Limit: 30,
|
|
Facets: []string{
|
|
"CategoryID",
|
|
},
|
|
Filter: filter_query,
|
|
}
|
|
|
|
results, err := s.meiliClient.Index(indexName).Search(query, searchReq)
|
|
if err != nil {
|
|
fmt.Printf("Meilisearch search error: %v\n", err)
|
|
return meilisearch.SearchResponse{}, err
|
|
}
|
|
|
|
return *results, nil
|
|
}
|
|
|
|
// HealthCheck checks if Meilisearch is healthy and accessible
|
|
func (s *MeiliService) HealthCheck() (*meilisearch.Health, error) {
|
|
health, err := s.meiliClient.Health()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("meilisearch health check failed: %w", err)
|
|
}
|
|
|
|
return health, nil
|
|
}
|
|
|
|
// GetIndexSettings retrieves the current settings for a specific index
|
|
func (s *MeiliService) GetIndexSettings(id_lang uint) (map[string]interface{}, error) {
|
|
indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10)
|
|
|
|
index := s.meiliClient.Index(indexName)
|
|
|
|
result := make(map[string]interface{})
|
|
|
|
// Get searchable attributes
|
|
searchable, err := index.GetSearchableAttributes()
|
|
if err == nil {
|
|
result["searchableAttributes"] = searchable
|
|
}
|
|
|
|
// Get filterable attributes
|
|
filterable, err := index.GetFilterableAttributes()
|
|
if err == nil {
|
|
result["filterableAttributes"] = filterable
|
|
}
|
|
|
|
// Get displayed attributes
|
|
displayed, err := index.GetDisplayedAttributes()
|
|
if err == nil {
|
|
result["displayedAttributes"] = displayed
|
|
}
|
|
|
|
// Get ranking rules
|
|
ranking, err := index.GetRankingRules()
|
|
if err == nil {
|
|
result["rankingRules"] = ranking
|
|
}
|
|
|
|
// Get distinct attribute
|
|
distinct, err := index.GetDistinctAttribute()
|
|
if err == nil && distinct != nil {
|
|
result["distinctAttribute"] = *distinct
|
|
}
|
|
|
|
// Get typo tolerance
|
|
typo, err := index.GetTypoTolerance()
|
|
if err == nil {
|
|
result["typoTolerance"] = typo
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// remove all tags from HTML text
|
|
func cleanHTML(s string) string {
|
|
// Simple regex to remove all HTML tags
|
|
re := regexp.MustCompile(`<[^>]*>`)
|
|
result := re.ReplaceAllString(s, "")
|
|
// Replace multiple spaces with single space
|
|
result = regexp.MustCompile(`\s+`).ReplaceAllString(result, " ")
|
|
return strings.TrimSpace(result)
|
|
}
|