上海备案证查询网站查询网站佛山网站建设外贸

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

上海备案证查询网站查询网站,佛山网站建设外贸,用ps做网站方法,电子商务网站建设 精品课目录 什么是倒排索引 定义 基本结构和原理 分词在倒排索引中的重要性 简单倒排索引的实现 接口定义 简单数据库的实现 倒排索引 正排索引 测试 总结 什么是倒排索引 定义 倒排索引#xff08;Inverted Index#xff09;是一种索引数据结构#xff0c;它是文档检…目录 什么是倒排索引 定义 基本结构和原理 分词在倒排索引中的重要性 简单倒排索引的实现 接口定义 简单数据库的实现 倒排索引 正排索引 测试 总结 什么是倒排索引 定义 倒排索引Inverted Index是一种索引数据结构它是文档检索系统中最常用的数据结构之一。在信息检索领域它用于快速地定位包含给定查询词的文档。与正向索引Forward Index相对正向索引是从文档到词汇的映射而倒排索引是从词汇到文档的映射。
基本结构和原理 倒排索引主要由两部分组成词汇表Vocabulary和倒排记录表Postings List。 词汇表包含了文档集合中出现的所有不同的词汇或词条。每个词汇都有一个指向其对应的倒排记录表的指针。例如在一个包含多篇新闻文章的文档集合中词汇表可能包含 “经济”“政治”“科技” 等词汇。 倒排记录表对于词汇表中的每个词汇倒排记录表记录了包含该词汇的所有文档的标识符Document ID以及可能的其他相关信息如词汇在文档中的位置、出现的频率等。比如对于词汇 “科技”其倒排记录表可能包含文档 ID 为 1、3、5 的记录表示这三篇文档中都出现了 “科技” 这个词汇。 假如现在有三份数据文档内容分别是  Doc 1:Java is the best programming language​Doc 2:PHP is the best programming language​Doc 3:Javascript is the best programming language 为了创建索引通过分词器将每个文档的内容拆成单独的词再将这些词条创建成不含重复词条的排序列表然后列出每个词条出现在哪个文档结果如下 termDoc 1Doc 2Doc 3Java√is√√√the√√√best√√√programming√√√language√√√PHP√√Javascript√√        这种结构由文档中所有不重复的词的列表构成对于其中每个词都有至少一个文档与与之关联。这种由属性值来确定记录的位置的结构就是倒排索引带有倒排索引的文件被称为倒排文件。         将上表转为更直观的图片来展示倒排索引
分词在倒排索引中的重要性 建立索引基础倒排索引是一种用于快速检索的数据结构。它的核心是将文档中的关键词提取出来建立关键词到文档的映射关系。分词就是这个提取关键词的过程只有通过分词才能将文本内容分解为一个个有意义的词汇单元为建立倒排索引提供基础。例如对于一篇文档 “我爱自然语言处理技术”如果不分词这个文档就会被当作一个整体很难进行有效的关键词检索而通过分词得到 “我”“爱”“自然语言处理”“技术” 这些词汇后就可以分别建立它们与该文档的索引关系。 提高检索效率和准确性当用户进行查询时倒排索引会根据用户输入的关键词来查找相关文档。精确的分词可以确保查询词和索引中的词汇准确匹配提高检索的准确性。例如在搜索引擎中如果用户输入 “自然语言处理”经过良好分词的倒排索引能够快速定位到包含这个词汇的文档而不会因为没有正确分词而错过相关文档。同时合理的分词还可以减少索引的大小提高检索效率。如果将一些无意义的组合词也作为索引词会增加索引的复杂度和存储量而通过分词去除不必要的组合只保留有意义的词汇可以使索引更加紧凑检索速度更快。
中文分词面临的挑战: 词汇的复杂性 词的歧义性中文中存在大量的歧义现象。例如 “下雨天留客天留我不留”不同的断句分词方式会产生不同的意思。可以是 “下雨天留客天留我不留。” 也可以是 “下雨天留客天留我不留。” 这种歧义给中文分词带来了很大的困难。 新词不断涌现随着社会的发展和科技的进步新的词汇不断出现如 “区块链”“人工智能”“元宇宙” 等。对于分词系统来说需要及时识别这些新词才能保证分词的准确性和完整性。 缺乏明显的分隔符与英文等语言不同中文句子中词与词之间没有明显的分隔符如英文中的空格。这使得计算机很难直观地判断一个词的起始和结束位置需要通过复杂的算法和规则来进行分词。 语言的灵活性和多样性中文有丰富的表达方式包括成语、俗语、古诗词等。这些特殊的语言形式也给分词带来了挑战。例如成语 “胸有成竹” 如果被错误地分割为 “胸有”“成竹”就会失去原有的语义影响分词的质量。
常用的中文分词库 jieba 分词库 特点jieba 是一个非常流行的中文分词库它具有多种分词模式包括精确模式、全模式和搜索引擎模式。精确模式试图将句子最精确地切开适合文本分析等场景全模式把句子中所有的可以成词的词语都扫描出来速度快但可能会产生冗余搜索引擎模式在精确模式的基础上对长词再次切分提高搜索引擎召回率。例如对于句子 “中华人民共和国”精确模式会分为 “中华人民共和国”全模式会分为 “中华”“华人”“人民”“共和”“共和国” 等搜索引擎模式会在精确模式的基础上对 “中华人民共和国” 进一步切分以适应搜索引擎的需求。 应用场景广泛应用于文本挖掘、信息检索、机器翻译等领域。例如在文本挖掘中可以使用 jieba 对文本进行分词然后进行词频统计等分析。 THULAC清华大学自然语言处理与社会人文计算实验室 特点它是由清华大学开发的中文词法分析工具包具有较高的分词准确性。它提供了词性标注等功能不仅可以分词还可以标注每个词的词性如名词、动词、形容词等。例如对于句子 “他高兴地跑了”除了将句子分为 “他”“高兴”“地”“跑”“了”还可以标注出 “他” 是代词“高兴” 是形容词“地” 是助词“跑” 是动词“了” 是语气词。 应用场景在自然语言处理研究和需要词性标注的应用场景中使用较多如情感分析中结合词性标注可以更好地分析句子的情感倾向。 简单倒排索引的实现 接口定义 定义三个接口分别是 数据库正排索引倒排索引规定都要实现Get和Add功能 // DB接口定义了数据库的基本操作用于获取和添加数据。type DB interface {Get(string) []stringAdd(string)}​// ForwardIndexer 用于根据给定的文档ID列表获取对应的原始字符串内容。type ForwardIndexer interface {Get([]int64) []stringAdd(int64, string)}​// InvertedIndexer 用于根据给定的字符串获取对应的文档ID列表以及添加倒排索引数据。type InvertedIndexer interface {Get(string) []int64Add(string, int64)} 简单数据库的实现 定义简单数据库结构体由id正排索引和倒排索引组成。 Get方法是先通过倒排索引由字符串找出id然后在通过正排索引由id找出匹配的字符串 Add方法把字符串存入倒排和正排 // SimpleDatabase结构体实现了DB接口内部整合了正向索引和倒排索引来管理数据。type SimpleDatabase struct {id int64fi ForwardIndexerii InvertedIndexer}​// NewSimpleDatabase创建一个新的SimpleDatabase实例初始化其正向索引和倒排索引相关组件。func NewSimpleDatabase() DB {return SimpleDatabase{id: 0, // 递增文档IDfi: NewForwardIndex(),ii: NewSimpleInverted(),}}​func (sd *SimpleDatabase) Get(s string) []string {// 先通过倒排索引根据输入字符串获取对应的文档ID列表ids : sd.ii.Get(s)// 再通过正排索引根据获取到的文档ID列表查找对应的原字符串return sd.fi.Get(ids)}​func (sd *SimpleDatabase) Add(s string) {atomic.AddInt64(sd.id, 1)id : sd.idaddToIndexes(sd.fi, sd.ii, id, s)}​func addToIndexes(fi ForwardIndexer, ii InvertedIndexer, id int64, s string) {// 倒排存入ii.Add(s, id)// 正排存入fi.Add(id, s)} 倒排索引 倒排索引结构由读写锁分词器和map组成 Get方法查找data返回id数组 Add先分词然后把分词后的结构以及对应id存入mapES中的分词器一般会大写转小写但是这里我偷个懒就直接存了 // SimpleInverted结构体实现了InvertedIndexer接口用于管理倒排索引数据。type SimpleInverted struct {sync.RWMutexdata     map[string][]int64analyzer Analyzer}​// NewSimpleInverted创建一个新的SimpleInverted实例初始化倒排索引数据存储结构和分析器。func NewSimpleInverted() InvertedIndexer {return SimpleInverted{data:     make(map[string][]int64),analyzer: NewSimpleAnalyzer(),}}​func (si *SimpleInverted) Get(s string) []int64 {si.RLock()result : si.data[s]si.RUnlock()return result}​func (si *SimpleInverted) Add(s string, id int64) {words : si.analyzer.Analyze(s)si.Lock()for _, word : range words {si.data[word] append(si.data[word], id)}si.Unlock()} 分词器 这里分词器的实现比较简单直接逐个拆开来存了在实际中分词器比这更加复杂和优雅往往伴随着一些分词的算法 这里用使用了两层嵌套的 for 循环来生成输入字符串的所有可能子串并将这些子串作为键存入一个 map 类型的变量 word 中。外层循环控制起始位置 i内层循环控制结束位置 j通过切片操作 su[i:j] 取出从位置 i 到位置 j不包含 j的子串然后将其转换为字符串作为 map 的键对应的值使用了空结构体 struct{}{}。 这样做虽然能实现分词但是非常暴力而且浪费空间。因为中文分词不像英文可以使用空格或者,进行简单切分一般的中文分词器都会采用词典分词因为我们是简单实现所以这里就采用了这种暴力写法(其实是太菜了不会更好的分词方法) // Analyzer接口定义了文本分析例如分词等操作的基本操作方法。type Analyzer interface {Analyze(s string) []string}​// SimpleAnalyzer结构体实现了Analyzer接口简单地进行字符串分析示例中较简单的逻辑可优化。type SimpleAnalyzer struct{}​// NewSimpleAnalyzer创建一个新的SimpleAnalyzer实例。func NewSimpleAnalyzer() Analyzer {return SimpleAnalyzer{}}​func (l *SimpleAnalyzer) Analyze(s string) (re []string) {// 转为rune可以有效处理中英文字符的字节大小问题su : []rune(s)sl : len(su)word : make(map[string]struct{})for i : 0; i sl; i {for j : i 1; j sl; j {word[string(su[i:j])] struct{}{}}}re make([]string, len(word))num : 0for index : range word {re[num] indexnum}return} 正排索引 这个比起倒排简单很多没啥好讲的 // forwardIndex结构体实现了ForwardIndexer接口用于管理正向索引数据。type forwardIndex struct {sync.RWMutexdata map[int64]string}​// NewForwardIndex创建一个新的forwardIndex实例初始化正向索引数据存储结构。func NewForwardIndex() ForwardIndexer {return forwardIndex{data: make(map[int64]string),}}​func (fi *forwardIndex) Get(ids []int64) (re []string) {re make([]string, len(ids))fi.RLock()for k, v : range ids {re[k] fi.data[v]}fi.RUnlock()return}​func (fi *forwardIndex) Add(id int64, s string) {fi.Lock()fi.data[id] sfi.Unlock()} 测试 单元测试代码如下一首《春江花月夜》来试试效果 func TestSimpleDatabaseWithChunJiangHuaYueYe(t *testing.T) {// 创建数据库实例db : NewSimpleDatabase()​// 添加《春江花月夜》的诗句假设逐句添加lines : []string{春江潮水连海平海上明月共潮生。,江流宛转绕芳甸月照花林皆似霰。,空里流霜不觉飞汀上白沙看不见。,江天一色无纤尘皎皎空中孤月轮。,江畔何人初见月江月何年初照人,人生代代无穷已江月年年望相似。,不知江月待何人但见长江送流水。,白云一片去悠悠青枫浦上不胜愁。,谁家今夜扁舟子何处相思明月楼,可怜楼上月徘徊应照离人妆镜台。,玉户帘中卷不去捣衣砧上拂还来。,此时相望不相闻愿逐月华流照君。,鸿雁长飞光不度鱼龙潜跃水成文。,昨夜闲潭梦落花可怜春半不还家。,江水流春去欲尽江潭落月复西斜。,斜月沉沉藏海雾碣石潇湘无限路。,不知乘月几人归落月摇情满江树。,}for _, line : range lines {db.Add(line)}​// 测试获取包含“江”字的字符串expectedJiang : []string{春江潮水连海平海上明月共潮生。,江流宛转绕芳甸月照花林皆似霰。,江天一色无纤尘皎皎空中孤月轮。,江畔何人初见月江月何年初照人,人生代代无穷已江月年年望相似。,不知江月待何人但见长江送流水。,江水流春去欲尽江潭落月复西斜。,不知乘月几人归落月摇情满江树。,}actualJiang : db.Get(江)if !reflect.DeepEqual(actualJiang, expectedJiang) {t.Errorf(Get for 江 failed. Expected: %v, Got: %v, expectedJiang, actualJiang)} else {fmt.Println(江)for _, s : range actualJiang {fmt.Println(s)}}​// 测试获取包含“月”字的字符串expectedYue : []string{春江潮水连海平海上明月共潮生。,江流宛转绕芳甸月照花林皆似霰。,江天一色无纤尘皎皎空中孤月轮。,江畔何人初见月江月何年初照人,人生代代无穷已江月年年望相似。,不知江月待何人但见长江送流水。,谁家今夜扁舟子何处相思明月楼,可怜楼上月徘徊应照离人妆镜台。,此时相望不相闻愿逐月华流照君。,江水流春去欲尽江潭落月复西斜。,斜月沉沉藏海雾碣石潇湘无限路。,不知乘月几人归落月摇情满江树。,}actualYue : db.Get(月)if !reflect.DeepEqual(actualYue, expectedYue) {t.Errorf(Get for 月 failed. Expected: %v, Got: %v, expectedYue, actualYue)} else {fmt.Println(月)for _, s : range actualYue {fmt.Println(s)}}​// 测试获取包含“花”字的字符串expectedHua : []string{江流宛转绕芳甸月照花林皆似霰。,昨夜闲潭梦落花可怜春半不还家。,}actualHua : db.Get(花)if !reflect.DeepEqual(actualHua, expectedHua) {t.Errorf(Get for 花 failed. Expected: %v, Got: %v, expectedHua, actualHua)} else {fmt.Println(花)for _, s : range actualHua {fmt.Println(s)}}​// 测试获取包含“海”字的字符串expectedHai : []string{春江潮水连海平海上明月共潮生。,斜月沉沉藏海雾碣石潇湘无限路。,}actualHai : db.Get(海)if !reflect.DeepEqual(actualHai, expectedHai) {t.Errorf(Get for 海 failed. Expected: %v, Got: %v, expectedHai, actualHai)} else {fmt.Println(海)for _, s : range actualHai {fmt.Println(s)}}} 测试结果通过可喜可贺 总结 Go简单实现了一下倒排索引感觉分词还是很重要的直接决定了整个倒排索引的表现还是要多学习一些厉害的分词器是怎么实现的~