设为首页 收藏本站
查看: 1281|回复: 0

[经验分享] 使用Hibernate+solr取代hibernate search

[复制链接]

尚未签到

发表于 2015-7-16 12:18:01 | 显示全部楼层 |阅读模式
  尝试使用solr取代hibernate search的方法,因本人对二者没有全面的了解,对二者都只是使用API级别,本文仅供参考。
  hibernate 4.1,solr3.6.0
  本人已实现,
  1.开箱即用的solr,就象hibernate search,只要引入JAR包,会自己注入事件,当sessionFactory初始化结束后,即更新schema.xml.
  2.hibernate进行insert,update,delete操作时,将数据提交到solr进行相应操作,都是基于事件操作
  3.查询接口提供
  待:更多查询的实现。
  二者简介介绍
  以下摘自各自官网

  Solr
  Solr is the popular, blazing fast open source enterprise search platform from the Apache Lucene project. Its major features include powerful full-text search, hit highlighting, faceted search, dynamic clustering, database integration, rich document (e.g., Word, PDF) handling, and geospatial search. Solr is highly scalable, providing distributed search and index replication, and it powers the search and navigation features of many of the world's largest internet sites.
  From:http://lucene.apache.org/solr/
  Hibernate Search
  Hibernate Search brings the power of full text search engines to the persistence domain model by combining Hibernate Core with the capabilities of the Apache Lucene™ search engine.
  From:http://hibernate.org/subprojects/search.html

  
  原因
  二者都是使用的apache lucene这个项目作为其基础。
  Hibernate Search的优点:
  1.hibernate search确实简单,加几个注解,配置几个选项,再只要使用FullText Search查询API即可操作,对索引的管理都不要操心。
  2.与hibernate集成完美,api使用与hiberante的API类似,上手度很高
  hibernate search的不足:
  1.它只能对一个实体内的数据进行索引查询,而不能对多个表全局查询,这个可以看到它生成的索引文件即可看出,一个实体一个文件夹保存索引
DSC0000.png
DSC0001.png
  2.分组查询等复杂查询支持度不够,highlight查询等没有,上述介绍中,solr介绍的兰色字体貌似都没有
  3.solr对lucene进行了很多二次封装,以及管理功能,方便扩展,管理,比如读写分离
  
  目标
  集成hibernate与solr,使用时,就象使用hibernate search那么简单.
  实验版本为:
  4.1.1.Final
