【Lucene】Apache Lucene全文检索引擎架构之中文分词和高亮显示

前面总结的都是使用Lucene的标准分词器,这是针对英文的,但是中文的话就不顶用了,因为中文的语汇与英文是不同的,所以一般我们开发的时候,有中文的话肯定要使用中文分词了,这一篇博文主要介绍一下如何使用smartcn中文分词器以及对结果的高亮显示。

1. 中文分词

使用中文分词的话,首先到添加中文分词的jar包。

 
  1. <!-- lucene中文分词器 -->

  2. <dependency>

  3. <groupId>org.apache.lucene</groupId>

  4. <artifactId>lucene-analyzers-smartcn</artifactId>

  5. <version>5.3.1</version>

  6. </dependency>

然后弄一些数据,使用中文分词器来生成一下索引,以便于后面搜索用到。

 
  1. public class Indexer {

  2.  
  3. private Directory dir; //存放索引的位置

  4.  
  5. //准备一下用来测试的数据

  6. private Integer ids[] = {1, 2, 3}; //用来标识文档

  7. private String citys[] = {"上海", "南京", "青岛"};

  8. private String descs[] = {

  9. "上海是个繁华的城市。",

  10. "南京是一个有文化的城市。",

  11. "青岛是一个美丽的城市。"

  12. };

  13.  
  14. //生成索引

  15. @Test

  16. public void index(String indexDir) throws Exception {

  17. dir = FSDirectory.open(Paths.get(indexDir));

  18. IndexWriter writer = getWriter();

  19. for(int i = 0; i < ids.length; i++) {

  20. Document doc = new Document();

  21. doc.add(new IntField("id", ids[i], Field.Store.YES));

  22. doc.add(new StringField("city", citys[i], Field.Store.YES));

  23. doc.add(new TextField("desc", descs[i], Field.Store.YES));

  24. writer.addDocument(doc); //添加文档

  25. }

  26. writer.close(); //close了才真正写到文档中

  27. }

  28.  
  29. //获取IndexWriter实例

  30. private IndexWriter getWriter() throws Exception {

  31. SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer();//使用中文分词器

  32. IndexWriterConfig config = new IndexWriterConfig(analyzer); //将标准分词器配到写索引的配置中

  33. IndexWriter writer = new IndexWriter(dir, config); //实例化写索引对象

  34. return writer;

  35. }

  36.  
  37. public static void main(String[] args) throws Exception {

  38. new Indexer().index("D:\\lucene2");

  39. }

  40. }

建立好了索引,接下来就是查询了。

 
  1. public class Searcher {

  2.  
  3. public static void search(String indexDir, String q) throws Exception {

  4.  
  5. Directory dir = FSDirectory.open(Paths.get(indexDir)); //获取要查询的路径,也就是索引所在的位置

  6. IndexReader reader = DirectoryReader.open(dir);

  7. IndexSearcher searcher = new IndexSearcher(reader);

  8. SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer(); //使用中文分词器

  9. QueryParser parser = new QueryParser("desc", analyzer); //查询解析器

  10. Query query = parser.parse(q); //通过解析要查询的String,获取查询对象

  11.  
  12. long startTime = System.currentTimeMillis(); //记录索引开始时间

  13. TopDocs docs = searcher.search(query, 10);//开始查询,查询前10条数据,将记录保存在docs中

  14. long endTime = System.currentTimeMillis(); //记录索引结束时间

  15. System.out.println("匹配" + q + "共耗时" + (endTime-startTime) + "毫秒");

  16. System.out.println("查询到" + docs.totalHits + "条记录");

  17.  
  18. for(ScoreDoc scoreDoc : docs.scoreDocs) { //取出每条查询结果

  19. Document doc = searcher.doc(scoreDoc.doc); //scoreDoc.doc相当于docID,根据这个docID来获取文档

  20. System.out.println(doc.get("city"));

  21. System.out.println(doc.get("desc"));

  22. String desc = doc.get("desc");

  23. }

  24. reader.close();

  25. }

  26.  
  27. public static void main(String[] args) {

  28. String indexDir = "D:\\lucene2";

  29. String q = "上海繁华"; //查询这个字符

  30. try {

  31. search(indexDir, q);

  32. } catch (Exception e) {

  33. e.printStackTrace();

  34. }

  35. }

  36. }

看一下查询结果:

匹配上海繁华共耗时15毫秒
查询到1条记录
上海
上海是个繁华的城市。

