`
osacar
  • 浏览: 212548 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

再谈compass:集成站内搜索

阅读更多
前段时间已经写了一篇关于compass的文章,相信大家对compass也已经有了一定的了解

由于最近做的项目中涉及到了站内搜索,而且是基于JPA注解形式的,在网上找了好久,关于JPA集成compass的例子很少,有些也是基于 xml的,基于注解形式的甚是少,没有办法只有去compass的官网下载英文文档自己研究一下,花费了一下午时间调试出来,集成到项目中!

在这里给大家分享下,希望大家可以少走些弯路!

1.去官方网站下载compass的jar包,我用的的2.1版本

http://www.compass-project.org/

ProductInfo.java

@Entity
@Searchable
public class ProductInfo implements Serializable{
  private static final long serialVersionUID = -8860864584425256200L;
  private Integer id;
  /** 货号 **/
  private String code;
  /** 产品名称 **/
  private String name;
  /** 产品类型 **/
  private ProductType type;
  /** 产品样式 **/
  private Set<ProductStyle> styles = new HashSet<ProductStyle>();

  public ProductInfo() {}

  @OneToMany(cascade={CascadeType.REMOVE,CascadeType.PERSIST}, mappedBy="product",fetch=FetchType.EAGER)
  @OrderBy("visible desc, id asc")
  @SearchableReference
  public Set<ProductStyle> getStyles() {
  return styles;
  }
  public void setStyles(Set<ProductStyle> styles) {
  this.styles = styles;
  }

  @Id @GeneratedValue
  @SearchableId 
  public Integer getId() {
  return id;
  }
  public void setId(Integer id) {
  this.id = id;
  }
  @Column(length=30)
  @SearchableProperty(index = Index.TOKENIZED, store = Store.YES)
  public String getCode() {
  return code;
  }
  public void setCode(String code) {
  this.code = code;
  }
  @Column(length=50,nullable=false)
  @SearchableProperty(index = Index.TOKENIZED, store = Store.YES)
  public String getName() {
  return name;
  }
  public void setName(String name) {
  this.name = name;
  }

  @ManyToOne(cascade=CascadeType.REFRESH,optional=false)
  @JoinColumn(name="typeid")
  @SearchableReference
  public ProductType getType() {
  return type;
  }
  public void setType(ProductType type) {
  this.type = type;
  }

  @Override
  public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  return result;
  }
  @Override
  public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  final ProductInfo other = (ProductInfo) obj;
  if (id == null) {
   if (other.id != null)
   return false;
  } else if (!id.equals(other.id))
   return false;
  return true;
  }
}



ProductType.java
@Entity
@Searchable
public class ProductType implements Serializable{
  private static final long serialVersionUID = 8106351120886053881L;
  /** 类别id **/
  private Integer typeid;
  /** 类别名称 **/
  private String name;
  /** 子类别 **/
  private Set<ProductType> childtypes = new HashSet<ProductType>();
  /** 所属父类 **/
  private ProductType parent;

  private Set<ProductInfo> products = new HashSet<ProductInfo>();

  @OneToMany(mappedBy="type", cascade=CascadeType.REMOVE)
  @SearchableReference
  public Set<ProductInfo> getProducts() {
  return products;
  }

  public void setProducts(Set<ProductInfo> products) {
  this.products = products;
  }

  public ProductType() {}

  @ManyToOne(cascade=CascadeType.REFRESH)
  @JoinColumn(name="parentid")
  public ProductType getParent() {
  return parent;
  }

  public void setParent(ProductType parent) {
  this.parent = parent;
  }
  @OneToMany(cascade={CascadeType.REFRESH,CascadeType.REMOVE},mappedBy="parent")
  public Set<ProductType> getChildtypes() {
  return childtypes;
  }

  public void setChildtypes(Set<ProductType> childtypes) {
  this.childtypes = childtypes;
  }

  @Column(length=36,nullable=false)
  public String getName() {
  return name;
  }

  public void setName(String name) {
  this.name = name;
  }

  @Id @GeneratedValue(strategy=GenerationType.AUTO)
  @SearchableId 
  public Integer getTypeid() {
  return typeid;
  }

  public void setTypeid(Integer typeid) {
  this.typeid = typeid;
  }

  @Override
  public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((typeid == null) ? 0 : typeid.hashCode());
  return result;
  }

  @Override
  public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  final ProductType other = (ProductType) obj;
  if (typeid == null) {
   if (other.typeid != null)
   return false;
  } else if (!typeid.equals(other.typeid))
   return false;
  return true;
  }
}


ProductStyle.java
@Entity
@Searchable
public class ProductStyle implements Serializable{
  private static final long serialVersionUID = -4926119953511144279L;
  private Integer id;
  /** 样式的名称 **/
  private String name;
  /** 图片 **/
  private String imagename;
  private String image140FullPath;
  /** 是否可见 **/
  private Boolean visible = true;
  private ProductInfo product;

  public ProductStyle() {}

  public ProductStyle(Integer id) {
  this.id = id;
  }

  public ProductStyle(String name, String imagename) {
  this.name = name;
  this.imagename = imagename;
  }
  @ManyToOne(cascade=CascadeType.REFRESH,optional=false)
  @JoinColumn(name="productid")
  @SearchableReference
  public ProductInfo getProduct() {
  return product;
  }
  public void setProduct(ProductInfo product) {
  this.product = product;
  }
  @Id @GeneratedValue
  @SearchableId 
  public Integer getId() {
  return id;
  }
  public void setId(Integer id) {
  this.id = id;
  }
  @Column(length=30,nullable=false)
  public String getName() {
  return name;
  }
  public void setName(String name) {
  this.name = name;
  }
  @Column(length=40,nullable=false)
  @SearchableProperty(index = Index.UN_TOKENIZED, store = Store.YES)
  public String getImagename() {
  return imagename;
  }
  public void setImagename(String imagename) {
  this.imagename = imagename;
  }
  @Column(nullable=false)
  public Boolean getVisible() {
  return visible;
  }
  public void setVisible(Boolean visible) {
  this.visible = visible;
  }
  @Transient 
  public String getImageFullPath(){
  return "/images/product/"+ this.getProduct().getType().getTypeid()+ "/"+
  this.getProduct().getId()+ "/prototype/"+ this.imagename;
  }

  @Transient 
  public String getImage140FullPath(){
  image140FullPath = "/images/product/"+ this.getProduct().getType().getTypeid()+ "/"+
  this.getProduct().getId()+ "/140x/"+ this.imagename;
  return image140FullPath;
  }

  @Override
  public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  return result;
  }
  @Override
  public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  final ProductStyle other = (ProductStyle) obj;
  if (id == null) {
   if (other.id != null)
   return false;
  } else if (!id.equals(other.id))
   return false;
  return true;
  }
}


这里要特别注意有集合类型要搜索或显示的时候,两边定义的@SearchableReference或 @SearchableComponent必须一致

2.再spring的配置文件中加入以下代码

<bean id="annotationConfiguration" class="org.compass.annotations.config.CompassAnnotationsConfiguration">
</bean>
  <!-- compass Bean -->
<bean id="compass" class="org.compass.spring.LocalCompassBean">
  <property name="compassConfiguration"
   ref="annotationConfiguration" />
  <property name="transactionManager" ref="txManager" />
  <property name="compassSettings">
   <props>
  <!-- 定义索引的存储位置 -->
<prop key="compass.engine.connection">d:/compass</prop>
<prop key="compass.transaction.factory">
    org.compass.spring.transaction.SpringSyncTransactionFactory
</prop>
  <!-- 定义分词器-->
<prop key="compass.engine.analyzer.MMAnalyzer.CustomAnalyzer">
org.mira.lucene.analysis.IK_CAnalyzer 
</prop>
</props>
</property>
     <property name="resourceDirectoryLocations">
   <list>
   <value>classpath:net/shopin/bean/product</value>
   </list>
  </property>

  </bean>

  <bean id="jpaGpsDevice"
  class="org.compass.gps.device.jpa.JpaGpsDevice">
  <property name="name">
   <value>JpaGpsDevice</value>
  </property>
  <property name="entityManagerFactory"
   ref="entityManagerFactory" />
  <property name="mirrorDataChanges">
   <value>true</value>
  </property>
  </bean>
  <!-- 数据库中的数据变化后同步更新索引 -->
  <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps"
  init-method="start" destroy-method="stop">
  <property name="compass" ref="compass" />
  <property name="gpsDevices">
   <list>
   <bean 
    class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper">
    <property name="gpsDevice" ref="jpaGpsDevice" />
   </bean>
   </list>
  </property>
  </bean>

  <bean id="compassTemplate"
  class="org.compass.core.CompassTemplate">
  <property name="compass" ref="compass" />
  </bean>

  <!-- 定时重建索引(利用quartz)或随Spring ApplicationContext启动而重建索引 -->
  <bean id="compassIndexBuilder"
  class="net.shopin.service.search.impl.CompassIndexBuilder"
  lazy-init="false">
  <property name="compassGps" ref="compassGps" />
  <property name="buildIndex" value="true" />
  <property name="lazyTime" value="5" />
  </bean>




3.自动建立索引的java bean
/**
  * 通过quartz定时调度定时重建索引或自动随Spring ApplicationContext启动而重建索引的Builder.
  * 会启动后延时数秒新开线程调用compassGps.index()函数.
  * 默认会在Web应用每次启动时重建索引,可以设置buildIndex属性为false来禁止此功能.
  * 也可以不用本Builder, 编写手动调用compassGps.index()的代码.
  *
  */
public class CompassIndexBuilder implements InitializingBean {
   // 是否需要建立索引,可被设置为false使本Builder失效.
   private boolean buildIndex = false;

   // 索引操作线程延时启动的时间,单位为秒 
   private int lazyTime = 10;

   // Compass封装 
   private CompassGps compassGps;

   // 索引线程 
   private Thread indexThread = new Thread() {

     @Override
     public void run() {
       try {
         Thread.sleep(lazyTime * 1000);
         System.out.println("begin compass index...");
         long beginTime = System.currentTimeMillis();
         // 重建索引.
         // 如果compass实体中定义的索引文件已存在,索引过程中会建立临时索引,
         // 索引完成后再进行覆盖.
         compassGps.index();
         long costTime = System.currentTimeMillis() - beginTime;
         System.out.println("compss index finished.");
         System.out.println("costed " + costTime + " milliseconds");
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
     }
   };

   /**
    * 实现<code>InitializingBean</code>接口,在完成注入后调用启动索引线程.
    *
    * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
    */
   public void afterPropertiesSet() throws Exception {
     if (buildIndex) {
       indexThread.setDaemon(true);
       indexThread.setName("Compass Indexer");
       indexThread.start();
     }
   }

   public void setBuildIndex(boolean buildIndex) {
     this.buildIndex = buildIndex;
   }

   public void setLazyTime(int lazyTime) {
     this.lazyTime = lazyTime;
   }

   public void setCompassGps(CompassGps compassGps) {
     this.compassGps = compassGps;
   }
}




4.建立索引Service 层代码

@Service
@Transactional 
public class SearchServiceBean extends DaoSupport implements SearchService {
  @Resource(name = "compass")
  Compass compass;

/** 创建索引 **/
public void index(ProductInfo p) {

CompassSession session = compass.openSession();
CompassTransaction tx = null;
try {
  tx = session.beginTransaction();
  session.create(p);
  tx.commit();
} catch (Exception e) {
  if (tx != null) {
tx.commit();
  }
  throw new RuntimeException(e);
  } finally {
  if (session != null) {
  session.close();
  }
  }
  }
  /** 删除一条索引 **/
  public void delete(ProductInfo p) {
  CompassTemplate ct = new CompassTemplate(compass);
  ct.delete(p);
  }
  /** 更新(重新创建)一条索引 **/
  public void update(final ProductInfo p) {
  CompassTemplate ct = new CompassTemplate(compass);

  CompassCallback<Object> action = new CompassCallback<Object>() {

   public Object doInCompass(CompassSession session)
    throws CompassException {
   session.delete(p);
   session.create(p);
   return null;
   }

  };

  ct.execute(action);
  }
  /** 索引查询 **/
  public List<ProductInfo> find(final String keywords) {
  CompassTemplate ct = new CompassTemplate(compass);
  return ct.execute(new CompassCallback<List<ProductInfo>>() {

   public List<ProductInfo> doInCompass(CompassSession session)
    throws CompassException {
   List<ProductInfo> result = new ArrayList<ProductInfo>();
   CompassQueryBuilder queryBuilder = session.queryBuilder();
   CompassHits hits = null; // session.find(query);
   /** 在所有字段中查询 **/
   CompassQuery allPropertyQuery = queryBuilder.queryString(keywords).toQuery();
   hits = allPropertyQuery.hits();
   /** 在指定字段中查询 **/
   // CompassQuery query = queryBuilder.term("name", keywords);
   // hits = query.hits();
   /** 指定范围查询 **/
//   CompassQuery dateRangeQuery =
//   queryBuilder.between("postTime",startTime, endTime, true);
//   hits = queryBuilder.bool()
//   .addMust(allPropertyQuery)
//   .addMust(dateRangeQuery)
//   .toQuery()
//   .hits();
//  System.out.println("---------");
   for (int i = 0; i < hits.length(); i++) {
    ProductInfo p = (ProductInfo) hits.data(i);
    /** 如果进行高亮的属性中没有出现关键字, 则返回null **/
//   String ht = hits.highlighter(i).fragment("name");
//   if (ht != null) {
//   p.setName(ht);
//   }
//   String hc = hits.highlighter(i).fragment("code");
//   if (hc != null) {
//   p.setCode(hc);
//   }
    result.add(p);
   }
   return result;
   }
  });
  }



控制层

@Controller("/search/gosearch")
public class SearchAction extends Action {
  @Resource(name = "searchServiceBean")
  private SearchService SearchService;

  @Override
  public ActionForward execute(ActionMapping mapping, ActionForm form, 
   HttpServletRequest request, HttpServletResponse response)
   throws Exception {
  String keywords=request.getParameter("word").trim();
  if(keywords==null||"".equals(keywords)){
   return mapping.findForward("noproduct");
  }
  System.out.println("------"+keywords);
  List<ProductInfo> list = SearchService.find(keywords);
  request.setAttribute("word", keywords);
  request.setAttribute("product",list);
     if(list.isEmpty()){
      return mapping.findForward("noproduct");
     }else{
      return mapping.findForward("list");

     }
  }
} 



junit测试
public class SearchTest {

  private static AbstractApplicationContext context;
  @BeforeClass 
  public static void setUpBeforeClass() throws Exception {
  try {
   context = new ClassPathXmlApplicationContext("beans.xml");
  } catch (Exception e) {
   e.printStackTrace();
  }
  }

  @Test 
  public void testDelete() {
  SearchService searchService = (SearchService) context 
  .getBean("searchServiceBean");
  ProductInfo p = new ProductInfo(2);
  searchService.delete(p);
  }

  @Test 
  public void createIndex(){
  SearchService searchService = (SearchService) context 
  .getBean("searchServiceBean");
  ProductInfoService productInfoService = (ProductInfoService) context 
  .getBean("productInfoServiceBean");
  List<ProductInfo> list=productInfoService.getAllProduct();
  for(ProductInfo productInfo:list){
//  System.out.println("-------"+productInfo.getName());
   searchService.index(productInfo);
  }
  }

  @Test 
  public void testSearch() {
  SearchService searchService = (SearchService) context 
  .getBean("searchServiceBean");
  String query = "手机";
  List<ProductInfo> ProductInfos;

   ProductInfos = searchService.find(query);
   for (ProductInfo p : ProductInfos) {
   System.out.println(p.getName());
   }
  System.out.println("------------");
  }
}

分享到:
评论

相关推荐

    Spring ,JPA,Compass使用注解开发的博客站内搜索

    标题 "Spring ,JPA,Compass使用注解开发的博客站内搜索" 涉及的是在Java开发环境中,利用Spring框架、Java Persistence API (JPA) 和 Compass搜索引擎来实现一个博客系统的站内搜索功能。这是一项关键的技术,因为...

    S2SH+compass (实现站内全文检索)

    标题中的"S2SH+compass"指的是一个基于Struts2(S),Spring(S)和Hibernate(H)这三种开源框架的Java Web应用,再加上Compass搜索引擎来实现站内全文检索的功能。这种组合常用于构建复杂的企业级应用,因为它提供...

    ssh+compass实现站内搜索分页.rar

    通过以上步骤,你可以在SSH框架下成功集成Compass实现站内搜索分页。这一过程涉及到Java Web开发的多个层面,包括MVC架构、数据库操作、全文检索以及用户体验设计。熟练掌握这些技能将有助于构建高效且功能丰富的Web...

    Compass全文检索系列之一:Compass入门

    本文将介绍Compass,一个基于Lucene的全文搜索引擎库,为Java开发者提供了一种简单易用的方式来集成全文检索功能。Compass不仅提供了与ORM框架(如Hibernate、JPA等)的无缝集成,还支持动态索引更新,使得实时数据...

    compass:我们走吧

    在实际开发中,`compass-master`通常包含了Compass的完整代码库,包括示例、配置文件和文档,开发者可以借此学习和了解Compass的工作原理以及如何在项目中集成使用。 4. **使用Compass的步骤**: - 安装Sass和...

    Compass 的java代码

    在Java应用中集成搜索引擎功能时,Compass提供了一种简化的方式来管理和操作Lucene索引。通过Compass,你可以将对象-关系映射(ORM)与全文检索完美结合,使得数据库中的数据能够被快速高效地搜索。 **Compass的...

    compass搜索引擎技术

    Compass搜索引擎技术是一种基于Lucene的全文检索框架,它提供了更高级别的API和集成机制,使得在Java应用程序中实现搜索引擎功能变得更加便捷。Compass的主要目标是将全文索引能力无缝地融入到现有的业务应用程序中...

    基于Lucene的搜索引擎框架Compass教程

    Compass不仅支持对关系数据库中的数据进行索引,还能与ORM框架如Hibernate、JPA等无缝集成,使得索引和搜索的数据可以与业务数据保持一致。 **二、Compass的核心特性** 1. **ORM集成**:Compass能够自动跟踪和更新...

    java搜索 compass资料

    ### Java搜索 Compass 资料知识点 #### 一、Compass 概述 Compass 是一个为 Java 应用程序提供全文检索功能的框架。它能够帮助开发者在 Java 应用程序中轻松实现复杂的搜索需求,并且具有较高的性能。Compass 基于...

    compass 全文搜索

    而Compass则在Lucene的基础上进行了封装,使得开发者可以更方便地在自己的应用程序中集成全文搜索功能。 Compass的核心特性包括: 1. **ORM集成**:Compass支持多种对象关系映射(ORM)框架,如Hibernate、JPA和...

    Compass原理深入学习笔记

    Compass是一款基于Apache Lucene的全文搜索引擎框架,它为开发者提供了更高级别的抽象层,简化了搜索引擎的集成工作。在理解Compass之前,我们需要先了解全文检索的基本概念和原理。 全文检索是相对于传统的基于...

    compass:Compass是一个轻量级的嵌入式分布式数据库访问层框架

    Compass是搜狗商业平台研发部开发的一套轻量级的分布式数据库访问框架,支持单库、主从库读写分离、分库、分库之后再分表、从库负载均衡和HA等使用场景,并且在框架层面提供了主从反延迟策略。Compass采用Spring配置...

    maptalks.control.compass:Maptalks指南针控件

    maptalks.control.compass maptalks罗盘控件。 例子 安装 使用npm npm install maptalks.control.compass : npm install maptalks.control.compass 。 用纱安装: yarn add maptalks.control.compass 。 从下载...

    compass完整可用项目

    【compass完整可用项目】是一个基于特定技术栈的软件开发项目,该项目的核心是Compass库,一个与Lucene紧密集成的全文搜索引擎工具。Compass提供了一种简单的方式来在Java应用程序中集成全文搜索功能,使得开发者...

    compass对象搜索引擎

    Compass对象搜索引擎是一款基于Lucene的全文搜索引擎框架,它为Java开发者提供了高级的搜索功能,使得在应用程序中集成全文检索变得更加便捷。Compass的核心理念是将数据库中的对象与Lucene索引之间建立映射...

    Codiad-Compass:用于 IDE 编码的 Compass 集成插件

    #Codiad 指南针 指南针命令集成插件 ##要求 ##安装 下载 zip 文件并将其解压缩到您的插件文件夹。 ##特征 创造 编译 干净的 手表 日志窗口 ##去做 国际化 #接触 推特: ##执照

Global site tag (gtag.js) - Google Analytics