Solr:企业级搜索应用服务器
在海量数据下,对MySQL等数据库进行模糊查询或者条件查询的效率是非常低的。模糊查询会使索引失效而进行全表扫描,所以就需要有东西去提升搜索效率。
SpringBoot中使用Solr
solr查询
// 直接查询总条数
long count =solrTemplate.count(“索引库名称”, query);
// 查询条件:判断当该字段不为空时
Criteria criteria =new Criteria("索引字段").isNotNull();
// 这里的分页是必须设置的,Rows 决定了查询的总数量的大小
Query query = new SimpleQuery();
query.setOffset(0L);
query.setRows(Integer.MAX_VALUE);
// 此处的分页是分组中的分页
// 这里的分页对应的是 groupEntry.getResult().getContent() 中的值,但是即使设置为0,也不会影响 groupEntry.getResult().getTotalElements()
GroupOptions groupOptions = new GroupOptions().addGroupByField("testinfo_devtype");
groupOptions.setOffset(0);
groupOptions.setLimit(0);
query.setGroupOptions(groupOptions);
- 导入maven依赖
<!--solr搜索依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
</dependency>
- 配置solr地址
spring:
data:
solr:
# Solr的地址
host: http://localhost:8983/solr
-
编写添加方法
// 批量添加 @PostMapping("saveAll") public void saveDatas() { List<Products> list = new ArrayList<>(); // 创建实体 Products products1 = new Products(); products1.setId("1"); products1.setMdName("rrp"); products1.setMdCode("B02010130395"); products1.setMdAge("121.196.150.36"); Products products2 = new Products(); products2.setId("2"); products2.setMdName("yq"); products2.setMdCode("B02010130395"); products2.setMdAge("121.196.150.36"); Products products3 = new Products(); products3.setId("3"); products3.setMdName("pg"); products3.setMdCode("B02010130395"); products3.setMdAge("121.196.150.36"); Products products4 = new Products(); products4.setId("4"); products4.setMdName("lh"); products4.setMdCode("B02010140495"); products3.setMdAge("121.196.150.36"); list.add(products1); list.add(products2); list.add(products3); list.add(products4); // 给索引库添加数据 UpdateResponse meta_db = solrTemplate.saveBeans("meta_db", list); // 提交 solrTemplate.commit("meta_db"); }
// 单个添加 @PostMapping public void saveData(){ // 创建实体 Products products = new Products(); products.setId("1"); products.setMdName("zhangsan"); products.setMdCode("10"); products.setMdAge("12"); // 给索引库添加数据 UpdateResponse meta_db = solrTemplate.saveBean("meta_db", products); // 提交 solrTemplate.commit("meta_db"); }
-
编写solr删除方法
@DeleteMapping public void deleteData() throws Exception { // 1. 根据id删除 solrTemplate.deleteByIds("meta_db",Arrays.asList("12")); // 2. 将满足查询条件的全部删除 SolrDataQuery query = new SimpleQuery(); // 设置查询条件 query.addCriteria(Criteria.where("md_code").startsWith("4")); solrTemplate.delete("meta_db", query); // 提交 solrTemplate.commit("meta_db"); }
-
编写solr查询方法
@GetMapping
public Object select() {
// 1. 指定主键id查询
// 参数1:索引库,参数2:指定id,参数3:查询的类型
Products meta_db = solrTemplate.getById("meta_db", "12", Products.class).get();
// 2. 根据某个字段简单查询(该字段为索引库(Filed)中的字段)
// Query : 指定查询条件
Query query = new SimpleQuery("md_age:19");
Page<Products> ans = solrTemplate.query("meta_db", query, Products.class);
// 3. 查询'md_name'字段中包含'测试'的文档(类似于模糊查询?)
Query queryByTest = new SimpleQuery();
// 索引库(Filed)中的字段 根据关键字'测试'查询
queryByTest.addCriteria(new Criteria("md_name").contains("测试"));
Page<Products> queryByTestResult = solrTemplate.query("meta_db", queryByTest, Products.class);
// 多条件查询:lessThan() 查询某字段的值小于其参数的所有值
queryByTest.addCriteria(new Criteria("md_name").contains("测试").and("id").lessThan(13));
Page<Products> queryByTwoTestResult = solrTemplate.query("meta_db", queryByTest, Products.class);
// 主要用来快速过滤,配合 query 进行操作
query = new SimpleQuery("md_code: *4*");
query.addFilterQuery(FilterQuery.filter(Criteria.where("md_age").contains("19")));
ans = solrTemplate.query("meta_db", query, Products.class);
// 4. 查询 只返回指定的字段
SimpleQuery simpleQuery = new SimpleQuery();
simpleQuery.addCriteria(Criteria.where("md_age").contains("19"));
// fl 查询 只返回查询到的数据的‘md_name’字段数据
simpleQuery.addProjectionOnFields("md_name");
List<Products> simpleQueryans = solrTemplate.query("meta_db", simpleQuery, Products.class).getContent();
// 5. 范围查询 排序
query = new SimpleQuery();
// 查询id值在12-13之间的数据 参数3,参数4 :分别表示不包含下界 上界,即为开区间
query.addCriteria(Criteria.where("id").between(12, 14, false, false));
// Sort.by() 根据某字段排序 descending() 倒排 ascending() 正排
query.addSort(Sort.by("id").ascending());
simpleQueryans = solrTemplate.query("meta_db", query, Products.class).getContent();
// 6. 分页查询
query = new SimpleQuery("*:*");
query.addSort(Sort.by("id").ascending());
// 指定偏移量,从0开始开训
query.setOffset(2L);
// 查询的size数量
query.setRows(4);
ans = solrTemplate.queryForPage("meta_db", query, Products.class);
// 文档数量
long totalDocNum = ans.getTotalElements();
// 文档集合
List<Products> docList = ans.getContent();
// 7. 分组查询
query = new SimpleQuery("*:*");
// addGroupByField() 分组的标准
// 请注意,分组查询,必须指定 offset/limit, 否则会抛异常,Pageable must not be null!
// GroupOptions:
// 必须指定 offset/limit,当两个条件都没有时会抛异常
// 只指定 offset 时,limit 默认为 1
// 只指定 limit 时,offset 默认为 0
GroupOptions groupOptions = new GroupOptions().addGroupByField("md_name").setOffset(0).setLimit(10);
query.setGroupOptions(groupOptions);
GroupPage<Products> groupResultans = solrTemplate.queryForGroupPage("meta_db", query, Products.class);
GroupResult<Products> groupResult = groupResultans.getGroupResult("md_name");
Page<GroupEntry<Products>> entries = groupResult.getGroupEntries();
for (GroupEntry<Products> sub : entries) {
// 分组字段的具体值
String groupValue = sub.getGroupValue();
// 组内成员
Page<Products> contentList = sub.getResult();
System.out.println("queryGroup v=" + groupValue + " content=" + contentList.getContent());
}
return entries;
}
filed字段常用属性
可以为给定字段类型指定的属性为分三大类:
- 特定于字段类型的类型属性
- 常规属性,solr支持任何字段类型
- 字段默认属性,可以在字段类型上指定,将由使用此类型的字段而不是默认行为继承
-
常规属性
name:fieldType的名称。
class:用于存储和索引此类型数据的类名。
positionIncreamentGap:对于多值字段,指定多个值之间的距离,以防止虚拟短语匹配。
autoGeneratePhraseQueries:对于文本字段,如果true,Solr自动为相邻术语生成短语查询。如果为false,术语必须用双引号括起来作为短语。
synonymQueryStyle:用于组合重叠查询项(即同义词)的分类的查询。 -
字段默认属性
这些属性可以在字段类型上指定,也可以在单个字段上指定,以覆盖字段类型的默认值。
正向索引和反向索引
也可以叫做正排序和倒排序
Solr web管理后台介绍
-
Dashboard 仪表盘
显示Solr的基本信息,包含solr版本,包含系统内存和jvm内存的使用情况,jvm参数等
-
Logging solr的运行日志
solr的运行日志, 用来查看solr运行是否有警告或者异常,以便及时处理
-
Core Admin 索引库管理
索引库管理:
这个界面很重要,这使多核的配置,索引库的优化等,变得非常简单;
主要功能包括:Add Core(添加核心,即索引库),Unload(卸载核心),Rename(重命名核心),Optimize(优化索引库)。
-
Core Selector 核心选择器
-
Overview(概览):查看索引的情况,例如:看看Num docs数量是否增加。包含基本统计如当前文档数;和实例信息如当前核心的配置目录;
-
Analysis(分析):检验分词效果,用来诊断潜在的 文本分析 的查询/索引问题。注意FieldType需要选定为与被分析内容类型一致。
-
Query(查询):这是一个查询界面,用的比较多,用来查询索引的文档,包含是否存在,排序是否正确等。稍后会介绍相关的查询参数。
-
Schema 当前索引库定义显示当前的schema的配置文件,即schema.xml的内容,例如:可以看到schema.xml 中的配置的字段等信息
-
Documents (索引文档)索引的相关操作,增加,修改,删除等,例如我们要增加一个索引.
a. 先要在solr 的D:\solr_home\mycore1\conf 的 schema.xml配置文件下,增加相关的字段field,例如:
<field name="title" type="string" indexed="true" stored="true" required="true" multiValued="false" />
b. 在如下页面,选择/update ,文档格式选择json ,然后submit 提交。这样 索引就增加上了。
c. 删除所以也是类似,只不过Document(s) 里面的xml一样 ,这个是删除全部的索引 :, 注意:这个节点不能少,否则删除动作的事务不会提交。
注意:如果没有做分词,相关的字段查询是精确匹配的,比如 将q 输入 title:me 即 查询title 为 me 的数据。
-
入门安装配置
-
注意前提是你的电脑上已经有了java和tomcat的环境。
-
下载后解压的指定目录
目录结构如下:
-
进入bin目录,启动solr
启动命令:solr start
关闭命令:solr stop -all
重启solr :solr restart –p p_num
-
打开浏览器访问地址
-
创建核心文件夹,名字随意
-
复制配置文件到核心文件夹里
-
创建Core Admin,先选择Core Admin,填写name与instanceDir,选择Add Core
-
创建doucument表
-
添加字段,注意name不可以重复
方式1:web端手动添加
方式2:配置文件中创建
<!--name 字段名--> <!--type 数据类型--> <!--Tokenized 是否分词--> <!--uninvertible --> <!--indexed 是否为索引--> <!--stored 是否存储--> <field name="md_code" type="string" uninvertible="true" indexed="true" stored="true"/> <field name="md_age" type="string" uninvertible="true" indexed="true" stored="true"/> <field name="md_name" type="string" uninvertible="true" indexed="true" stored="true"/>
-
,选择document,添加数据
-
查询,可以看到我们导入的数据
说明:
status 为 o 表示查询成功 ;
QTime 表示查询所用时间 ;
numFound 表示 查询数量
q 功能很强大,支持模糊查询、关联查询、and和or等。
常用命令
也可以通过
solr create -c
来创建项目实例
总结
安装好solr:启动,默认端口为8983
使用solr create -c来创建项目实例
在配置文件中创建索引列
![]()
在SpringBoot中导入maven依赖
spring-boot-starter-data-solr
编写配置类
SearchAutoSolrConfig
实现增删改查(增和改是同一个方法)
solr集成IK分词器
-
下载IK分词器,解压,如下图所示:
-
将jar包放到
\solr-8.8.2\server\solr-webapp\webapp\WEB-INF\lib
目录下 -
将其他文件放到
\solr-8.8.2\server\solr-webapp\webapp\WEB-INF\classes
目录下 -
进入solr实例目录下,随便一个实例的
conf
目录下,修改配置文件,将下面的配置添加进文中。<!-- ik分词器 --> <fieldType name="text_ik" class="solr.TextField"> <analyzer type="index"> <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" conf="ik.conf"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType> <!-- 设置业务系统Field --> <field name="item_title" type="text_ik" indexed="true" stored="true"/> <field name="item_sell_point" type="text_ik" indexed="true" stored="true"/> <field name="item_price" type="plong" 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_sell_point" dest="item_keywords"/>
-
测试分词
查询条件的组装
criteria.where() 自身是不能叠加的
criteria.and() 自身是可以叠加使用。例如
Query query = new SimpleQuery(); Criteria criteria = new Criteria("mdName").isNotNull(); criteria= criteria.and("id").is(1); criteria= criteria.and("mdName").is("123"); query.addCriteria(criteria);
创作不易,给点鼓励吧👍
![WeChat Pay](https://gitee.com/leaf_fiber/image/raw/master/image-20210708100550589.png)
支付宝打赏
![Alipay](https://gitee.com/leaf_fiber/image/raw/master/image-20210708100614445.png)
微信打赏