mirror of
https://github.com/bitmagnet-io/bitmagnet.git
synced 2026-07-22 04:05:17 -04:00
6358b27bc6
- `search_string` field is removed - text search vector for `content` and `torrent_contents` is generated in code with improvements in normalisation and tokenisation - the slow `LIKE` query is removed from text search - a query DSL is implemented which translates the input search string to a Postgres tsquery - a CLI command (`reindex`) is provided for updating the tsv for pre-existing records - the unused `tsv` and `search_string` fields are removed from the `torrents` table See https://github.com/bitmagnet-io/bitmagnet/issues/89
83 lines
1.7 KiB
Go
83 lines
1.7 KiB
Go
package fts
|
|
|
|
import (
|
|
"github.com/mozillazg/go-unidecode/table"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
func Tokenize(str string) [][]string {
|
|
l := tokenizerLexer{newLexer(str)}
|
|
var tokens [][]string
|
|
for {
|
|
phrase := l.readPhrase()
|
|
if len(phrase) == 0 {
|
|
break
|
|
}
|
|
tokens = append(tokens, phrase)
|
|
}
|
|
return tokens
|
|
}
|
|
|
|
type tokenizerLexer struct {
|
|
lexer
|
|
}
|
|
|
|
func TokenizeFlat(str string) []string {
|
|
var tokens []string
|
|
for _, phrase := range Tokenize(str) {
|
|
tokens = append(tokens, phrase...)
|
|
}
|
|
return tokens
|
|
}
|
|
|
|
func (l *tokenizerLexer) readPhrase() []string {
|
|
var phrase []string
|
|
var lexeme string
|
|
breakWord := func() {
|
|
if lexeme != "" {
|
|
phrase = append(phrase, lexeme)
|
|
lexeme = ""
|
|
}
|
|
}
|
|
appendStr := func(str string) {
|
|
lexeme = lexeme + str
|
|
}
|
|
for {
|
|
if l.isEof() {
|
|
breakWord()
|
|
return phrase
|
|
}
|
|
if ch, ok := l.readIf(IsWordChar); ok {
|
|
ch = unicode.ToLower(ch)
|
|
if ch < unicode.MaxASCII {
|
|
appendStr(string(ch))
|
|
} else {
|
|
// if the character is determined to be a language with unspaced words (e.g. Chinese, Japanese),
|
|
// each character will become a token; using this cutoff might not be perfect...
|
|
isNonBreakingLang := ch > '\u1FFF'
|
|
if isNonBreakingLang {
|
|
breakWord()
|
|
}
|
|
section := ch >> 8 // Chop off the last two hex digits
|
|
position := ch % 256 // Last two hex digits
|
|
if tb, ok := table.Tables[section]; ok {
|
|
if len(tb) > int(position) {
|
|
subst := tb[position]
|
|
appendStr(strings.TrimSpace(subst))
|
|
if isNonBreakingLang || len(subst) == 0 || subst[len(subst)-1] == ' ' {
|
|
breakWord()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
breakWord()
|
|
if len(phrase) > 0 {
|
|
return phrase
|
|
}
|
|
l.read()
|
|
}
|
|
}
|