最近在做一个多语言的内容管理系统,搜索引擎部分用的Lucene,本来自信对Lucene还是比较了解的,结果多语言部分还是碰到了麻烦。
我的一个Document数据结构是这样的,一组基本信息,如文章id(articleId),文章创建时间(createTime)等,最后是多语言版本的文章内容(articleContent),针对于不同语言类型,保存Field时名称追加语言识别码,如英文,就是articleContent_en。
Document结构如下:
//Field数量不固定,每种语言都会增加一个Field
Document{
articleId
createTime
...
articleContent_en
articleContent_ch
...
}
全文搜索时,只要有一种语言的文章内容匹配,搜索就返回该Document。最后显示的时候,也要给出用户所有语言版本的预览信息。
就在这里,我碰到一个问题,我使用中文Analyzer只能支持中文和英文的索引和搜索,假如文章是日文,Analyzer只能分出其中的中文部分。
开始我不想改变数据结构,毕竟这个结构对于搜索来说最简单,那么,我想到的是对不同语言的文章内容使用不同的Analyzer进行分词,也就是当我判断文章内容是日文的时候,使用Lucene自带的StandardAnalyzer进行一元分词处理。但很快发现这个方案行不通,因为Lucene在构建索引时,Analyzer是Document级的,也就是一个Document的所有Field只能使用同一个Analyzer进行解析,Lucene的示意代码如下:
//Field中没有传入Analyzer的方法
Document.add(new Field(...));
//此处可以看出,Analyzer是和Document级别对应的
IndexWriter.addDocument(Document, Analyzer);
之后我又想到了第二个解决方案,修改我的Document结构,将一个Document分解为基本信息Document和单个语言文章内容Document这样几个Document的组合结构。每个Document都有articleId这个Field,增加一个docType的Field区分是基本信息的Document还是文章内容的Document,假设基本信息的docType为1,文章内容为2。
Document结构如下:
//基本信息Document
Document{
docType = 1
articleId
createTime
...
}
//文章内容Document
Document{
docType = 2
articleId
articleContent
}
这样对于不同的语言种类的同一篇文章,就可以使用不同的Analyzer进行索引了。但是很快发现如果这么拆分,复合搜索的过程会变得很复杂,比如以下条件:
文章关键字为“尼斯湖 水怪 考证”
文章创建时间要在2005年之后
搜索过程变成了:
1. 用关键字和docType等于2两个条件搜索进行联合搜索,得出搜索含有关键字的文章Document。
2. 从第一次搜索结果的Document中提取所有关键字匹配的文章的articleId,联合createTime早于2005年以及docType等于1这两个条件进行第二次搜索,得出真正符合用户要求的结果。
3. 进行当前分页页面的内容提取,将基本信息Document作为主信息,利用articleId和docType等于2两个条件搜索其下所有语言版本文章内容,组合成完整信息返回给页面。代码如下:
class Article{
Document articleBaseInfoDoc;
List articleContentList;
}
这个方案理论上能解决问题,但是会使搜索过程复杂很多,也不是我希望看到的。
于是想到第三种方案,修改Analyzer。把我使用的中文Analyzer进行修改,判断语言种类,如果不是中文,则直接按照StandartAnalyzer方式进行分词。但是我用的那个Analyzer不是开源的,源码经过了混淆,读起来都异常费劲,更别说修改。
不知道有没有人碰到过和我相同的问题,能给我一些提示,非常感谢。
另外:
通过这个事我发现了Lucene设计上的一个费解的事情,Lucene索引时不能对Field级别进行不同Analyzer分词处理,但是搜索的时候可以进行不同Field使用不同Analyzer分词搜索,搜索代码如下:
//针对每一个Field的搜索解析器都可以传入不同的Analyzer
QueryParser parser = new QueryParser("articleContent", analyzer);
好生奇怪。