目錄: 一、solr的大概認識 二、solr安裝 三、solr的深度認識 四、solr的使用 (1)由於我們用到中文,所以需要中文分析器,這裡我用IK Analyzer 2012FF_hf1 (2)同時在schema.xml指定好業務域 field name...... (3)同時在schema.x ...
目錄
- 一、solr的大概認識
- 二、solr安裝
- 三、solr的深度認識
- 四、solr的使用
- 五、用java代碼增刪data到solr中
- 六、實際開發中導入資料庫數據到solr的data中的步驟
- 七、實際開發中實現搜索功能步驟
一、solr的大概認識
(1)在互聯網項目裡面,絕大部分是用全文檢索伺服器,
lucense(基於java的全文檢索api)和solr(基於lucense的全文檢索伺服器)都可以實現。用lucense需要自己來管理維護索引庫,進行索引庫的優化,緩存的添加。而solr配置一下就好了,比較方便。
(2)solr本質上是一個war包,然後部署到servlet容器中,容器你可以選擇用tomcat,也可以選擇更加輕量級的jetty
(3)反正solr就是:比如 好多好多商品,每個都好長名字。那我比如搜索 '漂亮手機' 的時候,solr自動劃分欄位(比如劃分成 ‘漂亮’,‘手機’),自動去匹配資料庫中對應的商品名列表,商品名列表也會被劃分,完全匹配的就會展示出來
(4)solr使用的時候分兩部分:把商品名列表放到solr;搜索商品
二、solr安裝
(1)安裝jdk(省略)
(2)下載 solr-4.10.3.tgz.tgz並解壓
鏈接:https://pan.baidu.com/s/1G6-aLXboFKThzRiDtUV-Xg
提取碼:0j9o
(3)安裝tomcat(省略)
(4)拷貝solr的war包到tomcat下
[root@localhost apache-tomcat-7.0.47]# cp /usr/solr/solr-4.10.3/dist/solr-4.10.3.war webapps/solr.war
(5)啟動tomcat自動解壓縮war包:
[root@localhost apache-tomcat-7.0.47]# bin/startup.sh
(6)查看控制台,檢查tomcat啟動情況:
[root@localhost apache-tomcat-7.0.47]# tail -f logs/catalina.out
(7)關閉tomcat
[root@localhost apache-tomcat-7.0.47]# bin/shutdown.sh
(8)刪除war包
[root@localhost apache-tomcat-7.0.47]# rm -f webapps/solr.war
(9)把一些jar包放到solr工程下麵去:
[root@localhost apache-tomcat-7.0.47]# cp /usr/solr/solr-4.10.3/example/lib/ext/* webapps/solr/WEB-INF/lib/
(10)配置solrhome
[root@localhost solr-4.10.3]# cp -r example/solr /usr/solr/solrhome
[root@localhost apache-tomcat-7.0.47]# cd webapps/solr/WEB-INF/
[root@localhost WEB-INF]# vim web.xml
修改solr/home的地址,並且去掉註釋
(11)再次開啟tomcat
[root@localhost apache-tomcat-7.0.47]# bin/startup.sh
(12)在Windows那邊訪問solr
http://192.168.25.128:8080/solr/
三、solr的深度認識
用戶可以通過http請求,向搜索引擎伺服器提交一定格式的XML文件或數據,生成索引;也可以通過Http Get操作提出查找請求,並得到XML格式的返回結果。
四、solr的使用
(1)由於我們用到中文,所以需要中文分析器,這裡我用IK Analyzer 2012FF_hf1
鏈接:https://pan.baidu.com/s/15TUJaTJir9d0A0FRaiBl_A
提取碼:5xrw
下載好IK Analyzer 2012FF_hf1文件後,安裝步驟:
<1>拷貝IKAnalyzer2012FF_u1.jar到tomcat的solr項目下的lib中:
[root@localhost apache-tomcat-7.0.47]# cd webapps/solr/WEB-INF/lib
[root@localhost lib]# cp /usr/solr/IK_Analyzer_2012FF_hf1/IKAnalyzer2012FF_u1.jar .
<2>拷貝三個文件到tomcat的solr項目下的classes文件中
[root@localhost lib]# cd ..
[root@localhost WEB-INF]# mkdir classes
[root@localhost IK_Analyzer_2012FF_hf1]# cp ext_stopword.dic IKAnalyzer.cfg.xml mydict.dic /usr/tomcat/apache-tomcat-7.0.47/webapps/solr/WEB-INF/classes
<3>在solrhome裡面的schema.xml定義一個fieldtype,來指定IK分析器。
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
(2)同時在schema.xml指定好業務域 field name......
由於solr本身就定義了id,所以我們用solr的id來保存我們要的id就可以了。
註意:string類型的是不可拆分的,而TextField類型的是可拆分的
<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="long" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category_name" type="string" indexed="true" stored="true" />
<field name="item_desc" type="text_ik" indexed="true" stored="false" />
(3)同時在schema.xml配置複製域
就是說你找一個商品的時候,可以在item_keywords中的四個域中找
<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"/>
<copyField source="item_category_name" dest="item_keywords"/>
<copyField source="item_desc" dest="item_keywords"/>
(4)啟動solr看看業務域是否能用
[root@localhost apache-tomcat-7.0.47]# bin/startup.sh
進入http://192.168.25.128:8080/solr/裡面的collection1的Analyse ,選擇一個域,比如:
五、用java代碼增刪data到solr中
(1)導包
<!-- 添加solrJ的依賴 -->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
</dependency>
(2)測試一下
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
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.SolrInputDocument;
import org.junit.Test;
public class TestSolrJ {
@Test
public void testAddDocument() throws Exception {
//創建一個SolrServer對象。創建一個HttpSolrServer對象
//需要指定solr服務的url
SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
//創建一個文檔對象SolrInputDocument
SolrInputDocument document = new SolrInputDocument();
//向文檔中添加域,必須有id域,域的名稱必須在schema.xml中定義
document.addField("id", "1234");
document.addField("item_title", "測試商品2");
document.addField("item_price", 1000);
//把文檔對象寫入索引庫
solrServer.add(document);
//提交
solrServer.commit();
}
@Test
public void deleteDocumentById() throws Exception {
SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
solrServer.deleteById("123");
//提交
solrServer.commit();
}
@Test
public void deleteDocumentByQuery() throws Exception {
SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
solrServer.deleteByQuery("item_title:測試商品3");
solrServer.commit();
}
}
六、實際開發中導入資料庫數據到solr的data中的步驟
<1>定義一個 (將資料庫的部分數據導入到solr的data中的)介面
import com.wine.common.pojo.WineResult;
public interface SearchItemService {
WineResult importItemsToIndex();
}
<2>實現上方介面
@Service
public class SearchItemServiceImpl implements SearchItemService {
@Autowired
private SearchItemMapper searchItemMapper;
@Autowired
private SolrServer solrServer;
@Override
public WineResult importItemsToIndex() {
try {
//1、先查詢所有商品數據
List<SearchItem> itemList = searchItemMapper.getItemList();
//2、遍歷商品數據添加到索引庫
for (SearchItem searchItem : itemList) {
//創建文檔對象
SolrInputDocument document = new SolrInputDocument();
//向文檔中添加域
document.addField("id", searchItem.getId());
document.addField("item_title", searchItem.getTitle());
document.addField("item_sell_point", searchItem.getSell_point());
document.addField("item_price", searchItem.getPrice());
document.addField("item_image", searchItem.getImage());
document.addField("item_category_name", searchItem.getCategory_name());
document.addField("item_desc", searchItem.getItem_desc());
//把文檔寫入索引庫
solrServer.add(document);
}
//3、提交
solrServer.commit();
} catch (Exception e) {
e.printStackTrace();
return WineResult.build(500, "數據導入失敗");
}
//4、返回添加成功
return WineResult.ok();
}
}
<3>solr連接文件applicationContext-solr.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 單機版solr的連接 -->
<bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
<constructor-arg name="baseURL" value="http://192.168.25.128:8080/solr/collection1"/>
</bean>
<!-- 集群版solr連接 -->
<!-- <bean id="cloudSolrServer" class="org.apache.solr.client.solrj.impl.CloudSolrServer">
<constructor-arg name="zkHost" value="192.168.25.128:2181,192.168.25.128:2182,192.168.25.128:2183"></constructor-arg>
<property name="defaultCollection" value="collection2"/>
</bean> -->
</beans>
七、實際開發中實現搜索功能步驟
(1)首先測試一下,輸入測試商品,看看搜索出什麼東西:
@Test
public void searchDocumet() throws Exception {
//創建一個SolrServer對象
SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
//創建一個SolrQuery對象
SolrQuery query = new SolrQuery();
//設置查詢條件、過濾條件、分頁條件、排序條件、高亮
//query.set("q", "*:*");
query.setQuery("測試商品");
//分頁條件
query.setStart(0);
query.setRows(10);
//設置預設搜索域
query.set("df", "item_keywords");
//設置高亮
query.setHighlight(true);
//高亮顯示的域
query.addHighlightField("item_title");
query.setHighlightSimplePre("<div>");
query.setHighlightSimplePost("</div>");
//執行查詢,得到一個Response對象
QueryResponse response = solrServer.query(query);
//取查詢結果
SolrDocumentList solrDocumentList = response.getResults();
//取查詢結果總記錄數
System.out.println("查詢結果總記錄數:" + solrDocumentList.getNumFound());
for (SolrDocument solrDocument : solrDocumentList) {
System.out.println(solrDocument.get("id"));
//取高亮顯示
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
List<String> list = highlighting.get(solrDocument.get("id")).get("item_title");
String itemTitle = "";
if (list != null && list.size() >0) {
itemTitle = list.get(0);
} else {
itemTitle = (String) solrDocument.get("item_title");
}
System.out.println(itemTitle);
System.out.println(solrDocument.get("item_sell_point"));
System.out.println(solrDocument.get("item_price"));
System.out.println(solrDocument.get("item_image"));
System.out.println(solrDocument.get("item_category_name"));
System.out.println("=============================================");
}
}
結果:(註意:sol按照匹配次數多的來排序)
我已經在solor中插入了數據(id,title,....):(123456, 測試商品2,...),(1,測試2商品,...),(2,2商品測試,...),(,7,66測試66商品,...),(5,2測試,...),(6,2商品,...)
查詢結果總記錄數:6
123456
<div>測試</div><div>商品</div>2
null
1000
null
null
=============================================
1
<div>測試</div>2<div>商品</div>
null
1000
null
null
=============================================
2
2<div>商品</div><div>測試</div>
null
1000
null
null
=============================================
7
66<div>測試</div>66<div>商品</div>
null
1000
null
null
=============================================
5
2<div>測試</div>
null
1000
null
null
=============================================
6
2<div>商品</div>
null
1000
null
null
=============================================
(2)具體代碼實現
<1>添加一個訪問solr的dao:
/**
* 查詢索引庫商品dao
*/
@Repository
public class SearchDao {
@Autowired
private SolrServer solrServer;
/**
SearchResult 這個pojo類裡面的數據:
private long totalPages;
private long recordCount;
private List<SearchItem> itemList;
**/
public SearchResult search(SolrQuery query) throws Exception{
//根據query對象進行查詢
QueryResponse response = solrServer.query(query);
//取查詢結果
SolrDocumentList solrDocumentList = response.getResults();
//取查詢結果總記錄數
long numFound = solrDocumentList.getNumFound();
SearchResult result = new SearchResult();
result.setRecordCount(numFound);
List<SearchItem> itemList = new ArrayList<>();
//把查詢結果封裝到SearchItem對象中
for (SolrDocument solrDocument : solrDocumentList) {
SearchItem item = new SearchItem();
item.setCategory_name((String) solrDocument.get("item_category_name"));
item.setId((String) solrDocument.get("id"));
//取一張圖片
String image = (String) solrDocument.get("item_image");
if (StringUtils.isNotBlank(image)) {
image = image.split(",")[0];
}
item.setImage(image);
item.setPrice((long) solrDocument.get("item_price"));
item.setSell_point((String) solrDocument.get("item_sell_point"));
//取高亮顯示
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
List<String> list = highlighting.get(solrDocument.get("id")).get("item_title");
String title = "";
if (list != null && list.size() > 0) {
title = list.get(0);
} else {
title = (String) solrDocument.get("item_title");
}
item.setTitle(title);
//添加到商品列表
itemList.add(item);
}
//把結果添加到SearchResult中
result.setItemList(itemList);
//返回
return result;
}
}
<2>添加調用dao的service類:
/**
* 搜索服務功能實現
*/
@Service
public class SearchServiceImpl implements SearchService {
@Autowired
private SearchDao searchDao;
@Override
public SearchResult search(String queryString, int page, int rows) throws Exception {
//根據查詢條件拼裝查詢對象
//創建一個SolrQuery對象
SolrQuery query = new SolrQuery();
//設置查詢條件
query.setQuery(queryString);
//設置分頁條件
if (page < 1) page =1;
query.setStart((page - 1) * rows);
if (rows < 1) rows = 10;
query.setRows(rows);
//設置預設搜索域
query.set("df", "item_title");
//設置高亮顯示
query.setHighlight(true);
query.addHighlightField("item_title");
query.setHighlightSimplePre("<font color='red'>");
query.setHighlightSimplePost("</font>");
//調用dao執行查詢
SearchResult searchResult = searchDao.search(query);
//計算查詢結果的總頁數
long recordCount = searchResult.getRecordCount();
long pages = recordCount / rows;
if (recordCount % rows > 0) {
pages++;
}
searchResult.setTotalPages(pages);
//返回結果
return searchResult;
}
}
<3>控制層
@Controller
public class SearchController {
@Autowired
private SearchService searchService;
@Value("${SEARCH_RESULT_ROWS}")
private Integer SEARCH_RESULT_ROWS;
@RequestMapping("/search")
public String search(@RequestParam("q")String queryString,
@RequestParam(defaultValue="1")Integer page, Model model) throws Exception {
//int a = 1/0;
//調用服務執行查詢
//把查詢條件進行轉碼,解決get亂碼問題
queryString = new String(queryString.getBytes("iso8859-1"), "utf-8");
SearchResult searchResult = searchService.search(queryString, page, SEARCH_RESULT_ROWS);
//把結果傳遞給頁面
model.addAttribute("query", queryString);
model.addAttribute("totalPages", searchResult.getTotalPages());
model.addAttribute("itemList", searchResult.getItemList());
model.addAttribute("page", page);
//返回邏輯視圖
return "search";
}
}