120 lines
2.1 KiB
Go
120 lines
2.1 KiB
Go
package search
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// ID ...
|
|
type ID struct {
|
|
Key interface{}
|
|
Score float64
|
|
Title []string
|
|
}
|
|
|
|
// Search ...
|
|
type Search struct {
|
|
Words map[interface{}][][]string
|
|
IgnoreWords []string
|
|
RemoveCharacters []string
|
|
}
|
|
|
|
// CleanSearch ...
|
|
func (DB *Search) CleanSearch(title string) []string {
|
|
s := []string{}
|
|
for _, c := range DB.RemoveCharacters {
|
|
title = strings.Replace(title, c, ` `, -1)
|
|
}
|
|
for _, v := range strings.Split(title, ` `) {
|
|
matched := false
|
|
if v == `` || v == ` ` {
|
|
continue
|
|
}
|
|
for _, w := range DB.IgnoreWords {
|
|
if v == w {
|
|
matched = true
|
|
}
|
|
}
|
|
if !matched {
|
|
s = append(s, strings.ToLower(v))
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Add ...
|
|
func (DB *Search) Add(key interface{}, st [][]string) {
|
|
if DB.Words == nil {
|
|
DB.Words = make(map[interface{}][][]string)
|
|
}
|
|
DB.Words[key] = append(DB.Words[key], st...)
|
|
|
|
}
|
|
|
|
// Ignore ...
|
|
func (DB *Search) Ignore(list []string) {
|
|
DB.IgnoreWords = list
|
|
}
|
|
|
|
// Replace ...
|
|
func (DB *Search) Replace(list []string) {
|
|
DB.RemoveCharacters = list
|
|
}
|
|
|
|
// Match ...
|
|
func (DB *Search) Match(Title string) []interface{} {
|
|
IDS := []ID{}
|
|
title := DB.CleanSearch(strings.ToLower(Title))
|
|
for k, v := range DB.Words {
|
|
tempKeys := []ID{}
|
|
for _, t := range v {
|
|
sim := similarity(t, title)
|
|
if sim > 0 {
|
|
tempKeys = append(tempKeys, ID{Key: k, Score: sim, Title: t})
|
|
}
|
|
}
|
|
if len(tempKeys) > 0 {
|
|
sort.Slice(tempKeys, func(i, j int) bool {
|
|
return tempKeys[i].Score > tempKeys[j].Score
|
|
})
|
|
IDS = append(IDS, tempKeys[0])
|
|
}
|
|
}
|
|
sort.Slice(IDS, func(i, j int) bool {
|
|
return IDS[i].Score > IDS[j].Score
|
|
})
|
|
|
|
keys := []interface{}{}
|
|
for _, v := range IDS {
|
|
keys = append(keys, v.Key)
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func similarity(a, b []string) float64 {
|
|
var s float64
|
|
var matched []int
|
|
loop:
|
|
for _, i := range a {
|
|
for f, l := range b {
|
|
if i == l && !intInSlice(f, matched) {
|
|
s++
|
|
matched = append(matched, f)
|
|
continue loop
|
|
} else if i != l {
|
|
s = s - ((float64(len(i)) * 0.1) * (0.125 / 2))
|
|
}
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func intInSlice(a int, list []int) bool {
|
|
for _, b := range list {
|
|
if b == a {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|