存档

‘行业案例’ 分类的存档
页: 1 2 后页

音乐搜索的极致

2009年10月15日

12530 PC客户端 咪咕 (页面最下方有一个很不显眼的下载链接) 搜索 原本计划是今天上线内测,20号正是随资源库后台一起上线,其实昨晚就已经替换掉了正式服务器上原来的接口。正因为昨晚悄无声息的上线,原本已经下班走到 家门口的我们,又被电话叫回公司,来解决一个刚刚发现的bug。

音乐搜索,第一期还没有特别做歌词的搜索,只对歌手名,歌曲名,专辑名做优化,加上数据量本身就很小(一共才不到100万首歌),只好在查询上做文章。我们当前一共设置了十层查询 Query:

1。精确匹配:歌手,歌曲,专辑,不分词字段,去掉前后多余空格,精确匹配
2。过滤后的精确匹配:歌手,歌曲,专辑,过滤字段,去掉所有特殊字符,英文转成小写,精确匹配
3。拼音全量匹配:歌手,歌曲,专辑,拼音全量字段,去掉所有非英文字符,英文转成小写,精确匹配
4。同音纠错匹配:歌手,歌曲,专辑,拼音全量字段,只对含中文的搜索词使用,中文转拼音,英文转小写,去掉所有特殊字符,精确匹配
5。拼音首字母匹配:歌手,拼音首字母字段,中文转拼音首字母,英文转小写,去掉所有特殊字符,精确匹配
6。前缀匹配:歌手,歌曲,专辑,不分词字段,去掉前后多余空格,英文转小写,前缀匹配
7。分词Must匹配:歌手,歌曲,专辑,(歌词),分词字段,分词,词之间使用Must连接,分词匹配
8。分词Should匹配:歌手,歌曲,专辑,(歌词),分词字段,分词,词之间使用Should连接,分词匹配
9。合并分词匹配:歌手+歌曲+专辑 分词字段,分词,(当前使用 Should 连接),分词匹配
10。模糊匹配:歌手,歌曲,专辑,分词字段,去掉前后多余空格,英文转小写,模糊匹配, 包含中文时模糊度:0.65 全英文模糊度:0.85

其中模糊匹配还分了两级:

a 拼音纠错
b 模糊查询,包括中文模糊和英文模糊(模糊度不一样)

当前拼音模糊是使用组合的办法来实现的:

1。建索引的时候,拼音全量字段里建的是字段的准确拼音,包括多音字的组合
2。搜索的时候,将用户输入的关键词转成拼音,在拼音全量字段里搜
3。模糊的时候,将用户输入关键词转成的拼音,按照模糊规则:n-l 互换,zh-z, ch-c, sh-s 互换,an-ang, en-eng, in-ing, on-ong 互换,每次只换一个(当前只支持模糊度为1的拼音模糊查询),如果有多个可以替换的点,则返回的结果为一个数组组合,然后使用 精确匹配在拼音全量字段进行查询

还有一种做法:

首先定义个所谓的拼音标准化过程:
n->l,zh->z, ch->c, sh->s ,an->ang, en->eng, in->ing, on->ong 不是互换,而是单向替换。
将一个拼音串的所有可替换点都替换后,得到的一个串,称为标准化串。
1。建索引的时候,歌曲名,歌手名,专辑名各新增一个标准化串字段,按”,”分词(多音字),存储字段的拼音标准化串
2。搜索的时候,将用户输入的关键词转成拼音,在拼音全量里面搜索
3。模糊的时候,将用户输入关键词的拼音再转成标准化串,在标准化串字段里面搜索

优点:不同那么复杂的组合逻辑
缺点:无法控制模糊度

拼一个很大的 Query 去 Lucene 里面查询最大的问题就是,排序很难控制。不停的查看 Lucene Explain 出来的打分细节,再微调 Query 之间的 boost 权值,再查看打分细节,再微调。特别是分词命中这个 Query ,Lucene 分词命中的默认打分规则,总觉得不太满意。自己做了一个 Similarity 的子类来算分,可毕竟不是专业的,考虑的不够全面,解决了一个问题,副作用带来更多的问题。最后,还是不得不放弃这个方向的尝试。

拼一个大 Query 的一个意外收获就是,发现 Lucene 2.9.0 的一个 bug:LUCENE-1974,提到官方 JIRA 后,很快被确认,并修复了,并且我提交的 TestCase 也被将接纳到 Lucene 的测试用例集合中。可惜 2.9.1 出来前,我们还是不得不将项目切换回 2.4.1 , 以避免这个 bug。

现在使用的 IK 分词器,总觉得行为有些奇怪,又没有什么地方可以设置的。天龙八部,最多分词分出来“天”,“八”是我们不想要的,最长分词,又分不出“天龙”,真是郁闷。

因为 Query 太复杂,Lucene 自带的标红效果不是很令人满意,所以标红的部分也是完全自己做的。仿照 Query 的模式,定义了一系列的规则,如全量命中,拼音命中,分词命中等,记录下每种规则匹配到的区段,最后做一次归并就可以了。

