网上搜索了一下关于 Lucene 教程的文章非常多,但是关于 SpringBoot 整合 Lucene 的非常少,可能一些涉及到搜索的项目都比较老,使用 Lucene 的比较少,使用 Solr 和 Elasticsearch 的可能比较多。但是文章少,并不代表没有人用,所以本文我教大家如何把 Lucene 和 SpringBoot 整合到一起。
至于,你们还不懂 Lucene 是什么的,建议看我前面的文章。有详细的教程。
SpringBoot 不论整合什么框架,都是先从 pom.xml 文件开始。同样的整合 Lucene 也需要引入 Lucene 相关的 jar 文件。
<!--对分词索引查询解析--> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>7.1.0</version> </dependency> <!--高亮 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>7.1.0</version> </dependency> <!--smartcn 中文分词器 SmartChineseAnalyzer smartcn分词器 需要lucene依赖 且和lucene版本同步--> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-smartcn</artifactId> <version>7.1.0</version> </dependency> <!--ik-analyzer 中文分词器--> <dependency> <groupId>cn.bestwu</groupId> <artifactId>ik-analyzers</artifactId> <version>5.1.0</version> </dependency> <!--MMSeg4j 分词器--> <dependency> <groupId>com.chenlb.mmseg4j</groupId> <artifactId>mmseg4j-solr</artifactId> <version>2.4.0</version> <exclusions> <exclusion> <groupId>org.apache.solr</groupId> <artifactId>solr-core</artifactId> </exclusion> </exclusions> </dependency>
Lucene 目前还没有提供 SpringBoot 方面的自动配置的 starter,所以引入的 jar 文件可能较多。
实例化 IndexReader 需要加载索引文件,所以实例化它是非常耗资源的。
IndexReader 是线程安全的,通常一个索引目录,我们只实例化一个 IndexReader 就够了。
@Configuration public class LuceneConfig { // 创建一个 Analyzer 实例 @Bean public Analyzer analyzer() { return new IKAnalyzer(false); } // 索引位置 @Bean public Directory directory() { return FSDirectory.open(Paths.get("indexDir/")); } // 创建 IndexReader @Bean public IndexReader indexReader(Directory directory) { return DirectoryReader.open(directory); } // 创建 SearcherManager @Bean public SearcherManager searcherManager(Directory directory) throws IOException { return new SearcherManager(directory, null); } // 创建 IndexSearcher @Bean public IndexSearcher indexSearcher(IndexReader indexReader){ return new IndexSearcher(indexReader); } }
同样的 IndexSearcher 实例一个也就够了。如果不够,可以使用 searcherManager 实例。
searcherManager 实例的用法,一般如下:
@Service public class XttblogService(){ @Autowired private SearcherManager searcherManager; public Set<Map<String, Object>> search(String keyword, int page) { IndexSearcher searcher = null; Set<Map<String, Object>> data = newLinkedHashSetWithExpectedSize(DEFAULT_PAGE_SIZE); try { searcher = searcherManager.acquire(); BooleanQuery query = ...... ...... } catch (IOException e) { logger.error("acquire beer searcher failed"); logger.error(e.getLocalizedMessage(), e); } catch (ParseException e) { logger.error("failed to build query for /"{}/"", keyword); } finally { if (searcher != null) { try { searcherManager.release(searcher); } catch (IOException e) { logger.error("release beer searcher failed"); logger.error(e.getLocalizedMessage(), e); } } } return data; } }
封装好了各个 bean 只有,查询搜索,创建索引,更新,删除索引之类的就非常简单了。
下面看几个贱的查询例子。
** * 执行查询,并打印查询到的记录数 * @param query * @throws IOException */ public void executeQuery(Query query) throws IOException { TopDocs topDocs = indexSearcher.search(query, 100); //打印查询到的记录数 System.out.println("总共查询到" + topDocs.totalHits + "个文档"); for (ScoreDoc scoreDoc : topDocs.scoreDocs) { //取得对应的文档对象 Document document = indexSearcher.doc(scoreDoc.doc); System.out.println("id:" + document.get("id")); System.out.println("title:" + document.get("title")); System.out.println("content:" + document.get("content")); } } /** * 分词打印 * @param analyzer * @param text * @throws IOException */ public void printAnalyzerDoc(Analyzer analyzer, String text) throws IOException { TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text)); CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class); try { tokenStream.reset(); while (tokenStream.incrementToken()) { System.out.println(charTermAttribute.toString()); } tokenStream.end(); } finally { tokenStream.close(); analyzer.close(); } } public void indexWriterBook(Book book) throws IOException { long start = System.currentTimeMillis(); // indexWriterConfig 也可以通过引入的方式来实现 //创建索引写入配置 IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); //创建索引写入对象 IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig); //创建Document对象,存储索引 Document doc = new Document(); int id = 1; //将字段加入到doc中 doc.add(new IntPoint("id", book.getId())); doc.add(new StringField("title", book.getTitle(), Field.Store.YES)); doc.add(new TextField("content", book.getContent(), Field.Store.YES)); doc.add(new StoredField("id", book.getId())); //将doc对象保存到索引库中 indexWriter.addDocument(doc); indexWriter.commit(); //关闭流 indexWriter.close(); long end = System.currentTimeMillis(); System.out.println("索引花费了" + (end - start) + " 毫秒"); } public void termQueryTitle(String title) throws IOException { String searchField = "title"; //这是一个条件查询的api,用于添加条件 TermQuery query = new TermQuery(new Term(searchField, title)); //执行查询,并打印查询到的记录数 executeQuery(query); } @Test public void BooleanQueryTest(String t, String t2) throws IOException { String searchField1 = "title"; String searchField2 = "content"; Query query1 = new TermQuery(new Term(searchField1, t)); Query query2 = new TermQuery(new Term(searchField2, t2)); BooleanQuery.Builder builder = new BooleanQuery.Builder(); // BooleanClause用于表示布尔查询子句关系的类, // 包 括: // BooleanClause.Occur.MUST, // BooleanClause.Occur.MUST_NOT, // BooleanClause.Occur.SHOULD。 // 必须包含,不能包含,可以包含三种.有以下6种组合: // // 1.MUST和MUST:取得连个查询子句的交集。 // 2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。 // 3.SHOULD与MUST_NOT:连用时,功能同MUST和MUST_NOT。 // 4.SHOULD与MUST连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。 // 5.SHOULD与SHOULD:表示“或”关系,最终检索结果为所有检索子句的并集。 // 6.MUST_NOT和MUST_NOT:无意义,检索无结果。 builder.add(query1, BooleanClause.Occur.SHOULD); builder.add(query2, BooleanClause.Occur.SHOULD); BooleanQuery query = builder.build(); //执行查询,并打印查询到的记录数 executeQuery(query); }
看吧,整合 SpringBoot 也是非常的简单。并没有大家想象的那么难。
: » Lucene 实战教程第十六章 SpringBoot 整合 Lucene
原创文章,作者:1402239773,如若转载,请注明出处:https://blog.ytso.com/251974.html