Solr-Solrj-Spring-Data-Solr
什么是Solr
- 直接使用sql搜索存在的问题:
- 大多数搜索引擎应用都必须具有某种搜索功能;
- 搜索功能往往是巨大的资源消耗;
- 它们由于沉重的数据库加载而拖垮你的应用的性能;
- 所有我们一般在做搜索的时候会把它单独转移到一个外部的搜索服务器当中进行;
- Apache Solr是一个流行的开源搜索服务器;
- Apache Solr:
- Solr是一个开源搜索平台,用于构建搜索应用程序;
- 是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口;
- 它建立在Lucene(全文搜索引擎)之上,Solr是企业级的,快速的和高度可扩展的;
- 用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。
- 为什么选择Solr?
- 第一点原因:来自SQL数据库在性能上缺乏亮点,基本上,你需要在你的查询中使用JOIN操作。
- 第二点原因:文档的天然数据特性松散的文本文件,这种查询都是需要使用LIKE,然而join和like都是性能杀手,在目前的数据库引擎中是不方便的;
- solr底层采用的是倒排索引,这种数据结构类似与美化过的词典。
- Solr 关键特性
- 基于标准的开放接口:Solr搜索服务器支持通过XML、JSON和HTTP查询和获取结果。
- 易管理:Solr可以通过HTML页面管理,Solr配置通过XML完成。
- 可伸缩性:能够有效地复制到另外一个Solr搜索服务器。
- 灵活的插件体系:新功能能够以插件的形式方便的添加到Solr服务器上。
- 强大的数据导入功能:数据库和其他结构化数据源现在都可以导入、映射和转化。
Solr安装
- 1、上传安装包:
- 2、对以上内容进行解压
- 解压tomcat:tar -zxvf apache-tomcat-8.5.32.tar.gz
- 改名:mv apache-tomcat-8.5.32 tomcat
- 解压solr:tar -zxvf solr-4.10.3.tar
- 解压IK(中文分词工具包):unzip IKAnalyzer.zip
- 3、复制solr.war到tomcat/webapp下
- cd /usr/local/solr/solr-4.10.3/example/webapps/
- cp solr.war /usr/local/solr/tomcat/webapps/
- 4、启动tomcat让solr.war自动解压
- /usr/local/solr/tomcat/bin/startup.sh
- 5、关闭tomcat
- /usr/local/solr/tomcat/bin/shutdown.sh
- 6、进入到webapps删除solr.war包
- cd /usr/local/solr/tomcat/webapps/
- rm -rf solr.war
- 7、将solr-4.10.3/example/lib/ext/目录下的所有jar包拷贝到/usr/local/solr/tomcat/webapps/solr/WEB-INF/lib目录中
- cd /usr/local/solr/solr-4.10.3/example/lib/ext
- cp * /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib
- 8、将solr-4.10.3/example/目录下的solr文件夹复制到/usr/local/solr/目录下并且重命名为solrhome
- cd /usr/local/solr/solr-4.10.3/example/
- cp -r solr /usr/local/solr/
- mv solr solrhome
- 9、配置tomcat/webapps/solr/WEB-INF/web.xml家的位置
- cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/
- vim web.xml
- 添加solrhome:/usr/local/solr/solrhome
- 10、启动tomcat
- /usr/local/solr/tomcat/bin/startup.sh
中文分词器
- IK Analyzer简介
- IK Analyzer 是一个开源的,基亍 java 语言开发的轻量级的中文分词工具包。
- 它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件
- IK实现了简单的分词歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。
- 作用:有中文语义分析的效果,对中文分词效果好.
- IK Analyzer(配置)
- 1、把IKAnalyzer2012FF_u1.jar添加到solr工程的lib目录下
- cd /usr/local/solr/IKAnalyzer/
- cp IKAnalyzer2012FF_u1.jar /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib/
- 1、把IKAnalyzer2012FF_u1.jar添加到solr工程的lib目录下
- 2、创建WEB-INF/classes文件夹
- cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/
- mkdir classes
- 3、把扩展词典、停用词词典、配置文件放到 solr 工程的 WEB-INF/classes 目录下
- cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes
- cp /usr/local/solr/IKAnalyzer/IKAnalyzer.cfg.xml ./
- cp /usr/local/solr/IKAnalyzer/ext_stopword.dic ./
- mv ext_stopword.dic stopword.dic
- 4、修改IKAnalyzer.cfg.xml配置文件
- stopword.dic已经有了,ext.dic还没有
- 创建ext.dic:touch ext.dic
- stopword.dic-停止词典:切分词的时候,凡是出现在停止词典中的词都会被过滤掉.
- ext.dic-扩展词典:凡是专有名词都会放到这里,如果自然语义中不是一个词, 放到这里后solr切分词的时候就会切分成一个词.
- 5、配置分词器
- 修改 Solrhome 的 schema.xml 文件:
- cd /usr/local/solr/solrhome/collection1/conf
- vim schema.xml
- 在最后添加
- 修改 Solrhome 的 schema.xml 文件:
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
- 自定义域名使用自己创建的分词器
<field name="content_ik" type="text_ik" indexed="true" stored="true"/>
- 6、配置完毕后重启tomcat:在浏览器进行访问http://192.168.1.9:8080/solr
域的分类
- 什么是域
- 域相当于数据库的表字段,用户存放数据
- 用户根据业务需要去定义相关的Field(域)
- 域的分类:
field普通域:大多数情况都可以用这个域来完成,主要定义了域名和域的类型.
copyField复制域:复制域中有source叫做源域,dest代表目标域,在维护数据的时候,源域中的内容会复制到目标域中一份,从目标域中搜索,就相当于从多个源域中搜索一样。
dynamicField动态域:solr中域名要先定义后使用,没有定义就使用会报错如果没有定义的域名想使用可以模糊匹配动态域,让没有定义的域名可以使用。
uniqueKey主键域:在添加数据的时候必须有主键域,没有会报错,这个不用添加也不用修改,就使用这个默认的域名id就可以.
- 域的常用属性
- name:指定域的名称
- type:指定域的类型
- indexed:是否索引
- stored:是否存储
- required:是否必须
- multiValued:是否多值
- 普通域
-
<field name="content_ik" type="text_ik" indexed="true" stored="true"/> <field name="item_goodsid" type="long" indexed="true" stored="true"/> <field name="item_title" type="text_ik" indexed="true" stored="true"/> <field name="item_price" type="double" indexed="true" stored="true"/> <field name="item_image" type="string" indexed="false" stored="true"/> <field name="item_category" type="string" indexed="true" stored="true"/> <field name="item_seller" type="text_ik" indexed="true" stored="true"/> <field name="item_brand" type="string" indexed="true" stored="true"/> <field name="item_updatetime" type="date" indexed="true" stored="true"/>
-
- 复制域
-
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/> <copyField source="item_title" dest="item_keywords"/> <copyField source="item_category" dest="item_keywords"/> <copyField source="item_seller" dest="item_keywords"/> <copyField source="item_brand" dest="item_keywords"/>
-
- 动态域
-
<dynamicField name="item_spec_*" type="string" indexed="true" stored="true"/>
-
Solrj
- 概述
solrJ是solr官方推出的客户端工具包,将solrj的jar包放到我们项目中,我们调用solrj中的api来远程给solr服务器发送命令,solr服务器就可以完成对索引库的操作(添加修改删除查询).
- 操作步骤
- 创建一个普通的Java工程
- 添加soloJ相关Jar包
- 添加或者修改(修改时,会把以前的内容删除,然后再添加)
- 查询所有
- 删除
Spring Data Solr
- Spring Data Solr简介
- Spring Data Solr就是为了方便Solr的开发所研制的一个框架
- 其底层是对SolrJ(官方API)的封装
- Spring Data Solr入门
- 创建maven工程SpringSolrProject jar项目
- 2.pom.xml中引入依赖
<properties>
<spring.version>5.1.7.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>1.5.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
</dependencies>
- 3.在src/main/resources下创建:applicationContext-solr.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/data/solr
http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- solr服务器地址 -->
<solr:solr-server id="solrServer" url="http://192.168.1.88:8080/solr" />
<!-- solr模板,使用solr模板可对索引库进行CRUD的操作 -->
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrServer" />
</bean>
</beans>
- 4.创建 cn.fmjava.pojo 包 引入 Item实体类
/**
* @author cpm
*/
@Data
public class Item implements Serializable {
/**
* 商品id,同时也是商品编号
*/
@Field
private Long id;
/**
* 商品标题
*/
@Field("item_title")
private String title;
/**
* 商品卖点
*/
private String sellPoint;
/**
* 商品价格,单位为:元
*/
@Field("item_price")
private BigDecimal price;
private Integer stockCount;
/**
* 库存数量
*/
private Integer num;
/**
* 商品条形码
*/
private String barcode;
/**
* 商品图片
*/
@Field("item_image")
private String image;
/**
* 所属类目,叶子类目
*/
private Long categoryid;
/**
* 商品状态,1-正常,2-下架,3-删除
*/
private String status;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
@Field("item_updatetime")
private Date updateTime;
private String itemSn;
private BigDecimal costPirce;
private BigDecimal marketPrice;
private String isDefault;
@Field("item_goodsid")
private Long goodsId;
private String sellerId;
private String cartThumbnail;
@Field("item_category")
private String category;
@Field("item_brand")
private String brand;
private String spec;
@Field("item_seller")
private String seller;
@Dynamic
@Field("item_spec_*")
private Map<String,String> specMap;
public Map<String, String> getSpecMap() {
return specMap;
}
public void setSpecMap(Map<String, String> specMap) {
this.specMap = specMap;
}
private static final long serialVersionUID = 1L;
}
- 5.配置业务域
- 修改solrhome的schema.xml 文件 设置业务系统 Field
<field name="item_goodsid" type="long" indexed="true" stored="true"/>
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_price" type="double" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category" type="string" indexed="true" stored="true" />
<field name="item_seller" type="text_ik" indexed="true" stored="true" />
<field name="item_brand" type="string" indexed="true" stored="true" />
<field name="item_updatetime" type="date" indexed="true" stored="true" />
- 复制域的作用在于将某一个Field中的数据复制到另一个域中
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_category" dest="item_keywords"/>
<copyField source="item_seller" dest="item_keywords"/>
<copyField source="item_brand" dest="item_keywords"/>
- 动态扩充字段时,我们需要使用动态域
<dynamicField name="item_spec_*" type="string" indexed="true" stored="true" />
- 配置:
- cd /usr/local/solr/solrhome/collection1/conf
- vim schema.xml
- 重启tomcat
/usr/local/solr/tomcat/bin/shutdown.sh /usr/local/solr/tomcat/bin/startup.sh
- 6.在实体类字段上添加@Field注解
- 7.创建测试类
- 添加
- 删除
- 查询
- 示例代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-solr.xml"})
public class TestSolr {
@Autowired
private SolrTemplate solrTemplate;
@Test
public void addItem(){
/*Item item = new Item();
item.setId(1L);
item.setBrand("brand");
item.setCategory("Category");
item.setPrice(new BigDecimal("100"));
item.setTitle("title123");
item.setImage("aaaa");
solrTemplate.saveBean(item);
solrTemplate.commit();*/
ArrayList arrayList = new ArrayList();
for (long i=2; i < 100;i++){
Item item = new Item();
item.setId(i);
item.setBrand("brand"+i);
item.setCategory("Category"+i);
item.setPrice(new BigDecimal("100"+i));
if (i % 2 ==0){
item.setTitle("鲁班"+i);
}else {
item.setTitle("title123"+i);
}
item.setImage("aaaa"+i);
arrayList.add(item);
}
solrTemplate.saveBeans(arrayList);
solrTemplate.commit();
}
@Test
public void testDelete(){
/*solrTemplate.deleteById("1");
solrTemplate.commit();*/
SimpleQuery simpleQuery = new SimpleQuery("*:*");
solrTemplate.delete(simpleQuery);
solrTemplate.commit();
}
@Test
public void testQuery(){
SimpleQuery simpleQuery = new SimpleQuery("*:*");
//设置分页
simpleQuery.setOffset(95); //从哪条记录开始查
simpleQuery.setRows(5);//本次查询多少条记录
ScoredPage<Item> items = solrTemplate.queryForPage(simpleQuery, Item.class);
//总页数
int totalPages = items.getTotalPages();
System.out.println("totalPages="+totalPages);
//总记录数
long totalElements = items.getTotalElements();
System.out.println("totalElements="+totalElements);
//本次查询的记录数
int numberOfElements = items.getNumberOfElements();
System.out.println("numberOfElements="+numberOfElements);
//本次查询的数据
List<Item> content = items.getContent();
for (Item item : content) {
System.out.println(item.getTitle());
}
}
@Test
public void testQuery2(){
SimpleQuery simpleQuery = new SimpleQuery();
Criteria criteria = new Criteria("item_title").contains("鲁班");
simpleQuery.addCriteria(criteria);
//设置分页
simpleQuery.setOffset(10); //从哪条记录开始查
simpleQuery.setRows(5);//本次查询多少条记录
ScoredPage<Item> items = solrTemplate.queryForPage(simpleQuery, Item.class);
//本次查询的数据
List<Item> content = items.getContent();
for (Item item : content) {
System.out.println(item.getTitle());
}
}
}