创建索引:
在这里采用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,但是这种方法适用于数据量较少的查询,要不然每次分页都查全部,太浪费了
2、使用searchAfter(...)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++) { //对搜索结果数据进行处理的代码 }
//可以使用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;