搜索功能"/>
CAE开发日志(2):搜索功能
1、CAE的搜索功能
因为一个call表对应了一首歌,当一个歌手的call表多起来的时候,歌曲的数目也会增多,此时用户就不能简单地通过“查看全部歌曲”来找出自己想要的call表,所以就需要引入搜索功能,但是搜索这个问题实际上还是要看用户群体的习惯性,而且call表都是日文/英文为主,用户的习惯并不能很好地预测。下面是我从一开始到现在对CAE的搜索功能的一些思考历程。
2、使用搜索引擎
一开始我是打算使用搜索引擎,具体来说是准备使用Lucene去实现的,到现在为止CAE的后台lib包中仍然保留了Lucene的jar包。
Lucene的基本功能的jar包就是lucene-analyzers-common-5.4.0.jar、lucene-core-5.4.0.jar、lucene-queryparser-5.4.0.jar,而多出来的lucene-analyzers-kuromoji-5.4.0.jar是Lucene自带的日文检索包。
我一开始的想法是,用户自己也不知道自己会搜些什么东西,可能是歌名,可能是歌手,可能是发售日期,甚至可能是歌词。歌名、歌手、发售日期这种都是简单的情况,因为可以直接使用sql查询就可以完成,但是歌词却并非如此,如果要支持对歌词的搜索的话就说明要支持全文检索,那就不得不用到Lucene了。总之,后台需要把用户的关键词所能联系到的所有可能性都返回给用户。
说到日文分词,就要简单地介绍一下kuromoji,kuromoji本来是一个独立的专用于日语的全文检索包,只是后来它被捐给了Lucene,现在它是Lucene默认自带的日文检索包。
一开始我还希望让歌名也加入全文检索的行列,因为我不希望使用sql的LIKE来进行歌名的模糊查询,所以既然歌词都使用了kuromoji,那歌名也搭一个顺风车吧。但是使用kuromoji其实并没有完全解决全文检索的问题,因为无论是歌名还是歌词,都不一定是纯日文的!因为有可能出现英文甚至是全英文的情况(例如Guilty Fever Eyes),我测试过使用kuromoji去对英文歌名进行分词,但是结果是,kuromoji根本就不会识别英文,所以分词也是失败的,检索自然也是失败的。
后来,我想到了一个权宜之计,在save动作前,先对歌名进行一次判断,判断它是哪种情况(纯英文/英文+日文/日文),这个判断抽出来封装成一个方法,下面将这段代码分享出来:
//日文的unicode集合private Set<Character.UnicodeBlock> japaneseUnicodeBlocks = new HashSet<Character.UnicodeBlock>(){{add(Character.UnicodeBlock.HIRAGANA);add(Character.UnicodeBlock.KATAKANA);add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS);}};//判断一个字符串是英文还是日文private boolean enOrJp(String word){//先把字符串的特殊字符用正则消去,然后再判断是否纯英文boolean result=word.replaceAll("[^a-zA-Z_\u2E80-\uFE4F]", "").matches("^[a-zA-z]*");//如果是纯英文则返回trueif(result){return result;}//如果不是纯英文则判断是否有日文,对每个字符进行轮询,一旦出现有日文则认为该字符串是日文并返回falsefor (char c : word.toCharArray()){if (japaneseUnicodeBlocks.contains(Character.UnicodeBlock.of(c))){result=false;break;}}return result;}
首先使用正则表达式,将字符串的一些特殊字符,如空格、☆等去掉,因为这些会对之后的判断造成误判。
然后再用正则表达式判断处理后的字符串是不是纯英文,如果是则返回,此时这段字符串就不会交给kuromoji去处理,而是交给Lucene默认的Analysis,也就是StandardAnalyzer去进行分词。
如果不是纯英文,那就开始判断是否包含了日文,这里把字符串变成一个char[]并且进行了遍历,对每一个字符都是用japaneseUnicodeBlocks变量去判断这个字符的unicode码是否在标准日文的unicode码的范围之中,如果是,则表示当前字符是日文,跳出循环。
japaneseUnicodeBlocks这个变量是一个日文的unicode码的set,可以看到初始化时它add了三个记录,第一个“HIRAGANA”代表平假名,第二个“KARAHANA”表示片假名,第三个“CJK_UNIFIED_IDEOGRAPHS”代表的是中国(China)、日本(Japanese)、韩国(Korea)三国的共用unicode码集合,这三个记录的并集就能包含所有日语的情况。
可以看到,上面的这种算法只是非常简陋的,中心思想就是“一旦出现日文,就无视英文的部分交给kuromoji来完成”,后续可以继续改良,可以按照比例来进行判断,例如50%以上是日文才交给kuromoji来分词。
当然,个人认为最根本的解决方法就是自己写一个分词器,但是我对分词器并不是很熟,而且算法也是一窍不通,这里我认为还是交给后人来完善好了,而且最好使用C++来写会更好(以后的后台也不能清一色的Java呀,要考虑多方面多语言发展,尽量发挥各种语言的优势,培养更多方向的人才)。
3、使用tag
采用搜索引擎来做还是太复杂了,而且用户也不一定会搜索歌名、歌词,我认为更有可能会搜索的是和正式的歌曲信息完全无关的关键词,例如假如用户想搜索“太陽を追いかけろ!”,用户不会真的把“太陽”这个日文输进去,也不会搜索歌词(可能他也记不住歌词),而更有可能会输入像“bd7”这样的关键词。
问题是,“bd7”这个关键词相当于是水水人们私底下这么喊的而已,并不是正式的歌曲信息,而且可能哪一天这个称呼就改了,而机器是不懂人类的潮流的,所以简单地使用sql已经无法解决问题,这时,我想到了B站的tag系统。
只要让用户自己编辑tag系统不就完了吗?让用户自己投票产生他们想要的tag,这些tag可以随着时间的推移或者对用户行为的监测分析而删除,这样不就可以达到需求了吗?我认为tag系统是一个非常好的想法,而且实现起来并不困难,在未来还可以让后台去收集用户行为,然后对用户行为进行分析甚至是预判,让系统自己也生成热门的tag,这就扯到nosql、数据分析、数据挖掘甚至是机器学习了,但是我觉得作为未来的一个CAE的发展方向来说,是一个不错的选择。
4、现况
后来我的同伴跟我说,既然大家装了这个app,那就表示大家都有一定的基础的,而且也不会出现搜歌词的需求,歌名也会好好地打上日文的,tag系统看起来很复杂的样子所以就不需要了,简单一点就行。
所以目前CAE还是使用sql的LIKE来完成搜索的功能的。。但是万一以后对搜索功能提出了更严格的要求时,我觉得搜索引擎和tag系统的开发就可以提上日程了。
更多推荐
CAE开发日志(2):搜索功能
发布评论