mall整合Elasticsearch實現商品搜尋
本文主要講解mall整合Elasticsearch的過程,以實現商品資訊在Elasticsearch中的匯入、查詢、修改、刪除為例。
SpringBoot實戰電商專案mall(25k+star)地址:
https://
github。com/macrozheng/m
all
專案使用框架介紹
Elasticsearch
Elasticsearch 是一個分散式、可擴充套件、實時的搜尋與資料分析引擎。 它能從專案一開始就賦予你的資料以搜尋、分析和探索的能力,可用於實現全文搜尋和實時資料統計。
Elasticsearch的安裝和使用
下載Elasticsearch6。2。2的zip包,並解壓到指定目錄,下載地址:
https://www。
elastic。co/cn/downloads
/past-releases/elasticsearch-6-2-2
安裝中文分詞外掛,在elasticsearch-6。2。2\bin目錄下執行以下命令:elasticsearch-plugin install
https://
github。com/medcl/elasti
csearch-analysis-ik/releases/download/v6。2。2/elasticsearch-analysis-ik-6。2。2。zip
執行bin目錄下的elasticsearch。bat啟動Elasticsearch
下載Kibana,作為訪問Elasticsearch的客戶端,請下載6。2。2版本的zip包,並解壓到指定目錄,下載地址:
https://
artifacts。elastic。co/do
wnloads/kibana/kibana-6。2。2-windows-x86_64。zip
執行bin目錄下的kibana。bat,啟動Kibana的使用者介面
訪問http://localhost:5601 即可開啟Kibana的使用者介面
Spring Data Elasticsearch
Spring Data Elasticsearch是Spring提供的一種以Spring Data風格來操作資料儲存的方式,它可以避免編寫大量的樣板程式碼。
常用註解
@Document
//標示對映到Elasticsearch文件上的領域物件
public
@interface
Document
{
//索引庫名次,mysql中資料庫的概念
String
indexName
();
//文件型別,mysql中表的概念
String
type
()
default
“”
;
//預設分片數
short
shards
()
default
5
;
//預設副本數量
short
replicas
()
default
1
;
}
@Id
//表示是文件的id,文件可以認為是mysql中表行的概念
public
@interface
Id
{
}
@Field
public
@interface
Field
{
//文件中欄位的型別
FieldType
type
()
default
FieldType
。
Auto
;
//是否建立倒排索引
boolean
index
()
default
true
;
//是否進行儲存
boolean
store
()
default
false
;
//分詞器名次
String
analyzer
()
default
“”
;
}
//為文件自動指定元資料型別
public
enum
FieldType
{
Text
,
//會進行分詞並建了索引的字元型別
Integer
,
Long
,
Date
,
Float
,
Double
,
Boolean
,
Object
,
Auto
,
//自動判斷欄位型別
Nested
,
//巢狀物件型別
Ip
,
Attachment
,
Keyword
//不會進行分詞建立索引的型別
}
Sping Data方式的資料操作
繼承ElasticsearchRepository介面可以獲得常用的資料操作方法
可以使用衍生查詢
在介面中直接指定查詢方法名稱便可查詢,無需進行實現,如商品表中有商品名稱、標題和關鍵字,直接定義以下查詢,就可以對這三個欄位進行全文搜尋。
/**
* 搜尋查詢
*
* @param name 商品名稱
* @param subTitle 商品標題
* @param keywords 商品關鍵字
* @param page 分頁資訊
* @return
*/
Page
<
EsProduct
>
findByNameOrSubTitleOrKeywords
(
String
name
,
String
subTitle
,
String
keywords
,
Pageable
page
);
在idea中直接會提示對應欄位
使用@Query註解可以用Elasticsearch的DSL語句進行查詢
@Query
(
“{”
bool
“ : {”
must
“ : {”
field
“ : {”
name
“ : ”
?
0
“}}}}”
)
Page
<
EsProduct
>
findByName
(
String
name
,
Pageable
pageable
);
專案使用表說明
pms_product
:商品資訊表
pms_product_attribute
:商品屬性引數表
pms_product_attribute_value
:儲存產品引數值的表
整合Elasticsearch實現商品搜尋
在pom。xml中新增相關依賴
<!——Elasticsearch相關依賴——>
org。springframework。boot
spring-boot-starter-data-elasticsearch
修改SpringBoot配置檔案
修改application。yml檔案,在spring節點下新增Elasticsearch相關配置。
data:
elasticsearch:
repositories:
enabled: true
cluster-nodes: 127。0。0。1:9300 # es的連線地址及埠號
cluster-name: elasticsearch # es叢集的名稱
新增商品文件物件EsProduct
不需要中文分詞的欄位設定成@Field(type = FieldType。Keyword)型別,需要中文分詞的設定成@Field(analyzer = “ik_max_word”,type = FieldType。Text)型別。
package
com。macro。mall。tiny。nosql。elasticsearch。document
;
import
org。springframework。data。annotation。Id
;
import
org。springframework。data。elasticsearch。annotations。Document
;
import
org。springframework。data。elasticsearch。annotations。Field
;
import
org。springframework。data。elasticsearch。annotations。FieldType
;
import
java。io。Serializable
;
import
java。math。BigDecimal
;
import
java。util。List
;
/**
* 搜尋中的商品資訊
* Created by macro on 2018/6/19。
*/
@Document
(
indexName
=
“pms”
,
type
=
“product”
,
shards
=
1
,
replicas
=
0
)
public
class
EsProduct
implements
Serializable
{
private
static
final
long
serialVersionUID
=
-
1L
;
@Id
private
Long
id
;
@Field
(
type
=
FieldType
。
Keyword
)
private
String
productSn
;
private
Long
brandId
;
@Field
(
type
=
FieldType
。
Keyword
)
private
String
brandName
;
private
Long
productCategoryId
;
@Field
(
type
=
FieldType
。
Keyword
)
private
String
productCategoryName
;
private
String
pic
;
@Field
(
analyzer
=
“ik_max_word”
,
type
=
FieldType
。
Text
)
private
String
name
;
@Field
(
analyzer
=
“ik_max_word”
,
type
=
FieldType
。
Text
)
private
String
subTitle
;
@Field
(
analyzer
=
“ik_max_word”
,
type
=
FieldType
。
Text
)
private
String
keywords
;
private
BigDecimal
price
;
private
Integer
sale
;
private
Integer
newStatus
;
private
Integer
recommandStatus
;
private
Integer
stock
;
private
Integer
promotionType
;
private
Integer
sort
;
@Field
(
type
=
FieldType
。
Nested
)
private
List
<
EsProductAttributeValue
>
attrValueList
;
//省略了所有getter和setter方法
}
新增EsProductRepository介面用於操作Elasticsearch
繼承ElasticsearchRepository介面,這樣就擁有了一些基本的Elasticsearch資料操作方法,同時定義了一個衍生查詢方法。
package
com。macro。mall。tiny。nosql。elasticsearch。repository
;
import
com。macro。mall。tiny。nosql。elasticsearch。document。EsProduct
;
import
org。springframework。data。domain。Page
;
import
org。springframework。data。domain。Pageable
;
import
org。springframework。data。elasticsearch。repository。ElasticsearchRepository
;
/**
* 商品ES操作類
* Created by macro on 2018/6/19。
*/
public
interface
EsProductRepository
extends
ElasticsearchRepository
<
EsProduct
,
Long
>
{
/**
* 搜尋查詢
*
* @param name 商品名稱
* @param subTitle 商品標題
* @param keywords 商品關鍵字
* @param page 分頁資訊
* @return
*/
Page
<
EsProduct
>
findByNameOrSubTitleOrKeywords
(
String
name
,
String
subTitle
,
String
keywords
,
Pageable
page
);
}
新增EsProductService介面
package
com。macro。mall。tiny。service
;
import
com。macro。mall。tiny。nosql。elasticsearch。document。EsProduct
;
import
org。springframework。data。domain。Page
;
import
java。util。List
;
/**
* 商品搜尋管理Service
* Created by macro on 2018/6/19。
*/
public
interface
EsProductService
{
/**
* 從資料庫中匯入所有商品到ES
*/
int
importAll
();
/**
* 根據id刪除商品
*/
void
delete
(
Long
id
);
/**
* 根據id建立商品
*/
EsProduct
create
(
Long
id
);
/**
* 批次刪除商品
*/
void
delete
(
List
<
Long
>
ids
);
/**
* 根據關鍵字搜尋名稱或者副標題
*/
Page
<
EsProduct
>
search
(
String
keyword
,
Integer
pageNum
,
Integer
pageSize
);
}
新增EsProductService介面的實現類EsProductServiceImpl
package
com。macro。mall。tiny。service。impl
;
import
com。macro。mall。tiny。dao。EsProductDao
;
import
com。macro。mall。tiny。nosql。elasticsearch。document。EsProduct
;
import
com。macro。mall。tiny。nosql。elasticsearch。repository。EsProductRepository
;
import
com。macro。mall。tiny。service。EsProductService
;
import
org。slf4j。Logger
;
import
org。slf4j。LoggerFactory
;
import
org。springframework。beans。factory。annotation。Autowired
;
import
org。springframework。data。domain。Page
;
import
org。springframework。data。domain。PageRequest
;
import
org。springframework。data。domain。Pageable
;
import
org。springframework。stereotype。Service
;
import
org。springframework。util。CollectionUtils
;
import
java。util。ArrayList
;
import
java。util。Iterator
;
import
java。util。List
;
/**
* 商品搜尋管理Service實現類
* Created by macro on 2018/6/19。
*/
@Service
public
class
EsProductServiceImpl
implements
EsProductService
{
private
static
final
Logger
LOGGER
=
LoggerFactory
。
getLogger
(
EsProductServiceImpl
。
class
);
@Autowired
private
EsProductDao
productDao
;
@Autowired
private
EsProductRepository
productRepository
;
@Override
public
int
importAll
()
{
List
<
EsProduct
>
esProductList
=
productDao
。
getAllEsProductList
(
null
);
Iterable
<
EsProduct
>
esProductIterable
=
productRepository
。
saveAll
(
esProductList
);
Iterator
<
EsProduct
>
iterator
=
esProductIterable
。
iterator
();
int
result
=
0
;
while
(
iterator
。
hasNext
())
{
result
++;
iterator
。
next
();
}
return
result
;
}
@Override
public
void
delete
(
Long
id
)
{
productRepository
。
deleteById
(
id
);
}
@Override
public
EsProduct
create
(
Long
id
)
{
EsProduct
result
=
null
;
List
<
EsProduct
>
esProductList
=
productDao
。
getAllEsProductList
(
id
);
if
(
esProductList
。
size
()
>
0
)
{
EsProduct
esProduct
=
esProductList
。
get
(
0
);
result
=
productRepository
。
save
(
esProduct
);
}
return
result
;
}
@Override
public
void
delete
(
List
<
Long
>
ids
)
{
if
(!
CollectionUtils
。
isEmpty
(
ids
))
{
List
<
EsProduct
>
esProductList
=
new
ArrayList
<>();
for
(
Long
id
:
ids
)
{
EsProduct
esProduct
=
new
EsProduct
();
esProduct
。
setId
(
id
);
esProductList
。
add
(
esProduct
);
}
productRepository
。
deleteAll
(
esProductList
);
}
}
@Override
public
Page
<
EsProduct
>
search
(
String
keyword
,
Integer
pageNum
,
Integer
pageSize
)
{
Pageable
pageable
=
PageRequest
。
of
(
pageNum
,
pageSize
);
return
productRepository
。
findByNameOrSubTitleOrKeywords
(
keyword
,
keyword
,
keyword
,
pageable
);
}
}
新增EsProductController定義介面
package
com。macro。mall。tiny。controller
;
import
com。macro。mall。tiny。common。api。CommonPage
;
import
com。macro。mall。tiny。common。api。CommonResult
;
import
com。macro。mall。tiny。nosql。elasticsearch。document。EsProduct
;
import
com。macro。mall。tiny。service。EsProductService
;
import
io。swagger。annotations。Api
;
import
io。swagger。annotations。ApiOperation
;
import
org。springframework。beans。factory。annotation。Autowired
;
import
org。springframework。data。domain。Page
;
import
org。springframework。stereotype。Controller
;
import
org。springframework。web。bind。annotation。*
;
import
java。util。List
;
/**
* 搜尋商品管理Controller
* Created by macro on 2018/6/19。
*/
@Controller
@Api
(
tags
=
“EsProductController”
,
description
=
“搜尋商品管理”
)
@RequestMapping
(
“/esProduct”
)
public
class
EsProductController
{
@Autowired
private
EsProductService
esProductService
;
@ApiOperation
(
value
=
“匯入所有資料庫中商品到ES”
)
@RequestMapping
(
value
=
“/importAll”
,
method
=
RequestMethod
。
POST
)
@ResponseBody
public
CommonResult
<
Integer
>
importAllList
()
{
int
count
=
esProductService
。
importAll
();
return
CommonResult
。
success
(
count
);
}
@ApiOperation
(
value
=
“根據id刪除商品”
)
@RequestMapping
(
value
=
“/delete/{id}”
,
method
=
RequestMethod
。
GET
)
@ResponseBody
public
CommonResult
<
Object
>
delete
(
@PathVariable
Long
id
)
{
esProductService
。
delete
(
id
);
return
CommonResult
。
success
(
null
);
}
@ApiOperation
(
value
=
“根據id批次刪除商品”
)
@RequestMapping
(
value
=
“/delete/batch”
,
method
=
RequestMethod
。
POST
)
@ResponseBody
public
CommonResult
<
Object
>
delete
(
@RequestParam
(
“ids”
)
List
<
Long
>
ids
)
{
esProductService
。
delete
(
ids
);
return
CommonResult
。
success
(
null
);
}
@ApiOperation
(
value
=
“根據id建立商品”
)
@RequestMapping
(
value
=
“/create/{id}”
,
method
=
RequestMethod
。
POST
)
@ResponseBody
public
CommonResult
<
EsProduct
>
create
(
@PathVariable
Long
id
)
{
EsProduct
esProduct
=
esProductService
。
create
(
id
);
if
(
esProduct
!=
null
)
{
return
CommonResult
。
success
(
esProduct
);
}
else
{
return
CommonResult
。
failed
();
}
}
@ApiOperation
(
value
=
“簡單搜尋”
)
@RequestMapping
(
value
=
“/search/simple”
,
method
=
RequestMethod
。
GET
)
@ResponseBody
public
CommonResult
<
CommonPage
<
EsProduct
>>
search
(
@RequestParam
(
required
=
false
)
String
keyword
,
@RequestParam
(
required
=
false
,
defaultValue
=
“0”
)
Integer
pageNum
,
@RequestParam
(
required
=
false
,
defaultValue
=
“5”
)
Integer
pageSize
)
{
Page
<
EsProduct
>
esProductPage
=
esProductService
。
search
(
keyword
,
pageNum
,
pageSize
);
return
CommonResult
。
success
(
CommonPage
。
restPage
(
esProductPage
));
}
}
進行介面測試
將資料庫中資料匯入到Elasticsearch
進行商品搜尋
專案原始碼地址
https://
github。com/macrozheng/m
all-learning/tree/master/mall-tiny-06