您现在的位置是:拨x拨x陪你一日三餐 > 探索
微信全文搜索技术优化
拨x拨x陪你一日三餐2023-06-06 07:23:24【探索】4人已围观
简介一、iOS微信全文搜索技术的现状全文搜索是使用倒排索引进行搜索的一种搜索方式。倒排索引也称为反向索引,是指对输入的内容中的每个Token建立一个索引,索引中保存了这个Token在内容中的具体位置。全文 百娘异航app入口
一、微信iOS微信全文搜索技术的全文现状
全文搜索是使用倒排索引进行搜索的一种搜索方式。倒排索引也称为反向索引,搜索百娘异航app入口是技术指对输入的内容中的每个Token建立一个索引,索引中保存了这个Token在内容中的优化具体位置。全文搜索技术主要应用在对大量文本内容进行搜索的微信场景。
微信终端涉及到大量文本搜索的全文业务场景主要包括联系人、聊天记录、搜索收藏的技术搜索。这些搜索功能从2014年上线至今,优化已经多年没有更新底层搜索技术,微信聊天记录使用的全文全文搜索引擎还是SQLite FTS3,而现在已经有SQLite FTS5,搜索收藏首页的技术搜索还是使用简单的Like语句去匹配文本,联系人搜索甚至用的优化是内存搜索(在内存中遍历所有联系人的所有属性进行匹配)。随着用户在微信上积累的数据越来越多,提升微信底层搜索技术的需求也越来越迫切。在2021年,我们对iOS微信的全文搜索技术进行了一次全面升级,本文主要介绍本次技术升级的工作经验。
二、全文搜索引擎的选型与优化
1、搜索引擎选型
iOS客户端可以使用的全文搜索引擎并不多,主要有SQLite三个版本的FTS组件、Lucene的C++实现版本CLucene和C语言桥接版本Lucy。这里给出了这些引擎在事务能力、技术风险、搜索能力、读写性能等方面的比较。

在事务能力方面,Lucene没有提供完整的事务能力,因为Lucene使用了多文件的存储结构,它没有保证事务的原子性。SQLite的FTS组件因为底层还是使用普通的表来实现的,可以完美继承SQLite的事务能力。
在技术风险方面,Lucene主要应用于服务端,在客户端没有大规模应用的案例,而且CLucene和Lucy自2013年后官方都停止维护了,技术风险较高。SQLite的FTS3和FTS4组件则是属于SQLite的旧版本引擎,官方维护不多了,而且这两个版本都是将一个词的索引存到一条记录中,极端情况下有超出SQLite单条记录最大长度限制的风险。SQLite的FTS5组件作为最新版本引擎也已经推出超过六年了,在安卓微信上也已经全量应用,所以技术风险是最低的。
在搜索能力方面,Lucene的发展历史比SQLite的FTS组件长很多,搜索能力相比也是最丰富的。特别是Lucene有丰富的搜索结果评分排序机制,但这个在微信客户端没有应用场景。因为我们的百娘异航app入口搜索结果要么是按照时间排序,要么是按照一些简单的自定义规则排序。在SQLite几个版本的引擎中,FTS5的搜索语法更加完备严谨,提供了很多接口给用户自定义搜索函数,所以搜索能力也相对强一点。
在读写性能方面,下面是用不同引擎对100万条长度为10的随机生成中文语句生成Optimize状态的索引的性能数据,其中每个语句的汉字出现频率按照实际的汉字使用频率:



可以看到,Lucene读取命中数量的性能比SQLite好很多,说明Lucene索引的文件格式很有优势,但是微信没有只读取命中数量的应用场景,Lucene的其他性能数据跟SQLite的差距不明显。SQLite FTS3和FTS5的大部分性能很接近,FTS5索引的生成耗时比FTS3高一截,这个有优化方法。
综合考虑这些因素,我们选择SQLite FTS5作为iOS微信全文搜索的搜索引擎。
2、实现FTS5的Segment自动Merge机制
SQLite FTS5会把每个事务写入的内容保存成一个独立的b树,称为一个segment,segment中保存了本次写入内容中的每个词在本次内容中行号(rowid)、列号和字段中的每次出现的位置偏移,所以这个segment就是该内容的倒排索引。多次写入就会形成多个segment,查询时就需要分别查询这些segment再汇总结果,从而segment数量越多,查询速度越慢。
为了减少segment的数量,SQLite FTS5引入了merge机制。新写入的segment的level为0,merge操作可以把level为i的现有segment合并成一个level为i+1的新的segment。merge的示例如下:

FTS5默认的merge操作有两种:
某一个level的segment达到4时就开始在写入内容时自动执行一部分merge操作,称为一次automerge。每次automerge的写入量跟本次更新的写入量成正比,需要多次automerge才能完整合并成一个新segment。Automerge在完整生成一个新的segment前,需要多次裁剪旧的segment的已合并内容,引入多余的写入量。本次写入后某一个level的segment数量达到16时,一次性合并这个level的segment,称为crisismerge。FTS5的默认merge操作都是在写入时同步执行的,会对业务逻辑造成性能影响,特别是crisismerge会偶然导致某一次写入操作特别久,这会让业务性能不可控。之前的测试中FTS5的建索引耗时较久,也主要因为FTS5的merge操作比其他两种引擎更加耗时。
我们在WCDB中实现FTS5的segment自动merge机制,将这些merge操作集中到一个单独子线程执行,并且优化执行参数,具体如下:
监听有FTS5索引的数据库每个事务变更到的FTS5索引表,抛通知到子线程触发WCDB的自动merge操作。Merge线程检查所有FTS5索引表中segment数超过 1 的level执行一次merge。Merge时每写入16页数据检查一次有没有其他线程的写入操作因为merge操作阻塞,如果有就立即commit,尽量减小merge对业务性能的影响。自动merge逻辑执行的流程图如下:

限制每个level的segment数量为1,可以让FTS5的查询性能最接近optimize(所有segment合并成一个)之后的性能,而且引入的写入量是可接受的。假设业务每次写入量为M,写入了N次,那么在merge执行完整之后,数据库实际写入量为**MN(log2(N)+1)**。业务批量写入,提高M也可以减小总写入量。
性能方面,对一个包含100w条中文内容,每条长度100汉字的fts5的表查询三个词,optimize状态下耗时2.9ms,分别限制每个level的segment数量为2、3、4时的查询耗时分别为4.7ms、8.9ms、15ms。100w条内容每次写入100条的情况下,按照WCDB的方案执行merge的耗时在10s内。
使用自动Merge机制,可以在不影响索引更新性能的情况下,将FTS5索引保持在最接近Optimize的状态,提高了搜索速度。
3、分词器优化
分词器性能优化
分词器是全文搜索的关键模块,它实现将输入内容拆分成多个Token并提供这些Token的位置,搜索引擎再对这些Token建立索引。SQLite的FTS组件支持自定义分词器,可以按照业务需求实现自己的分词器。
分词器的分词方法可以分为按字分词和按词分词。前者只是简单对输入内容逐字建立索引,后者则需要理解输入内容的语义,对有具体含义的词组建立索引。相比于按字分词,按词分词的优势是既可以减少建索引的Token数量,也可以减少搜索时匹配的Token数量,劣势是需要理解语义,而且用户输入的词不完整时也会有搜不到的问题。
为了简化客户端逻辑和避免用户漏输内容时搜不到的问题,iOS微信之前的FTS3分词器OneOrBinaryTokenizer是采用了一种巧妙的按字分词算法,除了对输入内容逐字建索引,还会对内容中每两个连续的字建索引,对于搜索内容则是按照每两个字进行分词。下面是一个用“北京欢迎你”去搜索相同内容的分词例子:

相比于简单的按字分词,这种分词方式的优势是可以将搜索时匹配的Token数量接近降低一半,提高搜索速度,而且在一定程度上可以提升搜索精度,比如搜索“欢迎你北京”就匹配不到“北京欢迎你”;这种分词方式的劣势就是保存的索引内容很多,基本输入内容的每个字都在索引中保存了三次,是一种用空间换时间的做法。
因为OneOrBinaryTokenizer用接近三倍的索引内容增长才换取不到两倍的搜索性能提升,不是很划算,所以我们在FTS5上重新开发了一种新的分词器VerbatimTokenizer,这个分词器只采用基本的按字分词,不保存冗余索引内容。同时在搜索时,每两个字用引号引起来组成一个Phrase,按照FTS5的搜索语法,搜索时Phrase中的字要按顺序相邻出现的内容才会命中,实现了跟OneOrBinaryTokenizer一样的搜索精度。 VerbatimTokenizer的分词规则示意图如下:

分词器能力扩展
VerbatimTokenizer还根据微信实际的业务需求实现了五种扩展能力来提高搜索的容错能力:
支持在分词时将繁体字转换成简体字。这样用户可以用繁体字搜到简体字内容,用简体字也能搜到繁体字内容,避免了因为汉字的简体和繁体字形相近导致用户输错的问题。支持Unicode归一化。Unicode支持相同字形的字符用不同的编码来表示,比如编码为\ue9的é和编码为\u65\u301的é有相同的字形,这会导致用户用看上去一样的内容去搜索结果搜不到的问题。Unicode归一化就是把字形相同的字符用同一个编码表示。支持过滤符号。大部分情况下,我们不需要支持对符号建索引,符号的重复量大而且用户一般也不会用符号去搜索内容,但是联系人搜索这个业务场景需要支持符号搜索,因为用户的昵称里面经常出现颜文字,符号的使用量不低。支持用Porter Stemming算法对英文单词取词干。取词干的好处是允许用户搜索内容的单复数和时态跟命中内容不一致,让用户更容易搜到内容。但是取词干也有弊端,比如用户要搜索的内容是“happyday”,输入“happy”作为前缀去搜索却会搜不到,因为“happyday”取词干变成“happydai”,“happy”取词干变成“happi”,后者就不能成为前者的前缀。这种badcase在内容为多个英文单词拼接一起时容易出现,联系人昵称的拼接英文很常见,所以在联系人的索引中没有取词干,在其他业务场景中都用上了。支持将字母全部转成小写。这样用户可以用小写搜到大写,反之亦然。这些扩展能力都是对建索引内容和搜索内容中的每个字做变换,这个变换其实也可以在业务层做,其中的Unicode归一化和简繁转换以前就是在业务层实现的。但是这样做有两个弊端,一个是业务层每做一个转换都需要对内容做一次遍历,引入冗余计算量,另一个是写入到索引中的内容是转变后的内容,那么搜索出来的结果也是转变后的,会和原文不一致,业务层做内容判断的时候容易出错。鉴于这两个原因,VerbatimTokenizer将这些转变能力都集中到了分词器中实现。
4、索引内容支持多级分隔符
SQLite的FTS索引表不支持在建表后再添加新列,但是随着业务的发展,业务数据支持搜索的属性会变多,如何解决新属性的搜索问题呢?特别是在联系人搜索这个业务场景,一个联系人支持搜索的字段非常多。一个直接的想法是将新属性和旧属性用分隔符拼接到一起建索引。但这样会引入新的问题,FTS5是以整个字段的内容作为整体去匹配的,如果用户搜索匹配的Token在不同的属性,那这条数据也会命中,这个结果显然不是用户想要的,搜索结果的精确度就降低了。
我们需要搜索匹配的Token中间不存在分隔符,那这样可以确保匹配的Token都在一个属性内。同时,为了支持业务灵活扩展,还需要支持多级分隔符,而且搜索结果中还要支持获取匹配结果的层级、位置以及该段内容的原文和匹配词。这个能力FTS5还不没有,而FTS5的自定义辅助函数支持在搜索时获取到所有命中结果中每个命中Token的位置,利用这个信息可以推断出这些Token中间有没有分隔符,以及这些Token所在的层级,所以我们开发了SubstringMatchInfo这个新的FTS5搜索辅助函数来实现这个能力。这个函数的大致执行流程如下:

