Lucene学习一:入门级Demo,创建索引和查询高亮显示

本文介绍如何使用Lucene实现中文文本的检索功能,包括索引建立、查询操作及高亮显示,并探讨两种分页策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建索引:

在这里采用maven构建工具,利用包之间的依赖我们只需引入两个maven依赖

<dependency>
   <groupId>com.janeluo</groupId>
    <artifactId>ikanalyzer</artifactId>
   <version>2012_u6</version>
</dependency>
<dependency>
     <groupId>org.apache.lucene</groupId>
     <artifactId>lucene-highlighter</artifactId>
     <version>4.7.2</version>
</dependency>


这里采用国人开源中文分词器IK,然后我们写创建索引的方法:

public static void makeIndex(Long id, String str) throws IOException {
    Analyzer analyzer = new IKAnalyzer(); //创建中文分词解析器
    // RAMDirectory directory = new RAMDirectory(); // 内存存储
    Directory dir = FSDirectory.open(new File("d:/test/lucene")); //文件存储,执行程序后,我们的索引文件将会放到该目录下
    IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer); //创建索引配置,把我们的分析器注入进去
    IndexWriter indexWriter = new IndexWriter(dir, writerConfig); // 创建真正的索引构造类
    
    Document document1 = new Document(); // 定义一个文档类型
    document1.add(new TextField("id", id+"", Field.Store.YES)); // 将我们需要构建索引的字段放入域中
    document1.add(new TextField("name", str, Field.Store.YES));
    
    indexWriter.addDocument(document1); // 将我们创建的域加入到索引文件中
    
    indexWriter.close();
  }


查询


  public static void search(String queryStr, String pathFile) throws ParseException, IOException {
    Analyzer analyzer = new IKAnalyzer(); // 构造分析器
    IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(FSDirectory.open(new File("d:/test/lucene"))));  创建文件索引查询器
    QueryParser parser = new QueryParser(Version.LUCENE_47, "name", analyzer);  定义查询模型
    Query query = parser.parse(queryStr); // 构建查询的Query对象
    
    QueryScorer scorer = new QueryScorer(query);  
    Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);// 得到得分的片段,就是得到一段包含所查询的关键字的摘要
    SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter(
    "<b><font color='red'>", "</font></b>");// 对查询的数据格式化;无参构造器的默认是将关键字加粗
    Highlighter highlighter = new Highlighter(simpleHTMLFormatter, scorer);// 根据得分和格式化
    highlighter.setTextFragmenter(fragmenter);// 设置成高亮
    
    int maxCount = 20;  // 最多查询多少条
    TopDocs topDocs = searcher.search(query, maxCount); // 此处没有分页,查全部
    ScoreDoc[] pageDocs = topDocs.scoreDocs; // 可以通过数组下表对其分页
    System.out.println("pageDocs size: "+pageDocs.length); // 命中条目数
    for (ScoreDoc doc : pageDocs) { // 循环将命中条目输出
      Document d = searcher.doc(doc.doc); 
      try {
        String str = highlighter.getBestFragment(analyzer, "content", d.get(pathFile)) ;// 构建高亮
        System.out.println(str);
      } catch (InvalidTokenOffsetsException e) {
        e.printStackTrace();
      }  
      System.out.println("id: "+ d.get("id") +"内容:"+d.get(pathFile)); 
    }
  }

关于分页看了一篇文章思路有两种

1、是全部查出来,然后利用循环将指定开始位置和结束位置进行分页,类似于mysql的limit,但是这种方法适用于数据量较少的查询,要不然每次分页都查全部,太浪费了

ScoreDoc[] sd = XXX;
// 查询起始记录位置
int begin = pageSize * (currentPage - 1);
// 查询终止记录位置
int end = Math.min(begin + pageSize, sd.length);
for (int i = begin; i < end && i <totalHits; i++) {
//对搜索结果数据进行处理的代码
}
2、使用searchAfter(...)
//可以使用Map保存必要的搜索结果, 主要是保存当前查询的页数
Map<String, Object> resultMap = new HashMap<String, Object>();
ScoreDoc after = null; // 可以理解为下一次搜索从此条之后
Query query = XX
TopDocs td = search.searchAfter(after, query, size); // 此方法是关键,after为null将从头开始查询,不为空则从after之后开始查询size条
  
//获取命中数
resultMap.put("num", td.totalHits);
  
ScoreDoc[] sd = td.scoreDocs;
for (ScoreDoc scoreDoc : sd) {
//经典的搜索结果处理
}
//搜索结果ScoreDoc总量减1
after = sd[td.scoreDocs.length - 1]; 
//保存after用于下次搜索,即下一页开始 
resultMap.put("after", after);
  
return resultMap;




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值