JAVA_WEB项目之Lucene实现检索结果排序和关键字在索引库中多字段查询结果进行高亮显示

上一篇介绍了JAVA_WEB项目之Lucene使用中文分词器IKAnalyzer3.2.8接下来对上一篇的代码实现排序的效果和关键字在索引库中多字段查询结果进行高亮显示。

首先是排序的效果:

Goods类,LuceneUtil类,ConfigureLucene类,测试类等的代码和上一篇的一样,只有HelloWordLucene里面的查询代码不一样。

/**
	 * 根据指定的条件查询,
	 * @param name 指定的关键字
	 * @return 封装了goods对象的list集合
	 */
	public List<Goods> queryGoods(String name){
		List<Goods> goodsList=new ArrayList<Goods>();
		//创建查询对象
		IndexSearcher searcher=null;
		try {
			searcher=LuceneUtil.getIndexSearcher();
			//  指定查询的关键字到索引库查询
			Query query=IKQueryParser.parse("name", name);
			/**
			 * 根据给定的关键字查询,与索引库Term去匹配,5代表: 期望返回的结果数
			 *  第一次查询: indexSearcher.search 只能获取文档的索引号和匹配的数量
			 *  返回的结果是TopDoc类型
			 *  totalHits: 命中数, 数组的长度,后面用来做分页
			 *  ScoreDoc[]: 存储匹配的文档编号的数组
			 *  Score: 文档的积分,按照命中率自动算出来
			 *  Doc:当前文档的编号
			 */
			//增加排序的效果
			/*对象查询的结果进行排序: Lucene排序有两种: 命中率排序, 根据字段排序
			 *注意 这两种排序方式不互斥的,如果选择按字段排序命中率是不会被计算出来, 但是字段排序本身可以支持多字段
			 *被排序的字段,和被删除更新一样 字段必须创建索引
			 * true代表的是降序
			 */
			Sort sort=new Sort(new SortField("id",SortField.INT, true),new SortField("price", SortField.DOUBLE,true));
			TopDocs topDocs= searcher.search(query, null, 5, sort);
			// 此变量/每页显示的记录数就是总页数
			System.out.println("真正命中的结果数:" + topDocs.totalHits);
			// 返回的是符合条件的文档编号,并不是文档本事
			ScoreDoc scoreDocs[]= topDocs.scoreDocs;
			for(int i=0;i<scoreDocs.length;i++){
				ScoreDoc scoreDoc= scoreDocs[i];
				System.out.println("真正的命中率:"+scoreDoc.score);
				System.out.println("存储的是文档编号:"+scoreDoc.doc);
				Document doc= searcher.doc(scoreDoc.doc);
				System.out.println(doc.get("id"));
				System.out.println(doc.get("name"));
				System.out.println(doc.get("price"));
				System.out.println(doc.get("remark"));
				System.out.println("---------");
//				Goods goods=new Goods();
//				goods.setId(Integer.parseInt(doc.get("id")));
//				goods.setName(doc.get("name"));
//				goods.setPrice(Double.parseDouble(doc.get("price")));
//				goods.setRemark(doc.get("remark"));
				goodsList.add(DocumentUtil.documentToGoods(doc));
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		} 
		return goodsList;
	}

效果显示:

商品编号:13,商品名称:IBM Computer12 ,商品价格:3333.9,商品的详细信息:null
商品编号:12,商品名称:IBM Computer12 ,商品价格:2333.9,商品的详细信息:null
商品编号:11,商品名称:IBM Computer12 ,商品价格:2333.9,商品的详细信息:null
商品编号:11,商品名称:IBM是全球知名的电脑厂商,现在已经专门做服务的,已经把生产版权转给联想了,商品价格:2333.9,商品的详细信息:null
接下来实现关键字查询高亮的效果的代码:

首先我们写一个高亮的工具类HighlighterUtil:

package com.shop.demo2;

import java.io.IOException;

import org.apache.lucene.search.Query;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.Scorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;

public class HighlighterUtil {

	private HighlighterUtil(){}
	private static Formatter formatter=null;
	static{
		 formatter=new SimpleHTMLFormatter("<font color='red'>", "</font>");
	}
	public static String setHighlighterText(Query query,String iniData,int length){
		String result=null;
		try {
			// query对象中有查询的关键字,字段匹配关键字的内容将会高亮
			Scorer scorer=new QueryScorer(query);
			// 实现高亮的工具类
			Highlighter highlighter=new Highlighter(formatter, scorer);
			// 设置高亮后的字符长度
			highlighter.setTextFragmenter(new SimpleFragmenter(length));
			//给指定字段进行高亮效果
			result= highlighter.getBestFragment(ConfigureLucene.getAna(), null,iniData);
			
			if(result==null){
				if(iniData.length()>length){
					result=iniData.substring(0, length);
				}else{
					result=iniData;
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}
}

修改上一篇DocumentUtil的代码如下:

package com.shop.demo2;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;

public class DocumentUtil {
	private DocumentUtil(){}
	/**
	 * 把goods对象转为document对象
	 */
	public static Document goodsToDocument(Goods goods){
		//把goods对象转为document
		Document doc=new Document();
		doc.add(new Field("id", goods.getId().toString(), Store.YES, Index.NOT_ANALYZED));
		doc.add(new Field("name", goods.getName(), Store.YES, Index.ANALYZED));
		doc.add(new Field("price", goods.getPrice().toString(), Store.YES, Index.NOT_ANALYZED));
		doc.add(new Field("remark", goods.getRemark(), Store.YES, Index.ANALYZED));
		return doc;
	}
	
	/**
	 * 把document对象转为goods对象
	 */
	public static Goods documentToGoods(Document doc){
		Goods goods=new Goods();
		goods.setId(Integer.parseInt(doc.get("id")));
		goods.setName(doc.get("name"));
		goods.setPrice(Double.parseDouble(doc.get("price")));
		goods.setRemark(doc.get("remark"));
		return goods;
	}
}

高亮的实现类:

/**
	 * 根据指定的条件查询,
	 * @param keyword 指定的关键字
	 * @return 封装了goods对象的list集合
	 */
	public List<Goods> queryGoods(String keyword){
		List<Goods> goodsList=new ArrayList<Goods>();
		//创建查询对象
		IndexSearcher searcher=null;
		try {
			searcher=LuceneUtil.getIndexSearcher();
			//  指定查询的关键字到索引库查询
			Query query=IKQueryParser.parseMultiField(new String[]{"name","remark"}, keyword);
			/**
			 * 根据给定的关键字查询,与索引库Term去匹配,5代表: 期望返回的结果数
			 *  第一次查询: indexSearcher.search 只能获取文档的索引号和匹配的数量
			 *  返回的结果是TopDoc类型
			 *  totalHits: 命中数, 数组的长度,后面用来做分页
			 *  ScoreDoc[]: 存储匹配的文档编号的数组
			 *  Score: 文档的积分,按照命中率自动算出来
			 *  Doc:当前文档的编号
			 */
			//增加排序的效果
			/*对象查询的结果进行排序: Lucene排序有两种: 命中率排序, 根据字段排序
			 *注意 这两种排序方式不互斥的,如果选择按字段排序命中率是不会被计算出来, 但是字段排序本身可以支持多字段
			 *被排序的字段,和被删除更新一样 字段必须创建索引
			 * true代表的是降序
			 */
			Sort sort=new Sort(new SortField("id",SortField.INT, true),new SortField("price", SortField.DOUBLE,true));
			TopDocs topDocs= searcher.search(query, null, 5, sort);
			// 此变量/每页显示的记录数就是总页数
			System.out.println("真正命中的结果数:" + topDocs.totalHits);
			// 返回的是符合条件的文档编号,并不是文档本事
			ScoreDoc scoreDocs[]= topDocs.scoreDocs;
			for(int i=0;i<scoreDocs.length;i++){
				ScoreDoc scoreDoc= scoreDocs[i];
				System.out.println("真正的命中率:"+scoreDoc.score);
				System.out.println("存储的是文档编号:"+scoreDoc.doc);
				Document doc= searcher.doc(scoreDoc.doc);
				System.out.println(doc.get("id"));
				System.out.println(doc.get("name"));
				System.out.println(doc.get("price"));
				System.out.println(doc.get("remark"));
				System.out.println("---------");
//				Goods goods=new Goods();
//				goods.setId(Integer.parseInt(doc.get("id")));
//				goods.setName(doc.get("name"));
//				goods.setPrice(Double.parseDouble(doc.get("price")));
//				goods.setRemark(doc.get("remark"));
				doc.getField("name").setValue(HighlighterUtil.setHighlighterText(query, doc.get("name"), 10));
				doc.getField("remark").setValue(HighlighterUtil.setHighlighterText(query, doc.get("remark"), 15));
				goodsList.add(DocumentUtil.documentToGoods(doc));
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		} 
		return goodsList;
	}
	

测试类:

	@Test
	public void testquery() {
		List<Goods> list= hellowod.queryGoods("ibm");
		for(Goods good:list){
			System.out.println("商品编号:"+good.getId()+",商品名称:"+good.getName()+
					",商品价格:"+good.getPrice()+",商品的详细信息:"+good.getRemark()
					);
		}
	}

查询的结果:

商品编号:12,商品名称:<font color='red'>IBM</font>,商品价格:4333.9,商品的详细信息:<font color='red'>IBM</font> Computer
商品编号:11,商品名称:<font color='red'>IBM</font>,商品价格:3333.9,商品的详细信息:<font color='red'>IBM</font> Computer
商品编号:11,商品名称:<font color='red'>IBM</font>是全球知名的,商品价格:2333.9,商品的详细信息:<font color='red'>IBM</font>有质量保证,耐用

我们可以发现高亮的html代码包裹着关键字。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值