用SolrJ操作Solr做搜索(上篇)
本文来自 网易云社区 。Solr是一个基于Apache Lucene ,流行的,极速,开源的企业搜索平台。主要由以下特点:1、高级的全文搜索功能2、专为高通量的网络流量进行的优化3、基于开放接口(XML和HTTP)的标准4、综合的HTML管理界面5、可伸缩性-能够有效地复制到另外一个Solr搜索服务器6、使用XML配置达到灵活性和适配性7、可扩展的插件体...
本文来自 网易云社区 。
Solr是一个基于Apache Lucene ,流行的,极速,开源的企业搜索平台。主要由以下特点:
1、高级的全文搜索功能
2、专为高通量的网络流量进行的优化
3、基于开放接口(XML和HTTP)的标准
4、综合的HTML管理界面
5、可伸缩性-能够有效地复制到另外一个Solr搜索服务器
6、使用XML配置达到灵活性和适配性
7、可扩展的插件体系
今天主要介绍用SolrJ来操作Solr处理数据。
1、系统环境
1、Solr5.5.0
2、Java 1.7
3、MySQL 5.7
4、SolrJ 5.5.0
5、Tomcat 7.0
6、Windows 7
PS:Solr各个版本差别略大,配置文件也不尽相同。需要谨慎选择版本型号,不然可能本文的一些配置无法生效。
2、Solr单机安装与部署
这里提供两种安装Solr的方式。 安装部署之前先到官网(http://archive.apache.org/dist/lucene/solr/)下载文件包。
一、Solr安装部署
1、启动
本地把安装包解压到E:\tools\solr\solr-5.5.0,在本路径执行 bin/solr.cmd start命令,默认端口是8983。
2、查看
访问链接http://localhost:8983/solr/ 我们就可以查到Solr已经启动了!
Solr就算安装好了。
二、Solr与tomcat集成
1、迁移solr工程
将solr-5.5.0\server\solr-webapp目录下的webapp文件夹拷贝到tomcat7下webapps下,并改名为solr
2、修改eb.xml
修改tomcat7\webapps\solr\WEB-INF目录下的web.xml文件,添加如下配置:
这里配置了Solr的主目录,后期创建core,日志信息都会在这个路径里面。
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>E:\\tools\\tomcat\\tomcat7\\apache-tomcat-7.0.54\\bin\\solr</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
3、拷贝jar包
将 solr-5.5.0\server\lib\ext目录下的所有jar包拷贝到tomcat7 -> webapps -> solr -> WEB-INF -> lib
4、拷贝log4j.properties
将 solr-5.5.0\server\resources目录下的log4j.properties文件拷贝到 D:\ apache-tomcat-7.0.54\solr\WEB-INF\classes下。配置后,可以查看系统日志信息。对于后期的全量,增量数据处理,错误信息查询等非常重要。
5、启动Tomcat
访问链接http://localhost/solr/index.html 我们就可以查到Solr已经启动了!
3、初始化数据
初始化数据包括两个部分,第一部分为为Solr建立core,第二部分为core放入索引数据(这里用SolrJ来处理,当然也可以配置MySQL实现增量,全量配置)。我们用8983端口的Solr来操作。
一、Solr创建Core
1、初始化Core
默认Solr的主目录为solr-5.5.0\server\solr\目录下面,我们就在这个目录创建core,命名为new_core,新建conf文件夹,把solr-5.5.0\example\example-DIH\solr\solr\conf里面的内容复制到solr-5.5.0\server\solr\new_core\conf里面;在solr-5.5.0\server\solr\new_core目录新建data文件夹。
2、添加core
在Solr Admin管理界面如下操作,这样一个core就创建成功了。
二、初始化Core数据
1、创建数据库表
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`categoryName` varchar(64) DEFAULT NULL,
`brandName` varchar(64) DEFAULT NULL,
`productName` varchar(128) DEFAULT NULL,
`productUrl` varchar(256) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=206085 DEFAULT CHARSET=utf8;
2、定义Model
public class Product {
public static final String ID = "id";
public static final String CATEGORYNAME = "cateGoryName";
public static final String BRANDNAME = "brandName";
public static final String COMMODITYNAME = "commodityName";
public static final String COMMODITYIMGURL = "commodityImgUrl";
public static final String SUGGESTION = "suggestion";
@Field(ID)
private String id ;
@Field(CATEGORYNAME)
private String cateGoryName;
@Field(BRANDNAME)
private String brandName;
@Field(COMMODITYNAME)
private String commodityName;
@Field(COMMODITYIMGURL)
private String commodityImgUrl;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCateGoryName() {
return cateGoryName;
}
public void setCateGoryName(String cateGoryName) {
this.cateGoryName = cateGoryName;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCommodityName() {
return commodityName;
}
public void setCommodityName(String commodityName) {
this.commodityName = commodityName;
}
public String getCommodityImgUrl() {
return commodityImgUrl;
}
public void setCommodityImgUrl(String commodityImgUrl) {
this.commodityImgUrl = commodityImgUrl;
}
}
@Field里面的字段名称需要能在Coremanaged-schema配置文件里面找到,如果没有则手动添加:
<field name="cateGoryName" type="string" indexed="true" stored="true" multiValued="false" />
<field name="brandName" type="string" indexed="true" stored="true" multiValued="false" />
<!-- 定义solr索引结果的字段 -->
<field name="commodityName" type="string" indexed="true" stored="true" multiValued="false" />
<field name="commodityImgUrl" type="string" indexed="true" stored="true" multiValued="false" />
3、添加数据
这里用Spring JdbcTemplate 来添加数据的,20W条数据花了2个小时醉了。。。 代码如下:
public DataSource createDataSource (){
DriverManagerDataSource dataSource = new DriverManagerDataSource("jdbc:mysql://localhost:3306/solr?useUnicode=true&characterEncoding=UTF-8", "root", "XXXX");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
public JdbcTemplate getJdbcTemplate(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(createDataSource());
return jdbcTemplate;
}
public boolean batchInsertProducts(final List<Product> list) {
String sql = "insert into product(categoryName, brandName, productName, productUrl) values (?, ?, ?, ?)";
getJdbcTemplate().batchUpdate(sql,new BatchPreparedStatementSetter(){
@Override
public void setValues(PreparedStatement ps,int i)throws SQLException
{
String categoryName = list.get(i).getCateGoryName();
String brandName = list.get(i).getBrandName();
String productName = list.get(i).getCommodityName();
String productUrl = list.get(i).getCommodityImgUrl();
ps.setString(1, categoryName);
ps.setString(2, brandName);
ps.setString(3, productName);
ps.setString(4, productUrl);
}
@Override
public int getBatchSize()
{
return list.size();
}
});
return true;
}
数据库有数据了,下面就把数据库数据索引到Solr里面:
public List<Product> findProducts(){
return getJdbcTemplate().query("select * from product", new RowMapper<Product>() {
@Override
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
Product product = new Product();
product.setId(String.valueOf(rs.getInt("id")));
product.setCateGoryName(rs.getString("categoryName"));
product.setBrandName(rs.getString("brandName"));
product.setCommodityName(rs.getString("productName"));
product.setCommodityImgUrl(rs.getString("productUrl"));
return product;
}
});
}
List<Product> list = new SolrServer().findProducts();
solrClient.indexProducts(list);
/**
* 索引所有数据到Solr
* @param list
* @throws Exception
*/
public void indexProducts(List<Product> list) throws Exception{
if(ObjectUtils.isEmpty(list)){
return;
}
httpSolrClient.addBeans(list);
commitSolrClient(httpSolrClient);
}
这样就把数据库的所有数据索引(部分数据为了测试后面的智能Suggest模块手动做了修改)到Solr上面了,可以用Solr Admin 看下:
4、Solr 实现分页查询数据
QueryBuilder.java
public class QueryBuilder {
/**
* 拼接查询参数
* @param queryStr
* @param filterMap
* @param solrQuery
*/
public static void handlerSolrQueryParamByOr(Map queryStr, Map filterMap, SolrQuery solrQuery){
System.out.println(combileQueryStr(queryStr, true));
if(!ObjectUtils.isEmpty(queryStr) && queryStr.size() > 0 ){
solrQuery.setQuery(combileQueryStr(queryStr, true));
}
if(!ObjectUtils.isEmpty(filterMap) && filterMap.size() > 0){
solrQuery.setFilterQueries(combileQueryStr(filterMap, true)); //过滤结果集[这里可以不用or连接,也可以空格 例如:id:72 id:73 id:74]
}
}
/**
* 拼接查询参数
* @param queryStr
* @param filterMap
* @param solrQuery
*/
public static void handlerSolrQueryParamByAnd(Map queryStr, Map filterMap, SolrQuery solrQuery){
System.out.println(combileQueryStr(queryStr, true));
if(!ObjectUtils.isEmpty(queryStr) && queryStr.size() > 0 ){
solrQuery.setQuery(combileQueryStr(queryStr, false));
}
if(!ObjectUtils.isEmpty(filterMap) && filterMap.size() > 0){
solrQuery.setFilterQueries(combileQueryStr(filterMap, true)); //过滤结果集[这里可以不用or连接,也可以空格 例如:id:72 id:73 id:74]
}
}
private static String combileQueryStr(Map queryStr, boolean flag) {
if(ObjectUtils.isEmpty(queryStr)){
return null;
}
String joinerStr = "AND";
if(flag){
joinerStr = "OR";
}
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry entry : queryStr.entrySet()) {
stringBuilder.append(entry.getKey() + ":" + "*" + entry.getValue() + "* " + joinerStr + " ");
}
return flag?stringBuilder.toString().substring(0, stringBuilder.toString().length()-4):stringBuilder.toString().substring(0, stringBuilder.toString().length()-5);
}
}
分页查询函数:
/**
* 查询索引数据
* @param queryStr
* @param pageNo
* @param pageSize
* @param sort
* @return
* @throws Exception
*/
public Map queryData(Map map, Map filterMap, int pageNo, int pageSize, String sort, Opt opt) throws Exception {
Map maps = new HashMap();
List proList = new ArrayList<>();
SolrQuery solrQuery = new SolrQuery();
if(opt.equals(Opt.ADD)){
QueryBuilder.handlerSolrQueryParamByAnd(map, filterMap, solrQuery);
}else if(opt.equals(Opt.OR)){
QueryBuilder.handlerSolrQueryParamByOr(map, filterMap, solrQuery);
}
int start = (pageNo - 1) * pageSize;
solrQuery.setStart(start); // 设置起始位置
solrQuery.setRows(pageSize); // 设置页大小
solrQuery.setHighlight(true); // 启用高亮
solrQuery.addHighlightField("commodityName"); // 设置高亮字段
solrQuery.setHighlightFragsize(200); // 设置高亮内容大小
solrQuery.setHighlightSimplePre(""); // 设置高亮前缀
solrQuery.setHighlightSimplePost(""); // 设置高亮后缀
if(sort != null){
solrQuery.setSort("//TODD", ORDER.desc);
}
QueryResponse queryResponse = httpSolrClient.query(solrQuery);
int qtime = queryResponse.getQTime();
SolrDocumentList solrDocumentList = queryResponse.getResults();
Map<String, Map<String, List<String>>> highlightingMaps = queryResponse.getHighlighting();
long totals = solrDocumentList.getNumFound(); // 查询到的总记录数
if (!solrDocumentList.isEmpty()) {
Iterator it = solrDocumentList.iterator();
while (it.hasNext()) {
SolrDocument solrDocument = it.next();
String id = solrDocument.getFieldValue("id").toString();
Map> highlightFieldMap = highlightingMaps.get(id);
if (!highlightFieldMap.isEmpty()) {
List highlightName = highlightFieldMap.get("commodityName"); //这里对命中的字段做高亮展示
if (highlightName != null && !highlightName.isEmpty()) {
String name = highlightName.get(0);
solrDocument.setField("commodityName", name);
}
}
Product product = doc2Bean(solrDocument);
proList.add(product);
}
}
maps.put("qtime", qtime);
maps.put("totals", totals);
maps.put("results", proList);
return maps;
}
执行,查看效果,当然我们也可以对结果集进行过滤(模糊过滤;字段类型过滤):
数据如下:
相关阅读:用SolrJ操作Solr做搜索(下篇)
本文来自网易云社区,经作者田躲躲授权发布。
更多推荐
所有评论(0)