当前位置: 首页 > article >正文

golang使用redis实现全文搜索

简介

使用redis实现全部文章精确到段落的搜索

实现思路

  • 文章分段,使用一张表单独记录下段落信息
  • 段落分词,把段落划分成词
  • 分词后使用有序集合记录到redis中,每个词语后记录含有该分词的段落ID集
  • 使用一个哈希键记录下每个段落的分词,用于分词信息的删除
  • 查询时先分词,再根据分的词把分词查到的对应的段落
  • 返回结果

具体实现

文章分段

  • 文章段落表结构
type TextModel struct {
    gorm.Model
	ArticleID uint   `json:"articleID"`
	Head      string `json:"head"`
	Body      string `json:"body"`
}
  • 分段函数
//这里因为我的项目里出现了循环导包,所以没有使用gorm的映射表进行处理
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, "#") {
			// 标题行
			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
}

段落分词

  • 使用第三方库进行分词
    https://github.com/go-ego/gse
    第三方库下载
go get -u github.com/go-ego/gse
  • 库初始化
func InitGse() {
	newGse, _ := gse.New()
	global_gse.Gse = newGse
}
  • 分词函数
func textParticiple(textList ...string) (words []string) {
	for _, text := range textList {
		word := global_gse.Gse.CutSearch(text, true)
		words = append(words, word...)
	}
	return
}

把分过的词保存到到redis中

  • 使用redis集合每个词对应的段落ID
func SetTextSearchIndex(textID uint, words []string) {
	for _, word := range words {
		if word == "" {
			continue
		}
		global.Redis.SAdd(fmt.Sprintf("text_%s", word), textID)
	}
}
  • 使用哈希键记录每个文章对应的段落和词语信息,用于信息删除
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)
}

查询操作

  • 通过将文本分词过后的查询词语获取一个段落集合
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
}
  • 根据查到id列表查询数据库
idList := redis_article.GetTextSearchIndex(cr.Key)
query := global.DB.Where("id in ?", idList)

后续处理,使搜索的文字有高亮提示

  • 可以将搜索的文字套在特定的标签中然后再返回信息

http://www.kler.cn/a/547965.html

相关文章:

  • 建造者模式构建对象
  • CentOS7 安装配置FTP服务
  • 鸿蒙开发:熟知@BuilderParam装饰器
  • STM32F10X 启动文件完整分析
  • Xilinx FPGA开发指南-7系列FPGA配置引脚定义
  • Vue 3 30天精进之旅:Day 25 - PWA支持
  • 学习sql的资源:sql练习平台;在线编辑器,免费sql教程,免费sql书籍
  • (LLaMa Factory)大模型训练方法--监督微调(Qwen2-0.5B)
  • Linux性能分析工具Trace使用
  • 【漫话机器学习系列】091.置信区间(Confidence Intervals)
  • 【Linux】:网络协议
  • C#关于静态关键词static详解
  • dl学习笔记(11):VGG,NIN,GooleNet经典架构pytorch实现
  • Linux第107步_Linux之PCF8563实验
  • jenkins服务启动-排错
  • SCI学术论文图片怎么免费绘制:drawio,gitmind
  • 深度学习框架TensorFlow怎么用?
  • 牛客周赛 Round 80
  • 批处理效率提升技巧
  • 设备智能化无线通信,ESP32-C2物联网方案,小尺寸芯片实现大功能