後期補充:java
爲何要用solr服務,爲何要用luncence?linux
問題提出:當咱們訪問購物網站的時候,咱們能夠根據咱們隨意所想的內容輸入關鍵字就能夠查詢出相關的內容,這是怎麼作到呢?這些隨意的數據不多是根據數據庫的字段查詢的,那是怎麼查詢出來的呢,爲何千奇百怪的關鍵字均可以查詢出來呢?算法
答案就是全文檢索工具的實現,luncence採用了詞元匹配和切分詞。舉個例子:北京天安門------luncence切分詞:北京 京天 天安 安門 等等這些分詞。因此咱們搜索的時候均可以檢索到。sql
有一種分詞器就是IKAnalyzer中文分詞器,它有細粒度切分和智能切分,即根據某種智能算法。數據庫
這就使用solr的最大的好處:檢索功能的實現。json
使用步驟;tomcat
(1)solr服務器搭建,由於solr是用java5開發的,因此須要jdk和tomcat。搭建部署服務器
(2)搭建完成後,咱們須要將要展現的字段引入solr的庫中。配置spring與solr結合,工程啓動的時候啓動solrmybatis
(3)將數據庫中的查詢內容導入到solr索引庫,這裏使用的是solrj的客戶端實現的。具體使用能夠參考apiapp
(4)創建搜索服務,供客戶端調用。調用solr,查詢內容,這中間有分頁功能的實現。solr高亮顯示的實現。
(5)客戶端接收頁面的請求參數,調用搜索服務,進行搜索。
業務字段判斷標準:
一、在搜索時是否須要在此字段上進行搜索。例如:商品名稱、商品的賣點、商品的描述
(這些至關於將標籤給了solr,導入商品數據後,solr對這些字段的對應的商品的具體內容進行分詞切分,而後,咱們就能夠搜索到相關內容了)
二、後續的業務是否須要用到此字段。例如:商品id。
須要用到的字段:
一、商品id
二、商品title
三、賣點
四、價格
五、商品圖片
六、商品分類名稱
七、商品描述
Solr中的業務字段:
一、id——》商品id
其餘的對應字段建立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開發,它是基於Lucene的全文搜索服務器。Solr提供了比Lucene更爲豐富的查詢語言,同時實現了可配置、可擴展,並對索引、搜索性能進行了優化。
Solr是一個全文檢索服務器,只須要進行配置就能夠實現全文檢索服務。有效下降頻繁訪問數據庫對數據庫形成的壓力。
第一步:將solr部署在linux系統下。
第二步:solrJ是solr的客戶端,使用它須要依賴solrJ的jar包。
第三步:將數據庫的內容添加到solr的索引庫,這樣查詢就在索引庫查詢,而不是數據庫了。
controller層:
1
2
3
4
5
6
7
8
9
10
11
12
|
@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
|
1
2
3
4
5
6
7
8
9
10
|
package
com.taotao.search.mapper;
import
java.util.List;
import
com.taotao.search.pojo.Item;
public
interface
ItemMapper {
List<Item> getItemList();
}
|
mapper.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?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>
|
第四步:從索引庫查詢的邏輯編寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
//從索引庫裏面獲取商品信息,如今這個dao層是從索引庫獲取信息,由於以前的寫的邏輯是將db裏面的數據導入到索引庫。後面的查詢都是從索引庫中進行,而不從數據庫了
@Repository
public
class
SearchDaoImpl
implements
SearchDao {
@Autowired
private
SolrServer solrServer;
@Override
public
SearchResult search(SolrQuery query)
throws
Exception {
//這是從索引庫裏面,直接執行查詢
QueryResponse response = solrServer.query(query);
//獲取查詢的結果
SolrDocumentList documentList= response.getResults();
SearchResult result=
new
SearchResult();
//這是獲取總記錄數
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的內容,因此這裏要建立一個商品的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;
}
}
|
第五步:索引庫內容創建好後,開始編寫對外的服務接口,即經過條件搜索具體的商品,好比手機,會顯示出總共的手機列表信息,第幾頁,總共多少頁,總共多少個搜索結果
請求的url:
/search/query?q={查詢條件}&page={page}&rows={rows}
返回的結果:TaotaoResult包裝商品列表。
建立一個sql語句對應的pojo,單獨創建一個pojo
用來裝顯示的內容列表:
1
2
3
4
5
6
7
8
9
10
|
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層:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@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>
|
前提是要寫好如何從索引庫讀取數據:
下面是服務的接口層編寫:
controller:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@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);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@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);
//設置默認的查詢搜索域,即默認的查詢
query.set(
"df"
,
"item_keywords"
);
//設置高亮顯示
query.setHighlight(
true
);
query.addHighlightField(
"item_title"
);
query.setHighlightSimplePre(
"<em style=\"color:red\">"
);
query.setHighlightSimplePost(
"</em>"
);
//執行查詢
SearchResult searchResult = searchDao.search(query);
//根據結果來計算商品總共多少頁
long
recordCount=searchResult.getRecordCount();
long
pageCount=recordCount/rows;
if
(recordCount % rows >
0
) {
pageCount++;
}
searchResult.setPageCount(pageCount);
searchResult.setCurPage((
long
) page);
return
searchResult;
}
}
|
客戶端經過輸入商品來實現搜索功能:
controller層:
@Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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);
//向頁面傳遞參數
model.addAttribute(
"query"
, queryString);
//model.addAttribute("totalPages", searchResult.getPageCount());
model.addAttribute(
"itemList"
, searchResult.getItemList());
model.addAttribute(
"page"
, page);
return
"search"
;
}
}
|
service層:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
@Service
public
class
SearchServiceImpl
implements
SearchService {
@Value
(
"${SEARCH_BASE_URL}"
)
private
String SEARCH_BASE_URL;
@Override
public
SearchResult search(String queryString,
int
page) {
//這裏須要的是鏈接+參數.這裏每頁顯示的記錄條數,能夠傳遞也能夠不用傳遞
// 調用taotao-search的服務
//查詢參數
Map<String, String> param =
new
HashMap<>();
param.put(
"q"
, queryString);
param.put(
"page"
, page +
""
);
try
{
//調用服務
String json = HttpClientUtil.doGet(SEARCH_BASE_URL, param);
//把字符串轉換成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
;
}
}
}
|