分词器在创建索引与搜索之时都会用到。上文我用icu分词器实现了简单的中文分词器,却发现不能直接在搜索之时使用,会打断一些lucene搜索语法的分析。
语法汇总:https://www.likecs.com/show-95873.html
比如,使用双引号进行全文搜索,"天文"
,普通分析器分词为:content:"天 文"
,我制作的自定义分词器却出现了冗余内容,结果为:content:"天文 天 文"
,反而查找不到任何有效内容。
有个疑问,content:"天 文"
与content:"天文"
是否有区别?结果应该是一样的,可能效率上有区分。
问号无法在双引号内使用。其实双引号之内,空格以及标点符号是被过滤掉的,搜索之时,匹配连续的关键词。
问号,如用 muscle? 搜索 muscles。如果分词器没有特定分词,那么也是搜索不到的,比如格林尼治天文台
,如果以格林?治天文台
为搜索语句,那么不管是标准分词器,还是自定义分词器,都是没有任何结果,反而不如搜格林 治天文台
。那是因为,标准分词器只生成单字索引,而自定义分词器也只能分词为:格林
+天文台
,索引里并没有存储完整的关键词。
星号同理。而且其实,使用星号问号之时,搜索语句并没有经过自定义分词器的分析,而是直接作为一个特殊的term。
目前,通过类似于“反射”、“反序列化”的简单方式修复自定义分词器对于双引号的打断。
因为以下经验公式应该是成立的 ——
new QueryParser(Version.LUCENE_47, "content", analyzer).parse(query.toString())
==query
所以,在第一遍 QueryParser.parse 后,得到 query.toString(),对此字符串进行魔改式修正 —— 搜索正则表达式 content:"(.?)"
以过滤掉双引号中的双字及以上词语即可,最后再次 QueryParser.parse 最终得到 query 之对象,搜索之锁钥。
我对于开源的态度是无限开放。希望能有人参与这无限开源。
v7.2
- 修复搜索引擎无法用双引号进行全文搜索的BUG。
- 实现搜索引擎输入栏的双引号按钮,有无选中内容均可点击。
- 修复相机取词(目前只有实时相机取词)
代码片段:
query = new QueryParser(Version.LUCENE_47, "content", analyzer).parse(phrase);
CMN.debug("breaked query::", query);
boolean debug_query = true;
if (phrase.contains("\"") || debug_query) {
try {
String raw = query.toString();
Pattern p = Pattern.compile("content:\"(.+?)\"");
Matcher m = p.matcher(raw);
StringBuffer sb = new StringBuffer();
boolean found = false;
while(m.find()) {
found = true;
m.appendReplacement(sb, "");
String raw_term = m.group(1);
int now = 0, last=-1;
// loop in "raw_term"
while (now < raw_term.length()) {
if (raw_term.charAt(now)==' ') {
boolean shouldStrip = true;
if (now-last-1 <= 1) shouldStrip = false;
if (shouldStrip) {
boolean quanYingWen = true;
for (int i = last+1; i < now; i++) {
if (WordBreakFilter.isBigram(raw_term.charAt(i))) {
quanYingWen = false;
break;
}
}
if(quanYingWen) shouldStrip = false;
}
if (shouldStrip) last = now;
else break;
}
now ++ ;
}
if (last > 0) raw_term = raw_term.substring(last+1);
sb.append("content:\"").append(raw_term).append("\"");
}
if (found || debug_query)
{
m.appendTail(sb);
raw = sb.toString();
//CMN.debug("修正前 query::", query);
query = new QueryParser(Version.LUCENE_47, "content", new StandardAnalyzer(Version.LUCENE_47)).parse(raw);
CMN.debug("修正后 query::", query);
}
} catch (Exception e) {
CMN.debug(e);
}
}
log :
修正前 query:: content:"格林 天文台 格 林 尼 治 天 文 台"
修正后 query:: content:"格 林 尼 治 天 文 台"