springboot 集成lucene (可下载demo代码)

引言

在阅读此文前,最好了解下【lucene原理】,这样有助于你能更好的理解此文

lucene原理:https://blog.csdn.net/yb546822612/article/details/103063493

如果觉得那文章太长,看得两眼发花,也可以下载在demo先跑起来,过把隐,然后对照此文边看边理解 

demo 码云地址在最底部

一、 新建springboot项目

 1、项目结构如下:

     引用jar包

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.7</version>
        </dependency>
        <!--对分词索引查询解析-->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>8.3.0</version>
        </dependency>

        <!--高亮 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>8.3.0</version>
        </dependency>

        <!--smartcn 中文分词器 SmartChineseAnalyzer  smartcn分词器 需要lucene依赖 且和lucene版本同步-->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-smartcn</artifactId>
            <version>8.3.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>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>

此处用的最新的lucene版本8.3.0

  2、编写lucene配制文件

@Configuration
public class LuceneConfig {
    /**
     * lucene索引,存放位置
     */
    public static final String LUCENEINDEXPATH="lucene/indexDir/";

    /**
     * 创建一个 Analyzer 实例
     *
     * @return
     */
    @Bean
    public Analyzer analyzer() {
        return new SmartChineseAnalyzer();
    }

    /**
     * 索引位置
     *
     * @return
     * @throws IOException
     */
    @Bean
    public Directory directory() throws IOException {

        Path path = Paths.get(LUCENEINDEXPATH);
        File file = path.toFile();
        if(!file.exists()) {
            //如果文件夹不存在,则创建
            file.mkdirs();
        }
        return FSDirectory.open(path);
    }

    /**
     * 创建indexWriter
     *
     * @param directory
     * @param analyzer
     * @return
     * @throws IOException
     */
    @Bean
    public IndexWriter indexWriter(Directory directory, Analyzer analyzer) throws IOException {
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        /**
         * 清空索引,下面两个方法,打开时,启动应用时,会自动清空所有索引,
         * 如果项目的数据比较多,建索引时间长或索引不能清空,这个一定要装着
         * 所以大家要根据实际情况慎用此开关
          */
        indexWriter.deleteAll();
        indexWriter.commit();
        return indexWriter;
    }

    /**
     * SearcherManager管理
     *
     * @param directory
     * @return
     * @throws IOException
     */
    @Bean
    public SearcherManager searcherManager(Directory directory, IndexWriter indexWriter) throws IOException {
        SearcherManager searcherManager = new SearcherManager(indexWriter, false, false, new SearcherFactory());
        ControlledRealTimeReopenThread cRTReopenThead = new ControlledRealTimeReopenThread(indexWriter, searcherManager,
                5.0, 0.025);
        cRTReopenThead.setDaemon(true);
        //线程名称
        cRTReopenThead.setName("更新IndexReader线程");
        // 开启线程
        cRTReopenThead.start();
        return searcherManager;
    }

}

   注意很上述:

    @Bean
    public IndexWriter indexWriter(Directory directory, Analyzer analyzer) throws IOException {
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        /**
         * 清空索引,下面两个方法,打开时,启动应用时,会自动清空所有索引,
         * 如果项目的数据比较多,建索引时间长或索引不能清空,这个一定要装着
         * 所以大家要根据实际情况慎用此开关
          */
        indexWriter.deleteAll();
        indexWriter.commit();
        return indexWriter;
    }

3、编写service

  

public interface LuceneService {
    /**
     * 增加索引
     * @param list
     * @throws IOException
     */
    public void createProductIndex(List<Product> list) throws IOException;

    /**
     * 查询
     * @param pageQuery
     * @return
     * @throws Exception
     * @throws ParseException
     */
    public PageQuery searchProduct(PageQuery pageQuery) throws Exception, ParseException;

    /**
     *删除
     * @param id
     * @throws IOException
     */
    public void deleteProductIndexById(String id) throws IOException;
}

service实现

@Service
public class LuceneServiceImpl implements LuceneService {
    @Autowired
    private IndexWriter indexWriter;

