什么是spring Data
Spring Data是一個用於簡化數據庫訪問,並支持雲服務的開源框架。其主要目標是使得對數據的訪問變得方便快 捷,並支持map-reduce框架和雲計算數據服務。 Spring Data可以極大的簡化JPA的寫法,可以在幾乎不用寫實現 的情況下,實現對數據的訪問和操作。除了CRUD外,還包括如分頁、排序等一些常用的功能。 Spring Data的官網:http://projects.spring.io/spring-data/
Spring Data常用的功能模塊如下:
spring data commons spring data JPA spring data Redis spring data for Apache Solr spring data ElasticSearch
什么是Spring Data ElasticSearch
Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操作,將原始操作elasticSearch的客戶端API 進 行封裝 。Spring Data為Elasticsearch項目提供集成搜索引擎。Spring Data Elasticsearch POJO的關鍵功能區域為 中心的模型與Elastichsearch交互文檔和輕松地編寫一個存儲庫數據訪問層。 官方網站:http://projects.spring.io/spring-data-elasticsearch/
引入坐標
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies>
# ES #開啟 Elasticsearch 倉庫(默認值:true) spring.data.elasticsearch.repositories.enabled=true #默認 9300 是 Java 客戶端的端口。9200 是支持 Restful HTTP 的接口 spring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300 #spring.data.elasticsearch.cluster-name Elasticsearch 集群名(默認值: elasticsearch) #spring.data.elasticsearch.cluster-nodes 集群節點地址列表,用逗號分隔。如果沒有指定,就啟動一個客戶端節點 #spring.data.elasticsearch.propertie 用來配置客戶端的額外屬性 #連接超時的時間 spring.data.elasticsearch.properties.transport.tcp.connect_timeout=120s
/** 其中,注解解釋如下: @Document(indexName="blob3",type="article"): indexName:索引的名稱(必填項) type:索引的類型 @Id:主鍵的唯一標識 @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text) index:是否索引 analyzer:存儲時使用的分詞器 searchAnalyze:搜索時使用的分詞器 store:是否存儲 type: 數據類型 注: 一旦添加了@Filed注解,所有的默認值都不再生效。此外,如果添加了@Filed注解,那么type字段必須指定。 所以一般不用添加。 */ @Document(indexName = "blog3",type = "article") public class Article { //@Field(store = true,type = FieldType.Integer) private Integer id; @Field(index = true,store = true,analyzer = "ik_smart",searchAnalyzer = "ik_smart",type = FieldType.text) private String title; @Field(index = true,store = true,analyzer = "ik_smart",searchAnalyzer = "ik_smart",type = FieldType.text) private String content;
增刪改查
test
@RunWith(SpringRunner.class) @SpringBootTest(classes = ApplicationRun.class) public class TestSpringDataES { @Autowired private ArticleService as; @Test //保存 public void testSave(){ Article a = new Article(); a.setId(1); a.setTitle("elasticSearch 3.0版本發布...更新"); a.setContent("ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口"); as.save(a); } @Test//修改 public void testUpdate(){ Article a = new Article(); a.setId(1); a.setTitle("elasticSearch 3.01版本發布...更新"); a.setContent("ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口"); as.save(a); } @Test //刪除 public void testDelete(){ Article a = new Article(); a.setId(1); as.delete(a); } @Test //批量保存 public void testSave2(){ for (int i = 1; i <= 100; i++) { Article a = new Article(); a.setId(i); a.setTitle(i+"elasticSearch 3.0版本發布...更新"); a.setContent(i+"ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口"); as.save(a); } } @Test //查詢所有保存 public void testFindAll(){ Iterable<Article> list = as.findAll(); for (Article article : list) { System.out.println(article); } } @Test public void TestFindByPage(){ // Pageable pageable= PageRequest.of(1,10); Pageable pageable= PageRequest.of(1,10, Sort.by(Sort.Order.asc("id;"))); Page page = as.findByPage(pageable); List<Article> list = page.getContent(); for (Article article : list) { System.out.println(article); } } @Test //根據title查詢 public void testFindByTitle(){ List<Article> list = as.findByTitle("版本"); for (Article article : list) { System.out.println(article); } } @Test //根據title查詢 public void testFindByTitlePage(){ Pageable pageable=PageRequest.of(0,20,Sort.by(Sort.Order.asc("id"))); Page page = as.findByTitle("版本", pageable); List<Article> list = page.getContent(); for (Article article : list) { System.out.println(article); } } }
service
public interface ArticleService { //保存 public void save(Article article); //刪除 public void delete(Article article); //查詢 public Iterable<Article> findAll(); //分頁查詢 public Page findByPage(Pageable pageable); public List<Article> findByTitle(String title); public Page findByTitle(String title,Pageable pageable); }
impl
@Service public class ArticleServiceImpl implements ArticleService { @Autowired private ArticleDao articleDao; @Override public void save(Article article) { articleDao.save(article); } @Override public void delete(Article article) { articleDao.delete(article); } @Override//Sort.by(Sort.Order.asc("id") 根據id排序 public Iterable<Article> findAll() { return articleDao.findAll(Sort.by(Sort.Order.asc("id"))); } @Override public Page findByPage(Pageable pageable) { return articleDao.findAll(pageable); } @Override public List<Article> findByTitle(String title) { return articleDao.findByTitle(title); } @Override public Page findByTitle(String title, Pageable pageable) { return articleDao.findByTitle(title,pageable); } }
dao
//ElasticsearchRepository<實體類,實體類的主鍵類型> : 提供了CRUD的操作 public interface ArticleDao extends ElasticsearchRepository<Article,Integer> { //根據title字段查詢 public List<Article> findByTitle(String title); public Page findByTitle(String title, Pageable pageable); }
常用查詢命名規則
Kibana是一個基於Node.js的Elasticsearch索引庫數據統計工具,可以利用Elasticsearch的聚合功能,生成各種圖表,如柱形圖,線狀圖,餅圖等。
而且還提供了操作Elasticsearch索引數據的控制台,並且提供了一定的API提示,非常有利於我們學習Elasticsearch的語法。
安裝
因為Kibana依賴於node,需要在windows下先安裝Node.js,然后安裝kibana,最新版本與elasticsearch保持一致,也是5.6.8
解壓即可!
運行
進入安裝目錄下的bin目錄-->雙擊kibana.bat
發現kibana的監聽端口是5601
控制台
進入之后選擇左側的DevTools菜單,即可進入控制台頁面,在頁面右側,我們就可以輸入請求,訪問Elasticsearch了。
創建索引庫
語法
Elasticsearch采用Rest風格API,因此其API就是一次http請求,你可以用任何工具發起http請求 創建索引的請求格式: - 請求方式:PUT - 請求路徑:/索引庫名
使用kibana創建
相當於是省去了elasticsearch的服務器地址
而且還有語法提示,非常舒服。
查看索引數據庫
語法
GET /索引庫名
刪除索引庫
語法
DELETE /索引庫名
類型及映射操作
有了`索引庫`,等於有了數據庫中的`database`。接下來就需要索引庫中的`類型`了,也就是數據庫中的`表`。創建數據庫表需要設置字段約束,索引庫也一樣,
在創建索引庫的類型時,需要知道這個類型下有哪些字段,每個字段有哪些**約束**信息,這就叫做`字段映射(mapping)` 字段的約束我們在學習Lucene中我們都見到過,包括到不限於: - 字段的數據類型 - 是否要存儲 - 是否要索引 - 是否分詞 - 分詞器是什么
創建字段映射
語法
PUT /索引庫名/_mapping/類型名稱 { "properties": { "字段名": { "type": "類型", "index": true, "store": true, "analyzer": "分詞器" } } }
-
-
type:類型,可以是text、long、short、date、integer、object等
-
index:是否索引,默認為true
-
store:是否存儲,默認為false
-
analyzer:分詞器,這里的
ik_max_word
即使用ik分詞器
查看映射關系
語法
GET /索引庫名/_mapping
附錄:映射屬性
1)type
Elasticsearch中支持的數據類型非常豐富:
這里說幾個關鍵的:
-
String類型,又分兩種:
-
text:可分詞,不可參與聚合
-
keyword:不可分詞,數據會作為完整字段進行匹配,可以參與聚合
-
-
Numerical:數值類型,分兩類
-
基本數據類型:long、interger、short、byte、double、float、half_float
-
浮點數的高精度類型:scaled_float
-
需要指定一個精度因子,比如10或100。elasticsearch會把真實值乘以這個因子后存儲,取出時再還原。
-
-
-
Date:日期類型
elasticsearch可以對日期格式化為字符串存儲,但是建議我們存儲為毫秒值,存儲為long,節省空間。
-
Array:數組類型
-
進行匹配時,任意一個元素滿足,都認為滿足
-
排序時,如果升序則用數組中的最小值來排序,如果降序則用數組中的最大值來排序
-
-
Object:對象
{
name:"Jack",
age:21,
girl:{
name: "Rose",
age:21
}
}
如果存儲到索引庫的是對象類型,例如上面的girl,會把girl編程兩個字段:girl.name和girl.age
2)index
index影響字段的索引情況。
-
true:字段會被索引,則可以用來進行搜索過濾。默認值就是true
-
false:字段不會被索引,不能用來搜索
index的默認值就是true,也就是說你不進行任何配置,所有字段都會被索引。
但是有些字段是我們不希望被索引的,比如商品的圖片信息,就需要手動設置index為false。
3)store
是否將數據進行額外存儲。
在學習lucene和solr時,我們知道如果一個字段的store設置為false,那么在文檔列表中就不會有這個字段的值,用戶的搜索結果中不會顯示出來。
但是在Elasticsearch中,即便store設置為false,也可以搜索到結果。
原因是Elasticsearch在創建文檔索引時,會將文檔中的原始數據備份,保存到一個叫做_source
的屬性中。而且我們可以通過過濾_source
來選擇哪些要顯示,哪些不顯示。
而如果設置store為true,就會在_source
以外額外存儲一份數據,多余,因此一般我們都會將store設置為false,事實上,store的默認值就是false。
4)boost
權重,新增數據時,可以指定該數據的權重,權重越高,得分越高,排名越靠前。
一次創建索引庫和類型
put /索引庫名 { "settings":{ "索引庫屬性名":"索引庫屬性值" }, "mappings":{ "類型名":{ "properties":{ "字段名":{ "映射屬性名":"映射屬性值" } } } } }
文檔操作
新增文檔
通過POST請求,可以向一個已經存在的索引庫中添加文檔數據。
POST /索引庫名/類型名 { "key":"value" }
另外,需要注意的是,在響應結果中有個_id
字段,這個就是這條文檔數據的唯一標示
,以后的增刪改查都依賴這個id作為唯一標示。
可以看到id的值為:r9c1KGMBIhaxtY5rlRKv
,這里我們新增時沒有指定id,所以是ES幫我們隨機生成的id。
查看文檔
根據rest風格,新增是post,查詢應該是get,不過查詢一般都需要條件,這里我們把剛剛生成數據的id帶上。
通過kibana查看數據:
GET /test1/goods/r9c1KGMBIhaxtY5rlRKv
新增文檔並自定義id
POST /索引庫名/類型/id值 { ... } 示例: POST /test1/goods/2 { "title":"大米手機", "images":"http://image.leyou.com/12479122.jpg", "price":2899.00 }
修改數據
把剛才新增的請求方式改為PUT,就是修改了。不過修改必須指定id,
-
id對應文檔存在,則修改
-
id對應文檔不存在,則新增
比如,我們把使用id為3,不存在,則應該是新增:
PUT /test1/goods/3 { "title":"超米手機", "images":"http://image.leyou.com/12479122.jpg", "price":3899.00, "stock": 100, "saleable":true }
我們再次執行剛才的請求,不過把數據改一下:
PUT /test1/goods/3 { "title":"超大米手機", "images":"http://image.leyou.com/12479122.jpg", "price":3299.00, "stock": 100, "saleable":true }
刪除數據
刪除使用DELETE請求,同樣,需要根據id進行刪除:
語法
DELETE /索引庫名/類型名/id值
查詢
-
基本查詢
-
_source
過濾 -
結果過濾
-
高級查詢
-
GET /索引庫名/_search { "query":{ "查詢類型":{ "查詢條件":"查詢條件值" } } }
這里的query代表一個查詢對象,里面可以有不同的查詢屬性
-
查詢類型:
-
例如:
match_all
,match
,term
,range
等等
-
-
查詢條件:查詢條件會根據類型的不同,寫法也有差異
GET /test1/_search { "query":{ "match_all": {} } }
-
-
match_all
:代表查詢所有
匹配查詢
我們先加入一條數據
PUT /test1/goods/3 { "title":"小米電視4A", "images":"http://image.leyou.com/12479122.jpg", "price":3899.00 }
-
or關系
match
GET /test1/_search { "query":{ "match":{ "title":"小米電視" } } }
-
and關系
某些情況下,我們需要更精確查找,我們希望這個關系變成and
,可以這樣做:
GET /goods/_search { "query":{ "match":{ "title":{"query":"小米電視","operator":"and"} } } }
詞條匹配
GET /test1/_search { "query":{ "term":{ "price":2699.00 } } }
POST /test1/goods/4 { "title":"apple手機", "images":"http://image.leyou.com/12479122.jpg", "price":6899.00 }
GET /test1/_search { "query": { "fuzzy": { "title": "appla" } } }
上面的查詢,也能查詢到apple手機
我們可以通過fuzziness
來指定允許的編輯距離:
GET /test1/_search { "query": { "fuzzy": { "title": { "value":"appla", "fuzziness":1 } } } }
排序
GET /test1/_search
{
"query": {
"match": {
"title": "小米手機"
}
},
"sort": [
{
"price": {
"order": "desc"
}
}
]
}
分頁
elasticsearch的分頁與mysql數據庫非常相似,都是指定兩個值:
-
from:開始位置
-
size:每頁大小
GET /test1/_search { "query": { "match_all": {} }, "sort": [ { "price": { "order": "asc" } } ], "from": 3, "size": 3 }
高亮
高亮原理:
-
服務端搜索數據,得到搜索結果
-
把搜索結果中,搜索關鍵字都加上約定好的標簽
-
前端頁面提前寫好標簽的CSS樣式,即可高亮
elasticsearch中實現高亮的語法比較簡單:
GET /test1/_search { "query": { "match": { "title": "手機" } }, "highlight": { "pre_tags": "<em>", "post_tags": "</em>", "fields": { "title": {} } } }
在使用match查詢的同時,加上一個highlight屬性:
-
pre_tags:前置標簽
-
post_tags:后置標簽
-
fields:需要高亮的字段
-