关键词提示,即用户在搜索框里输入的同时,下拉一个提示列表。现在的做法是建了一个单独的关键词索引,用户输入的时候,使用前缀去匹配。中文的 Trie 树比英文复杂不少,所以最开始没有选它。但现在发现关键词索引太大了,Lucene 更新太慢,才后悔最初的选型失误。关键词里面需要保存词频的信息,搜索量的信息,所以以后的更新肯定也会不少。明天继续想办法解决这个问题。

做完这个项目以后,大约所有的搜索功能,都不会让我觉得害怕了吧。

原创,转载请著名出处:唐福林 博客雨 http://blog.fulin.org/2009/10/acme_of_music_search.html

fulin 开发, 行业案例

Lucene 重建索引流程设计(草稿)

2009年4月3日

流程设计草稿,欢迎拍砖!

Lucene 重建索引流程设计

TangFulin <tangfulin@gmail.com>

一. php client 端:

1. update 与 rebuild 分开

2. update 准实时:insert,update,delete 实时调用更新索引接口(带 primery key 的update 和 delete)

3. rebuild 使用命令行或者 cron 运行,不能使用 web 页面(有运行时间限制),但可以在后台管理系统中作触发(如何防止重复触发?)

二. Java IndexServer:(接受 client 发过来的数据,输出为临时 xml 文件)

1. 日常 update 的 xml 临时文件可以考虑保存在内存文件系统中(保留最近n天的文件debug使用)

2. 更多的处理过程 log (debug 使用,日常监控使用)

3. rebuild 的 xml 临时文件一定要保存在内存文件系统中

4. xml 文件按年或月分目录

5. rebuild 的过程中,update 数据需要为新索引保留一份,等 rebuild 完成后更新新的索引(需要一个 rebuild_update 目录,等搜索切换到使用新的索引后,用该目录替换原来的 update 目录)

三. Java IndexWriter:(读取 update xml 文件,更新索引)

1. update 与 rebuild 分开,以便设置不同的合并因子等参数,以达到最快的 rebuild 速度

2. 每一个索引对应一个 update 文件目录,当索引切换的时候,update 目录跟着切换,以保证索引数据一致

四. Java IndexRebuilder:(读取 rebuild xml 文件,新建索引)

1. rebuild 过程:

a. 正常情况: client 发送 update 数据给 IndexServer ,IndexServer 将数据写入 update 目录,IndexRebuilder 定期扫描 update 目录,读取 xml 文件并更新索引

b. client 发送“重建索引开始”消息给 IndexServer,IndexServer 设置标志位,从当前开始,所有的 update xml 都抄送一份到 rebuild_update 目录。同时给 IndexRebuilder 发送 “重建索引开始” 消息。(消息中能否带有这次重建索引的大致的条目数?可以用来确定派生多少个线程)

c. client 发送重建索引数据给 IndexServer,IndexServer 将这些数据输出到 rebuild 目录下

d. IndexRebuilder 收到 “重建索引开始” 消息后,(根据大致的条目数,相应的派生线程)扫描 rebuild 目录,使用其中的 xml 文件建立索引

e. client 发送“重建索引结束”消息给 IndexServer, IndexServer 转发消息给 IndexRebuilder

f. IndexRebuilder 收到“重建索引结束”消息后,等待所有线程工作完成,然后开始使用 rebuild_update 中的数据更新新的索引

g. IndexRebuilder 更新索引到一个可用状态后(如何判定?某一次列目录发现没有新xml文件?),停止更新,开始 切换到使用新索引

2. 切换到使用新索引过程:

a. IndexRebuilder 发送“停止更新索引”消息给 IndexWriter,后者停止更新旧索引,close 打开的文件

b. IndexRebuilder 拷贝新索引,覆盖旧索引

c. IndexRebuilder 将旧的 update 目录指向 rebuild_update 目录

d. IndexRebuilder 发送“停止抄送 update xml 文件到 rebuild_update” (重建索引完成)命令给 IndexServer,并将 rebuild_update 指向新的空目录

e. IndexRebuilder 发送“重新开始更新索引”消息给 IndexWriter,后者 reopen 索引,并照常更新

f. IndexRebuilder 清除旧索引文件,等待下一次重建索引消息

3. 重建索引的加速:(初步设想)

a. 根据索引大致的条目数,预先派生线程

b. 每个线程单独建立索引,完成后再归并

c. 预先派生线程数目,以及归并策略(1次归并,或者多次,每次把n个归并成1个)需要测试

五. IndexSearch:(读取索引,响应搜索请求)

1. 同步索引:从 IndexWriter 同步到 IndexSearch 上,使用 bash 脚本,rsync

2. reopen:索引更新以后,发消息通知 IndexSearch 重新读入索引,可以使用 curl

fulin 行业案例, 项目管理

页: 1 2 后页
页: 1 2 后页