lucene搜索引擎的初级使用

一些网站项目中常常有全文搜索需求。若从头开始写代码是很不明智的,因为:

  • findAll()再进行文本匹配效率极低

  • SELECT LIKE形式在数据量大的时候效率也很低。详见:lucene检索与关键字like性能对比

  • 以上检索方式要实现字符通配、组合逻辑检索均不方便

因此,使用lucene检索引擎可以十分方便的满足全文检索需求。

另外,网上虽然有类似hibernate search 或者 solr 这样的基于lucene的集成引擎,但是在一些小规模的应用场景,直接调用lucene反而更容易实现。特别是在本人对Spring的配置和声明不熟悉的情况下,直接部署
hibernate search 可能反而出现一些无法预料的错误。

引用包

使用MAVEN引入,包括以下组件:

  • lucence 核心

  • 中文分词器


 <!-- lucene core -->
 <dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-core</artifactId>
    <version>4.7.2</version>
 </dependency>
 <dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-queryparser</artifactId>
    <version>4.7.2</version>
 </dependency>
 <!-- lucene core -->

 <!-- 中文分词器 -->
 <dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-analyzers-smartcn</artifactId>
    <version>4.7.2</version>
 </dependency>
 <!-- 中文分词器 -->

 一般使用方式

lucene 可以从任何数据源中创建索引文件,然后从索引文件中进行搜索。因此,其使用步骤大致即可分为:创建索引和搜索。

建立索引和搜索时需要保持一致的公共声明


    //公共变量声明
    private String indexFile = "C://INDEX";
    Version version = Version.LUCENE_47;
    Analyzer analyzer = new SmartChineseAnalyzer(version);
    String fileds = new String[] {"introduction","itemName"};

创建索引


    @Override
    public void updateIndex() throws Exception {
        List<WebMerchantInfo> list;
        //存放索引的文件夹
        File indxeFile;
        //创建Directory对象
        Directory directory;
        //创建IndexWriterConfig
        IndexWriterConfig indexWriterConfig ;
        //创建IndexWriter
        IndexWriter indexWriter;


        try {
            indxeFile = new File(indexFile);
            directory =FSDirectory.open(indxeFile);
            indexWriterConfig = new IndexWriterConfig(version, analyzer);
            indexWriterConfig.setOpenMode(OpenMode.CREATE);
            indexWriter = new IndexWriter(directory, indexWriterConfig);
        } catch (Exception e) {
            WifiLogUtil.wifiLogError(String.format("%s %s", this.getClass().getName(),"updateIndex"), e);
            throw new SystemWifiException("初始化索引错误");
        }

        //从数据库中读取出所有的新闻记录以便进行索引的创建
        try {
            list = wmiDao.findAll();
            DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
            for (WebMerchantInfo o : list) {
                try{
                    //建立一个lucene文档
                    Document doc = new Document();
                    //得到信息
                    String itemName =o.getItemName();
                    String id = o.getMerchantInfoId() + "";
                    String introduction = o.getIntroduction();
                    String putTime = o.getPutTime();
                    if(itemName == null || introduction == null || putTime == null || id == null){
                        continue;
                    }
                    doc = addDoc(id, itemName, introduction, putTime);
                    indexWriter.addDocument(doc);
                } catch(Exception e){
                    e.printStackTrace();
                }

            }
            indexWriter.close();

        } catch (SQLException e) {
            WifiLogUtil.wifiLogError(String.format("%s %s", this.getClass().getName(),"updateIndex"), e);
            throw new SystemWifiException("构造索引错误");

        }

    }

    private Document addDoc(String id, String itemName, String introduction, String putTime) throws UnsupportedEncodingException{
        try {
            Document doc = new Document();
            FieldType ft = new FieldType();
            ft.setStored(true);         
            ft.setIndexed(true);         
            ft.setTokenized(false); 
            doc.add(new Field("id", id,ft));
            doc.add(new Field("itemName", itemName, TextField.TYPE_STORED));
            doc.add(new Field("introduction", introduction, TextField.TYPE_STORED));
            doc.add(new Field("putTime", putTime, ft));
            return doc;
        } catch (Exception e) {
            WifiLogUtil.wifiLogError(String.format("%s %s", this.getClass().getName(),"addDoc"), e);
            throw new SystemWifiException("索引单元Document处理错误");
        }

    }

搜索


    @Override
    public List<WebMerchantInfo>  keyWordSearch(String topic) throws Exception {
        if(topic.isEmpty() || topic == null){
            return null;
        }
        IndexSearcher searcher = null;  
        List<WebMerchantInfo> rList =  null;
        List<ScoreDoc[]> hitsList = null;
        ScoreDoc[] hits=null;
        Query query=null;  

        try {
            searcher = new IndexSearcher(DirectoryReader.open(FSDirectory.open(new File(indexFile))));  
            rList = new ArrayList<WebMerchantInfo>();
            hitsList = new ArrayList<ScoreDoc[]>();
        } catch (Exception e) {
            WifiLogUtil.wifiLogError(String.format("%s %s", this.getClass().getName(),"keyWordSearch"), e);
            throw new SystemWifiException("基础信息获取错误");
        }

        try {
            BooleanClause.Occur[] clauses = { BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD };
            query = MultiFieldQueryParser.parse(version,topic, fields, clauses, analyzer);
        } catch (Exception e) {  
            WifiLogUtil.wifiLogError(String.format("%s %s", this.getClass().getName(),"keyWordSearch"), e);
            throw new SystemWifiException("搜索器构造错误");
        }
        try{
            if (searcher!=null) {  
                TopDocs results=searcher.search(query, 10);//只取排名前十的搜索结果  
                hits=results.scoreDocs;  
                Document document=null;
                if (hits.length>0) {
                    for (ScoreDoc o: hits) {  
                         document=searcher.doc(o.doc);  
                         String introduction=document.get("introduction");
                         String itemName = document.get("itemName");
                         String putTime = document.get("putTime");
                         String id = document.get("id");
                         WebMerchantInfo w = new WebMerchantInfo();
                         w.setItemName(itemName);
                         w.setIntroduction(introduction);
                         w.setPutTime(putTime);
                         w.setMerchantInfoId(Long.valueOf(id));
                         rList.add(w);
                    }  
                }else{
                    System.out.println("没查到结果");
                    return null;
                }
//                searcher.close();  
                return rList;

            }else{
                 System.out.println("没查找到索引");  
                 return null;
            }
        } catch(Exception e){
            WifiLogUtil.wifiLogError(String.format("%s %s", this.getClass().getName(),"keyWordSearch"), e);
            throw new SystemWifiException("结果搜索错我");
        }

    }

性能优化

  • 建立索引是需要进行一次findAll操作,可以将建立索引的过程放在表数据发生变化时候触发,平时搜索可以直接根据现有索引进行搜索。
  • lucene支持在内存中建立索引,因此,若内存足够大可以尝试将索引建立在内存中。

包装框架

支持Annotation注解方式使用。与hibernate结合紧密。

详见官网: hibernate search

一些博客:

基于Spring的Hibernate Search全文检索功能示例

hibernate search 基本查询

solr

对JPA支持不佳。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值