golang使用redis實(shí)現(xiàn)全文搜索功能詳解
簡(jiǎn)介
使用redis實(shí)現(xiàn)全部文章精確到段落的搜索
實(shí)現(xiàn)思路
文章分段,使用一張表單獨(dú)記錄下段落信息
段落分詞,把段落劃分成詞
分詞后使用有序集合記錄到redis中,每個(gè)詞語(yǔ)后記錄含有該分詞的段落ID集
使用一個(gè)哈希鍵記錄下每個(gè)段落的分詞,用于分詞信息的刪除
查詢時(shí)先分詞,再根據(jù)分的詞把分詞查到的對(duì)應(yīng)的段落
返回結(jié)果
具體實(shí)現(xiàn)
文章分段
文章段落表結(jié)構(gòu)
type TextModel struct { gorm.Model ArticleID uint `json:"articleID"` Head string `json:"head"` Body string `json:"body"` }
分段函數(shù)
//這里因?yàn)槲业捻?xiàng)目里出現(xiàn)了循環(huán)導(dǎo)包,所以沒有使用gorm的映射表進(jìn)行處理 type TextModel struct { ArticleID uint `json:"article_id"` Head string `json:"head"` Body string `json:"body"` } func MdContentTransformation(id uint, title string, content string) (list []TextModel) { lines := strings.Split(content, "\n") var headList []string var bodyList []string var body string headList = append(headList, title) var flag bool for _, line := range lines { if strings.HasPrefix(line, "```") { flag = !flag } if !flag && strings.HasPrefix(line, "#") { // 標(biāo)題行 headList = append(headList, getHead(line)) if strings.TrimSpace(body) != "" { bodyList = append(bodyList, getBody(body)) } body = "" continue } body += line } if body != "" { bodyList = append(bodyList, getBody(body)) } if len(headList) > len(bodyList) { bodyList = append(bodyList, "") } if len(headList) != len(bodyList) { log.Errorf("headList與bodyList 不一致 \n headList:%q %d\\\n bodyList: %q %d\n", headList, len(headList), bodyList, len(bodyList)) return } for i := 0; i < len(headList); i++ { list = append(list, TextModel{ ArticleID: id, Head: headList[i], Body: bodyList[i], }) } return } func getHead(head string) string { s := strings.TrimSpace(strings.Join(strings.Split(head, " ")[1:], " ")) return s } func getBody(body string) string { body = strings.TrimSpace(body) return body }
段落分詞
使用第三方庫(kù)進(jìn)行分詞
第三方庫(kù)下載
go get -u github.com/go-ego/gse
庫(kù)初始化
func InitGse() { newGse, _ := gse.New() global_gse.Gse = newGse }
分詞函數(shù)
func textParticiple(textList ...string) (words []string) { for _, text := range textList { word := global_gse.Gse.CutSearch(text, true) words = append(words, word...) } return }
把分過的詞保存到到redis中
使用redis集合每個(gè)詞對(duì)應(yīng)的段落ID
func SetTextSearchIndex(textID uint, words []string) { for _, word := range words { if word == "" { continue } global.Redis.SAdd(fmt.Sprintf("text_%s", word), textID) } }
使用哈希鍵記錄每個(gè)文章對(duì)應(yīng)的段落和詞語(yǔ)信息,用于信息刪除
func SetTextSearchWords(articleID uint, textID uint, words []string) { _words, _ := json.Marshal(words) global.Redis.HSet(fmt.Sprintf("text_search_words_%d", articleID), strconv.Itoa(int(textID)), _words) }
查詢操作
通過將文本分詞過后的查詢?cè)~語(yǔ)獲取一個(gè)段落集合
func GetTextSearchIndex(text string) []string { //分詞 words := global_gse.Gse.CutSearch(text, true) var _words []string for _, word := range words { _words = append(_words, fmt.Sprintf("text_%s", word)) } vals, _ := global.Redis.SUnion(_words...).Result() return vals }
根據(jù)查到id列表查詢數(shù)據(jù)庫(kù)
idList := redis_article.GetTextSearchIndex(cr.Key) query := global.DB.Where("id in ?", idList)
后續(xù)處理,使搜索的文字有高亮提示
可以將搜索的文字套在特定的標(biāo)簽中然后再返回信息
以上就是golang使用redis實(shí)現(xiàn)全文搜索功能詳解的詳細(xì)內(nèi)容,更多關(guān)于go redis全文搜索的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
node-exporter被檢測(cè)出來pprof調(diào)試信息泄露漏洞問題
這篇文章主要介紹了node-exporter被檢測(cè)出來pprof調(diào)試信息泄露漏洞問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04Golang觀察者模式優(yōu)化訂單處理系統(tǒng)實(shí)例探究
當(dāng)涉及到訂單處理系統(tǒng)時(shí),觀察者設(shè)計(jì)模式可以用于實(shí)現(xiàn)訂單狀態(tài)的變化和通知,在這篇文章中,我們將介紹如何使用Golang來實(shí)現(xiàn)觀察者設(shè)計(jì)模式,并提供一個(gè)基于訂單處理系統(tǒng)的代碼示例2024-01-01Gin框架中的GET和POST表單處理的實(shí)現(xiàn)
Gin框架提供了簡(jiǎn)單而強(qiáng)大的機(jī)制來處理GET和POST表單提交的數(shù)據(jù),通過c.Query、c.PostForm、c.Bind和c.Request.FormFile等方法,可以輕松地獲取和處理各種表單數(shù)據(jù),感興趣的可以了解一下2025-03-03