三、全文搜索应用逻辑优化
1、数据库表格式优化
1.1 非文本搜索内容的保存方式
在实际应用中,我们除了要在数据库中保存需要搜索的文本的FTS索引,还需要额外保存这个文本对应的业务数据的id、用于结果排序的的属性(常见的是业务数据的创建时间)以及其他需要直接跟随搜索结果读出的内容,这些都是不参与文本搜索的内容。根据非文本搜索内容的不同存储位置,我们可以将FTS索引表的表格式分成两种:
第一种方式是将非文本搜索内容存储在额外的普通表中,这个表保存FTS索引的Rowid和非文本搜索内容的映射关系,而FTS索引表的每一行只保存可搜索的文本内容,这个表格式类似于这样:
这种表格式的优势是FTS索引表的内容很简单,不熟悉FTS索引表配置的同学不容易出错,而且普通表的可扩展性好,支持添加新列;劣势则是搜索时需要先用FTS索引的Rowid读取到普通表的Rowid,这样才能读取到普通表的其他内容,搜索速度慢一点,而且搜索时需要联表查询,搜索SQL语句稍微复杂一点。
第二种方式是将非文本搜索内容直接和可搜索文本内容一起存储在FTS索引表中,表格式类似于这样:
这种方式的优劣势跟前一种方式恰好相反,优势是搜索速度快而且搜索方式简单,劣势是扩展性差且需要更细致的配置。
因为iOS微信以前是使用第二种表格式,而且微信的搜索业务已经稳定不会有大变化,我们现在更加追求搜索速度,所以我们还是继续使用第二种表格式来存储全文搜索的数据。
1.2 避免冗余索引内容
FTS索引表默认对表中的每一列的内容都建倒排索引,即便是数字内容也会按照文本来处理,这样会导致我们保存在FTS索引表中的非文本搜索内容也建了索引,进而增大索引文件的大小、索引更新的耗时和搜索的耗时,这显然不是我们想要的。
FTS5支持给索引表中的列添加UNINDEXED约束,这样FTS5就不会对这个列建索引了,所以给可搜索文本内容之外的所有列添加这个约束就可以避免冗余索引。
1.3 降低索引内容的大小
前面提到,倒排索引主要保存文本中每个Token对应的行号(rowid)、列号和字段中的每次出现的位置偏移,其中的行号是SQLite自动分配的,位置偏移是根据业务的实际内容,这两个我们都决定不了,但是列号是可以调整的。
在FTS5索引中,一个Token在一行中的索引内容的格式是这样的:

从中可以看出,如果我们把可搜索文本内容设置在第一列的话(多个可搜索文本列的话,把内容多的列放到第一列),就可以少保存列分割符0x01和列号,这样可以明显降低索引文件大小。
所以我们最终的表格式是这样:

1.4 索引文件大小优化数据
下面是iOS微信优化前后的平均每个用户的索引文件大小对比:

2、索引更新逻辑优化
为了将全文搜索逻辑和业务逻辑解耦,iOS微信的FTS索引是不保存在各个业务的数据库中的,而是集中保存到一个专用的全文搜索数据库,各个业务的数据有更新之后再异步通知全文搜索模块更新索引。整体流程如下:

这样做既可以避免索引更新拖慢业务数据更新的速度,也能避免索引数据更新出错甚至索引数据损坏对业务造成影响,让全文搜索功能模块能够充分独立。
2.1 保证索引和数据的一致
业务数据和索引数据分离且异步同步的好处很多,但实现起来也很难,最难的问题是如何保证业务数据和索引数据的一致,也即要保证业务数据和索引数据要逐条对应,不多不少。曾经iOS微信在这里踩了很多坑,打了很多补丁都不能完整解决这个问题,我们需要一个更加体系化的方法来解决这个问题。
为了简化问题,我们可以把一致性问题可以拆成两个方面分别处理,一个是保证所有业务数据都有索引,这个用户的搜索结果就不会有缺漏;第二个是保证所有索引都对应一个有效的业务数据,这样用户就不会搜到无效的结果。
要保证所有业务数据都有索引,首先要找到或者构造一种一直增长的数据来描述业务数据更新的进度,这个进度数据的更新和业务数据的更新能保证原子性,而且根据这个进度的区间能拿出业务数据更新的内容,这样我们就可以依赖这个进度来更新索引。在微信的业务中,不同业务的进度数据不同,聊天记录是使用消息的rowid,收藏是使用收藏跟后台同步的updateSequence,而联系人找不到这种一直增长的进度数据,我们是通过在联系人数据库中标记有新增或有更新的联系人的微信号来作为索引更新进度。进度数据的使用方法如下:

