本文记录第一次使用全文搜索引擎Solr,主要介绍Solr环境搭建,数据查询及数据同步,不当之处请指教。此说明使用solr8.7.0版本。
2. 解压后目录结构如下
3. doc命令进入solr下bin目录,输入solr start命令启动服务,默认端口是8983,表示启动成功,浏览器输入http://127.0.0.1:8983/solr可以访问表示启动成功。
4. 创建core,doc窗口输入命令solr create -c [core名称],查看solr-8.7.0\server\solr目录下会出现与core名称相同文件夹表示创建成功(也可以使用web端创建,但是创建时失败,建议使用命令创建)
5. 配置core
5.1创建dataConfig.xml配置文件,配置数据库地址,以及entity,query定义sql满足检索查询需要,多个表数据可以使用UNION连接
<?xml version="1.0" encoding="UTF-8" ?>
<dataConfig>
<dataSource
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://172.0.0.1:3306/test"
user="renzhx" password="123456"
batchSize="-1"/>
<document>
<entity name="search" pk="2" query="SELECT CONCAT(news_id,'-','news') id,news_title entry_body,'news' entry_typ FROM web_news" >
<field column="id" name="id"/>
<field column="entry_body" name="entryBody"/>
<field column="entry_typ" name="entryType"/>
</entity>
</document>
</dataConfig>
5.2在managed-schema中配置dataConfig.xml中的field以及分词器,本文使用ik_work分词器
<field name="entryBody" type="ik_word" indexed="true" stored="true"/>
<field name="entryType" type="string"/>
<field name="entryTime" type="string"/>
<fieldType name="ik_word" 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>
5.3 完成上述操作后命令重启solr即可,solr stop,solr start
5.4使用solr web管理页面导入数据,选中创建Core,进入Core压面后选中DataImport按照下图所示进行数据导入。
5.5验证数据导入是否成功,选中query,直接选中Execute Query进行查询,数据即可展示出来,配置完成。
6. Java调用服务,直接上代码
pom文件引入依赖
<!--solr全文检索-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
</dependency>
application.yml
spring:
data:
solr:
host: http://127.0.0.1:8983/solr
6.1创建实体类
@SolrDocument(solrCoreName = "search")
public class SolrEntry {
@Id
@Field
private String id;
@Field
private String entryBody;
@Field
private String entryType;
@Field
public String entryTime;
}
6.2 实现查询、新增,修改、删除功能
@Service
public class SolrServiceImpl implements SolrService {
@Autowired
private SolrClient solrClient;
@Autowired
private WebHotSearchMapper hotSearchMapper;
/**
* 查询数据
* @param param
* @return
*/
@Override
public QueryResponse search(Map<String, Object> param) {
QueryResponse queryResponse = null;
Integer pageNum = (Integer)param.get("pageNum");
if(pageNum == null)pageNum = 0;
Integer pageSize = (Integer)param.get("pageSize");
if(pageSize == null) pageSize = 10;
String coreName = (String)param.get("coreName");
if(coreName == null){
return null;
}
String keyWord = (String)param.get("keyWord");
SolrQuery where = new SolrQuery();
// 设置分页
where.setStart(pageNum - 1);
where.setRows(pageSize);
// 设置关键词
if("".equals(keyWord)||keyWord == null){
keyWord = "*";
}
where.setQuery("entryBody:" + keyWord);
// 添加过滤器
String entryType = (String)param.get("entryType");
if(entryType != null&& entryType != ""){
where.setFilterQueries("entryType:" + entryType);
}
where.setSort("entryTime", SolrQuery.ORDER.desc);
WebHotSearch hotSearch = new WebHotSearch();
try {
queryResponse = solrClient.query(coreName,where);
hotSearch.setHotWord(keyWord);
hotSearch.setCreateTime(DateUtils.getNowDate());
hotSearch.setCreateBy(SecurityUtils.getUsername());
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CustomException e){
hotSearch.setCreateBy("游客");
}
hotSearchMapper.insertWebHotSearch(hotSearch);
return queryResponse;
}
/**
* solr同步-新增或修改
* @param solrEntry
* @param coreName
* @return
*/
@Override
public String insertOrUpdate(SolrEntry solrEntry,String coreName) {
SolrInputDocument in = new SolrInputDocument();
in.setField("id",solrEntry.getId());
in.setField("entryBody",solrEntry.getEntryBody());
in.setField("entryType",solrEntry.getEntryType());
try {
solrClient.add(coreName,in);
solrClient.commit(coreName);
return solrEntry.getId();
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "-1";
}
/**
* solr数据同步-删除
* @param solrEntry
* @param coreName
* @return
*/
@Override
public String delete(SolrEntry solrEntry,String coreName) {
String id = solrEntry.getId() + "-" + solrEntry.getEntryType();
try {
solrClient.deleteById(coreName,id);
solrClient.commit(coreName);
return id;
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "-1";
}
}
6.3数据同步使用注解实现。
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SolrKey {
public String value() default "ID";
}
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SolrSynchro {
// 类型,区分solr数据来源
public String type() default "";
// solr核心名称
public String coreName() default "";
// 同步方法 INSERT UPDATE DELETE
public String method() default "";
}
@Aspect
@Component
public class SolrSynchroAspect {
@Autowired
private SolrService solrService;
@Pointcut("@annotation(com.tydt.framework.aspectj.lang.annotation.SolrSynchro)")
public void solrSynchroPointCut(){
}
@AfterReturning("solrSynchroPointCut()")
public void doAfterReturning(JoinPoint joinPoint){
// 获取第一个参数
Object arg = joinPoint.getArgs()[0];
// 获取类所有属性
Field[] fields = arg.getClass().getDeclaredFields();
SolrEntry solrEntry = new SolrEntry();
SolrSynchro solrSynchro = getSolrSynchro(joinPoint);
String type = solrSynchro.type();
String coreName = solrSynchro.coreName();
solrEntry.setEntryType(type);
try{
for (Field field : fields) {
// 判断属性是否被指定注解
boolean present = field.isAnnotationPresent(SolrKey.class);
if(present){
// 获取字段注解value
SolrKey solrKey = field.getAnnotation(SolrKey.class);
String keyValue = solrKey.value();
// 获取字段名称
String fieldName = field.getName();
// 首字母大写
fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
// 获取getter方法
Method method = arg.getClass().getMethod("get" + fieldName);
// 执行getter方法获取值
if("ID".equals(keyValue)){// solr ID字段
Long solrValue = Long.parseLong(method.invoke(arg).toString()) ;
// ID
solrEntry.setId(solrValue + "-" + type);
}else if("BODY".equals(keyValue)){// solr 检索词条内容
String solrValue = (String) method.invoke(arg);
solrEntry.setEntryBody(solrValue);
}
}
}
// 判断更新、删除、添加
switch (solrSynchro.method()){
case "INSERT":
case "UPDATE":
solrService.insertOrUpdate(solrEntry,coreName);
break;
case "DELETE":
solrService.delete(solrEntry,coreName);
break;
}
}catch (NoSuchMethodException e){
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 获取需要同步的方法
*/
public SolrSynchro getSolrSynchro(JoinPoint point) {
MethodSignature signature = (MethodSignature) point.getSignature();
SolrSynchro solrSynchro = AnnotationUtils.findAnnotation(signature.getMethod(), SolrSynchro.class);
if (Objects.nonNull(solrSynchro))
{
return solrSynchro;
}
return AnnotationUtils.findAnnotation(signature.getDeclaringType(), SolrSynchro.class);
}
}
6.4使用注解进行同步在service实现类使用同步注解同步
@SolrSynchro(type = "notice",coreName = "search",method = "INSERT")
public int inserttest(WebNotice webNotice)
{
}
参考文章:
https://www.cnblogs.com/zouwangblog/p/12171015.html
https://blog.csdn.net/vtopqx/article/details/73224510
https://www.jianshu.com/p/05a161add1a6