2. 高亮显示

  一般查询出来的效果都要高亮显示的,例如百度里查出来的结果都会标红啥的,Lucene中也可以这么干。首先要引入高亮显示的jar包。

 
  1. <!-- lucene高亮显示 -->

  2. <dependency>

  3. <groupId>org.apache.lucene</groupId>

  4. <artifactId>lucene-highlighter</artifactId>

  5. <version>5.3.1</version>

  6. </dependency>

然后要在上面搜索的java代码中添加以下高亮显示的部分。

 
  1. public class Searcher {

  2.  
  3. public static void search(String indexDir, String q) throws Exception {

  4.  
  5. //省略……

  6. System.out.println("匹配" + q + "共耗时" + (endTime-startTime) + "毫秒");

  7. System.out.println("查询到" + docs.totalHits + "条记录");

  8.  
  9. SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<b><font color=red>","</font></b>"); //如果不指定参数的话,默认是加粗,即<b><b/>

  10. QueryScorer scorer = new QueryScorer(query);//计算得分,会初始化一个查询结果最高的得分

  11. Fragmenter fragmenter = new SimpleSpanFragmenter(scorer); //根据这个得分计算出一个片段

  12. Highlighter highlighter = new Highlighter(simpleHTMLFormatter, scorer);

  13. highlighter.setTextFragmenter(fragmenter); //设置一下要显示的片段

  14.  
  15.  
  16. for(ScoreDoc scoreDoc : docs.scoreDocs) { //取出每条查询结果

  17. Document doc = searcher.doc(scoreDoc.doc); //scoreDoc.doc相当于docID,根据这个docID来获取文档

  18. System.out.println(doc.get("city"));

  19. System.out.println(doc.get("desc"));

  20. String desc = doc.get("desc");

  21.  
  22. //显示高亮

  23. if(desc != null) {

  24. TokenStream tokenStream = analyzer.tokenStream("desc", new StringReader(desc));

  25. String summary = highlighter.getBestFragment(tokenStream, desc);

  26. System.out.println(summary);

  27. }

  28. }

  29. reader.close();

  30. }

  31.  
  32. public static void main(String[] args) {

  33. String indexDir = "D:\\lucene2";

  34. String q = "上海繁华"; //查询这个字符

  35. try {

  36. search(indexDir, q);

  37. } catch (Exception e) {

  38. e.printStackTrace();

  39. }

  40. }

  41. }

看一下查询结果:

匹配上海繁华共耗时15毫秒
查询到1条记录
上海
上海是个繁华的城市。
上海是个繁华的城市。

  这里简单解释一下上面程序中的那个得分,也就是说,在一段文本中,可能搜出来有关键字的地方不止一处,所以Lucene会自动计算每一处的得分,也就是最接近用户搜索,然后显示该位置附近的一些片段。上面的例子中描述部分太少了,就一句话,体现不出来,我把对南京的描述加长一点,如下:

南京是一个文化的城市南京,简称宁,是江苏省会,地处中国东部地区,长江下游,濒江近海。全市下辖11个区,总面积6597平方公里,2013年建成区面积752.83平方公里,常住人口818.78万,其中城镇人口659.1万人。[1-4] “江南佳丽地,金陵帝王州”,南京拥有着6000多年文明史、近2600年建城史和近500年的建都史,是中国四大古都之一,有“六朝古都”、“十朝都会”之称,是中华文明的重要发祥地,历史上曾数次庇佑华夏之正朔,长期是中国南方的政治、经济、文化中心,拥有厚重的文化底蕴和丰富的历史遗存。[5-7] 南京是国家重要的科教中心,自古以来就是一座崇文重教的城市,有“天下文枢”、“东南第一学”的美誉。截至2013年,南京有高等院校75所,其中211高校8所,仅次于北京上海;国家重点实验室25所、国家重点学科169个、两院院士83人,均居中国第三。[8-10] 。

这下够长了,如果我搜索“南京文化”,看一下结果:

南京是一个文化的城市南京,简称宁,是江苏省会,地处中国东部地区,长江下游,濒江近海。全市下辖11个区,总面积6597平方公里,2013年建成区面积752.83平方公里,常住人口818.78万,其中

如果我搜索“南京文明”,再看一下结果:

城镇人口659.1万人。[1-4] “江南佳丽地,金陵帝王州”,南京拥有着6000多年文明史、近2600年建城史和近500年的建都史,是中国四大古都之一,有“六朝古都”、“十朝都会”之称,是中华文明

  这就是Lucene中所谓的得分,其实也就是最匹配的片段。可以看出,Lucene的中文检索也是很强大的,当然咯,如果是专业搞搜索的,那还得好好研究研究,一般开发中站内搜索已经够使用了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值