    @Override
    public void createProductIndex(List<Product> productList) throws IOException {
        List<Document> docs = new ArrayList<Document>();
        for (Product p : productList) {
            Document doc = new Document();
            doc.add(new StringField("id", p.getId() + "", Field.Store.YES));
            doc.add(new TextField("skuName", p.getSkuName(), Field.Store.YES));
            doc.add(new TextField("cid1Name", p.getCid1Name(), Field.Store.YES));
            doc.add(new TextField("clickurl", p.getClickurl(), Field.Store.YES));

            Double price = p.getPrice();
            doc.add(new DoublePoint("price", price));
            doc.add(new StoredField("price", p.getPrice()));
            doc.add(new DoublePoint("discount", p.getDiscount()));
            doc.add(new StoredField("discount", p.getDiscount()));
            doc.add(new DoublePoint("discountRate", p.getDiscountRate()));
            doc.add(new StoredField("discountRate", p.getDiscountRate()));
            doc.add(new DoublePoint("cid1", p.getCid1()));
            // 正排索引用于排序、聚合
            doc.add(new DoubleDocValuesField("price", price));
            // 存储到索引库
            doc.add(new StoredField("cid1", p.getCid1()));
            docs.add(doc);
        }
        indexWriter.addDocuments(docs);
       // indexWriter.updateDocument(docs);
        indexWriter.commit();
      //  indexWriter.close();
    }
    @Autowired
    private Analyzer analyzer;

    @Autowired
    private SearcherManager searcherManager;
    @Override
    public PageQuery searchProduct(PageQuery pageQuery) throws Exception, ParseException {
        searcherManager.maybeRefresh();
        IndexSearcher indexSearcher = searcherManager.acquire();
//        Analyzer analyzer = new IKAnalyzer(true);
//        DirectoryReader directoryReader = DirectoryReader.open(FSDirectory.open(Paths.get(LuceneConfig.LUCENEINDEXPATH)));
//        //索引查询器
//        IndexSearcher indexSearcher = new IndexSearcher(directoryReader);

        Product params = pageQuery.getParams();
        Map<String, String> queryParam = pageQuery.getQueryParam();
        BooleanQuery.Builder builder = new BooleanQuery.Builder();
        Sort sort = new Sort();
        // 排序规则
        com.test.lucene.model.Sort sort1 = pageQuery.getSort();
        if (sort1 != null && sort1.getOrder() != null) {
            if ("ASC".equals(sort1.getOrder().toUpperCase())) {
                sort.setSort(new SortField(sort1.getField(), SortField.Type.FLOAT, false));
            } else if ("DESC".equals((sort1.getOrder()).toUpperCase())) {
                sort.setSort(new SortField(sort1.getField(), SortField.Type.FLOAT, true));
            }
        }

        // 模糊匹配,匹配词
        String keyStr = params.getSkuName();
        if (params != null && params.getSkuName() != null) {
            // 输入空格,不进行模糊查询
            if (!"".equals(keyStr.replaceAll(" ", ""))) {
                builder.add(new QueryParser("skuName", analyzer).parse(keyStr), BooleanClause.Occur.MUST);
            }
        }

        // 精确查询
        if (params != null && params.getCid1() != null) {
            builder.add(new TermQuery(new Term("cid1", String.valueOf(params.getCid1()))), BooleanClause.Occur.MUST);
        }
//        if (params != null && params.getGetEndTimeForL() != null) {
//            builder.add(new TermQuery(new Term("cid1", String.valueOf(params.getCid1()))), BooleanClause.Occur.MUST);
//        }
//        if (queryParam.get("lowerPrice") != null && queryParam.get("upperPrice") != null) {
//            // 价格范围查询
//            builder.add(FloatPoint.newRangeQuery("price", Float.parseFloat(queryParam.get("lowerPrice")),
//                    Float.parseFloat(queryParam.get("upperPrice"))), BooleanClause.Occur.MUST);
//        }
        PageInfo pageInfo = pageQuery.getPageInfo();
        TopDocs topDocs = indexSearcher.search(builder.build(), pageInfo.getPageNum() * pageInfo.getPageSize(), sort);

        pageInfo.setTotal(topDocs.totalHits.value);
        ScoreDoc[] hits = topDocs.scoreDocs;
        List<Product> pList = new ArrayList<Product>();
        for (int i = 0; i < hits.length; i++) {
            Document doc = indexSearcher.doc(hits[i].doc);
            Product Product = new Product();
            Product.setId(Integer.parseInt(doc.get("id")));
            Product.setSkuName(doc.get("skuName"));
            Product.setCid1(Long.valueOf(doc.get("cid1")));
            Product.setCid1Name(doc.get("cid1Name"));
            Product.setCid1Name(doc.get("cid1Name"));
            Product.setUrl(doc.get("url"));
            Product.setMaterialUrl(doc.get("materialUrl"));
            Product.setClickurl(doc.get("clickurl"));
            Product.setPrice(Double.valueOf(doc.get("price")));
            Product.setCommissionShare(doc.get("commissionShare") != null ?Double.valueOf(doc.get("commissionShare")):null);
            Product.setDiscount(doc.get("discount") != null ? Double.valueOf(doc.get("discount")):null);
            Product.setDiscountRate(doc.get("discountRate") != null ? Double.valueOf(doc.get("discountRate")):null);
            Product.setPingouPrice(doc.get("pingouPrice") != null ? Double.valueOf(doc.get("pingouPrice")):null);
            Product.setLink(doc.get("link"));
            pList.add(Product);
        }
        pageQuery.setPageInfo(pageInfo);
        pageQuery.setResults(pList);
        return pageQuery;
    }

