SpringBoot 整合 Spring Data Solr
測(cè)試類(lèi)使用 solrClient 進(jìn)行添加、查詢(xún)、刪除文檔的操作在這篇的代碼基礎(chǔ)上繼續(xù)演示的
兩篇文章的區(qū)別:
上一篇是通過(guò)SolrClient 連接 Solr,然后用 SolrClient 來(lái)調(diào)用查詢(xún)方法進(jìn)行全文檢索
這一篇是 自定義dao組件,通過(guò)繼承CrudRepository 接口,用 dao 接口來(lái)調(diào)用查詢(xún)方法進(jìn)行全文檢索
Spring Data Solr的功能(生成DAO組件):
這種方式在Spring Boot 2.5已經(jīng)不再推薦使用了,需要手動(dòng)添加@EnableSolrRepositories來(lái)啟動(dòng)DAO組件。
通過(guò)這種方式訪(fǎng)問(wèn)Solr索引庫(kù),確實(shí)不如直接用SolrClient那么靈活。
Spring Data Solr大致包括如下幾方面功能:
DAO接口只需繼承 CrudRepository,Spring Data Solr 就能為DAO組件提供實(shí)現(xiàn)類(lèi)。
1、Spring Data Solr 支持方法名關(guān)鍵字查詢(xún),只不過(guò)Solr查詢(xún)都是全文檢查查詢(xún)。
2、Spring Data Solr 同樣支持用 @Query注解指定自定義的查詢(xún)語(yǔ)句 。
3、Spring Data Solr 同樣支持 DAO組件添加自定義的查詢(xún)方法。
通過(guò)添加額外的父接口,并為額外的該接口提供實(shí)現(xiàn)類(lèi),Spring Data Solr 就能該實(shí)現(xiàn)類(lèi)中的方法“移植”到DAO組件中。
4、不支持Example查詢(xún)和Specification查詢(xún)。
【說(shuō)明:】
與前面介紹的NoSQL技術(shù)不同的是,Solr屬于全文檢索引擎,因此它的方法名關(guān)鍵字查詢(xún)也是基于全文檢索的。
例如對(duì)于findByName(String name)方法,假如傳入?yún)?shù)為“瘋狂”,
這意味著查詢(xún)name字段中包含“瘋狂”關(guān)鍵字的文檔,而不是查詢(xún)name字段值等于“瘋狂”的文檔。
@SolrDocument注解 可指定一個(gè)collection屬性,用于指定該實(shí)體類(lèi)映射哪個(gè)索引庫(kù)(單機(jī)就是Core或集群模式就是Collection)。
@Query查詢(xún)(屬于半自動(dòng))
@Query注解所指定的就是標(biāo)準(zhǔn)的 Lucene 的查詢(xún)語(yǔ)法
@Query("?0:?1")
List<Book> findByQuery(String field, Double term);
代碼演示:
代碼是基于:使用 SolrClient 連接 Solr 這篇文章來(lái)修改的
1、演示通過(guò)dao組件來(lái)保存文檔
1、實(shí)體類(lèi)指定索引庫(kù)
指定該 Book 類(lèi)映射到 books 索引庫(kù)里面
2、修改日志級(jí)別
日志級(jí)別,可以用來(lái)看sql具體的執(zhí)行語(yǔ)句
3、創(chuàng)建 Dao 接口
DAO接口只需繼承 CrudRepository,Spring Data Solr 就能為DAO組件提供實(shí)現(xiàn)類(lèi)。
此時(shí)寫(xiě)的方法還不需要用到。
只是需要用到這個(gè)BookDao接口。
4、先刪除所有文檔
用前面寫(xiě)的測(cè)試方法,先把前面測(cè)試的文檔先刪除干凈。
5、創(chuàng)建測(cè)試類(lèi)
區(qū)別:
添加文檔的代碼都是一樣的,只是整合 Spring Data Solr 用到的是 bookDao 接口來(lái)實(shí)現(xiàn),之前是使用solrClient來(lái)實(shí)現(xiàn)。
6、演示結(jié)果
成功通過(guò) dao 組件來(lái)添加文檔。
如果代碼出錯(cuò),因?yàn)榘姹締?wèn)題顯示沒(méi)有bookDao這個(gè)bean,那么就通過(guò)注解手動(dòng)啟用Dao組件
我依賴(lài)是這個(gè),演示的時(shí)候能成功執(zhí)行代碼,所以沒(méi)有手動(dòng)啟用上面說(shuō)的注解@EnableSolrRepositories
為了后面方便演示,把文檔刪了,改成這些。
2、根據(jù) title_cn 字段是否包含關(guān)鍵字來(lái)查詢(xún)
3、查詢(xún)指定價(jià)格范圍的文檔
4、查詢(xún)Description 字段中包含關(guān)鍵詞的文檔
查詢(xún)Description 字段中包含關(guān)鍵詞的文檔(Matches 需要正則表達(dá)式)
如圖:正則表達(dá)式里面 ,/故事.+/ 兩個(gè)字的就查不到,如果是 /故.+/ 一個(gè)字就查的到。
/故事.+/ 兩個(gè)字的就查不到
/故.+/ 一個(gè)字就查的到
5、查詢(xún)集合中的這些id的文檔
6、@Query查詢(xún)(自定義的半自動(dòng)查詢(xún))
Spring Data Solr的功能(實(shí)現(xiàn)自定義查詢(xún)方法):
自定義查詢(xún)方法(屬于全手動(dòng))
讓DAO接口繼承自定義DAO接口、并為自定義DAO接口提供實(shí)現(xiàn)類(lèi),可以為DAO組件添加自定義查詢(xún)方法。
Spring Data solr會(huì)將自定義DAO組件實(shí)現(xiàn)的方法移植DAO組件中。
自定義查詢(xún)方法可使用SolrClient來(lái)實(shí)現(xiàn)查詢(xún)方法,SolrClient 是 Solr本身提供的API,功能比較強(qiáng)大。
代碼演示:
自定義查詢(xún)方法且高亮顯示
需求:自定義一個(gè)關(guān)鍵字查詢(xún)的方法,返回的結(jié)果中,對(duì)關(guān)鍵字進(jìn)行高亮顯示。
代碼解釋?zhuān)?br> 下面的代碼:
1、先在查詢(xún)的時(shí)候添加實(shí)現(xiàn)高亮的代碼
2、在查詢(xún)后返回來(lái)的文檔中,獲取高亮信息
3、將獲取到的高亮信息封裝回 Book 對(duì)象即可。
(其實(shí)就是要返回的book對(duì)象中的description字段里面的關(guān)鍵字前后多了< span > 標(biāo)簽字符串, 就算是實(shí)現(xiàn)了關(guān)鍵字的高亮效果)
1、自定義CustomBookDao組件
同時(shí)讓 bookDao 也繼承這個(gè) CustomBookDao
為了方便統(tǒng)一用 bookDao 來(lái)調(diào)用查詢(xún)方法
2、CustomBookDaoImpl 實(shí)現(xiàn)類(lèi)寫(xiě)自定義方法
3、測(cè)試:成功實(shí)現(xiàn)關(guān)鍵字的高亮顯示
4、部分代碼解釋
1、代碼中的設(shè)置對(duì)應(yīng)圖形界面中的設(shè)置
在查詢(xún)條件中,添加高亮設(shè)置。
如圖:通過(guò)圖形界面跟測(cè)試代碼的相同條件的查詢(xún),來(lái)演示代碼設(shè)置高亮效果時(shí)對(duì)應(yīng)的樣子
2、對(duì)獲取高亮信息并封裝回book對(duì)象的解釋
對(duì)這部分代碼進(jìn)行詳細(xì)解釋
查詢(xún)時(shí)對(duì)關(guān)鍵字添加了高亮的操作,此時(shí)把具體的高亮信息(就是關(guān)鍵字前后添加了高亮的 < span > 代碼,在查詢(xún)后返回的結(jié)果文檔里面,生成了如圖的這個(gè)字符串)拿出來(lái),封裝回 description 這個(gè)屬性里面。
比如查的時(shí)候,是查 description 這個(gè)字段里面包含“熱血” 的關(guān)鍵詞,
如果不加高亮的代碼,那么返回來(lái)的數(shù)據(jù)是:
“description”:[“講述廢材綱成為第十代首領(lǐng)的熱血故事A”]},
如果加高亮的代碼,那么返回來(lái)的數(shù)據(jù)是:
“description”:[“講述廢材綱成為第十代首領(lǐng)的<span style=“color:red”>熱血< /span >故事A”]},
關(guān)鍵字前后多了 <span style=“color:red”> < /span > 這兩個(gè)字符串。
所以我們這一步就是要把加高亮后返回的這個(gè)多了這兩個(gè)高亮顯示的字符串的數(shù)據(jù),給封裝到 Book 對(duì)象里面的description 字段里面。
如圖:通過(guò)圖形界面跟測(cè)試代碼的相同條件的查詢(xún),來(lái)演示代碼具體獲取到的高亮信息長(zhǎng)啥樣
如果不封裝的話(huà),那么查詢(xún)后返回來(lái)的結(jié)果,這個(gè)description字段的數(shù)據(jù)依然是沒(méi)有加高亮代碼的。
所以需要把高亮的信息獲取出來(lái),再設(shè)置到 Book 對(duì)象里面的 description 字段里面,這樣再返回這個(gè) book對(duì)象,此時(shí)Book對(duì)象里面的 description 值就有高亮顯示的功能了。
(其實(shí)就是要返回的book對(duì)象中的description字段里面的關(guān)鍵字前后多了< span > 標(biāo)簽字符串, 就算是實(shí)現(xiàn)了關(guān)鍵字的高亮效果)
代碼優(yōu)化:
如圖:根據(jù)上面的代碼解釋?zhuān)梢钥闯龃藭r(shí)的 highLightDesc 字符串相當(dāng)于就是具有高亮效果的 description 的值。
description 的值長(zhǎng)這樣:
[“講述廢材綱成為第十代首領(lǐng)的熱血故事A”]},
highLightDesc 的值長(zhǎng)這樣
[“講述廢材綱成為第十代首領(lǐng)的<span style=“color:red”>熱血< /span >故事A”]},
我們需要把
[“講述廢材綱成為第十代首領(lǐng)的<span style=“color:red”>熱血< /span >故事A”]},
這個(gè)具有高亮效果的值封裝回 Book 對(duì)象里面。
但是這個(gè)highLightDesc 這個(gè)字符串畢竟不是 description ,
所以如圖直接把 highLightDesc 作為 description 字段封裝進(jìn)去,其實(shí)是不太合邏輯的。
所以可以?xún)?yōu)化下
優(yōu)化代碼:
假如我不希望改變Book對(duì)象的屬性值,但是又希望能將高亮的信息傳出去,因此可以考慮為Book對(duì)象增加一個(gè)Map類(lèi)型的屬性,該屬性用于保存高亮信息。
1、先添加一個(gè)用于保存高亮信息的字段
2、封裝對(duì)象時(shí),把 highLightDesc 改回正常的 description 字段,此時(shí)可以看到,關(guān)鍵字并沒(méi)有高亮顯示。
3、把該id的文檔的高亮信息設(shè)置到這個(gè)字段里面
如圖:這樣也能實(shí)現(xiàn)高亮效果
這種寫(xiě)法的好處:
既不會(huì)破壞原來(lái)這個(gè) Book 對(duì)象的屬性值,同時(shí)也能將高亮信息傳出來(lái)
@EnableSolrRepositories 注解解釋
該注解其實(shí)和Spring Boot的其他 @EnableXxxRepositories注解大同小異。
@EnableSolrRepositories注解用于啟用Solr Repository支持。
一旦程序顯式使用該注解,那Spring Data Solr 的 Repository自動(dòng)配置就會(huì)失效(Spring Boot 2.5本來(lái)就沒(méi)有啟用Repository的自動(dòng)配置)。
因此,當(dāng)需要連接多個(gè)Solr索引庫(kù)時(shí)或進(jìn)行更多定制時(shí),可手動(dòng)使用該注解。
使用@EnableSolrRepositories注解時(shí)要指定如下屬性:
- basePackages:指定掃描哪個(gè)包下的DAO組件(Repository組件)。
- solrClientRef:指定基于哪個(gè) SolrClient 來(lái)實(shí)現(xiàn) Repository 組件,默認(rèn)值是 solrClient。
- solrTemplateRef:指定基于哪個(gè) SolrTemplate 來(lái)實(shí)現(xiàn)Repository組件,默認(rèn)是 solrTemplate。
上面 solrClientRef 與 solrTemplateRef 兩個(gè)屬性只要指定其中之一即可。
如圖:不過(guò)這個(gè)注解我暫時(shí)沒(méi)用到。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-826454.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-826454.html
完整代碼
SolrConfig 手動(dòng)配置自定義的SolrClient
package cn.ljh.solrboot.config;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.solr.SolrProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.solr.repository.config.EnableSolrRepositories;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.Optional;
//手動(dòng)配置自定義的SolrClient
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({HttpSolrClient.class, CloudSolrClient.class})
@EnableConfigurationProperties(SolrProperties.class)
//由于本項(xiàng)目沒(méi)有配置 SpringBoot 為 Spring Data Solr 提供的 Starter 組件,因此需要手動(dòng)啟用Dao組件
//@EnableSolrRepositories(basePackages = "cn.ljh.solrboot.dao",solrClientRef = "solrClient")
public class SolrConfig
{
//把配置文件中的屬性值注入到這個(gè)成員變量里面
@Value("${spring.data.solr.username}")
private String username;
@Value("${spring.data.solr.password}")
private String password;
//此處需要配置一個(gè) SolrClient(直接抄SolrAutoConfiguration的源碼就可以了)
@Bean
public SolrClient solrClient(SolrProperties properties)
{
//通過(guò)系統(tǒng)屬性來(lái)設(shè)置連接Solr所使用的認(rèn)證信息
// 設(shè)置使用基本認(rèn)證的客戶(hù)端
System.setProperty("solr.httpclient.builder.factory",
"org.apache.solr.client.solrj.impl.PreemptiveBasicAuthClientBuilderFactory");
// 設(shè)置認(rèn)證的用戶(hù)名和密碼
System.setProperty("basicauth", username + ":" + password);
if (StringUtils.hasText(properties.getZkHost()))
{
return new CloudSolrClient.Builder(Arrays.asList(properties.getZkHost()), Optional.empty()).build();
}
return new HttpSolrClient.Builder(properties.getHost()).build();
}
}
Book 實(shí)體類(lèi)
package cn.ljh.solrboot.domain;
import lombok.Data;
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.solr.core.mapping.SolrDocument;
import java.util.List;
import java.util.Map;
/**
* author JH
*/
@Data
//指定該 Book 類(lèi)映射到 books 索引庫(kù)里面
@SolrDocument(collection = "books")
public class Book
{
//該id字段會(huì)被映射到索引庫(kù)的 id field,而在索引庫(kù)中 ,id field 被自定為標(biāo)志屬性
//@Id
//添加這個(gè) @Field 注解,就能自動(dòng)映射到索引庫(kù)中同名的field
@Field
private Integer id;
//這就表示這個(gè) title ,映射到索引庫(kù)中的 title_cn 這個(gè)字段
@Field("title_cn")
private String title;
@Field
private String description;
@Field
private Double price;
//用于保存高亮信息
private Map<String, List<String>> highLight;
//構(gòu)造器
public Book(Integer id, String title, String description, Double price)
{
this.id = id;
this.title = title;
this.description = description;
this.price = price;
}
}
BookDao 組件
package cn.ljh.solrboot.dao;
import cn.ljh.solrboot.domain.Book;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.solr.repository.Query;
import java.util.List;
// DAO接口只需繼承 CrudRepository,Spring Data Solr 就能為DAO組件提供實(shí)現(xiàn)類(lèi)
//參數(shù)1:指定要進(jìn)行數(shù)據(jù)訪(fǎng)問(wèn)的實(shí)體類(lèi)是 Book, 也就是指定要操作的實(shí)體是 Book 參數(shù)2:Book 實(shí)體的主鍵的類(lèi)型將被映射為整數(shù)類(lèi)型
public interface BookDao extends CrudRepository<Book,Integer>,CustomBookDao
{
//這些基于方法名關(guān)鍵字查詢(xún),都是全文檢索的查詢(xún)---------------------------------------------
//根據(jù) title_cn 字段是否包含關(guān)鍵字來(lái)查詢(xún)
List<Book> findByTitle(String term);
//查詢(xún)指定價(jià)格范圍的文檔
List<Book> findByPriceBetween(Double start , Double end);
//查詢(xún)Description 字段中包含關(guān)鍵詞的文檔(Matches 需要正則表達(dá)式)
List<Book> findByDescriptionMatches(String descPattern);
//查詢(xún)集合中的這些id的文檔
List<Book> findByIdIn(List<Integer> ids);
//@Query查詢(xún)(自定義的半自動(dòng)查詢(xún))------------------------------------------------------
//查 field 字段包含 term 這個(gè)關(guān)鍵詞 的文檔; ?0 就是指第一個(gè)參數(shù) field ; ?1 就是指第二個(gè)參數(shù) term
@Query("?0:?1")
//field:查這個(gè)字段 term:關(guān)鍵詞
List<Book> findByQuery(String field, String term);
}
CustomBookDao 自定義dao組件
package cn.ljh.solrboot.dao;
import cn.ljh.solrboot.domain.Book;
import java.util.List;
/**
* author JH 2024-02
*/
public interface CustomBookDao
{
//通過(guò)關(guān)鍵字查詢(xún)并高亮顯示
List<Book> highLightFindByDescription(String term);
}
CustomBookDaoImpl 自定義查詢(xún)方法
package cn.ljh.solrboot.dao.impl;
import cn.ljh.solrboot.dao.CustomBookDao;
import cn.ljh.solrboot.domain.Book;
import lombok.SneakyThrows;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* author JH 2024-02
*/
public class CustomBookDaoImpl implements CustomBookDao
{
// 借助于 SolrClient ,可以實(shí)現(xiàn) solr 的所有功能,比如: 高亮功能
private final SolrClient solrClient;
//通過(guò)構(gòu)造器進(jìn)行依賴(lài)注入
public CustomBookDaoImpl(SolrClient solrClient)
{
this.solrClient = solrClient;
}
//通過(guò)關(guān)鍵字查詢(xún)并高亮顯示
@SneakyThrows
@Override
public List<Book> highLightFindByDescription(String term)
{
//定義查詢(xún)
SolrQuery solrQuery = new SolrQuery("description:" + term);
//開(kāi)啟高亮顯示功能(對(duì)應(yīng)圖形界面中的 hl 復(fù)選框)
solrQuery.setHighlight(true);
//所謂高亮,就是在關(guān)鍵詞前面和后面設(shè)置要添加的字符串片段
//(對(duì)應(yīng)圖形界面中的 hl.simple.pre)
solrQuery.setHighlightSimplePre("<span style=\"color:red\">");
//(對(duì)應(yīng)圖形界面中的 hl.simple.post)
solrQuery.setHighlightSimplePost("</span>");
//設(shè)置對(duì)哪個(gè)字段進(jìn)行高亮顯示(對(duì)應(yīng)圖形界面中的 hl.fl)
solrQuery.addHighlightField("description");
//執(zhí)行查詢(xún) 參數(shù)1:到“books”索引庫(kù)查詢(xún) , 參數(shù)2:查詢(xún)的條件
QueryResponse response = solrClient.query("books", solrQuery);
//獲取查詢(xún)后返回的文檔列表
SolrDocumentList docLists = response.getResults();
//獲取高亮信息
//該Map的key就是文檔的id
Map<String, Map<String, List<String>>> high = response.getHighlighting();
//創(chuàng)建一個(gè)集合,用來(lái)存放封裝了高亮信息的Book對(duì)象
List<Book> bookList = new ArrayList<>();
for (SolrDocument doc : docLists)
{
//此處就要將 SolrDocument 文檔中的信息提取出來(lái),封裝到 Book 對(duì)象中
String id = (String) doc.getFieldValue("id");
String title = (String) doc.getFieldValue("title_cn");
String description = (String) doc.getFieldValue("description");
double price = (Float) doc.getFieldValue("price");
//獲取高亮后的字段值
//通過(guò)文檔的id,獲取該文檔的高亮信息
Map<String, List<String>> highLightDoc = high.get(id);
//再通過(guò)description這個(gè)key獲取對(duì)應(yīng)的value值(List類(lèi)型)
List<String> stringList = highLightDoc.get("description");
//因?yàn)樵搇ist集合中只有一個(gè)元素,所以只獲取第一個(gè)元素即可
String highLightDesc = stringList.get(0);
//將從 SolrDocument 文檔中取出的高亮信息再封裝回Book對(duì)象就可以了
//這里是把 highLightDesc 作為 description 這個(gè)屬性的值封裝進(jìn)去,其實(shí)不太好。
//Book book = new Book(Integer.parseInt(id),title,highLightDesc,price);
//假如我不希望改變Book對(duì)象的屬性值,但是又希望能將高亮的信息傳出去,因此可以考慮為Book對(duì)象增加一個(gè)Map類(lèi)型的屬性,該屬性用于保存高亮信息
Book book = new Book(Integer.parseInt(id),title,description,price);
//把該id的文檔的高亮信息設(shè)置到這個(gè)字段里面
book.setHighLight(highLightDoc);
bookList.add(book);
}
return bookList;
}
}
application.properties 配置文件
# 現(xiàn)在演示的是單機(jī)模式,所以先指定這個(gè)host
spring.data.solr.host=http://127.0.0.1:8983/solr
# 連接 Solr 索引庫(kù)的用戶(hù)名和密碼(就是Solr的圖形界面)
spring.data.solr.username=root
spring.data.solr.password=123456
# 日志級(jí)別,可以用來(lái)看sql具體的執(zhí)行語(yǔ)句
logging.level.org.springframework.data.solr=debug
BookDaoTest 基于DAO組件測(cè)試
package cn.ljh.solrboot;
import cn.ljh.solrboot.dao.BookDao;
import cn.ljh.solrboot.domain.Book;
import lombok.SneakyThrows;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.solr.repository.Query;
import java.util.List;
/**
* author JH 2024-02
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class BookDaoTest
{
//依賴(lài)注入
@Autowired
private BookDao bookDao;
//添加文檔到books索引庫(kù)的測(cè)試類(lèi)
@ParameterizedTest
//這些參數(shù)相當(dāng)于一個(gè)個(gè)文檔
@CsvSource({
"1,火影忍者,講述鳴人成為村長(zhǎng)的事情,200",
"2,七龍珠,講述賽亞人的成長(zhǎng)故事,300",
"3,家庭教師A,講述廢材綱成為第十代首領(lǐng)的熱血故事A,400",
"4,家庭教師B,講述廢材綱成為第十代首領(lǐng)的熱血故事B,500"
})
public void testSave(Integer id, String title, String description, Double price)
{
Book book = new Book(id, title, description, price);
//使用bookDao來(lái)保存數(shù)據(jù)對(duì)象時(shí),無(wú)需如之前一樣指定索引庫(kù)的名稱(chēng),
//因?yàn)锽ook類(lèi)上面有@SolrDocument(collection = "books")修飾,已經(jīng)指定了該數(shù)據(jù)類(lèi)所映射的索引庫(kù)
bookDao.save(book);
}
//根據(jù) title_cn 字段是否包含關(guān)鍵字來(lái)查詢(xún)
@ParameterizedTest
//測(cè)試時(shí)只需要一個(gè)參數(shù)用這個(gè)注解
@ValueSource(strings = {
"龍珠",
"家庭"
})
public void testFindByTitle(String term){
//查詢(xún)
List<Book> books = bookDao.findByTitle(term);
//打印
books.forEach(System.err::println);
}
//查詢(xún)指定價(jià)格范圍的文檔
@ParameterizedTest
//測(cè)試時(shí)需要多個(gè)參數(shù)用這個(gè)注解,多個(gè)參數(shù)在一個(gè)雙引號(hào)里面用逗號(hào)隔開(kāi)
@CsvSource({
"100,200",
"200,300"
})
public void testFindByPriceBetween(Double start , Double end){
List<Book> books = bookDao.findByPriceBetween(start, end);
books.forEach(System.err::println);
}
//查詢(xún)Description 字段中包含關(guān)鍵詞的文檔(Matches 需要正則表達(dá)式)
@ParameterizedTest
//正則表達(dá)式必須放在兩個(gè)斜杠//里面, . 這個(gè)點(diǎn)表示匹配任意字符 , + 號(hào)表示出現(xiàn) 1 到多次
@ValueSource(strings = {
"/故.+/",
"/熱.+/"
})
public void testFindByDescriptionMatches(String descPattern){
List<Book> books = bookDao.findByDescriptionMatches(descPattern);
books.forEach(System.err::println);
}
//查詢(xún)集合中的這些id的文檔
@ParameterizedTest
@CsvSource({
"1,2",
"1,3"
})
public void testFindByIdIn(Integer id1 , Integer id2){
List<Integer> ids = List.of(id1, id2);
List<Book> books = bookDao.findByIdIn(ids);
books.forEach(System.err::println);
}
//@Query查詢(xún)(自定義的半自動(dòng)查詢(xún))------------------------------------------------------
@ParameterizedTest
@CsvSource({
"title_cn,家庭",
"description,故事*"
})
public void testFindByQuery(String field, String term){
List<Book> books = bookDao.findByQuery(field, term);
books.forEach(System.err::println);
}
//自定義查詢(xún)方法且高亮顯示
@ParameterizedTest
@ValueSource(strings = {
"熱*",
"村*"
})
public void testHighLightFindByDescription(String term){
List<Book> books = bookDao.highLightFindByDescription(term);
books.forEach(System.err::println);
}
}
SolrClientTest 基于SolrClient測(cè)試
package cn.ljh.solrboot;
import cn.ljh.solrboot.domain.Book;
import lombok.SneakyThrows;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.SolrParams;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
// SpringBootTest.WebEnvironment.NONE: 指定測(cè)試的web環(huán)境為非Web環(huán)境。
// 通常情況下,我們會(huì)將該參數(shù)設(shè)置為NONE,表示不需要啟動(dòng)內(nèi)嵌的Web容器,從而更加快速地執(zhí)行測(cè)試
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class SolrClientTest
{
@Autowired
private SolrClient solrClient;
//添加文檔到books索引庫(kù)的測(cè)試類(lèi)
@SneakyThrows
@ParameterizedTest
//這些參數(shù)相當(dāng)于一個(gè)個(gè)文檔
@CsvSource({
"1,火影忍者,講述成為村長(zhǎng)的故事,200",
"2,七龍珠,講述賽亞人的成長(zhǎng)故事,300",
"3,家庭教師,講述廢材綱成為第十代首領(lǐng)的熱血故事,400"
})
public void testSave(Integer id, String title, String description, Double price)
{
Book book = new Book(id, title, description, price);
//向 books 邏輯索引庫(kù)添加文檔 ; 參數(shù)1:索引庫(kù)的名字 , 參數(shù)2:映射文檔的實(shí)體對(duì)象 ,參數(shù)3 :500 毫秒的提交時(shí)間
solrClient.addBean("books", book, 500);
}
//查詢(xún)索引庫(kù)中的文檔的測(cè)試類(lèi)
@SneakyThrows
@ParameterizedTest
//這個(gè)注解用來(lái)進(jìn)行多次測(cè)試,一個(gè)字符串代表一次測(cè)試方法。
@CsvSource({
"title_cn,忍者",
"description,成為",
"description,成*"
})
//參數(shù)1:要查詢(xún)的字段 參數(shù)2:要查詢(xún)的關(guān)鍵詞
public void testQuery(String field, String term)
{
//創(chuàng)建查詢(xún),表明在 field 字段中查詢(xún) term 關(guān)鍵字
SolrParams params = new SolrQuery(field + ":" + term);
//執(zhí)行查詢(xún)操作,去 books 這個(gè)索引庫(kù)里面查詢(xún),得到響應(yīng)
QueryResponse queryResponse = solrClient.query("books", params);
//返回所得到的文檔
SolrDocumentList docList = queryResponse.getResults();
//遍歷所有的文檔
for (SolrDocument doc : docList)
{
System.err.println("獲取所有 field 的名字:" + doc.getFieldNames());
//遍歷文檔中的每個(gè)字段名
for (String fn : doc.getFieldNames())
{
//通過(guò)字段名獲取字段值
System.err.println("filed名稱(chēng):【 " + fn + " 】,field 的值:【" + doc.getFieldValue(fn) + " 】");
}
}
}
//根據(jù)文檔的id來(lái)刪除文檔
@SneakyThrows
@ParameterizedTest
@ValueSource(strings = {"1"})
public void testDeleteById(String id)
{
//根據(jù)文檔的id來(lái)刪除
//參數(shù)1:指定刪除哪個(gè)索引庫(kù)的文檔 參數(shù)2:刪除這個(gè)id的文檔 參數(shù)3:指定多久提交執(zhí)行這個(gè)刪除操作,這里是500毫秒
solrClient.deleteById("books",id,500);
}
//根據(jù)提供的字段和關(guān)鍵詞,通過(guò)查詢(xún),如果該字段包含該關(guān)鍵詞,則該文檔會(huì)被刪除掉
@SneakyThrows
@ParameterizedTest
@CsvSource({
//"title_cn,龍珠"
//匹配所有的文檔,也就是刪除所有文檔
"*,*"
})
//這個(gè)字段包含這個(gè)關(guān)鍵詞的則會(huì)被刪除掉
public void testDeleteByQuery(String field, String term)
{
//因?yàn)?參數(shù)2 需要的類(lèi)型是String,所以這里不用創(chuàng)建SolrQuery查詢(xún)對(duì)象
//str 打印出來(lái) ===> q=title_cn:龍珠
String str = field + ":" + term;
//參數(shù)1:指定刪除哪個(gè)索引庫(kù)的文檔 參數(shù)2:字段名+關(guān)鍵詞 參數(shù)3:指定多久提交執(zhí)行這個(gè)刪除操作,這里是500毫秒
solrClient.deleteByQuery("books",str,500);
}
}
pom.xml 依賴(lài)文檔
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<groupId>cn.ljh</groupId>
<artifactId>solrboot</artifactId>
<version>1.0.0</version>
<name>solrboot</name>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 最基礎(chǔ)的Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot 2.5.3 不再為 Spring Data Solr 提供 Starter,因此只能手動(dòng)添加 Spring Data Solr 依賴(lài) -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>4.3.11</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
到了這里,關(guān)于09、全文檢索 -- Solr -- SpringBoot 整合 Spring Data Solr (生成DAO組件 和 實(shí)現(xiàn)自定義查詢(xún)方法)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!