• 关于 Lucene 搜索语法与分词的浅显研究


    分词器在创建索引与搜索之时都会用到。上文我用icu分词器实现了简单的中文分词器,却发现不能直接在搜索之时使用,会打断一些lucene搜索语法的分析。

    语法汇总:https://www.likecs.com/show-95873.html

    问题 / issues

    比如,使用双引号进行全文搜索,"天文",普通分析器分词为:content:"天 文",我制作的自定义分词器却出现了冗余内容,结果为:content:"天文 天 文",反而查找不到任何有效内容。

    有个疑问,content:"天 文"content:"天文"是否有区别?结果应该是一样的,可能效率上有区分。

    问号无法在双引号内使用。其实双引号之内,空格以及标点符号是被过滤掉的,搜索之时,匹配连续的关键词。

    问号,如用 muscle? 搜索 muscles。如果分词器没有特定分词,那么也是搜索不到的,比如格林尼治天文台,如果以格林?治天文台为搜索语句,那么不管是标准分词器,还是自定义分词器,都是没有任何结果,反而不如搜格林 治天文台。那是因为,标准分词器只生成单字索引,而自定义分词器也只能分词为:格林+天文台,索引里并没有存储完整的关键词。

    星号同理。而且其实,使用星号问号之时,搜索语句并没有经过自定义分词器的分析,而是直接作为一个特殊的term。

    修复 / workaround fix

    目前,通过类似于“反射”、“反序列化”的简单方式修复自定义分词器对于双引号的打断。

    因为以下经验公式应该是成立的 ——

    new QueryParser(Version.LUCENE_47, "content", analyzer).parse(query.toString()) == query

    所以,在第一遍 QueryParser.parse 后,得到 query.toString(),对此字符串进行魔改式修正 —— 搜索正则表达式 content:"(.?)" 以过滤掉双引号中的双字及以上词语即可,最后再次 QueryParser.parse 最终得到 query 之对象,搜索之锁钥。

    附无限词典 v7.2 更新日志

    我对于开源的态度是无限开放。希望能有人参与这无限开源。

    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);
    				}
    			}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    log :

    修正前 query:: content:"格林 天文台 格 林 尼 治 天 文 台" 
    修正后 query:: content:"格 林 尼 治 天 文 台" 
    
    • 1
    • 2
  • 相关阅读:
    python面向对象基础-封装
    (208)Verilog HDL:时钟双沿触发器
    Lightsail VPS 实例在哪些方面胜过 EC2 实例?
    【wpa_supplicant】driver如何告诉supplicant自己做的一些事情以及结果
    【SpringBoot项目】SpringBoot项目-瑞吉外卖【day02】员工管理业务开发
    码住!Elsevier-最全清样/校样(Proof)处理流程
    云计算-Linux-mv,cat,less,head,tail,rm命令学习
    数据结构-----排序的概念、常见排序的实现以及排序算法的特点、非比较排序、排序相关例题
    Vue3学习笔记+报错记录
    JS面向对象的几种设计模式
  • 原文地址:https://blog.csdn.net/sinat_27171121/article/details/128172024