3.6.0
  
  步骤
  1.自动增加实体的solr字段结构(在系统启动的时候,mapping绑定时,处理hibernate search的注解如@Indexed,@Field的字段).这是因为solr在添加索引之前,所有字段必须在schema.xml里定义,不然会报错。对实体的解析,直接使用hibernate search已有代码进行操作。省却不少工作量。
  2.索引变更处理(处理hibernate events),包括新增,更新,删除
  3.索引查询(查询API提供,简单封装solrj)
  
  详细步骤:
  1.entity到solr字段结构定义处理
  这个参考的是hibernate search的实现方式:
  实现接口org.hibernate.integrator.spi.Integrator即可。
  如hibernate search:

  public class HibernateSearchIntegrator implements Integrator {
  private static final Log log = LoggerFactory.make();     
    public static final String AUTO_REGISTER = "hibernate.search.autoregister_listeners";
  private FullTextIndexEventListener listener;
  @Override     
    public void integrate(      
            Configuration configuration,      
            SessionFactoryImplementor sessionFactory,      
            SessionFactoryServiceRegistry serviceRegistry) {      
        

  它是使用java ServiceLoader的把Integrator接口下的实现自动加载进来(以下二段是原理讲解,须在META-INFO下定义实现的位置):

  org.hibernate.integrator.internal.IntegratorServiceImpl.IntegratorServiceImpl(LinkedHashSet, ClassLoaderService):
  for ( Integrator integrator : classLoaderService.loadJavaServices( Integrator.class ) )
  
  org.hibernate.service.classloading.internal.ClassLoaderServiceImpl.loadJavaServices(Class):
  final ServiceLoader loader = ServiceLoader.load( serviceContract, serviceLoaderClassLoader );
  
  org.hibernate.internal.SessionFactoryImpl:
  for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) {     
        integrator.integrate( cfg, this, this.serviceRegistry );      
        integratorObserver.integrators.add( integrator );      
    }      
最后被加载到了SessionFactory里边了。

  加载完了,会自己执行:

  org.hibernate.integrator.spi.Integrator.integrate(Configuration, SessionFactoryImplementor, SessionFactoryServiceRegistry)
  在org.hibernate.internal.SessionFactoryImpl.SessionFactoryImpl(Configuration, Mapping, ServiceRegistry, Settings, SessionFactoryObserver):
  for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) {     
            integrator.integrate( cfg, this, this.serviceRegistry );      
            integratorObserver.integrators.add( integrator );      
        }

  在自己实现的类里,提交实体的field定义到solr:

  @Override     
    public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory,      
            SessionFactoryServiceRegistry serviceRegistry) {      
        // TODO Auto-generated method stub      
        System.out.println(configuration);      
        Iterator classMappings = configuration.getClassMappings();      
        while(classMappings.hasNext()) {      
            PersistentClass next = classMappings.next();//得到实体列表
  //提交到solr:localhost:8080/solr/updateschema

  提交转成json提交:

  SolrServer server = new CommonsHttpSolrServer("http://localhost:8082/solr-server");      
        UpdateRequest req = new UpdateRequest("/updateschema");      
        SolrInputDocument doc1 = new SolrInputDocument();      
        doc1.addField("name_sex_girl", "{\"type\":\"maxWord\",\"indexed\":true,\"stored\":false,\"termVectors\":false,\"termPositions\":false,\"termOffsets\":false}");
  Collection docs = new ArrayList();     
        docs.add(doc1);      
        req.add(docs);      
        UpdateResponse rsp = req.process(server);

  当然,localhost:8080/solr/updateschema是咱们自己定义的,它专门处理update schema的处理
  在solrconf.xml里加入自己实现的:

       
  

  SchemaUpdateHanlder 实现

  public class SchemaUpdateHanlder extends SchemaStreamHandlerBase{
  @Override     
      protected ContentStreamLoader newLoader(SolrQueryRequest req, UpdateRequestProcessor processor) {      
        return new SchemaXMLLoader(processor, inputFactory);      
      }

  相关实现

  public class SchemaUpdateProcessorFactory extends UpdateRequestProcessorFactory {     
    @Override      
    public UpdateRequestProcessor getInstance(SolrQueryRequest req, SolrQueryResponse rsp, UpdateRequestProcessor next) {      
        return new SchemaUpdateProcessor(req, next);      
    }      
}
  
  class SchemaUpdateProcessor extends UpdateRequestProcessor {     
    private final SolrQueryRequest req;      
    private final UpdateHandler updateHandler;
  public SchemaUpdateProcessor(SolrQueryRequest req, UpdateRequestProcessor next) {     
        super(next);      
        this.req = req;      
        this.updateHandler = new SchemaUpdateHandler(req.getCore());      
    }
  @Override     
    public void processAdd(AddUpdateCommand cmd) throws IOException {      
        // FIXME modify schema here      
        SolrInputDocument docs = cmd.getSolrInputDocument();      
        for (SolrInputField field : docs) {      
            String name = field.getName();      
            SchemaField field2 = req.getSchema().getFieldOrNull(name);      
            if(null==field2) {      
                Field f=JasonUtil.toObjectFromJson(field.getValue().toString(), Field.class);      
                  SolrConfig.getSchemaConfig().addField(f);      
            }

  查看schema.xml,果然有了:

  

  等全部加载完成后,再调用solr reload指令,使配置生效。
  http://localhost:8081/solr/admin/cores?action=RELOAD&core=collection1
  我的是代码调用的:



1     if (needReload) {
2             // schema结束后,重载
3             CoreContainer coreContainer = req.getCore().getCoreDescriptor().getCoreContainer();
4             coreContainer.getCoreNames();
5             for (String coreName : coreContainer.getCoreNames()) {
6                 try {
7                     coreContainer.reload(coreName);
8                 } catch (ParserConfigurationException e) {
9                     // TODO Auto-generated catch block
10                     e.printStackTrace();
11                 } catch (SAXException e) {
12                     // TODO Auto-generated catch block
13                     e.printStackTrace();
14                 }
15             }
16         }
  
  
  2.索引变更处理
  hibernate4变更了对事件的处理机制,之前可以在配置文件里使用的方式已不适用:

        

  我暂时找到的是,使用代码方式

  listener = new FullTextIndexEventListener(  );
  EventListenerRegistry listenerRegistry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(
                EventListenerRegistry.class);      
        //TODO if the event is duplicated, do not initialize the newly created listener      
        listenerRegistry.addDuplicationStrategy( new DuplicationStrategyImpl( FullTextIndexEventListener.class ) );      
        listenerRegistry.getEventListenerGroup( EventType.POST_INSERT ).appendListener( listener );      
        listenerRegistry.getEventListenerGroup( EventType.POST_UPDATE ).appendListener( listener );      
        listenerRegistry.getEventListenerGroup( EventType.POST_DELETE ).appendListener( listener );      
        listenerRegistry.getEventListenerGroup( EventType.POST_COLLECTION_RECREATE ).appendListener( listener );      
        listenerRegistry.getEventListenerGroup( EventType.POST_COLLECTION_REMOVE ).appendListener( listener );      
        listenerRegistry.getEventListenerGroup( EventType.POST_COLLECTION_UPDATE ).appendListener( listener );      
        listenerRegistry.getEventListenerGroup( EventType.FLUSH ).appendListener( listener );      
        listenerRegistry.getEventListenerGroup( EventType.LOAD ).appendListener( listener );      
        IntegratorService integratorService = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(      
                IntegratorService.class);
  
  事件的实现:
  public class FullTextIndexEventListener implements PostDeleteEventListener,     
    PostInsertEventListener, PostUpdateEventListener,      
    PostCollectionRecreateEventListener, PostCollectionRemoveEventListener,      
    PostCollectionUpdateEventListener, FlushEventListener,LoadEventListener{

  实现时,对索引的提交,与updateschema相同:

  SolrServer server = new CommonsHttpSolrServer("http://localhost:8082/solr-server");      
UpdateRequest req = new UpdateRequest("/update");

  这下,solr里就有数据了
DSC0002.png
  接下来,想怎么查询,还不是看自己去组合solr的参数罢了。
  如代码

  public  Page query(Query q) {     
        Page ret = new Page();
  try {     
            SolrQuery query = new SolrQuery();      
            query.setStart(q.getStart());      
            query.setRows(q.getRows());      
            query.setQuery(q.toString());      
            for (Entry order : q.getOrder().entrySet()) {      
                query.addSortField(order.getKey(), order.getValue());      
            }      
            QueryResponse rsp = solrServer.query(query);      
            ret.setNumFound(rsp.getResults().getNumFound());      
            ret.setqTime(Long.valueOf(rsp.getHeader().get("QTime").toString()));
  logger.info(rsp.getResults());     
            @SuppressWarnings("unchecked")      
            List beans = getBinder().getBeans(q.getQueryClazz(), rsp.getResults());
  ret.setResult(beans);     
        } catch (Exception e) {      
            logger.error("SOLR查询出错:" + q.toString(), e);      
            throw new MyException("SOLR查询出错:" + q.toString(), e);      
        }      
        return ret;      
    }


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-87294-1-1.html 上篇帖子: .NET开发过程中的全文索引使用技巧之Solr(转) 下篇帖子: Windows下面安装和配置Solr 4.9(二)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表