1. 學習計劃 1、Solr服務搭建 2、Solrj使用測試 3、把資料庫中的數據導入索引庫 4、搜索功能的實現 2. Solr服務搭建 2.1. Solr的環境 Solr是java開發。 需要安裝jdk。 安裝環境Linux。 需要安裝Tomcat。 2.2. 搭建步驟 第一步:把solr 的壓縮 ...
1. 學習計劃
1、Solr服務搭建
2、Solrj使用測試
3、把資料庫中的數據導入索引庫
4、搜索功能的實現
2. Solr服務搭建
2.1. Solr的環境
Solr是java開發。
需要安裝jdk。
安裝環境Linux。
需要安裝Tomcat。
2.2. 搭建步驟
第一步:把solr 的壓縮包上傳到Linux系統
第二步:解壓solr。
第三步:安裝Tomcat,解壓縮即可。
第四步:把solr部署到Tomcat下。
第五步:解壓縮war包。啟動Tomcat解壓。
tail -f ../logs/catalina.out 查看tomcat運行情況 f是迴圈讀取的意思
第六步:把/root/solr-4.10.3/example/lib/ext目錄下的所有的jar包,添加到solr工程中。
[root@localhost ext]# pwd
/root/solr-4.10.3/example/lib/ext
[root@localhost ext]# cp * /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib/
第七步:創建一個solrhome。/example/solr目錄就是一個solrhome。複製此目錄到/usr/local/solr/solrhome
[root@localhost example]# pwd
/root/solr-4.10.3/example
[root@localhost example]# cp -r solr /usr/local/solr/solrhome
[root@localhost example]#
第八步:關聯solr及solrhome。需要修改solr工程的web.xml文件。
第九步:啟動Tomcat
http://192.168.25.154:8080/solr/
和windows下的配置完全一樣。
2.3. 配置業務域
schema.xml中定義
1、商品Id
2、商品標題
3、商品賣點
4、商品價格
5、商品圖片
6、分類名稱
創建對應的業務域。需要制定中文分析器。
創建步驟:
第一步:把中文分析器添加到工程中。
1、把IKAnalyzer2012FF_u1.jar添加到solr工程的lib目錄下
2、把擴展詞典、配置文件放到solr工程的WEB-INF/classes目錄下。
第二步:配置一個FieldType,制定使用IKAnalyzer
修改schema.xml文件
修改Solr的schema.xml文件,添加FieldType:
<fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType> |
第三步:配置業務域,type制定使用自定義的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="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_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"/> |
第四步:重啟tomcat
3. 搜索工程搭建
要實現搜索功能,需要搭建solr服務、搜索服務工程、搜索系統
3.1. 搜索服務工程搭建
可以參考e3-manager創建。
e3-search(聚合工程pom)
|--e3-search-interface(jar)
|--e3-search-Service(war)
e3-search-web(war)
4. 使用solrJ管理索引庫
使用SolrJ可以實現索引庫的增刪改查操作。
4.1. 添加文檔
第一步:把solrJ的jar包添加到工程中。
第二步:創建一個SolrServer,使用HttpSolrServer創建對象。
第三步:創建一個文檔對象SolrInputDocument對象。
第四步:向文檔中添加域。必須有id域,域的名稱必須在schema.xml中定義。
第五步:把文檔添加到索引庫中。
第六步:提交。
@Test public void addDocument() throws Exception { // 第一步:把solrJ的jar包添加到工程中。 // 第二步:創建一個SolrServer,使用HttpSolrServer創建對象。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第三步:創建一個文檔對象SolrInputDocument對象。 SolrInputDocument document = new SolrInputDocument(); // 第四步:向文檔中添加域。必須有id域,域的名稱必須在schema.xml中定義。 document.addField("id", "test001"); document.addField("item_title", "測試商品"); document.addField("item_price", "199"); // 第五步:把文檔添加到索引庫中。 solrServer.add(document); // 第六步:提交。 solrServer.commit(); }
4.2. 刪除文檔
4.2.1. 根據id刪除
第一步:創建一個SolrServer對象。
第二步:調用SolrServer對象的根據id刪除的方法。
第三步:提交。
@Test public void deleteDocumentById() throws Exception { // 第一步:創建一個SolrServer對象。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第二步:調用SolrServer對象的根據id刪除的方法。 solrServer.deleteById("1"); // 第三步:提交。 solrServer.commit(); }
4.2.2. 根據查詢刪除
@Test public void deleteDocumentByQuery() throws Exception { SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); solrServer.deleteByQuery("title:change.me"); solrServer.commit(); }
4.3. 查詢索引庫
查詢步驟:
第一步:創建一個SolrServer對象
第二步:創建一個SolrQuery對象。
第三步:向SolrQuery中添加查詢條件、過濾條件。。。
第四步:執行查詢。得到一個Response對象。
第五步:取查詢結果。
第六步:遍歷結果並列印。
4.3.1. 簡單查詢
@Test public void queryDocument() throws Exception { // 第一步:創建一個SolrServer對象 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第二步:創建一個SolrQuery對象。 SolrQuery query = new SolrQuery(); // 第三步:向SolrQuery中添加查詢條件、過濾條件。。。 query.setQuery("*:*"); // 第四步:執行查詢。得到一個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")); System.out.println(solrDocument.get("item_title")); System.out.println(solrDocument.get("item_price")); } }
4.3.2. 帶高亮顯示
@Test public void queryDocumentWithHighLighting() throws Exception { // 第一步:創建一個SolrServer對象 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第二步:創建一個SolrQuery對象。 SolrQuery query = new SolrQuery(); // 第三步:向SolrQuery中添加查詢條件、過濾條件。。。 query.setQuery("測試"); //指定預設搜索域 query.set("df", "item_keywords"); //開啟高亮顯示 query.setHighlight(true); //高亮顯示的域 query.addHighlightField("item_title"); query.setHighlightSimplePre("<em>"); query.setHighlightSimplePost("</em>"); // 第四步:執行查詢。得到一個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 = null; 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_price")); } }
5. 把商品數據導入到索引庫中
5.1. Dao層
5.1.1. Sql語句
SELECT a.id, a.title, a.sell_point, a.price, a.image, b.`name` category_name FROM `tb_item` a LEFT JOIN tb_item_cat b ON a.cid = b.id WHERE a.`status`=1
需要自己創建Mapper文件。
5.1.2. 創建對應數據集的pojo
public class SearchItem implements Serializable{ private String id; private String title; private String sell_point; private long price; private String image; private String category_name; }
5.1.3. 介面定義
public interface ItemMapper { List<SearchItem> getItemList(); } |
5.1.4. Mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="cn.e3mall.search.mapper.ItemMapper" > <select id="getItemList" resultType="cn.e3mall.common.pojo.SearchItem"> SELECT a.id, a.title, a.sell_point, a.price, a.image, b.`name` category_name FROM `tb_item` a LEFT JOIN tb_item_cat b ON a.cid = b.id WHERE a.`status`=1 </select> </mapper>
5.2. Service層
5.2.1. 功能分析
1、查詢所有商品數據。
2、迴圈把商品數據添加到索引庫。使用solrJ實現。
3、返回成功。返回E3Result
參數:無
返回值:E3Result
5.2.2. solrJ添加索引庫
1、把solrJ的jar包添加到工程。
2、創建一個SolrServer對象。創建一個和sorl服務的連接。HttpSolrServer。
3、創建一個文檔對象。SolrInputDocument。
4、向文檔對象中添加域。必須有一個id域。而且文檔中使用的域必須在schema.xml中定義。
5、把文檔添加到索引庫
6、Commit。
@Test public void addDocument() throws Exception { // 1、把solrJ的jar包添加到工程。 // 2、創建一個SolrServer對象。創建一個和sorl服務的連接。HttpSolrServer。 //如果不帶Collection預設連接Collection1 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 3、創建一個文檔對象。SolrInputDocument。 SolrInputDocument document = new SolrInputDocument(); // 4、向文檔對象中添加域。必須有一個id域。而且文檔中使用的域必須在schema.xml中定義。 document.addField("id", "test001"); document.addField("item_title", "測試商品"); // 5、把文檔添加到索引庫 solrServer.add(document); // 6、Commit。 solrServer.commit(); }
5.2.3. 代碼實現
/** * 將商品數據導入索引庫 * <p>Title: SearchItemServiceImpl</p> * <p>Description: </p> * <p>Company: www.itcast.cn</p> * @version 1.0 */ @Service public class SearchItemServiceImpl implements SearchItemService { @Autowired private ItemMapper itemMapper; @Autowired private SolrServer solrServer; @Override public E3Result importItmes() { try { //查詢商品列表 List<SearchItem> itemList = itemMapper.getItemList(); //導入索引庫 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()); //寫入索引庫 solrServer.add(document); } //提交 solrServer.commit(); //返回成功 return E3Result.ok(); } catch (Exception e) { e.printStackTrace(); return E3Result.build(500, "商品導入失敗"); } } }
5.2.4. SolrServer的配置
<?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"> <bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg index="0" value="http://192.168.25.154:8080/solr"/> </bean> </beans>
5.2.5. 發佈服務
5.3. 表現層
後臺管理工程中調用商品導入服務。
5.3.1. 功能分析
請求的url:/index/item/import
響應的結果:json數據。可以使用E3Result
5.3.2. Controller
@Controller public class SearchItemController { @Autowired private SearchItemService searchItemService; @RequestMapping("/index/item/import") @ResponseBody public E3Result impotItemIndex() { E3Result result = searchItemService.importItmes(); return result; } }
5.4. 解決Mapper映射文件不存在異常
在e3-search-service的pom文件中需要添加資源配置。
<!-- 如果不添加此節點mybatis的mapper.xml文件都會被漏掉。 --> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
6. 搜索功能實現
6.1. 使用sorlJ 查詢索引庫
//使用solrJ實現查詢 @Test public void queryDocument() throws Exception { //創建一個SolrServer對象 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); //創建一個查詢對象,可以參考solr的後臺的查詢功能設置條件 SolrQuery query = new SolrQuery(); //設置查詢條件 // query.setQuery("阿爾卡特"); query.set("q","阿爾卡特"); //設置分頁條件 query.setStart(1); query.setRows(2); //開啟高亮 query.setHighlight(true); query.addHighlightField("item_title"); query.setHighlightSimplePre("<em>"); query.setHighlightSimplePost("</em>"); //設置預設搜索域 query.set("df", "item_title"); //執行查詢,得到一個QueryResponse對象。 QueryResponse queryResponse = solrServer.query(query); //取查詢結果總記錄數 SolrDocumentList solrDocumentList = queryResponse.getResults(); System.out.println("查詢結果總記錄數:" + solrDocumentList.getNumFound()); //取查詢結果 Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); for (SolrDocument solrDocument : solrDocumentList) { System.out.println(solrDocument.get("id")); //取高亮後的結果 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"); } System.out.println(title); 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")); } }
6.2. 功能分析
把搜索結果頁面添加到工程中。
請求的url:/search
請求的方法:GET
參數:
keyword:查詢條件
Page:頁碼。如果沒有此參數,需要給預設值1。
返回的結果:
1)商品列表
2)總頁數
3)總記錄數
使用jsp展示,返回邏輯視圖。
商品列表使用:SearchItem表示。
需要把查詢結果封裝到一個pojo中:
1)商品列表List<SearchItem>
2)總頁數。Int totalPages。總記錄數/每頁顯示的記錄數向上取整。把每頁顯示的記錄是配置到屬性文件中。
3)總記錄數。Int recourdCount
public class SearchResult implements Serializable { private List<SearchItem> itemList; private int totalPages; private int recourdCount; } |
6.3. Dao層
跟據查詢條件查詢索引庫,返回對應的結果。
參數:SolrQuery
返回結果:SearchResult
@Repository public class SearchDao { @Autowired private SolrServer solrServer; public SearchResult search(SolrQuery query) throws Exception { //根據查詢條件查詢索引庫 QueryResponse queryResponse = solrServer.query(query); //取查詢結果總記錄數 SolrDocumentList solrDocumentList = queryResponse.getResults(); long numFound = solrDocumentList.getNumFound(); //創建一個返回結果對象 SearchResult result = new SearchResult(); result.setRecourdCount((int) numFound); //創建一個商品列表對象 List<SearchItem> itemList = new ArrayList<>(); //取商品列表 //取高亮後的結果 Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); for (SolrDocument solrDocument : solrDocumentList) { //取商品信息 SearchItem searchItem = new SearchItem(); searchItem.setCategory_name((String) solrDocument.get("item_category_name")); searchItem.setId((String) solrDocument.get("id")); searchItem.setImage((String) solrDocument.get("item_image")); searchItem.setPrice((long) solrDocument.get("item_price")); searchItem.setSell_point((String) solrDocument.get("item_sell_point")); //取高亮結果 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"); } searchItem.setTitle(itemTitle); //添加到商品列表 itemList.add(searchItem); } //把列表添加到返回結果對象中 result.setItemList(itemList); return result; } }
6.4. Service層
需要有一個介面一個實現類,需要對外發佈服務。
參數:String keyWord
int page
int rows
返回值:SearchResult
業務邏輯:
1)根據參數創建一個查詢條件對象。需要指定預設搜索域,還需要配置高亮顯示。
2)調用dao查詢。得到一個SearchResult對象
3)計算查詢總頁數,每頁顯示記錄數就是rows參數。
@Service public class SearchServiceImpl implements SearchService { @Autowired private SearchDao searchDao; @Value("${DEFAULT_FIELD}") private String DEFAULT_FIELD; @Override public SearchResult search(String keyWord, int page, int rows) throws Exception { //創建一個SolrQuery對象 SolrQuery query = new SolrQuery(); //設置查詢條件 query.setQuery(keyWord); //設置分頁條件 query.setStart((page - 1) * rows); //設置rows query.setRows(rows); //設置預設搜索域 query.set("df", DEFAULT_FIELD); //設置高亮顯示 query.setHighlight(true); query.addHighlightField("item_title"); query.setHighlightSimplePre("<em style=\"color:red\">"); query.setHighlightSimplePost("</em>"); //執行查詢 SearchResult searchResult = searchDao.search(query); //計算總頁數 int recourdCount = searchResult.getRecourdCount(); int pages = recourdCount / rows; if (recourdCount % rows > 0) pages++; //設置到返回結果 searchResult.setTotalPages(pages); return searchResult; } }
6.4.1. 發佈服務
6.5. 表現層
6.5.1. 引用服務
在e3-search-web中添加介面依賴
Springmvc.xml
6.5.2. Controller
請求的url:/search
請求的方法:GET
參數:
keyword:查詢條件
Page:頁碼。如果沒有此參數,需要給預設值1。
返回的結果:
使用jsp展示,返回邏輯視圖。
@Controller public class SearchController { @Autowired private SearchService searchService; @Value("${PAGE_ROWS}") private Integer PAGE_ROWS; @RequestMapping("/search") public String search(String keyword,@RequestParam(defaultValue="1") Integer page, Model model) throws Exception { //需要轉碼 keyword = new String(keyword.getBytes("iso8859-1"), "utf-8"); //調用Service查詢商品信息 SearchResult result = searchService.search(keyword, page, PAGE_ROWS); //把結果傳遞給jsp頁面 model.addAttribute("query", keyword); model.addAttribute("totalPages", result.getTotalPages()); model.addAttribute("recourdCount", result.getRecourdCount()); model.addAttribute("page", page); model.addAttribute("itemList", result.getItemList()); //返回邏輯視圖 return "search"; } }