    @Override
    public void deleteProductIndexById(String id) throws IOException {
        indexWriter.deleteDocuments(new Term("id",id));
        indexWriter.commit();
    }
}

 三、运行测试

    1、生成索引

   


    @RequestMapping("creat")
    @ResponseBody
    public String create() throws Exception{
        List<Product> list = new ArrayList<Product>();
        Product product = new Product();
        product.setId(1);
        product.setBindType(10);
        product.setBrandCode("001");
        product.setBrandName("联想");
        product.setCid1(10000L);
        product.setCid1Name("电脑");
        product.setClickurl("www.baidu.com");
        product.setComments(100L);
        product.setCommission(10.0);
        product.setCommissionShare(20.0);
        product.setCreateTime(new Date());
        product.setDesc("desc");
        product.setDiscount(10.0);
        product.setDiscountRate(30.0);
        product.setSkuId(635373L);
        product.setPrice(999.01);
        product.setSkuName("硕扬 i7升十二线程/RX560 4G独显/16G内存办公游戏台式组装电脑主机DIY组装机");
        list.add(product);
        luceneService.createProductIndex(list);
        return "hello world" ;
    }

访问 localhost:8080/create后

发现 F:\git-resp\test\test-demo\lucene\indexDir  目录生成以下文件,其实这就是索引文件, 

这个目录地址就是LuceneConfig文件中配制的LUCENEINDEXPATH地址
public static final String LUCENEINDEXPATH="lucene/indexDir/";

与你项目的根目录地址相同

2、查询索引

controler代码

    @RequestMapping("find")
    @ResponseBody
    public PageInfo<Product> find(@RequestBody Product pro) throws Exception{
        PageInfo pageInfo = new PageInfo();
        pageInfo.setPageNum(pro.getPage());
        pageInfo.setPageSize(pro.getLimit());
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageInfo(pageInfo);
        pageQuery.setParams(pro);
        PageQuery result  = luceneService.searchProduct(pageQuery);

        PageInfo<Product> pageResult = new PageInfo<Product>();
        pageResult.setPageSize(pro.getLimit());
        pageResult.setPageNum(pro.getPage());
        pageResult.setTotal(result.getPageInfo().getTotal());
        pageResult.setList(result.getResults());
        return pageResult;
    }

  post请求

返回结果

{

    "total": 1,

    "list": [

        {

            "id": 1,

            "cid1": 10000,

            "cid1Name": "电脑",

            "commission": null,

            "commissionShare": null,

            "bindType": null,

            "brandCode": null,

            "brandName": null,

            "comments": null,

            "discount": 10.0,

            "eliteId": null,

            "eliteName": null,

            "getEndTime": null,

            "getStartTime": null,

            "link": null,

            "materialUrl": null,

            "owner": null,

            "pingouPrice": null,

            "pingouTmCount": null,

            "pingouUrl": null,

            "price": 999.01,

            "quota": null,

            "shopId": null,

            "shopName": null,

            "skuId": null,

            "skuName": "硕扬 i7升十二线程/RX560 4G独显/16G内存办公游戏台式组装电脑主机DIY组装机",

            "spuid": null,

            "url": null,

            "useEndTime": null,

            "useStartTime": null,

            "clickurl": "www.baidu.com",

            "discountRate": 30.0,

            "updateTime": null,

            "createTime": null,

            "page": null,

            "limit": null,

            "desc": null

        }

    ],

    "pageNum": 1,

    "pageSize": 10,

    "size": 0,

    "startRow": 0,

    "endRow": 0,

    "pages": 0,

    "prePage": 0,

    "nextPage": 0,

    "isFirstPage": false,

    "isLastPage": false,

    "hasPreviousPage": false,

    "hasNextPage": false,

    "navigatePages": 0,

    "navigatepageNums": null,

    "navigateFirstPage": 0,

    "navigateLastPage": 0

}

看到这里,说明我们springboot集成lucene成功了

demo 码云地址:https://gitee.com/xing_xin/springboot-lucene.git

发布了57 篇原创文章 · 获赞 22 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/yb546822612/article/details/103063641
今日推荐