SpringMvc整合Lucene.入门实例

时间:2017-11-12 点击:503

Lucene是一个开放源代码的全文检索引擎工具包。最近学了一下Lucene并整合进博客,简单我的理解和使用姿势。


前言:

之所以使用Lucene,因为它比传统使用Like方式查数据库快。

Lucene可以把它看作是搜索引擎,可以实现类型百度这种。


使用Lucene(分为5步,这里用Lucene 7.1.0 作例子)

Pom.xml引入

<dependency>
   <groupId>org.apache.lucene</groupId>
   <artifactId>lucene-core</artifactId>
   <version>7.1.0</version>
</dependency>

<dependency>
   <groupId>org.apache.lucene</groupId>
   <artifactId>lucene-highlighter</artifactId>
   <version>7.1.0</version>
</dependency>
<dependency>
   <groupId>org.apache.lucene</groupId>
   <artifactId>lucene-analyzers-common</artifactId>
   <version>7.1.0</version>
</dependency>
<dependency>
   <groupId>org.apache.lucene</groupId>
   <artifactId>lucene-queryparser</artifactId>
   <version>7.1.0</version>
</dependency>
<!-- 结果高亮 -->
<dependency>
   <groupId>org.apache.lucene</groupId>
   <artifactId>lucene-memory</artifactId>
   <version>7.1.0</version>
</dependency>

配置好依赖的Bean

@Bean //建立索引路径
public Directory directory() throws IOException{   
    String derictoryName = "F:\\article";     
    return FSDirectory.open( Paths.get(derictoryName));
}
@Bean
public IndexWriter indexWriter(Directory directory,Analyzer analyzer)throws IOException{
    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    config.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
    IndexWriter writer = new IndexWriter(directory,config);
    writer.commit();  //这里必须提交一次,主要是建立空索引。不然的话整合在web项目会出现索引建立失败的问题,
    return writer;
}
//多例的
//我们这里采用的是单写多读
@Bean
@Scope("prototype")
public IndexReader indexReader(Directory directory)throws IOException{
    IndexReader reader = DirectoryReader.open(directory);
    return reader;
}
//分词器
@Bean
public Analyzer StandardAnalyzer(){
    return new StandardAnalyzer();   
}

1.为内容建立索引

//建立索引
@Scheduled(cron = "0 0 0/2 1/1 * ? ") //每两个小时建立一次索引 //同步防止在启动的时候建立索引因为文件锁的问题
public synchronized void createIndex () {
    try {
        indexWriter.deleteAll(); //删除原来的文章索引
        List<Article> articles = articleManagerService.selectAll();
        //拿到article
        for(Article article : articles){
            Document document = new Document();
            document.add(new Field(articleEnum.articleId.name,article.getId().toString(), TextField.TYPE_STORED));
            document.add(new Field(articleEnum.articleTitle.name,article.getArticletitle(),TextField.TYPE_STORED));
            document.add(new Field(articleEnum.articleJson.name,JSON.toJSONString(article),TextField.TYPE_STORED));
            indexWriter.addDocument(document);
        }
        logger.info("新建立索引个数:"  + articles.size());
        indexWriter.commit();
    }catch (IOException e){
        throw new RuntimeException(e);
    }
}

2.读取索引

3.创建索引的Query

4.查询

5.对结果进行分页、高亮

/**
 * 分页方式 有两种,一直是根据结果分页,一直是使用IndexSearcher.searchAfter(Query query, pageSize);
 * @param search
 * @param currentPage 当前页面
 * @param pageSize 长度
 * @return
 */
public Map<String,Object> searchArticleTitleAfter(String search, int currentPage, int pageSize){
    IndexReader indexReader = applicationContext.getBean(IndexReader.class);
    List<Article> list = new ArrayList<>();
    Map<String,Object> map = new HashMap<>(2);
    try {
        IndexSearcher searcher = new IndexSearcher(indexReader);
        //4、创建索引的Query
        //第二个参数代表着要搜索的域
        //指定搜索字段和分析器
        QueryParser parser=new QueryParser(articleEnum.articleTitle.name, analyzer);
        //用户输入内容
        Query query=parser.parse(search);
        //获取上一页的最后一个元素
        ScoreDoc lastSd = getLastScoreDoc(currentPage, pageSize, query, searcher);
        //通过最后一个元素去搜索下一页的元素
        TopDocs tds = searcher.searchAfter(lastSd,query, pageSize);

        //=====结果高亮的  我也是复制的- -
        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);
        //====

        for(ScoreDoc sd:tds.scoreDocs) {
            Document doc = searcher.doc(sd.doc);
            String articleTitle = doc.get(articleEnum.articleTitle.name);
            Article article = JSON.parseObject(doc.get(articleEnum.articleJson.name),Article.class);
             if(articleTitle!=null){
                TokenStream tokenStream=analyzer.tokenStream(articleEnum.articleTitle.name, new StringReader(articleTitle));
                article.setArticletitle(highlighter.getBestFragment(tokenStream, articleTitle)); //结果高亮
            }
            list.add(article);
        }
        map.put("total",tds.totalHits); //总页码
        map.put("list",list);      
    }catch (Exception e){
        e.printStackTrace();
        logger.info("error:" + e.getMessage());
    }finally {
        try {
            indexReader.close();
        }catch (IOException e){
            e.printStackTrace();
        }

    }
    return map;
}

/**
 * 根据页码和分页大小获取上一次的最后一个scoredocs
 * @param pageIndex
 * @param pageSize
 * @param query
 * @param searcher
 * @return
 * @throws IOException
 */
private ScoreDoc getLastScoreDoc(int pageIndex,int pageSize,Query query,IndexSearcher searcher) throws IOException {
    if(pageIndex==1)return null;//如果是第一页就返回空
    int num = pageSize*(pageIndex-1);//获取上一页的最后数量
    TopDocs tds = searcher.search(query, num);
    return tds.scoreDocs[num-1];
}

如果对Lucene想深入了解可参阅官方文档http://lucene.apache.org/core/7_1_0/index.html


标签:spring 分类:知识共享

上一篇: SpringMvc使用Redis缓存

下一篇: 2017-11-10 博客更新