什么是solr:
solr是一个apache的全文检索引擎系统, 就是个war包, 部署到Tomcat下就可以独立运行,
我们使用它的客户端工具包 solrj 来远程调用solr服务器, 完成对索引库的操作(对索引库的添加修改删除, 查询)
solr底层使用lucene编写。
Lucene是一个全文检索引擎工具包,它不是一个完整的全文检索应用
而Solr的目标是打造一款企业级的搜索引擎系统
solr作用:
对于大数据量搜索或者查询, 速度非常快, 并且不会随着数据量的增大而减缓查询速度.
主要应用于大型的互联网项目中, 做大规模数据查询.
solr同类型技术:
elasticsearch是solr的同类型技术, elasticsearch在搜索的时候速度比solr要快.但是使用起来比solr要复杂。企业中现在elasticsearch比较流行
solr全文检索算法(倒排索引表算法):
使用场景: 大数据量搜索查询, 例如: 京东, 天猫的搜索功能.
描述: 查询前先将查询的内容抽取出来组成文档(document), 也就相当于字典的正文,
然后进行切分词, 将切分出来的词组成索引(index)相当于字段的目录,
查询的时候先查询索引根据索引找文档, 这个过程叫做全文检索
总结: 和字典原理一样.
优点: 查询速度快, 并且不会随着查询的数据量增大而变慢, 查询结果精确
缺点: 索引会额外占用大量的磁盘空间.(因此solrhome要与solr程序分离,不能部署到tomcat中)
顺序扫描法:
使用场景: 数据库中的like模糊查询就是用的这种算法
描述: 拿着需要查询的关键字, 到内容中逐字逐行的对比, 直到查询内容结束
优点: 查询准确
缺点: 查询速度慢, 并且会随着查询内容量增大越来越慢.
切分词:
将一句一句话, 切分成一个一个词, 去掉停用词(的, 地得, a,an,the等), 去掉空格和标点符号,
大写字母全部转成小写字母.
solr部署到Linux服务器步骤 *:
1. 在/usr/local目录下创建solr文件夹
2. 复制solr安装包, ik分词器包, tomcat包到这个目录下, 并且解压
3. 将solr/example/webapps/solr.war复制到tomcat/webapps目录下
4. 启动tomcat目的是对war包解压, 解压完成后关闭tomcat
5. 到tomcat/webapps目录中删除solr.war
6. 复制solr/example/lib/ext下的所有到 tomcat/webapps/solr/WEB-INf/lib目录下
7. 复制solr/example/solr目录到 /usr/loca/solr目录下并且改名问solrhome
8. 配置solrhome的位置到tomcat/webapps/solr/WEB-INF/web.xml中
9. 启动tomcat, 浏览器访问http://服务器地址:端口/solr看到solr页面后证明部署成功
solrhome就是solr的家, 一个solr服务器只能有一个solrhome, 一个solrhome中可以有多个solr实例,
里面的collection1 文件夹就是默认的solr实例, 一个solrhome中可以同时有多个实例, 实例中有索引库,
实例和实例之间是互相隔离的.
注意:
-
域名要先定义后使用, 没有定义的域名直接使用会报错
-
solr中添加数据的时候必须有主键域id, 没有会报错
-
solr中没有修改方法, 添加就是修改, 每次修改数据的时候, 都是根据id主键先去查询,如果查到了, 将原有数据删除, 将新数据添加进去, 这就是修改;如果没有根据id查询到数据, 则直接添加, 就成了添加.
-
删除:利用delete标签删除
根据id删除
<delete>
<query>id: 002</query>
</delete>
<commit/>
删除所有:
<delete>
<query>*:*</query>
</delete>
<commit/>
solr中域的作用:
自定义域名和类型就是为了保存数据库表中一列一列的数据, 表中的列名要和索引库的域名对应
solr中域的分类:
field普通域: 大多数情况都可以用这个域来完成, 主要定义了域名和域的类型.
dynamicField动态域: solr中域名要先定义后使用, 没有定义就使用会报错, 如果没有定义的域名想使用可以
模糊匹配动态域, 让没有定义的域名可以使用.
uniqueKey主键域: 在添加数据的时候必须有主键域, 没有会报错, 这个不用添加也不用修改,
就使用这个默认的域名id就可以.
copyField复制域: 复制域中有source叫做源域, dest代表目标域,
在维护数据的时候, 源域中的内容会复制到目标域中一份, 从目标域中搜索, 就相当于从多个源域中搜索一样.
ik中文分词器:
作用: 有中文语义分析的效果, 对中文分词效果好.
配置文件:
stopword.dic停止词典: 且分词的时候, 凡是出现在停止词典中的词都会被过滤掉.
ext.dic扩展词典: 凡是专有名词都会放到这里, 如果自然语义中不是一个词, 放到这里后solr切分词的时候就会切分成一个词.
SolrJ
solrJ是solr官方推出的客户端工具包, 将solrj的jar包放到我们项目中, 我们调用solrj中的api来远程给
solr服务器发送命令, solr服务器就可以完成对索引库的操作
SolrJ Demo
1、配置业务域
因为域名需要先定义后使用,所以要根据数据库表中的所需要数据的列名
在 solr的schema.xml文件定义要存储的Field,这里不详细配置
2、搭建环境
导入需要的jar包
3、演示solrJ的增删操作
public class TestIndexManager {
@Test
public void testIndexCreateAndUpdate() throws Exception {
/**
* 创建和solr服务器连接
* http://192.168.200.128:8080/solr是连接的默认实例也就是collection1实例
* http://192.168.200.128:8080/solr/collection2实例
*/
SolrServer solrServer = new HttpSolrServer("http://192.168.200.128:8080/solr");
//创建文档对象
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", "004");
doc.addField("title", "水浒传");
doc.addField("price", "50");
//添加或者修改
solrServer.add(doc);
//提交
solrServer.commit();
}
@Test
public void testIndexDelete() throws Exception {
SolrServer solrServer = new HttpSolrServer("http://192.168.200.128:8080/solr");
//单个删除
solrServer.deleteById("001");
//删除所有
solrServer.deleteByQuery("*:*");
//提交
solrServer.commit();
}
}
4、演示solrJ的查询操作
public class TestIndexSearch {
@Test
public void testIndexSearch() throws Exception {
SolrServer solrServer = new HttpSolrServer("http://192.168.200.128:8080/solr");
//创建查询对象
SolrQuery query = new SolrQuery();
//设置查询条件(查询所有)
query.setQuery("*:*");
//查询并返回响应
QueryResponse queryResponse = solrServer.query(query);
//从响应中获取结果集
SolrDocumentList results = queryResponse.getResults();
System.out.println("====count======" + results.getNumFound());
for (SolrDocument result : results) {
System.out.println("===id====" + result.get("id"));
System.out.println("====title===" + result.get("title"));
}
}
}
Spring Data Solr
Spring Data Solr其底层是对SolrJ的封装,使其由面向命令变得更加符合Java面向对象开发的思想
Spring Data Solr Demo
1、引入依赖(略)和 定义所需要的域名
2、配置文件
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.200.128:8080/solr" />
<!-- solr模板,使用solr模板可对索引库进行CRUD的操作 -->
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrServer" />
</bean>
</beans>
3、创建实体类(属性名与域名对应)
public class Item implements Serializable {
//属性名与域名不同则需要额外配置所对应的域名
@Field
private Long id;
@Field("item_title")
private String title;
@Field("item_price")
private BigDecimal price;
@Field("item_image")
private String image;
@Field("item_brand")
private String brand;
//get/set方法省略...
}
4、添加删除操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-solr.xml")
public class TestIndexManager {
@Autowired
private SolrTemplate solrTemplate;
@Test
public void testIndexCreatAndUpdate() {
List<Item> itemList = new ArrayList<Item>();
for(long i= 1; i < 100; i++) {
Item item = new Item();
item.setId(i);
item.setTitle("三星手机" + i);
item.setPrice(new BigDecimal("9999"));
item.setBrand("三星");
itemList.add(item);
}
//保存
solrTemplate.saveBeans(itemList);
//提交
solrTemplate.commit();
}
@Test
public void testIndexDelte() {
//根据主键域id删除
solrTemplate.deleteById("1");
//创建查询对象
Query query = new SimpleQuery("*:*");
//根据查询条件删除
solrTemplate.delete(query);
//提交
solrTemplate.commit();
}
}
5、查询操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-solr.xml")
public class TestIndexSearch {
@Autowired
private SolrTemplate solrTemplate;
@Test
public void testSearch() {
//创建查询对象
//Query query = new SimpleQuery("*:*");
//创建查询对象
Query query = new SimpleQuery();
//创建查询条件对象(注意这里的Criteria对象和mybatis中的那个不是同一个)
Criteria criteria = new Criteria("item_title").contains("手机");
//查询对象中放入查询条件
query.addCriteria(criteria);
//从第几条开始查询
query.setOffset(11);
//设置每页查询多少条数据
query.setRows(20);
//查询并返回结果
ScoredPage<Item> items = solrTemplate.queryForPage(query, Item.class);
//总页数
int totalPages = items.getTotalPages();
//查询到的总记录数
long totalElements = items.getTotalElements();
//查询到的数据集合
List<Item> content = items.getContent();
//每页有多少条数据
int numberOfElements = items.getNumberOfElements();
}
}
实现简单的搜索功能(利用Spring Data Solr)
1、向solr索引库导入数据库数据
省略配置spring环境
@Component
public class DataImportToSolr {
@Autowired
private SolrTemplate solrTemplate;
@Autowired
private ItemDao itemDao;
public void importItemDataToSolr() {
ItemQuery query = new ItemQuery();
ItemQuery.Criteria criteria = query.createCriteria();
criteria.andStatusEqualTo("1");
List<Item> items = itemDao.selectByExample(query);
if (items != null) {
for (Item item : items) {
//获取规格json格式字符串
String specJsonStr = item.getSpec();
Map map = JSON.parseObject(specJsonStr, Map.class);
item.setSpecMap(map);
}
//保存
solrTemplate.saveBeans(items);
//提交
solrTemplate.commit();
}
}
public static void main(String[] args) {
ApplicationContext contexnt = new ClassPathXmlApplicationContext("classpath*:spring/applicationContext*.xml");
DataImportToSolr bean = (DataImportToSolr)contexnt.getBean("dataImportToSolr");
bean.importItemDataToSolr();
}
}
2、定义域名 和 修改实体类
配置文件中定义要使用的域名
pojo实体类的属性上加 @Field 注解
3、web层接收页面传入的关键字参数
由于这里响应回页面的是json流,所以页面自己实现跳转功能
@RestController
@RequestMapping("/itemsearch")
public class SearchController {
@Reference
private SearchService searchService;
/**
* 返回的数据有查询到的集合, 总记录数, 总页数
*/
@RequestMapping("/search")
public Map<String, Object> search(@RequestBody Map paramMap) {
Map<String, Object> resultMap = searchService.search(paramMap);
return resultMap;
}
}
4、Service
@Service
public class SearchServiceImpl implements SearchService {
@Autowired
private SolrTemplate solrTemplate;
@Override
public Map<String, Object> search(Map paramMap) {
/**
* 获取查询条件
*/
//获取查询关键字
String keywords = String.valueOf(paramMap.get("keywords"));
//当前页
Integer pageNo = Integer.parseInt(String.valueOf(paramMap.get("pageNo")));
//每页查询多少条数据
Integer pageSize = Integer.parseInt(String.valueOf(paramMap.get("pageSize")));
/**
* 封装查询对象
*/
//创建查询对象
Query query = new SimpleQuery();
//创建查询条件对象
Criteria criteria = new Criteria("item_keywords").is(keywords);
//将查询条件放入查询对象中
query.addCriteria(criteria);
//计算从第几条开始查询
if (pageNo == null || pageNo <= 0) {
pageNo = 1;
}
Integer start = (pageNo - 1) * pageSize;
//设置从第几条开始查询
query.setOffset(start);
//设置每页查询多少条数据
query.setRows(pageSize);
/**
* 查询并返回结果
*/
ScoredPage<Item> items = solrTemplate.queryForPage(query, Item.class);
Map<String, Object> resultMap = new HashMap<>();
//查询到的结果集
resultMap.put("rows", items.getContent());
//查询到的总页数
resultMap.put("totalPages", items.getTotalPages());
//查询到的总条数
resultMap.put("total", items.getTotalElements());
return resultMap;
}
}
spring Data Solr里面的Criteria对象中的方法, is和contains的区别:
contains: 是相当于数据库中like模糊查询的方式, 将查询关键字当成一个整体进行模糊查询
is: 将查询关键字使用对应这个域的分词器进行切分词, 然后将切分出来的每个词, 进行查询.