lucene 3.0.2 操作进阶
转自:Bannings
http://blog.csdn.net/zhangao0086/article/details/
Analyzer(分词器)
分词器能以某种规则对关键字进行分词,将分好的词放到目录中,以作为检索到的条件,在创建索引时会使用到分词器,在搜索时也将用到分词器,这两个地方要使用同一个分词器,否则可能找不到结果.分词器一般的工作流程:
- 切分关键词
- 去除停用词
- 对于英文单词,把所有字母转为小写
注:有的分词器对英文支持的非常好,还能对英文单词进行时态还原.
停用词的概念
有些词在文本中出现的频率非常高,但是对文本所携带的信息基本不产生影响,例如英文的“a、an、the、of”,或中文的“的、了、着”,以及各种标点符号等,这样的词称为停用词(stop word).文本经过分词之后,停用词通常被过滤掉,不会被进行索引.在检索的时候,用户的查询中如果含有停用词,检索系统也会将其过滤掉(因为用户输入的查询字符串也要进行分词处理).排除停用词可以加快建立索引的速度,减小索引库文件的大小
常用的中文分词器
中文的分词比较复杂,因为不是一个字就是一个词,而且一个词在另外一个地方就可能不是一个词,如在"帽子和服装"中,"和服"就不是一个词.对于中文分词,通常有三种方式:
- 单字分词
- 二分法分词
- 词典分词
单字分词:就是按照中文一个字一个字地进行分词.如:"我们是中国人",效果:"我"、"们"、"是"、"中"、"国"、"人".(StandardAnalyzer就是这样)
二分法分词:按两个字进行切分.如:"我们是中国人",效果:"我们"、"们是"、"是中"、"中国"、"国人".(CJKAnalyzer就是这样)
词库分词:按某种算法构造词,然后去匹配已建好的词库集合,如果匹配到就切分出来成为词语.通常词库分词被认为是最理想的中文分词算法.如:"我们是中国人",效果为:"我们"、"中国人".(使用极易分词的MMAnalyzer.可以使用极易分词,或者是庖丁分词分词器、IKAnalyzer等).
测试分词器
| /** |
| * 使用指定的分词器对指定的文本进行分词,并打印结果 |
| * @param analyzer |
| * @param text |
| * @throws Exception |
| */ |
| private void testAnalyzer(Analyzer analyzer, String text) throws Exception { |
| System.out.println("当前使用的分词器:" + analyzer.getClass()); |
| TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text)); |
| tokenStream.addAttribute(TermAttribute.class); |
| while (tokenStream.incrementToken()) { |
| TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class); |
| System.out.println(termAttribute.term()); |
| } |
| } |
Highlighter(高亮器)
在搜索结果中经常可以看到,自己搜索的关键字加上了一些效果,以突出显示,Lucene自然提供了这样的设置,我们需要用到Highlighter这个类,用之前需要配置好:
| /** |
| * Formatter:设置高亮器的格式,无参构造函数表示使用<b>标签 |
| * Scorer:Highlighter需要知道哪些关键词是需要高亮的,需要需要查询条件 |
| */ |
| Formatter formatter = new SimpleHTMLFormatter(); |
| Scorer scorer = new QueryScorer(query); |
| Highlighter highlighter = new Highlighter(formatter,scorer); |
| //除了上面两个以外,还需要生成一段摘要,以便搜索的时候显示,指定摘要的大小为20个字符 |
| Fragmenter fragmenter = new SimpleFragmenter(); |
| highlighter.setTextFragmenter(fragmenter); |
只需要配置这三样就可以了,接着我们要在每一次获取Field对象数据的时候做一些工作,因为高亮器实际上就是在内容中加了一点样式,我们当然要指定在哪里加:
| /** |
| * 在循环获取每一条记录的时候,让高亮器找到需要高亮的关键词, |
| * 要提供相应的分词器和告诉它高亮哪一个Field中的内容 |
| * 一次只能高亮一个Field,如需要高亮多个Field,需要写多次 |
| * 就像这样: |
| String text1 = highlighter.getBestFragment( |
| Configuration.analyzer, "title", |
| doc.get("title")); |
| */ |
| String text = highlighter.getBestFragment(Configuration.analyzer, "content", doc.get("content")); |
| if(text != null){ |
| doc.getField("content").setValue(text); |
| } |
一定要放在循环里面,highlighter.getBestFragment()方法本身没有副作用,也就是不改变原有的值,返回一个改变后的结果,所以要手动地改变Field中原有的值,并且if的条件最好不要省略,有时候可以会有这样一种情况,出现关键字的位置在其他Field里面,所以如果当前高亮的属性值中没有出现搜索关键字,则返回null.
排序
排序有几种方式,最常用的也就是相关度排序,把最有可能是用户需要的数据放在前面.由高到低排序,默认即是使用相关度排序.当然,我们也可以控制相关度排分的比重,比如我们想让一条记录的得分加倍,就要在建立索引时,加几句操作:
| Document doc = DocumentUtils.docConvert(article, Document.class); |
| //setBoost()方法需要一个float类型的参数,表示将相关度得分的因子增加多少倍 |
| doc.setBoost(2F); |
| indexWriter.addDocument(doc); |
这样加进去的索引,就会改变默认的相关度得分因子.如果我们想靠某个Field的值来排序也可以,默认是升序,如果是按某个Field的值来排序,那将不会生成相关度得分,因为没有必要.假设按ID进行升序排列:
| Sort sort = new Sort(new SortField("id",SortField.INT)); |
| TopDocs topDocs = indexSearcher.search(query,null, ,sort); |
IndexSearcher的search()方法需要改成接收4个参数的重载方法,第二个参数需要一个Filter,这里不需要,就传入null,Sort需要知道按什么排序,由SortField的第一个构造参数指明,第二参数指明类型,接收一个int值,由SortField对象的常量值表示.还可以加入第三个参数:
| Sort sort = new Sort(new SortField("id", SortField.INT, true)); |
表示是否倒序排序.也可以指定多个排序规则.由多个SortField组成第1顺序、第2顺序...
过滤
使用Filter可以对搜索结果进行过滤,以获得更小范围的结果.使用Filter对性能的影响很大(有可能会使查询慢上百倍).假如我要看ID从5到15的:
| //第三个参数:是否包含最小值(5);第四个参数:是否包含最大值(15) |
| Filter filter = NumericRangeFilter.newIntRange("id", , , true,true); |
| //这个时候就不需要第四个参数来指定排序了,search()这个方法有很多重载版本 |
| TopDocs topDocs = indexSearcher.search(query,filter, ); |
光这样写还不行,会看不到结果.这是因为要过滤的值,如果是数字,需要以指定的格式存储才行,否则将按字符串的方式来比较.
对于这个问题,需要引出一个工具类:NumericUtils,这个工具类专门做数值与数值或字符串间的转换工作.要在对象到Document以及Document到对象的转换的时候进行,这是对于数值,如果是日期类型,需要使用这个工具类:DateTools.
注:这样做了以后,可能还是不行,对于使用NumericUtils把数字转换为字符串,一定要使用Index.NOT_ANALYZED,以保存能够正确的使用Filter
其他搜索
首先,有两种搜索方式:
- 使用QueryParser(或MultiFieldQueryParser)解析查询字符串的方式
- 自己直接创建Query子类的实例方式
由于可以使用Query对象的toString()方法打印出对应的查询语法,所以以第二种方式做的话,可以看相应的第一种查询方法:
| /* 1.匹配所有对应的查询字符串为: *:* |
| Query query = new MatchAllDocsQuery(); |
| 2.范围查询对应的查询字符串为: id:[5 TO 15] |
| Query query = NumericRangeQuery.newIntRange("id", 5, 15, true, true); |
| 范围查询对应的查询字符串为: id:{5 TO 15} |
| Query query = NumericRangeQuery.newIntRange("id", 5, 15, false,false); |
| 范围查询对应的查询字符串为: id:{5 TO 15] |
| Query query = NumericRangeQuery.newIntRange("id", 5, 15, false, true); |
| 3.关键词对应的查询字符串为: title:lucene |
| Query query = new TermQuery(new Term("title", "lucene")); |
| 4.通配符对应的查询字符串为: title:lucen? |
| Query query = new WildcardQuery(new Term("title", "lucen?")); |
| 通配符对应的查询字符串为: title:lu*ne |
| Query query = new WildcardQuery(new Term("title", "lu*ne")); |
| 5.短语对应的查询字符串为: title:"lucene ? ? 工作" |
| PhraseQuery phraseQuery = new PhraseQuery(); |
| phraseQuery.add(new Term("title", "lucene"), 0); // 第一个词的索引是0 |
| phraseQuery.add(new Term("title", "工作"), 3); |
| 短语对应的查询字符串为: title:"lucene 工作"~5 |
| phraseQuery.add(new Term("title", "lucene")); |
| phraseQuery.add(new Term("title", "工作")); |
| phraseQuery.setSlop(5); // 指定这些词中间的间隔最多不会超过5个词 |
| 6.布尔查询 |
| 对应的查询语法两种: |
| 1. + 代表MUST,-表示NOT |
| 2. AND、OR、NOT,注意要全是大写 |
| 3. MUST 必须满足 |
| MUST_NOT 非 |
| SHOULD 多个SHOULD一起用,是OR的关系 |
| Query query1 = new TermQuery(new Term("title", "lucene")); |
| Query query2 = NumericRangeQuery.newIntRange("id", 5, 15, false, true); |
| 对应的查询字符串为: +title:lucene +id:{5 TO 15] |
| 对应的查询字符串为: title:lucene AND id:{5 TO 15] |
| booleanQuery.add(query1, Occur.MUST); |
| booleanQuery.add(query2, Occur.MUST); |
| 对应的查询字符串为: +title:lucene -id:{5 TO 15] |
| 对应的查询字符串为: title:lucene NOT id:{5 TO 15] |
| booleanQuery.add(query1, Occur.MUST); |
| booleanQuery.add(query2, Occur.MUST_NOT); |
| 对应的查询字符串为: title:lucene id:{5 TO 15] |
| 对应的查询字符串为: title:lucene OR id:{5 TO 15] |
| booleanQuery.add(query1, Occur.SHOULD); |
| booleanQuery.add(query2, Occur.SHOULD); |
| ---------------------------------------------------- |
| MUST + SHOULD,与只有一个MUST效果相同 |
| SHOULD + MUST_NOT,这时SHOULD就相当MUST |
| MUST_NOT + MUST_NOT,没有匹配结果,也不报错。 |
| */ |
lucene 3.0.2 操作进阶的更多相关文章
- moloch1.8.0简单操作手册
moloch1.8.0简单操作手册 Sessions 页面:Sessions主要通过非常简单的查询语言来构建表达式追溯数据流量,以便分析. SPIView 页面: SPIGraph页面:SPIGrap ...
- 关于Lucene 3.0升级到Lucene 4.x 备忘
最近,需要对项目进行lucene版本升级.而原来项目时基于lucene 3.0的,很古老的一个版本的了.在老版本中中,我们主要用了几个lucene的东西: 1.查询lucene多目录索引. 2.构建R ...
- Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤
原文地址: Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤 - 网络资源是无限的 - 博客频道 - CSDN.NET http://blog.csdn.net/fen ...
- Lucene 6.0下使用IK分词器
Lucene 6.0使用IK分词器需要修改修改IKAnalyzer和IKTokenizer. 使用时先新建一个MyIKTokenizer类,一个MyIkAnalyzer类: MyIKTokenizer ...
- Lucene 4.0 正式版发布,亮点特性中文解读[转]
http://blog.csdn.net/accesine960/article/details/8066877 2012年10月12日,Lucene 4.0正式发布了(点击这里下载最新版),这个版本 ...
- Ubuntu14.04 64位机上安装OpenCV2.4.13(CUDA8.0)版操作步骤
Ubuntu14.04 64位机上安装CUDA8.0的操作步骤可以参考http://blog.csdn.net/fengbingchun/article/details/53840684,这里是在已经 ...
- ThinkPHP5.0框架开发--第7章 TP5.0数据库操作
ThinkPHP5.0框架开发--第7章 TP5.0数据库操作 第7章 TP5.0数据库操作 ===================================================== ...
- mysql8.0.16操作记录
mysql8.0.16操作记录 2.1.登录 -uroot -p'AnvcTMagdLarwNV3CKaC' mysql: [Warning] Using a password on the comm ...
- MDN 文档高级操作进阶教程
MDN 文档高级操作进阶教程 MDN 文档, 如何优雅的使用 MDN 文档上的富文本编辑器 pre & 语法高亮器 code & note box source code 上传附件 i ...
随机推荐
- iOS图形处理和性能(转)
在之前的文章里,我们探讨了基于多种不同技术来实现自定义的UIButton,当然不同的技术所涉及到的代码复杂度和难度也不一样.但是我也有意提到了基于不同方法的实现所体现出的性能表现也不一一相同. [ ...
- 使用osgconv工具对模型进行旋转
osgconv -o 90-1,0,0 --use-world-frame src.3ds dst.3ds 视线方向沿X轴正方向,将src.3ds顺时针旋转90度,保存为dst.3ds
- [Android Pro] Android Support 包里究竟有什么
reference to : http://www.2cto.com/kf/201411/350928.html 随着 Android 5.0 Lollipop 的发布,Android 又为我们提供了 ...
- CSS-Transform-transition-Animation
Transform 根据我的理解,transform和width.height.background一样,都是dom的属性,不同的是它是css3旗下的,比较屌,能够对原来的dom元素进行移动.缩放.转 ...
- 解决iphone5,5s有锁版(AU,SB,S版等等)ios7越狱后+86、FT、IM等一切问题
最近无聊,给大家发一个关于完美解决iphone5,5c.5s有锁版本机号码.+86.短信.facetime.imessage等问题.是ios7系统哦!(本人亲测iphone5 SB版 双模卡解锁)相当 ...
- 桶排序(bucket sort)
Bucket Sort is a sorting method that subdivides the given data into various buckets depending on cer ...
- Eclipse 代码格式化
http://blog.csdn.net/prstaxy/article/details/7839197 http://jingyan.baidu.com/article/9158e00044efb6 ...
- 【Python】【解决】UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 1: ordinal not in range(128)
1.问题描述 今天在升级Ubuntu到14.04,使用命令行启动软件更新器,进行版本升级,结果开始升级就异常退出了,具体打印如下: $update-manager -d 正在检查新版 Ubuntu 使 ...
- hrbustoj 1545:基础数据结构——顺序表(2)(数据结构,顺序表的实现及基本操作,入门题)
基础数据结构——顺序表(2) Time Limit: 1000 MS Memory Limit: 10240 K Total Submit: 355(143 users) Total Accep ...
- Android快捷开关实现(转)
在Android源码中,提供的快捷开关相对是比较少的,Android4.0系统默认提供的桌面快捷开关AppWidget上只有5种开关(分别是Wifi开关.蓝牙开关.GPS开关.同步开关.亮度设置开关) ...