背景
原来的楼盘库的搜索时采用lucene为索引,并且每天定时重建索引,这样编辑经常反映:修改和新增楼盘必须等到lucene定时重建后才能对外发布其搜索,并且无论楼盘有无修改,lucene都必须定时重建.经过小组讨论决定使用mongodb代替现有的lucene作为楼盘库的搜索,理由有以下几点
1)mongodb可以自由的同步mysql的数据,不必受定时重建的影响
2)楼盘库的搜索并没有复杂的检索分词,查询的语句和特点很适用mongodb
3)mongodb属于分布式文档存储数据库,有很好的扩展性,适用于以后的发展
4)经过压力测试与lucene对比,mongodb在简单查询的性能表现上比lucene略有优势
应用的工具及服务器
工具
1)MongoDB
2)Morphia,一个实现Java对象到MongoDB双向映射的类库
3)httpsqs,基于HTTP GET/POST协议的轻量级开源简单消息队列服务
必须用到的jar分别为:httpsqs4j.jar,mongo-2.2.jar,morphia-0.97.jar
服务器
正式服务器,ip外网220.181.333.333,内网192.168.86.333,端口27017,只支持内网连接
测试服务器,ip外网220.181.333.333
1)Spring整合Morphia
com.netease.product.mongodb.base.MorphiaBean 继承 com.google.code.morphia.Morphia ,并重载createDatastore()
mapPackage为指定需要注解的domain包
isMongo为自定义的标志位
创建db的命名为product_house_ +city 对应楼盘的城市
(注:详见MorphiaBean.java,mongodb.xml)
2)domain的设计
morphia的所有注解domain类全部存放于com.netease.product.mongodb.domain下
其中ProductInfo为@Entity实体类,其余都为@Embedded嵌入类,嵌入类需要再实体类中声明,如
这样我们在应用中只需对ProductInfo这个实体类进行操作即可.
(注:其他注解 @Id指定为主键,@Indexed为该字段创建索引,@Transient忽略该字段)
3)创建MongoDB记录
对外提供创建的接口为
com.netease.product.mongodb.index.ProductIndex.createProduct(Product product)
内部类DataMovement主要提供对ProductInfo接口字段进行整合特别处理的功能,如别名,网友打分,销售状态排序,这
些需要特别处理的字段都在此定义
4)查询MongoDB接口
对外统一提供的查询接口为com.netease.product.mongodb.search.ProductSearch
public RowSet getResults(Row param,String[] sort, boolean isOR, int beginNum, int size)
参数:
param为一组key value查询条件,如
row.put("district !=", district);不等于关系,将符号连接在key后面
并且param的各种字段特殊处理写在
ProductSearch.paramHandle(Row param)
sort为排序条件,其中desc需加"-"符号,asc则不用,如 new String[]{"-price"} ,按价格降序排列
isOR为是否或条件查询,目前只提供楼盘名和楼盘拼音的or查询,这部分将在下一阶段进一步完善
(注:详见com.netease.product.mongodb.search.ProductSearch)
5)切换MongoDB和lucene
在SearchAction中保持原来的接口,并新建SearchMongoAction,在每个SearchAction接口前部都新加
if(Constant.FACADE.getMorphiaBean().getIsMongo()==1){ //是否使用mongo进行查询
return new SearchMongoAction().xfs(this.getRequest(), this.getResponse());
}
通过状态位进行判断,如mongodb出现问题,可以将状态位切换回lucene的状态位,减少mongodb初步上线时对系统的影
响
5)使用队列同步Mysql和MongoDB
(注:httpsqs和spring的整合见httpsqs.html和HttpSQSBean.java)
对ProductDao中的更新楼盘的method进行拦击,将其更新的productid插入httpsqs队列中,调用
QueueBean.pushQueueByCity(String id)放入队列
配置定时器TimeService.getQueue()取出队列,并根据队里的productid进行mysql和mongodb的同步