利用solr實現(xiàn)商品的搜索功能(實例講解)
后期補充:
為什么要用solr服務(wù),為什么要用luncence?
問題提出:當我們訪問購物網(wǎng)站的時候,我們可以根據(jù)我們隨意所想的內(nèi)容輸入關(guān)鍵字就可以查詢出相關(guān)的內(nèi)容,這是怎么做到呢?這些隨意的數(shù)據(jù)不可能是根據(jù)數(shù)據(jù)庫的字段查詢的,那是怎么查詢出來的呢,為什么千奇百怪的關(guān)鍵字都可以查詢出來呢?
答案就是全文檢索工具的實現(xiàn),luncence采用了詞元匹配和切分詞。舉個例子:北京天安門------luncence切分詞:北京 京天 天安 安門 等等這些分詞。所以我們搜索的時候都可以檢索到。
有一種分詞器就是IKAnalyzer中文分詞器,它有細粒度切分和智能切分,即根據(jù)某種智能算法。
這就使用solr的最大的好處:檢索功能的實現(xiàn)。
使用步驟;
(1)solr服務(wù)器搭建,因為solr是用java5開發(fā)的,所以需要jdk和tomcat。搭建部署
(2)搭建完成后,我們需要將要展示的字段引入solr的庫中。配置spring與solr結(jié)合,工程啟動的時候啟動solr
(3)將數(shù)據(jù)庫中的查詢內(nèi)容導(dǎo)入到solr索引庫,這里使用的是solrj的客戶端實現(xiàn)的。具體使用可以參考api
(4)建立搜索服務(wù),供客戶端調(diào)用。調(diào)用solr,查詢內(nèi)容,這中間有分頁功能的實現(xiàn)。solr高亮顯示的實現(xiàn)。
(5)客戶端接收頁面的請求參數(shù),調(diào)用搜索服務(wù),進行搜索。
業(yè)務(wù)字段判斷標準:
1、在搜索時是否需要在此字段上進行搜索。例如:商品名稱、商品的賣點、商品的描述
(這些相當于將標簽給了solr,導(dǎo)入商品數(shù)據(jù)后,solr?qū)@些字段的對應(yīng)的商品的具體內(nèi)容進行分詞切分,然后,我們就可以搜索到相關(guān)內(nèi)容了)
2、后續(xù)的業(yè)務(wù)是否需要用到此字段。例如:商品id。
需要用到的字段:
1、商品id
2、商品title
3、賣點
4、價格
5、商品圖片
6、商品分類名稱
7、商品描述
Solr中的業(yè)務(wù)字段:
1、id——》商品id
其他的對應(yīng)字段創(chuàng)建solr的字段。
<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" /> <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"/>
重新啟動tomcat
Solr 是Apache下的一個頂級開源項目,采用Java開發(fā),它是基于Lucene的全文搜索服務(wù)器。Solr提供了比Lucene更為豐富的查詢語言,同時實現(xiàn)了可配置、可擴展,并對索引、搜索性能進行了優(yōu)化。
Solr是一個全文檢索服務(wù)器,只需要進行配置就可以實現(xiàn)全文檢索服務(wù)。有效降低頻繁訪問數(shù)據(jù)庫對數(shù)據(jù)庫造成的壓力。
第一步:將solr部署在linux系統(tǒng)下。
第二步:solrJ是solr的客戶端,使用它需要依賴solrJ的jar包。
第三步:將數(shù)據(jù)庫的內(nèi)容添加到solr的索引庫,這樣查詢就在索引庫查詢,而不是數(shù)據(jù)庫了。
controller層:
@Controller @RequestMapping("/manager") public class ItemController { @Autowired private ItemService itemService; @RequestMapping("/importall") @ResponseBody public TaotaoResult importAllItem(){ TaotaoResult result= itemService.importAllItem(); return result; } }<br>service層編寫:<br>多表查詢商品,顯示在頁面的邏輯編寫:<br>mapper.java
package com.taotao.search.mapper; import java.util.List; import com.taotao.search.pojo.Item; public interface ItemMapper { List<Item> getItemList(); }
mapper.xml
<?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="com.taotao.search.mapper.ItemMapper"> <select id="getItemList" resultType="com.taotao.search.pojo.Item"> 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 </select> </mapper>
第四步:從索引庫查詢的邏輯編寫:
//從索引庫里面獲取商品信息,現(xiàn)在這個dao層是從索引庫獲取信息,因為之前的寫的邏輯是將db里面的數(shù)據(jù)導(dǎo)入到索引庫。后面的查詢都是從索引庫中進行,而不從數(shù)據(jù)庫了 @Repository public class SearchDaoImpl implements SearchDao { @Autowired private SolrServer solrServer; @Override public SearchResult search(SolrQuery query) throws Exception { //這是從索引庫里面,直接執(zhí)行查詢 QueryResponse response = solrServer.query(query); //獲取查詢的結(jié)果 SolrDocumentList documentList= response.getResults(); SearchResult result=new SearchResult(); //這是獲取總記錄數(shù) result.setRecordCount(documentList.getNumFound()); List<Item> itemList=new ArrayList<>(); //商品的高亮顯示,即當鼠標移到字上時,該字體變色,這是從QueryResponse中獲取的 Map<String, Map<String, List<String>>> highlighting = response.getHighlighting(); for (SolrDocument solrDocument : documentList) { //每個SolrDocument都是一個商品pojo的內(nèi)容,所以這里要創(chuàng)建一個商品的pojo對象,來獲取詳細的字段 Item item=new Item(); item.setId((String) solrDocument.get("id")); //高亮顯示是title的高亮顯示 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); item.setPrice((Long) solrDocument.get("item_price")); item.setImage((String) solrDocument.get("item_image")); item.setCategory_name((String) solrDocument.get(" item_category_name")); item.setSell_point((String) solrDocument.get("item_sell_point")); itemList.add(item); } result.setItemList(itemList); return result; } }
第五步:索引庫內(nèi)容建立好后,開始編寫對外的服務(wù)接口,即通過條件搜索具體的商品,比如手機,會顯示出總共的手機列表信息,第幾頁,總共多少頁,總共多少個搜索結(jié)果
請求的url:
/search/query?q={查詢條件}&page={page}&rows={rows}
返回的結(jié)果:TaotaoResult包裝商品列表。
創(chuàng)建一個sql語句對應(yīng)的pojo,單獨建立一個pojo
用來裝顯示的內(nèi)容列表:
public class Item { private String id; private String title; private String sell_point; private long price; private String image; private String category_name; private String item_des; }
controller層:
@Controller public class SearchController { @Autowired private SearchService searchService; @RequestMapping(value="/query", method=RequestMethod.GET) @ResponseBody public TaotaoResult search(@RequestParam("q")String queryString, @RequestParam(defaultValue="1")Integer page, @RequestParam(defaultValue="60")Integer rows) { //查詢條件不能為空 if (StringUtils.isBlank(queryString)) { return TaotaoResult.build(400, "查詢條件不能為空"); } SearchResult searchResult = null; try { queryString = new String(queryString.getBytes("iso8859-1"), "utf-8"); searchResult = searchService.search(queryString, page, rows); } catch (Exception e) { e.printStackTrace(); return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e)); } return TaotaoResult.ok(searchResult); } }<br><br><br> 1 <span style="font-size: 16px">service層:利用solrJ的solrQurery來查詢:</span>
前提是要寫好如何從索引庫讀取數(shù)據(jù):
下面是服務(wù)的接口層編寫:
controller:
@Controller public class SearchController { @Autowired private SearchService searchService; @RequestMapping(value="/query", method=RequestMethod.GET) @ResponseBody public TaotaoResult search(@RequestParam("q")String queryString, @RequestParam(defaultValue="1")Integer page, @RequestParam(defaultValue="60")Integer rows) { //查詢條件不能為空 if (StringUtils.isBlank(queryString)) { return TaotaoResult.build(400, "查詢條件不能為空"); } SearchResult searchResult = null; try { queryString = new String(queryString.getBytes("iso8859-1"), "utf-8"); searchResult = searchService.search(queryString, page, rows); } catch (Exception e) { e.printStackTrace(); return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e)); } return TaotaoResult.ok(searchResult); } }
@Service public class SearchServiceImpl implements SearchService { @Autowired private SearchDao searchDao; @Override public SearchResult search(String queryString, int page, int rows) throws Exception { SolrQuery query=new SolrQuery(); query.setQuery(queryString); query.setStart((page-1)*rows); query.setRows(rows); //設(shè)置默認的查詢搜索域,即默認的查詢 query.set("df","item_keywords"); //設(shè)置高亮顯示 query.setHighlight(true); query.addHighlightField("item_title"); query.setHighlightSimplePre("<em style=\"color:red\">"); query.setHighlightSimplePost("</em>"); //執(zhí)行查詢 SearchResult searchResult = searchDao.search(query); //根據(jù)結(jié)果來計算商品總共多少頁 long recordCount=searchResult.getRecordCount(); long pageCount=recordCount/rows; if (recordCount % rows > 0) { pageCount++; } searchResult.setPageCount(pageCount); searchResult.setCurPage((long) page); return searchResult; } }
客戶端通過輸入商品來實現(xiàn)搜索功能:
controller層:
@Controller
public class SearchController { @Autowired private SearchService searchService; @RequestMapping("/search") public String search(@RequestParam("q")String queryString, @RequestParam(defaultValue="1")Integer page, Model model) { if (queryString != null) { try { queryString = new String(queryString.getBytes("iso8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } SearchResult searchResult = searchService.search(queryString, page); //向頁面?zhèn)鬟f參數(shù) model.addAttribute("query", queryString); //model.addAttribute("totalPages", searchResult.getPageCount()); model.addAttribute("itemList", searchResult.getItemList()); model.addAttribute("page", page); return "search"; } }
service層:
@Service public class SearchServiceImpl implements SearchService { @Value("${SEARCH_BASE_URL}") private String SEARCH_BASE_URL; @Override public SearchResult search(String queryString, int page) { //這里需要的是連接+參數(shù).這里每頁顯示的記錄條數(shù),可以傳遞也可以不用傳遞 // 調(diào)用taotao-search的服務(wù) //查詢參數(shù) Map<String, String> param = new HashMap<>(); param.put("q", queryString); param.put("page", page + ""); try { //調(diào)用服務(wù) String json = HttpClientUtil.doGet(SEARCH_BASE_URL, param); //把字符串轉(zhuǎn)換成java對象 TaotaoResult taotaoResult = TaotaoResult.formatToPojo(json, SearchResult.class); SearchResult result = (SearchResult) taotaoResult.getData(); return result; /* if (taotaoResult.getStatus() == 200) { }*/ } catch (Exception e) { e.printStackTrace(); return null; } } }
以上這篇利用solr實現(xiàn)商品的搜索功能(實例講解)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java刷題之最小k個數(shù)的思路及具體實現(xiàn)
這篇文章主要介紹了Java刷題之最小k個數(shù)的思路及具體實現(xiàn),最小K個數(shù)是一個經(jīng)典的top-K問題,可以通過整體排序、建立小根堆或大根堆的方式解決,排序方式時間復(fù)雜度較高,適合數(shù)據(jù)量小的場景,小根堆適合k較小的情況,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-10-10Springboot解決no main manifest attribute錯誤
在開發(fā)Springboot項目時,使用java -jar命令運行jar包可能出現(xiàn)no main manifest attribute錯誤,本文就來介紹一下該錯誤的解決方法,感興趣的可以了解一下2024-09-09