最近在做毕业设计,一个电商APP,遇到搜索商品的问题,以往做的数据库模糊查询感觉不是那么的高大上,于是决定使用Solr搜索引擎,在此给同样想法的小伙伴一点借鉴,望共勉。

一、Solr部署

1.Solr下载

部署solr通常有2中方式,一个是部署在外部的web容器中例如tomcat,另一个是使用solr内置的jetty作为web容器。因为我做的是微服务项目,感觉独立部署方便一点,所以我们这里采用内置的jetty作为web容器的部署方式。

Solr官网下载适合的版本,windows下选择后缀为.zip的安装包,博主选择的是5.2.1,下载之后找到合适的位置解压

2.Sorl启动 

在cmd窗口进入solr的解压目录下的bin文件夹点击下列命令:

注意窗口不要关闭,否则会断开服务器

在浏览器访问solr的管理界面 ,出现下面界面表示启动成功

3. 创建core 

方法一:命令行创建
bin目录下cmd窗口执行,如下命令:

 方法二:solr管理页面 创建

1.在下图目录中新建new_core

2.上图中的configsets文件中存放的是基本的配置文件,把configsets中的basic_configs下的conf拷贝到new_core中,然后新建文件夹data,作为索引数据的存放文件

3.在solr管理页面中点击core admin 下的 add core,修改name 和instanceDir为new_core,然后点击add core 

4.创建完成 

刷新界面,可以看到我们创建的core

 二、Solr使用

导入数据

solr中负责导入数据的模块叫做DataImportHandler,它有多种实现方式

数据库导入

这里做示范,我们选择一个比较简单的表结构进行数据导入

solr支持多中形式的数据导入,其中最常用的就是从数据库导入数据
我们可以从solr自带的/example/example-DIH/solr/db/conf中找到从数据库导入数据的相关配置作为参考,然后修改coreTest1内的配置

1.修改solrconfig.xml

在最后其后添加如下配置

<requestHandler name="/dataimport" class="solr.DataImportHandler">
    <lst name="defaults">
      <str name="config">db-data-config.xml</str>
    </lst>
  </requestHandler>

2.从example中拷贝db-data-config.xml到coreTest1,并根据数据库的使用情况进行修改,我这里使用的是mysql

<dataConfig>
    <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/shopsystem" user="root" password="root" />
    <document>
        <entity name="item" query="select * from user">
            <field column="user_id" name="id" />
            <field column="user_sex" name="user_sex" />
            <field column="user_name" name="user_name" />
        </entity>
    </document>
</dataConfig>

这里有个坑,column对应数据库的列名,name为显示的列名,对应下面schema.xml文件中的name,这里必须要有一个name为id

3.将mysql的数据库连接jar拷贝到solr根目录的dist文件中,然后修改solrconfig.xml,加载这个jar包

<lib dir="${solr.install.dir:../../../..}/dist/" regex=".*\.jar" />

4.修改managed-schema为schema.xml,如果已经存在则忽略,根据db-data-config.xml中的配置的从数据库导入的字段进行修改.

<field name="user_sex" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="user_name" type="string" indexed="true" stored="true" required="true" multiValued="false" />

这里不需要再设置id列,因为这个文件中已经默认存在,这也是第2步中注意事项所说的 

5.在core admin选项中 选择刚刚修改的coreTest1,然后点击reload按钮,加载刚刚上面修改的配置

6.开始导入数据,选择刚刚修改的coreTest1下面的DataImport选项,然后点击execute按钮

7.如果还是没成功可以去左侧导航栏的Logging查看那个地方有问题,一步步总会成功的

 solr管理界面导入

 服务器导入

数据库导入个人感觉适合查询数据集中的情况,我要查询的数据在多个表中, 而且数据会插入不同的core中,所以我选择了在服务端随着数据的改变通过代码对数据进行更新。

下面是一个导入数据的工具类,直接调用即可,读者可根据注解自行修改