无论业务数据是否保存成功、更新通知是否到达全文搜索模块、索引数据是否保存成功,这套索引更新逻辑都能保证保存成功的业务数据都能成功建到索引。这其中的一个关键点是数据和进度要在同个事务中一起更新,而且要保存在同个数据库中,这样才能保证数据和进度的更新的原子性(WCDB创建的数据库因为使用WAL模式而无法保证不同数据库的事务的原子性)。还有一个操作图中没有画出,具体是微信启动时如果检查到业务进度小于索引进度,这种一般意味着业务数据损坏后被重置了,这种情况下要删掉索引并重置索引进度。
对于每个索引都对应有效的业务数据,这就要求业务数据删除之后索引也要必须删掉。现在业务数据的删除和索引的删除是异步的,会出现业务数据删掉之后索引没删除的情况。这种情况会导致两个问题,一个是冗余索引会导致搜索速度变慢,但这个问题出现概率很小,这个影响可以忽略不计;第二个问题是会导致用户搜到无效数据,这个是要避免的。因为要完全删掉所有无效索引成本比较高,所以我们采用了惰性检查的方法来解决这个问题,具体做法是搜索结果要显示给用户时,才检查这个数据是否有效,无效的话不显示这个搜索结果并异步删除对应的索引。因为用户一屏能看到的数据很少,所以检查逻辑带来的性能消耗也可以忽略不计。而且这个检查操作实际上也不算是额外加的逻辑,为了搜索结果展示内容的灵活性,我们也要在展示搜索结果时读出业务数据,这样也就顺带做了数据有效性的检查。
2.2 建索引速度优化
索引只有在搜索的时候才会用到,它的更新优先级并没有业务数据那么高,可以尽量攒更多的业务数据才去批量建索引。批量建索引有以下三个好处:
减少磁盘的写入次数,提高平均建索引速度。在一个事务中,建索引SQL语句的解析结果可以反复使用,可以减少SQL语句的解析次数,进而提高平均建索引速度。减少生成Segment的数量,从而减少Merge Segment带来的读写消耗。当然,也不能保留太多业务数据不建索引,这样用户要搜索时会来不及建索引,从而导致搜索结果不完整。有了前面的Segment自动Merge机制,索引的写入速度非常可控,只要控制好量,就不用担心批量建索引带来的高耗时问题。我们综合考虑了低端机器的建索引速度和搜索页面的拉起时间,确定了最大批量建索引数据条数为100条。同时,我们会在内存中cache本次微信运行期间产生的未建索引业务数据,在极端情况下给没有来得及建索引的业务数据提供相对内存搜索,保证搜索结果的完整性。因为cache上一次微信运行期间产生的未建索引数据需要引入额外的磁盘IO,所以微信启动后会触发一次建索引逻辑,对现有的未建索引业务数据建一次索引。总结一下触发建索引的时机有三个:
未建索引业务数据达到100条。进入搜索界面。微信启动。2.3 删除索引速度优化
索引的删除速度经常是设计索引更新机制时比较容易忽视的因素,因为被删除的业务数据量容易被低估,会被误以为是低概率场景,但实际被用户删除的业务数据可能会达到50%,是个不可忽视的主场景。而且SQLite是不支持并行写入的,删除索引的性能也会间接影响到索引的写入速度,会为索引更新引入不可控因素。
因为删除索引的时候是拿着业务数据的id去删除的,所以提高删除索引速度的方式有两种:
建一个业务数据id到FTS索引的rowid的普通索引。在FTS索引表中去掉业务数据Id那一列的UNINDEXED约束,给业务数据Id添加倒排索引。这里倒排索引其实没有普通索引那么高效,有两个原因:
倒排索引相比普通索引还带了很多额外信息,搜索效率低一些。如果需要多个业务字段才能确定一条倒排索引时,倒排索引是建不了联合索引的,只能匹配其中一个业务字段,其他字段就是遍历匹配,这种情况搜索效率会很低。2.4 索引更新性能优化数据
聊天记录的优化前后索引性能数据如下:
收藏的优化前后索引性能数据如下:
3、搜索逻辑优化
用户在iOS微信的首页输入内容搜索时,搜索的整体流程如下:
用户变更搜索框的内容之后,会并行发起所有业务的搜索任务,各个搜索任务执行完之后才再将搜索结果返回到主线程给页面展示。这个逻辑会随着用户变更搜索内容而继续重复。
3.1 单个搜索任务支持并行执行
虽然现在不同搜索任务已经支持并行执行,但是不同业务的数据量和搜索逻辑差别很大,数据量大或者搜索逻辑复杂的任务耗时会很久,这样还不能充分发挥手机的并行处理能力。我们还可以将并行处理能力引入单个搜索任务内,这里有两种处理方式:
对于搜索数据量大的业务(比如聊天记录搜索),可以将索引数据均分存储到多个FTS索引表(注意这里不均分的话还是会存在短板效应),这样搜索时可以并行搜索各个索引表,然后汇总各个表的搜索结果,再进行统一排序。这里拆分的索引表数量既不能太多也不能太少,太多会超出手机实际的并行处理能力,也会影响其他搜索任务的性能,太少又不能充分利用并行处理能力。以前微信用了十个FTS表存储聊天记录索引,现在改为使用四个FTS表。对于搜索逻辑复杂的业务(比如联系人搜索),可以将可独立执行的搜索逻辑并行执行。比如在联系人搜索任务中,我们将联系人的普通文本搜索、拼音搜索、标签和地区的搜索、多群成员的搜索并行执行,搜完之后再合并结果进行排序。这里为什么不也用拆表的方式呢?因为这种搜索结果数量少的场景,搜索的耗时主要是集中在搜索索引的环节,索引可以看做一颗B树,将一颗B树拆分成多个,搜索耗时并不会成比例下降。3.2 搜索任务支持中断
用户在搜索框持续输入内容的过程中可能会自动多次发起搜索任务,如果在前一次发起的搜索任务还没执行完时,就再次发起搜索任务,那前后两次搜索任务就会互相影响对方性能。这种情况在用户输入内容从短到长的过程中还挺容易出现的,因为搜索文本短的时候命中结果就很多,搜索任务也就更加耗时,从而更有机会撞上后面的搜索任务。太多任务同时执行还会容易引起手机发烫、爆内存的问题。所以我们需要让搜索任务支持随时中断,这样就可以在后一次搜索任务发起的时候,能够中断前一次的搜索任务,避免任务量过多的问题。
搜索任务支持中断的实现方式是给每个搜索任务设置一个CancelFlag,在搜索逻辑执行时每搜到一个结果就判断一下CancelFlag是否置位,如果置位了就立即退出任务。外部逻辑可以通过置位CancelFlag来中断搜索任务。逻辑流程如下图所示:
为了让搜索任务能够及时中断,我们需要让检查CancelFlag的时间间隔尽量相等,要实现这个目标就要在搜索时避免使用OrderBy子句对结果进行排序。因为FTS5不支持建立联合索引,所以在使用OrderBy子句时,SQLite在输出第一个结果前会遍历所有匹配结果进行排序,这就让输出第一个结果的耗时几乎等于输出全部结果的耗时,中断逻辑就失去了意义。不使用OrderBy子句就对搜索逻辑添加了两个限制:
从数据库读取所有结果之后再排序。我们可以在读取结果时将用于排序的字段一并读出,然后在读完所有结果之后再对所有结果执行排序。因为排序的耗时占总搜索耗时的比例很低,加上排序算法的性能大同小异,这种做法对搜索速度的影响可以忽略。不能使用分段查询。在全文搜索这个场景中,分段查询其实是没有什么作用的。因为分段查询就要对结果排序,对结果排序就要遍历所有结果,所以分段查询并不能降低搜索耗时(除非按照FTS索引的Rowid分段查询,但是Rowid不包含实际的业务信息)。3.3 搜索读取内容最少化
搜索时读取内容的量也是决定搜索耗时的一个关键因素。FTS索引表实际是有多个SQLite普通表组成的,这其中一些表格存储实际的倒排索引内容,还有一个表格存储用户保存到FTS索引表的全部原文。当搜索时读取Rowid以外的内容时,就需要用Rowid到保存原文的表的读取内容,索引表输出结果的内部执行过程如下:
所以读取内容越少输出结果的速度越快,而且读取内容过多也会有消耗内存的隐患。我们采用的方式是搜索时只读取业务数据id和用于排序的业务属性,排好序之后,在需要给用户展示结果时,才用业务数据id按需读取业务数据具体内容出来展示。这样做的扩展性也会很好,可以在不更改存储内容的情况下,根据各个业务的需求不断调整搜索结果展示的内容。
这里还有一个要特别提一下的地方,就是搜索时尽量不要读取高亮信息(SQLite的highlight函数有这个能力)。因为要获取高亮字段不仅要将文本的原文读取出来,还要对文本原文再次分词,才能定位命中位置的原文内容,搜索结果多的情况下分词带来的消耗非常明显。那展示搜索结果时如何获取高亮匹配内容呢?我们采用的方式是将用户的搜索文本进行分词,然后在展示结果时查找每个Token在展示文本中的位置,然后将那个位置高亮显示。同样因为用户一屏看到的结果数量是很少的,这里的高亮逻辑带来的性能消耗可以忽略。
当然在搜索规则很复杂的情况下,直接读取高亮信息是比较方便,比如联系人搜索就使用前面提到的SubstringMatchInfo函数来读取高亮内容。这里主要还是因为要读取匹配内容所在的层级和位置用于排序,所以逐个结果重新分词的操作在所难免。
3.4 搜索性能优化数据
下面是微信各搜索业务优化前后的搜索耗时对比:
四、总结
目前iOS微信已经将这套新全文搜索技术方案全量应用到聊天记录、联系人和收藏的搜索业务中。使用新方案之后,全文搜索的索引文件占用空间更小,索引更新耗时更少,搜索速度也更快了,可以说全文搜索的性能得到了全方位提升。
很赞哦!(191)
站长推荐
友情链接
- 5x社区发源地
- 7w7w7w7w乳液
- k频道导航网址备用
- 1000部禽兽视频免费
- 66kkmm换成什么网址了
- 800免费视频观看网址
- lutube官方网址
- 艾杏一二三网址
- 藏经阁路线一
- 刺激网站网址免费
- 5xsq社区
- 给我一个网址你懂得2023
- 7x7x7x7人成免费进入
- 7x7x7x7x任你燥免费
- 大象传媒秘密入口3秒自动进入
- 5151四虎最新网址
- 父亲猜女儿视频网址
- 5xs社区在线视频播放
- 5x社区不一样的视觉盛宴
- 草莓视频网址是什么
- 5xsq高清在线视频
- 5x杜区在线视频5xsq
- 720在线视频网址
- 高老庄在线视频网址
- w939w79w79w乳液
- 111we四虎最新网址
- 1000个小视频
- baby5xx视频观看
- 5g天天看5g天天爽
- 5xsq兴趣社区高清视频
- k频道网址导入口
- 5x兴趣社区最新发布地址
- 67194短视频网址发布
- 5xsq社区最新获取免费
- 点此进入甸伊圆自动转入
- 91永久发地布地扯ebay
- 爱情岛永久实用网址
- k频道网址导航中心
- 67194短视频网址
- 拔x拔x为永久在线观看
- 5x视频社区在线视频
- 44kkmm最新网址
- ysl水蜜桃86在线视频
- 18未成年禁止观看1000部
- 草莓视频安卓网址
- 5x社区最新视频播放
- 91大神网址链接
- 2023猫咪在线播放官网网址
- 91天媒传媒在线视频1
- 藩金莲传媒免费入口老夫子
- 5xsp直接进入
- 91成品短视频官网入口
- 5xx兴趣社区
- 999abab最新网址
- 922tv最新线路网址
- 5xsq在线观看免费
- pp628备用网址
- 91网址永久发布备用
- 91pom的新网址是
- 1000部拍拍拍18勿入辣妞范
- 福艳天下韵母柳可欣218章
- ae人口ae永久菠萝
- k频道网址导航网红主播
- 2023中文无字幕入口网站
- 成品视频观看入口
- 藩金莲传媒免费入口众乐乐
- bl视频肉在线网址
- a视频在线免播放观看网址
- 5x社区5s社区5xsq进入
- 刺激在线视频网址
- 8x8x8x新的网址观看
- 884aa是不是换网址了
- 19fff改什么网址了
- 成品入口网站视频
- 大象的秘密入口
- 5x社5x社区视频新地址
- 5x社区在线视频老网址
- 5x在线观看
- dxj1000国产片免费
- 第一站视频网址
- 大象dx秘密入口大象
- 1000部拍拍拍免费视频误入
- dxtv555xyz在线观看
- sao66改成什么网址了
- 大香伊煮大象伊甸118
- 给个动漫网址你懂得
- 1000部未成年人禁入
- 1000禁大全免费禽兽级别
- gv在线快捷看免费观看网址
- 成品片a免费入口
- 91por内部网址
- v视界vsj2入口国产
- 5xvw88域名
- kpd频道网址入口
- 本站网址最新获取
- 18以内禁入1000部
- 5x5xsq视频5xsq
- a樱花福精品利院
- a资源网址免费
- k频道视频网址导航入口
- 大象依甸圆短视频
- 爱琴岛论坛独家提供网址
- 334eee最新网址
- 2023看片网址
- 5x免费视频5xsq进入
- lubute最新网址
- 5566yyyy网址大全
- 2023在线观看的a站网址
- 888btbt最新网址
- 草莓羞愧无线观看网址
- 91app网址
- 爱情岛一独家提供网址大全
- 给我一个网址懂得2023
- 动漫3d区入口
- dx2023秘密入口免费
- 大象人口点击进入
- 18末年人在线观看app
- 5x社区免费视频
- 成品大香伊煮焦成品
- 岛国在线网址
- 1000拍拍拍
- 7w7w7w7飞机
- 5x兴趣社交免费视频
- 1000部精彩视频免费
- 91网址登陆
- 给个网址吧老铁2023
- 2023最新桃花源网址
- 给个网址在线
- 5g国产天天5g天天看
- 4388x2最新网站网址
- 点击进入点击进入精彩内容
- 岛国网址日韩
- 5x线观看视频5xsq
- 444kk网址改成什么了
- 2023网址你们懂得
- 5x社区极品视频发源地
- 大象传媒18勿秘蜜入口
- hhh555网址更新成什么了
- 91网址怎么进
- 775me换成什么网址啦
- x5社区怎么进去
- 5x兴趣社区免费视频
- 18成品免费网站入口
- 67194网址
- 869pp网址进不去
- 538在线视频5x线视频
- 恶魔六点后院网址
- 8x8x8x人成免费观视频
- se1000在线精品视频
- 爱琴岛论坛独家提供网址
- 大象网址回导航入口
- 草莓视频在线观看网址
- 9906a四虎在线观看网址
- baoyutv最新网址
- k频道直播间2站网址入口
- 5xsp456社区在线视频
- 成品a免费入口
- 4484x全国最大网址
- 5x社区视频新地址
- 5x社区免费最新入口
- 91网址chienses
- 869pp网址进不去
- 538se网站最新网址
- 67194段视频网址发布页
- 2023男人的网址免费观看
- 61794成视频网址
- 4444kk现在网址是多少
- kk44kk升级网址
- 8插8插华为x拨插5g免费
- 3atv国内能打开的网址
- 爱如潮水现场视频578
- 大象传媒18勿秘密入
- 777aj最新网址
- 67194短视频发布网址
- 半夜睡不着求网址2023
- k频道网址导航网红主播
- 1000个小视频
- 5g囯产天天5g天天
- 成品视频网站w在线
- 15分钟1000部大片
- 91官网备用网址
- ai换脸热巴在线观看网址
- 5x社区免费5xbv77
- 136导航网址导航
- w卡哇伊直播aj5w网址
- 2023年可以看的网址
- k频道k频道最近网址
- x7x7x7x7任你燥水蜜桃
- 浮力网址最新线路
- 51区绝密视频
- 草榴视频网址
- 1000视频高清视频大全
- k频道网址导航网址入口
- 98精区国品一区
- 艾杏hd第一网址
- sea8精品最新网址入口
- 992ty的另一个网址
- lutube最新网址
- 5x在线视频手机视频
- 999abab最新网址
- 成品在线短视频免费入口
- 成品网站直接进入
- 99cscs新的网址是什么
- 5g最新域址永久
- uu有你足矣已满18入口域名
- 成版年蝴蝶视频入口免费
- 91爱拍原创视频网址
- 2023uc开车求个网址
- 2023年可以看的网址
- 5g天天5g天气爽在线观看
- ae86防和谐网址
- 911成品视频入口
- 1000部麻辣范视频
- k频道网址导航网址入口
- qqq258最新无毒网址
- 993ff换了那个网址
- 5x在线手机免费观看
- lubute最新网址
- 2023年嫩叶草新地址进入
- 5x5xsp社区在线视频
- 1000部禽兽禁止片免费
- 成品片a免费入口蘑菇视
- 爱矢峰子息子寝取
- 成品片a免费蘑菇视频
- ai换脸在线观看网址
- 大象传媒18勿秘密免费入口
- 3344的网址是什么
- 7w7w7w7飞机
- 成品伊园1688精品推荐
- 差差视频免费首入口网页
- ae人口ae永久菠萝
- kk4444换哪个网址了
- 365每日更新最新网址
- 大象伊园甸锦绣
- 5x兴趣社交进入离开
- 动物与人在线网址
- 浮力草草网址最新线路
- 给个直接放的网址2023
- 5x兴趣社区免费视频新址
- 成品动漫视频网站入口
- 5x线观看视频5xsq
- 222eee最新网址发布器
- 办卡主播asmr免费网址
- 大象99永久回家的路
- 77777大象传媒入口
- 给个免费网址你们懂得2023
- 72部息子母中文字幕
- 夫妻4人一起租房子
- 51在线视频5xsq
- 番茄最新网址
- 拔x拔x为永久在线观看
- 3d彩漫工作日的妈妈
- yw5568优物入口
- 1000个免费视频
- 5xsq最新社区地址进入
- 97ss新网址97ss成人
- 1000部拍拍拍18勿入辣妞范
- 2023求一个在线观看网址
- 橙子视频网站版网址
- 22eee网址改成多少了
- 999abab换什么网址了
- 8x8x网址
- u罗汉狮子妈妈
- pp628新的网址是啥
- 5177tv浮力网址
- 1000免费拍拍观看
- 5x社区真正网址
- my19111蜜芽入口
- 5xx兴趣社区高清视频
- 5xx7gz8v的视频播单
- 5g永久免费不需安装
- 大象回家视频网页版入口
- 7x7x7x7x7任你燥水蜜桃
- 5x手机观看免费视频
- 5g天天5g天天爽5g
- 大伊香大伊香煮大象伊甸
- 成年女人免费视频网址
- k频道在线视频网址最新
- 2023年最新免费看a网址
- health2官网网址
- 成品伊园1688精品推荐
- 包多多官网入口
- 藏经阁破解版无限
- 5x社区免费观看视频播放
- 5x线视频新址
- 插槽8x插槽视频在线观看
- 5g国产天天5g运动
- 藩金莲精品传媒免费入口
- seegams网站网址
- 1000部免费视频大全集
- k频道网址入口频道网址
- 5xsq社区免费视频
- 成品l688网站入口
- 成品78w林妹妹免费
- 成品网站直接进入
- 5x社区直播免费视频
- 4x4x4x4x在线观看
- 带你进入新世界地址
- ygf杨贵妃传媒网站入口
- 5x社区在线观看免费手机视频
- 1000在线观看大全
- 5x发源地打造社区
- f2富二代视频网址入口
- 1769资源站最稳定网址
- ysl水蜜桃86在线视频
- a樱花福精品利院在线观看
- 777777大象传媒视频入口
- 94vvv最新网址
- 5x社会区直接进入
- 拔x拔x8x81000部视频
- 5s社区怎么进入
- 1000部拍拍拍视频
- 255hh的新域名获取网址
- 44kkmm改什么网址了
- 播放视频0x8007007e
- 百媚导舰官方入口
- 1000部免费视频
- 5x社区发源地在线
- 1000部麻辣范视频
- 5xsq社区最新获取免费
- diy101hd在线网址
- yw53777龙物视频入口
- 18勿看1000个视频视频
- 91中文字日产乱幕六区
- 5x社区免费最新入口
- 大象传媒18勿秘密入口
- 成品片a免费入口直接进入
- 7cdy备用网址
- 3d全彩妈妈的无私奉献蛙漫
- adc年龄确认入口网址
- 大象伊甸区三三三区区区
- x7x7x7x7x7水蜜桃
- 19fff改什么网址了
- 恶魔六点内院网址
- ぉ母さんの息子
- 拔x拔x海外华为永久视频全集版
- 5xso社区免费视频
- 5xx兴趣免费视频
- k频道kpd45网址在线播放
- 538se网站最新网址
- 92成a人v免费视频网址
- 3344tx换什么网址
- 5g最新域址永久
- a天v堂一区
- 18禁止观看1000部免费
- 77ququ新网址
- nnuu44最新网网址
- 67194免费发布网址
- vr视频在线观看网址
- 51x社区免费视频5xsq
- k频道网址kkpd
- 3344最新网址
- k频道网址导航道
- 5spx社区发源地免费视频
- 5x社区视频视频大全
- 5xsp在线观看视频
- 5566yyyy网址大全
- 5xsq社区高清视频进入
- 大象永久伊园甸2023
- 4444kk改成什么网址了
- 233bobo最新网址
- qyule电信网址最新
- pp628新网址在线
- 8x8x8x新的网址观看
- 5x兴趣社区5xsq
- yemalu网址改什么了
- k视频网址导航最新
- 2023能看的岛国网址大
- 69714在线观看网址视频
- kk55kk最新网址在线观看
- 8擦八拔8n拿走不谢
- k频道网址导航中心
- 成品短视频在线免费入口
- ss导航入口
- 8x8x8x水蜜桃
- k频道网址导航最新域名
- 5xsp一切从这里开始
- 成品1688网站在线入口
- w永久99w乳液78
- 1000个未成年观看视频
- 2023uc网址拿走不谢
- 福利院天狼私人入口伊甸
- 720的网站网址
- mg555xyz在线观看
- 1000部拍拍拍免费网站
- ysl水蜜桃86免费高清完整
- 5x社区发源地从这里开始
- 大佬给个网址睡不着
- 大象伊甸院秘密通道
- 大香伊煮焦在线观看
- 5x社区在线视频老网址
- 59yyy新网址永久免费
- k频道在线视频网址最新
- 72部息子の母中文字幕
- 91popn网址多少
- 初中生自抠网址
- 5x123社区在线视频
- 5spx社区移动入口
- v片在线站网址
- 7x7x7x任意躁在线观看
- ae人口ae永久菠萝
- k频道网址鸭子tv
- 350gao在线网址
- b站在线观看人数在哪
- v片在线免费观看网址
- a湿地福利院yy
- 废柴网视频网址入口
- ae86备用网址入口
- 8x插槽视频8网页版
- 给个免费网址你们懂得2023
- 5x在线社区手机视频
- 5xsp社在线观看
- 91成品短视频茄子
- 阧阴探探短视频无需安装
- se01网址线路1橙子视频
- 大象传媒18勿秘密免费入口
- 恶魔六点内院网址
- 51成品短视频入口
- 77777大象传媒视频入口
- 大象国产大象传媒
- dabolu最新网址
- 3344tt最新网址
- 2023网址男人懂得
- 1000部禁止大全免费
- 5xsq社区最新网站
- 51动漫无限观看入口
- 92午夜神器1000
- 2023跪求一个免费网址谢谢
- 岛国动作大片在线视频网址
- x7x7x7x任意槽
- 4虎tv新的网址
- 4x4x4x4x在线观看
- w939w79w79w乳液
- 5x社区免费线播观看
- 百娘导舫官方入口京东
- 5x社区免费视频老地址
- 高清网址人成在线观看
- 100部深夜看e黄禁用免费
- k频道网址鸭子tv
- 成品在线免费视频入口
- 5x社区离线视频5x
- 5xsp456社区在线视频
- 宝宝你好会夹呀14章
- 91aaa网址
- 插槽8x插槽在线观看
- 5xsq社区最新网站
- 51短视频app无限看
- 大象2023秘密通道入口
- 沉迷美母柳淑云免费
- 5x社区手机视频在线观看
- 800免费视频观看网址
- 5x发原地从这里开始
- 5x社区打造极品视觉盛宴
- k频道网址导航鸭子
- 1000部未满十八不进
- 1000部拍拍拍视频免费
- 爱染恭子母と息子
- 72部母息子在线观看
- lutube最近网址发布
- 成品片a入口免费
- 91先生是哪个网址
- ae人口ae永久菠萝
- 3344mp改成什么网址了
- 成品片g免费入口
- 成app视频i91入口
- 番茄官方新网址
- 61794网址在线观看
- 成品大香伊煮蕉国色天香视频
- a在线观看网址
- se1000在线精品视频
- 9u-有你有我足矣首页
- 成品大香伊煮蕉小辣板在线观看
- 10000000禁止观看app
- u罗汉 妈妈从不拒绝
- 点此进入伊甸
- 1000部免费视频在线
- 成品动漫视频网站入口
- 33susu换什么网址了
- 5xsq从这里开始
- 3344nr换成什么网址
- 5g国产天天5g天天科学新发现
- 5x社区视频5xs0发源地
- 成人爽片网址
- 51区绝密视频
- 岛国搬运最新网址
- 耽美bl网址导航
- 1000辣妹范1000部视频
- a在线观看网址
- 5x社区5xsq离开进入
- 1024网址入口2023
- 2023网址懂得免费
- 大象伊甸元园2023入口直达
- 沉母柳淑云第二章免费
- 5x8在线观看手机视频
- 88pipi换网址了
- 爱情岛独家提供实用网址
- 5x视频从这里开始
- 5x兴趣社区5xsq
- 5x社区网址获取网站
- 69714小视频网址发布