-
Notifications
You must be signed in to change notification settings - Fork 4
mirror repository of flexse in google code. Author: [email protected]
ArkEngine/flexse
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
看sphinx的文档 (1) 为什么要做这个东东 -1- 搜索产品内部需要 我们的相关搜索和搜索建议,本质上还是倒排结构。 -2- 搜索院对其他部门的技术支持 云城搜索/C2C搜索/积分商城搜索。。 (2) 架构愿景和应用前景 -1- 一张图,表示云搜索,叙述工作流程,小数据+大数据量扩展 -2- 应用前景,框架的应用 + 插件使用 (3) 特性 性能方面 -0- 实时索引 -1- 快速建库 -2- 快速查询 -3- 超大数据 功能方面 -4- 算法强大 -5- 功能全配 -6- 灵活配置 数据恢复 -7- 崩溃恢复 架构远景 -8- 云搜索化 二次开发 -9- 支持插件 (1) 倒排索引 -1- index_group = mem_indexer + disk_indexer -2- mem_indexer = postinglist + creat_sign #1# postinglist = (hash-bucket) + (headlist) + memblocks -3- disk_indexer = 二级索引 + [1级索引cache] + fileblock + diskv 索引管理逻辑 -1- mem/disk的时间节点 -2- dump逻辑 -3- 修改和删除(bitmap+idmap) (2) 文档属性 -1- bitlist + structmask (3) 文档详细 -1- detaildb = fileblock + diskv 服务搭建 (1) 线程组成 -1- equeue + query_threads -2- update_thread -3- day_merger_thread -4- his_merger_thread -5- ontime_thread (2) 通信协议 -1- xhead + json =============================================================== (1) 概述 flexse目前是一个搜索的框架,提供了搜索引擎中数据的存储和访问,特别实现了倒排数据的实时索引。 -1- 倒排索引原理 倒排索引抽象成数据结构,可以理解为map<string, vector<index_t>>,string就是分词形成的每 个term,而vector<index_t>就是含有这个term的各个文档ID列表,index_t就是描述这个term属性 的结构,index_t中必须含有一个ID。通过flexse/utils/indexer/index_group/index_group.cpp 中的get_posting_list方法,可以获得一个term对应的postinglist,如果内存不够存储,则返回 最新的内存大小的postinglist,失败返回-1。postinglist按照ID降序排列。 -2- 如何做到实时索引和实时更新(插件开发者不需要知道) 每个文档都会有个外部ID和内部ID,外部ID都是连续的,内部ID也是连续的,一个外部ID对应于一 个最新的内部ID。通过flexse/utils/idmap来管理内部和外部ID,当插入或更新一个文档时,根据 该文档的外部ID,来检查是否已经为其分配过内部ID,如果不存在,则内部ID自增后,为其分配一 个内部ID;如果已经为其分配过内部ID,则把内部ID对应的bitmap对应位置设置为1,且为其分配一 个新内部ID。 这样,当失效的内部ID经过mod_bitset过滤时,就能去掉已经失效的文档了。 举个例子: 文档1含有term: a/b/c, 外部ID为1,插入后,为其分配内部ID为1; 文档1更新,term更新为: a/d/e,更新后,为其分配一个新的内部ID为2,同时把mod_bitset中,内 部ID为1的位置设置为1。当我们搜索a时,可以得到内部ID为1和2的文档,经过mod_bitset过滤后, 文档2得以保留,去掉了失效的文档1。 -3- 如何访问文档属性数据 文档属性数据存储于文件中,以mmap的方式load到内存中,以数组的方式访问,使用内部ID作为偏移 以structmask的机制来访问数据,structmask的原理见这个wiki (2) 更新 -1- 如何更新倒排索引postinglist 输入: xhead+json-string,有固定的格式,解析过程详见代码flexse/plugin/flexse/ 输出: xhead. 测试工具: flexse/flexse/test/update.py,与配置文件flexse/flexse/conf/plugin.config.json 相互对应,目前支持分词/前缀/数组前缀这三种方式 postinglist根据term形成的机制分为两种类型,NLP分词和前缀生成,视频搜索视需求来选择这两 个类型 a) NLP分词形成的term,在flexse/utils/nlp_processor/nlp_processor.cpp中可以设置分词形成 的各个term的描述信息,如tf/idf/offset/title_hit/tag_hit等等,需要注意的是,视频全网 搜索的offset计算,建议使用title即可,因为视频的描述信息在各大网站上看,基本都是空的 b) 前缀生成的term,比如"TAG^搞笑"等等,term的描述一般都为默认值 -2- 如何更新文档属性document-attribute 这部分代码已经完成,原理是根据配置中,迭代STRUCTMASK/document_attr中各个字段,把其中的 key<->value存入vector中,update_thread.cpp中对外部的doc_id进行内部ID分配,然后更新内部 ID对应的document_attribute属性 (3) 查询 输入为xhead+json-string,有固定的格式,解析过程详见代码flexse/plugin/flexse/ 输出是xhead+struct数组(不使用json或其他序列化方案是为了性能考虑),返回值表示struct数组 的sizeof大小 查询操作在flexse/plugin/flexse/flexse_plugin.cpp中实现 测试工具: flexse/flexse/test/qquery.py,与配置文件flexse/flexse/conf/plugin.config.json 相互对应,目前支持分词/前缀/数组前缀这三种方式 查询的步骤一般可以分为 a) 根据termlist,读取对应的postinglist。 b) 把一组postinglist交给归并算法进行合并,目前已经支持按照term的权重进行归并(algo.cpp)。 c) 对归并结果postinglist进行过滤,目前已经支持按照某个字段执行(等于/小于/大于/大于小于 /集合这5种过滤)(algo.cpp) d) 对过滤结果postinglist进行调权,目前已经支持按照某个字段执行(等于/小于/大于/大于小于 /集合这5种调权)(algo.cpp) e) 按照权重返回top2000的结果,把每个ID的document-attribute带上 ----------------------------------------- (1) 对数据的抽象 -1- 倒排索引 -2- 文档属性 -3- 文档详细 (2) 对流程的抽象 -1- 更新流程 -2- 查询流程 ----------------------------------------- (1) 调权 -1- L0层, query与term的相关性(title_hit/anchor_hit/tag_hit/offset) -2- L1层, 文档自身属性调权(等于/大于/小于/区间/集合) -3- L2层, 用户个性化调权(点击调权+用户类型与文档分类切合度) (2) 过滤 -1- 对文档属性进行(等于/大于/小于/区间/集合)几种过滤 -2- 实现标题内搜索 -3- 站内搜索(等于/集合) -4- 标签搜索(tag索引) (3) 排序 -1- 可以按照任意的field进行排序 -2- 可以实现"对信誉度最高的前30个商户按照最近销量排序" (4) 聚类 -1- 可以根据某个字段进行group_count ----------------------------------------- (1) query分析 -1- 纠错 -2- 同义词 -3- term的weight (2) query语法树 -1- a&b&c, b->b|B, c->c|C, a&(b|B)&(c|C) -2- 按照weight进行merge,实现模糊查询,不必要求每个关键词都命中(百度视频搜索),后续可以强制必须命中某些term ----------------------------------------- (1) 搜索直达车 -1- SEU(标准实体单元)的资源建设,如电视剧电影->视频搜索,商品信息->电商 ----------------------------------------- (1) 数据的分片(Sharding) -1- php-interface处对key进行滚动分区(建立一个监控机制) -2- 如果key不是连续自增的外部ID,则需要对key进行签名,我们为其分配外部ID -3- 文档详细的访问采用的key为分片时的key,或者是其他形式,如签名 -4- mongodb的sharding访问需要支持按照DB进行sharding (2) 数据的复制(Repset) -1- 通过消息队列复制消息,各个服务互不干扰 -2- 对消息队列的进度进行监控,发现异常队列,及时报警 -3- 每个app独占一个消息队列文件序列 ----------------------------------------- 画个图来表明flexse是怎么构建的 shijing的wiki (1) 如何提高可测性 -1- 模块化编程 a) 每个类或函数做简单的事情,一个4百行的函数和linux的管道 b) 性能考虑会打破规律 -2- 面向接口编程 a) 面向实现编程与面向接口编程,要对对象或函数的应用环境考虑清楚(需求),然后设计合适的接口。一句话就是想清楚再干。 b) 类的协作是通过接口来完成的,面向接口编程是复用性的前提,电脑的USB接口 c) 类之间通信简单易懂,扩展性好,提高复用性,扩展性,松耦合 c) 团队更应该使用面向接口编程 -3- 做好异常处理(fileblock的一个异常的例子,尽早的发现错误,测试也是调试,要得到有效的测试) -4- 只要是接口,就可以执行单元测试(接口就是协议,就是预期,不想是电脑彩票) (2) 单元测试角度 -1- offset by 1(我灌入了2800万term,测试出了一个bug) -2- 临界值() -3- 小数据集合(灯下黑) -4- 大数据测试 -5- 压力测试(多线程并发) (3) 单测之前 -1- 编译警告去除 -2- 静态代码检查工具pclint -3- 运行时测试工具valgrind -4- 冥思 a) 如果那陀代码很恶心,那他一定会出问题。(重构?: 经历就是财富,不要担心没人关注) b) 小心代码copy,即使是自己的代码,copy也会出问题(周六的SB-bug) c) 时常进行codereview (4) 单元测试好处 -1- 回归测试(我的struct宏曾经几经变动,谢谢test.cpp,别人接手时,也会有信心) -2- 增强信心(我的代码都是经过单元测试的,如果我现在放弃了,多可惜) -3- 节奏欢快(把开发的焦点聚焦于当前任务,因为我对之前经过单元测试的代码有信心) -4- 合作顺畅(我们的代码都是经过单元测试的,代码bug的数量可以得到控制,不会严重打击我们的合作心情) -5- 大型软件系统中,BUG就像癌症一样,越早发现越好 -6- 专业习惯受益终审 (5) 覆盖率测试 (6) gtest测试
About
mirror repository of flexse in google code. Author: [email protected]
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published