`

使用hibernate search和solr简化企业级搜索

    博客分类:
  • solr
阅读更多

项目需求需要做站内搜索,从网上找到如下文章,如是转载过来了

 

转载 http://jiaoxiupengl-163-com.iteye.com/blog/438060 

 

 

 最近刚忙完一个电影网站,其中的全文搜索的功能我就是用Solr完成的,在此将我在开发中遇到的问题以及怎样解决问题的经验拿出来与大家分享。

    我们这个网站有一个站内搜索的功能,例如站内新闻,输入关键字去搜索。数据库里有上万条数据,如果去挨个like,效率会很低,经领导指点,说可以试一试HibernateSearch和Apache solr结合mmseg4j分词进行全文检索,于是我就开始我的Solr之旅。
    一开始在网上搜了很多例子拿来入门,首先是分词,mmseg4j是用来分词的,常用的分词分析器有三种:MaxWordAnalyzer(最大分词),SimpleAnalyzer(简单的),ComplexAnalyzer(复杂的),最开始我用的是ComplexAnalyzer,看上去很不错,后来遇到了个小问题,例如“吴宇森吃羊肉串”,经过ComplexAnalyzer分分词后,用Solr去搜“吴宇森”会返回想要的结果,但是“吴宇”去搜什么也没返回。这是一个让人很头疼的问题,于是我试验了MaxWordAnalyzer,发现“吴宇”,“吴宇森”都能返回正确的结果,这才是我们想要的。 
    一段测试例子,大家可以拿去试一下MaxWordAnalyzer,SimpleAnalyzer,ComplexAnalyzer之间的区别。 

 

import java.io.IOException;  
  
import junit.framework.TestCase;  
  
import org.apache.lucene.analysis.Analyzer;  
import org.apache.lucene.document.Document;  
import org.apache.lucene.document.Field;  
import org.apache.lucene.index.CorruptIndexException;  
import org.apache.lucene.index.IndexWriter;  
import org.apache.lucene.queryParser.ParseException;  
import org.apache.lucene.queryParser.QueryParser;  
import org.apache.lucene.search.IndexSearcher;  
import org.apache.lucene.search.Query;  
import org.apache.lucene.search.ScoreDoc;  
import org.apache.lucene.search.TopDocs;  
import org.apache.lucene.store.Directory;  
import org.apache.lucene.store.RAMDirectory;  
  
import com.chenlb.mmseg4j.analysis.MaxWordAnalyzer;  
  
public class LuceneUseSimpleAnalyzerTest extends TestCase {  
  
    Directory dir;  
    Analyzer analyzer;  
  
    @Override  
    protected void setUp() throws Exception {  
        String txt = "吴宇森吃羊肉串";  
        //analyzer = new SimpleAnalyzer();     
        //analyzer = new ComplexAnalyzer();  
        //分词分析器  
        analyzer = new MaxWordAnalyzer();  
        //内存索引对象  
        dir = new RAMDirectory();  
        IndexWriter iw = new IndexWriter(dir, analyzer);  
        Document doc = new Document();  
        //Field.Store.YES表示在索引里将整条数据存储  
        doc.add(new Field("txt", txt, Field.Store.YES, Field.Index.ANALYZED));  
        iw.addDocument(doc);  
        iw.commit();  
        iw.optimize();  
        iw.close();  
    }  
  
    public void testSearch() {  
        try {  
            //实例化搜索器  
            IndexSearcher searcher = new IndexSearcher(dir);  
            //构造Query对象  
            QueryParser qp = new QueryParser("txt", analyzer);  
            Query q = qp.parse("吴宇森");   
            System.out.println(q);  
            //搜索相似度最高的10条  
            TopDocs tds = searcher.search(q, 10);  
            //命中的个数  
            System.out.println("======size:" + tds.totalHits + "========");  
            //输出返回结果  
            for (ScoreDoc sd : tds.scoreDocs) {  
                System.out.println(sd.score);  
                System.out.println(searcher.doc(sd.doc).get("txt"));  
            }  
        } catch (CorruptIndexException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (ParseException e) {  
            e.printStackTrace();  
        }  
    }  
  
}  

 

   可见mmseg4j是以非常灵活的分词工具而且分词速度也很快,2.5M的长篇小说用Complex模式是5.3秒左右,用Simple模式是2.9秒左右,好的,分词搞定了。再提一点,如何将mmseg4j应用到我们的Entity上的,我用的是元数据声明的方式:

 

@Field(name = "newsTitle", store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = MaxWordAnalyzer.class))   
private String title;  
      
@Field(name = "newsSummary", store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = MaxWordAnalyzer.class))   
private String summary;  
      
@Field(name = "newsPublishedTime", store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = MaxWordAnalyzer.class))  
private Date publishedTime;  

     这里面的name =  "newTitle",name = "newsSummry",是生成索引的名称,同时还要在Solr的schema.xml里定义与之相对应的field:

 

<field name="newsTitle" type="textMax" indexed="true" stored="true"/>  
<field name="newsSummary" type="textMax" indexed="true" stored="true"/>  
<field name="newsPublishedTime" type="date" indexed="true" stored="true" default="NOW" multiValued="false"/>  
     说到这,再提一下如何将集合建立索引以及配置,例如OneToMany,首先在一的一端进行声明:
@IndexedEmbedded  
private Set<PlotKeyword> plotKeywords = new HashSet<PlotKeyword>(); //关键词联想  
   然后在多的一端指定到底是哪一个字段建立索引:   
@Field(store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = MaxWordAnalyzer.class))  
private String summary;  
     在这里你可以不给你的索引字段加name,默认会在索引库里有name="plotKeywords.summary"这样一个索引名称,同时也不要忘记在Solr的schema.xml里定义与之相对应的field:

  <field name="plotKeywords.summary" type="textMax" indexed="true" stored="true"/>

   type="textMax" ,对应schema.xml里的:

 

<fieldType name="textMax" class="solr.TextField" positionIncrementGap="100" >    
    <analyzer>    
            <tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="max-word" dicPath="D:/data/dict"/>    
            <filter class="solr.LowerCaseFilterFactory"/>    
    </analyzer>    
</fieldType>  

     dicPath="D:/data/dict"是词库的路径,如果我们用的是MaxWordAnalyzer进行的分词,那么为了保证Solr能搜到我们想要的结果,必须在schema.xml里配置上面一段fieldType,指定mode="max-word",这样Solr就会按照最大分词去给我们返回与之相对应的结果,“吴宇”,“吴宇森”,都会返回结果。

 

 

 

    如何将Solr集成到我们的项目中呢?很简单,就拿Tomcat举例,解压Solr,将..\apache-solr-1.3.0\example\solr 文件夹拷贝到Tmocat的bin文件夹下,配置schema.xml上面提到了,还有索引库路径,在solrconfig.xml里配置:


 

 

<dataDir>${solr.data.dir:D:/data/index}</dataDir>  

 

  然后在web.xml里面配置Solr的SolrDispatchFilter:

 

<filter>  
     <filter-name>SolrRequestFilter</filter-name>  
     <filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class>  
</filter>  
  
<filter-mapping>  
     <filter-name>SolrRequestFilter</filter-name>  
     <url-pattern>/*</url-pattern>  
</filter-mapping>  
 

     在这里就不提引入的第三方jar文件,可以参考Solr文档。要注意的是HibernateSearch结合mmseg4j分词时候,我们用到了自己的词库,需要指定一个虚拟机参数:-Dmmseg.dic.path=d:/data/dict,在这里我们将分词用到的词库放到了d:/data/dict,有可能词库过大造成虚拟机内存溢出,还要加参数: -Xmx256m -Xmx512m。就这样Solr就集成到我们的项目中了,而且HibernateSearch帮我们管理了索引库,增加,删除,还有修改没有个被索引的字段,HibernateSearch都会帮我们同步索引库。

 

 

 

    Solr的查询语法很灵活,大家可以参考官方文档,在这里我要提一下查询or和and,Solr默认的配置是or,在schema.xml里:

    <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->

 <solrQueryParser defaultOperator="OR"/>  

     如果想用到and,还有一种方式在Url里指定参数fq,过滤条件,例如:q=kaka&fq=age:[15 to 20],搜索条件是kaka,并且age是15到20岁之间。

 

    Solr支持很多种查询输出格式,用参数wt指定,有xml, json, php, phps,我这里用到了json。一段JavaScript供大家参考:

   $.ajax({

     type: "post",//使用post方法访问后台  
    dataType: "json",//返回json格式的数据  
    url: "/select/",//要访问的后台地址  
    data: "q=" + keywords + "&start=" + 0 + "&rows=" + 5 + "&indent=" + "on" + "&wt=" + "json" + "&sort=" + "newsPublishedTime asc",//要发送的数据  
    success: function(j) {//msg为返回的数据,在这里做数据绑定  
         var docs = j.response.docs;  
              for (var i=0; i<docs.length; i++) {  
                     var date = docs[i].newsPublishedTime;  
                     var title = docs[i].newsTitle;  
                     var summary = docs[i].newsSummary;  
              }  
       }  
});  
 

   一切都顺利进行,但是马上就遇到了一个新问题,重建索引后Solr也必须重新拿启动,要么Solr不会用最新的索引库,Solr有自己的缓存,这个很让让人头疼,如果删除一条数据,HibernateSearch会帮我们同步索引库,但是Solr的缓存还是缓存之前没有删除的数据。我试图通过配置文件不用Solr的缓存,但是没有效果,根据官方文档上说的意思是:Solr的缓存是干不掉的。这绝对不是我们想要的结果,但是最后还是解决了,在sorlconfig.xml里配置:

<requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />  
    然后访问/update?commit=true,Solr就会放弃之前的缓存,去重新检索我们的索引库建立新的缓存,这正是我们想要的结果。

 

分享到:
评论

相关推荐

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

    1. **Spring框架**:Spring是一个开源的Java企业级应用框架,提供依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等核心特性,极大地简化了Java应用的开发过程。 2. **Hibernate ORM**:Hibernate是一个...

    hibernate-search-4.5.2.Final-dist.tar.gz

    这个压缩包"hibernate-search-4.5.2.Final-dist.tar.gz"包含了Hibernate Search 4.5.2.Final版本的所有组件和资源,是开发人员进行企业级搜索解决方案构建的重要工具。 一、Hibernate Search概述 Hibernate Search...

    搜索功能设计java实现

    - **Apache Solr** 另一个基于Lucene的搜索平台,专注于企业级搜索。它提供了更丰富的管理和配置选项,适合大型项目。 - **XML/JSON接口**:Solr使用XML或JSON进行通信,允许通过HTTP请求发送查询和管理索引。 6....

    struts2+spring3+hibernate3实现商城系统

    Struts2+Spring3+Hibernate3是Java开发中常见的企业级应用框架组合,被称为SSH框架。这个商城系统利用这三个框架的协同工作,构建了一个高效、稳定且功能丰富的平台。接下来,我们将深入探讨这些关键技术及其在商城...

    java工程师简历_java简历.doc

    第一个项目是淘嘟嘟网上商城,他参与了需求分析和项目构建,负责商品管理、广告管理和搜索展示。项目采用了SpringMVC、MyBatis、jQuery、FastDFS、Redis、Solr、Maven等技术。他利用Maven提高了开发效率,使用Solr...

    java网络爬虫+数据库+jsp+搜索引擎.rar.rar

    Solr是另一个强大的搜索引擎,适合大型企业级应用。这两者都支持复杂的查询语法和丰富的数据分析功能。 结合以上技术,我们可以创建一个完整的系统,如:Java网络爬虫负责定期抓取网站数据,然后将数据存储到数据库...

    ssh框架 博客系统

    Spring框架是核心,它提供了一个全面的编程和配置模型,旨在简化企业级应用的开发。Spring提供了依赖注入(DI)和面向切面编程(AOP),使得开发者可以更加关注业务逻辑,而不是底层的基础设施。此外,Spring还包含...

    订餐系统 基于ssh框架

    此外,为了提高系统的性能和用户体验,可能还会涉及到缓存技术(如Spring Cache)、搜索引擎集成(如Solr或Elasticsearch)以优化菜品搜索,以及安全框架(如Spring Security)来保障用户的账户安全。而测试方面,...

    ssh2综合实例-免费电子商务平台【源码】

    7. **扩展与优化**:这个电商平台可能还涉及到了缓存策略(如使用Spring Cache)、搜索引擎集成(如Solr或Elasticsearch)、性能监控(如使用Spring Boot Actuator)等高级特性。开发者可以基于此源码进行功能扩展和...

    Lucene初级教程.doc

    10. **与其他工具结合**:在实际开发中,Lucene常常与Spring Data、Hibernate Search等框架集成,以简化应用集成和管理。 **学习资源** 由于题目中提及的博文链接无法直接访问,这里推荐一些通用的学习资源: - ...

    java游戏论坛 毕业设计

    SSH框架,全称为Spring、Struts和Hibernate,是Java领域广泛应用的企业级开发框架组合,具有良好的模块化和可扩展性,使得开发复杂的Web应用程序变得更为简便。 1. **Spring框架**:Spring作为核心容器,负责管理...

    JAVA 企业门户新闻网

    9. **搜索引擎集成**:为了方便用户搜索,可能集成了Solr或Elasticsearch等全文搜索引擎,提供高效的全文检索功能。 10. **容器化部署**:Docker容器化技术可能用于部署,通过Dockerfile定义运行环境,确保应用在...

    在线商店系统用了经典的三大框架

    Spring框架则扮演了整个应用的胶水角色,它提供了一个全面的应用编程接口(API)和基础设施支持,用于构建企业级的Java应用。Spring的核心特性包括依赖注入(DI)和面向切面编程(AOP)。DI使得组件之间的耦合度降低...

    Java面试参考简历.docx

    - **Spring** 是一个轻量级的开源应用框架,旨在简化企业级应用程序的开发过程。 - **Spring MVC**:是Spring框架的一部分,用于构建Web应用程序,它实现了MVC设计模式。 - **Spring Boot**:基于Spring框架,提供了...

    Lucence资料大全

    4. 分布式搜索:通过Solr或Elasticsearch等基于Lucene的高级框架,实现大规模数据的分布式搜索。 5. 高级查询:包括范围查询、地理位置查询、自定义评分函数等,满足复杂查询需求。 6. 集成优化:与Spring、...

    基于JSP论坛系统毕业设计论文 基于J2EE财务管理系统毕业设计论文 基于J2EE个人博客系统毕业设计论文

    - 搜索功能:可能涉及到全文搜索,如Solr或Elasticsearch。 - 社交集成:分享按钮,评论插件,如Disqus。 这些项目作为毕业设计论文的主题,涵盖了Web开发中的许多核心概念和技术,对深入理解和掌握Java Web开发...

    java+实现+电子商务系统

    2. **Spring框架**:Spring是Java企业级应用开发的核心框架,提供了依赖注入(DI)和面向切面编程(AOP)等特性,用于简化项目结构,管理对象之间的依赖关系,并实现解耦。 3. **Spring Boot**:Spring Boot基于...

    java人事管理系统

    2. **Spring框架**:Spring是Java EE开发中的核心框架,提供依赖注入、AOP(面向切面编程)、事务管理等功能,简化企业级应用的开发。 3. **MyBatis**:MyBatis是一个持久层框架,它允许开发者将SQL与Java代码直接...

    论坛系统源码

    1. **Spring**:Spring 是一个全面的企业级应用开发框架,它简化了Java EE应用的开发工作。Spring 提供了一个配置和依赖注入机制,可以将复杂的对象关联关系进行解耦,使得代码更易于测试和维护。此外,Spring 还...

Global site tag (gtag.js) - Google Analytics