@Service
public class SolrService<T> {

	// 指定solr服务器的地址
	private final static String SOLR_URL = "http://localhost:8983/solr/";

	private String solrCore = "shopstem";// 指定的存储数据的collection

	/**
	 * 创建SolrServer对象
	 * 
	 * 该对象有两个可以使用,都是线程安全的 1、CommonsHttpSolrServer:启动web服务器使用的,通过http请求的 2、
	 * EmbeddedSolrServer:内嵌式的,导入solr的jar包就可以使用了 3、solr
	 * 4.0之后好像添加了不少东西,其中CommonsHttpSolrServer这个类改名为HttpSolrClient
	 * 
	 * @return
	 */
	public HttpSolrClient createSolrServer() {
		HttpSolrClient solr = null;
		solr = new HttpSolrClient(SOLR_URL);
		solr.setConnectionTimeout(100);
		solr.setDefaultMaxConnectionsPerHost(100);
		solr.setMaxTotalConnections(100);
		return solr;
	}

	public void addBeansBatch(List<T> list) throws IOException, SolrServerException {
		HttpSolrClient solr = new HttpSolrClient(SOLR_URL + solrCore);
		solr.addBeans(list);
		solr.commit();
		solr.close();
	}

	public void addBean(T t) throws IOException, SolrServerException {
		HttpSolrClient solr = new HttpSolrClient(SOLR_URL + solrCore);
		solr.addBean(t);
		solr.commit();
		solr.close();
	}

	/**
	 * 往索引库添加文档
	 * 
	 * @throws IOException
	 * @throws SolrServerException
	 */
	public void addDoc() throws SolrServerException, IOException {
		// 构造一篇文档
		SolrInputDocument document = new SolrInputDocument();
		// 往doc中添加字段,在客户端这边添加的字段必须在服务端中有过定义
		document.addField("id", "4");
		document.addField("goods_name", "LG 55LG63CJ-CA 4K液晶");
		document.addField("goods_price", "1000");
		document.addField("attr_name", "黄色,自由组合");
		document.addField("type_name", "超薄电视");
		// 获得一个solr服务端的请求,去提交 ,选择具体的某一个solr core
		HttpSolrClient solr = new HttpSolrClient(SOLR_URL + solrCore);
		solr.add(document);
		solr.commit();
		solr.close();
	}

	/**
	 * 根据id从索引库删除文档
	 */
	public void deleteDocumentById(String id) throws Exception {
		// 选择具体的某一个solr core
		HttpSolrClient server = new HttpSolrClient(SOLR_URL + solrCore);
		// 删除文档
		server.deleteById(id);
		// 删除所有的索引
		//server.deleteByQuery("*:*");
		// 提交修改
		server.commit();
		server.close();
	}

	/**
	 * 查询
	 * 
	 * @throws Exception
	 */
	public List<Goods> querySolr(String search) throws Exception {
		HttpSolrClient solrServer = new HttpSolrClient(SOLR_URL + solrCore);
		SolrQuery query = new SolrQuery();
		// 下面设置solr查询参数
		query.set("q", search);// 参数q 查询所有
		//query.set("q","*长虹*");//相关查询,比如某条数据某个字段含有周、星、驰三个字 将会查询出来
		// ,这个作用适用于联想查询

		// 参数fq, 给query增加过滤查询条件
		// query.addFilterQuery("id:[0 TO 9]");//id为0-9

		// 给query增加布尔过滤条件
		// query.addFilterQuery("description:演员"); //description字段中含有“演员”两字的数据

		// 参数df,给query设置默认搜索域
		// query.set("df", "name");

		//query.setQuery("name:*");
		//query.setQuery("goods_name:"+search+" OR goods_price:"+search+"  OR type_name:"+search+"" );//name
		// 包含zhangsan或者123
		// query.setQuery("name:*zhangsan* AND description:*zhangsan*" );//
		// name包含且

		// 分组查询
		//query.setFacet(true);
		//query.addFacetField("name", "description");// 两个域有各自独立的结果
		/*
		 * FacetComponet有两种排序选择,分别是count和index,
		 * count是按每个词出现的次数,index是按词的字典顺序。如果查询参数不指定facet.sort,solr默认是按count排序。
		 */
		query.setFacetSort(FacetParams.FACET_SORT_COUNT);
		/* query.setFacetLimit(101); */// 设置返回结果条数 ,-1表示返回所有,默认值为100
		/* query.setParam(FacetParams.FACET_OFFSET, "100"); */// 开始条数,偏移量,它与facet.limit配合使用可以达到分页的效果
		query.setFacetMinCount(1);// 设置 限制 count的最小返回值,默认为0
		query.setFacetMissing(false);// 不统计null的值
		/* query.setFacetPrefix("test");//设置前缀 */

		// 参数sort,设置返回结果的排序规则
		// query.addSort("id",SolrQuery.ORDER.asc);
		// query.addSort("name", SolrQuery.ORDER.desc);

		// 设置分页参数
		// query.setStart(0);
		// query.setRows(10);//每一页多少值

		// 参数hl,设置高亮
		query.setHighlight(true);
		// 设置高亮的字段
		query.addHighlightField("goods_name");
		// 设置高亮的样式
		query.setHighlightSimplePre("<font color='red'>");
		query.setHighlightSimplePost("</font>");

		// 获取查询结果
		QueryResponse response = solrServer.query(query);
		// 两种结果获取:得到文档集合或者实体对象

		// 获取高亮数据结果
		// Map<String, Map<String, List<String>>> map =
		// response.getHighlighting();

		// 得到FacetField结果
		System.out.println(response.getFacetFields());

		// 获取高亮数据结果
		System.out.println("高亮数据结果" + response.getHighlighting());

		// 查询得到文档的集合
		SolrDocumentList solrDocumentList = response.getResults();
		System.out.println("通过文档集合获取查询文档数量:" + solrDocumentList.getNumFound());
		// 遍历列表
		List<Goods> list = new ArrayList<Goods>();
		for (SolrDocument doc : solrDocumentList) {
			Goods goods = new Goods();
			goods.setGoods_id(Integer.parseInt(doc.get("goods_id").toString().substring(doc.get("goods_id").toString().indexOf("[")+1,doc.get("goods_id").toString().length()-1)));
			//goodsdetail.setGoods_name( doc.get("goods_name").toString().substring(doc.get("goods_name").toString().indexOf("[")+1,doc.get("goods_name").toString().length()-1));
			//goodsdetail.setType_name( doc.get("type_name").toString().substring(doc.get("type_name").toString().indexOf("[")+1,doc.get("type_name").toString().length()-1));
			//goodsdetail.setAttr_name(doc.get("attr_name").toString().substring(doc.get("attr_name").toString().indexOf("[")+1,doc.get("attr_name").toString().length()-1));
			System.out.println(goods.toString());
			list.add(goods);
		}

		// 得到实体对象
//		List<GoodsDetail> tmpLists = response.getBeans(GoodsDetail.class);
//		if (tmpLists != null && tmpLists.size() > 0) {
//			System.out.println("实体对象赋值内容:");
//			for (Person per : tmpLists) {
//				System.out.println(per.toString());
//			}
//		}
//		System.out.println(tmpLists);
		return list;
	}

	public static void main(String[] args) throws Exception {
		SolrService solr = new SolrService();
		// solr.createSolrServer();
		solr.addDoc();
		//solr.addPersonIndex();
		//solr.addPersonBatch();
		//solr.deleteDocumentById("149d9e7b-064f-4977-bc21-a9c0c61fbf32");
		//solr.querySolr("超薄电视");
	}

}

下面是我放一下我所实现的web端及APP端的搜索功能图

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