命令查詢職責(zé)分離模式(Command Query Responsibility Segregation,CQRS)從業(yè)務(wù)上分離修改 (Command,增,刪,改,會(huì)對(duì)系統(tǒng)狀態(tài)進(jìn)行修改)和查詢(Query,查,不會(huì)對(duì)系統(tǒng)狀態(tài)進(jìn)行修改)的行為。從而使得邏輯更加清晰,便于對(duì)不同部分進(jìn)行針對(duì)性的優(yōu)化。
CQRS有以下幾點(diǎn)有點(diǎn):
1.分工明確,可以負(fù)責(zé)不同的部分;
2.將業(yè)務(wù)上的命令和查詢的職責(zé)分離能夠提高系統(tǒng)的性能、可擴(kuò)展性和安全性。并且在系統(tǒng)的演化中能夠保持高度的靈活性,能夠防止出現(xiàn)CRUD模式中,對(duì)查詢或者修改中的某一方進(jìn)行改動(dòng),導(dǎo)致另一方出現(xiàn)問(wèn)題的情況;
3.邏輯清晰,能夠看到系統(tǒng)中的那些行為或者操作導(dǎo)致了系統(tǒng)的狀態(tài)變化;
4.可以從數(shù)據(jù)驅(qū)動(dòng)(Data-Driven) 轉(zhuǎn)到任務(wù)驅(qū)動(dòng)(Task-Driven)以及事件驅(qū)動(dòng)(Event-Driven)。
因此Command使用數(shù)據(jù)庫(kù),Query使用效率查詢效率更高的Elasticsearch。
如何確保數(shù)據(jù)庫(kù)和Elasticsearch的數(shù)據(jù)的一致性?
我們可以使用事件驅(qū)動(dòng)(Event-Driven)即Spring Data的Domain Event同步數(shù)據(jù),可參考文章:http://www.ythuaji.com.cn/article/154225.html 。
當(dāng)老數(shù)據(jù)庫(kù)有大量數(shù)據(jù)需要導(dǎo)入Elasticsearch時(shí),可參考文章:http://www.ythuaji.com.cn/article/153563.html
Spring Data Elasticsearch使用的是transport client,而Elasticsearch官網(wǎng)推薦使用REST client。阿里云的Elasticsearch使用transport client目前還在存在問(wèn)題,阿里云推薦使用REST client。
本示例使用的是Spring Data Jest鏈接Elasticsearch(目前只有spring boot2.0以上版本支持),Elasticsearch的版本為:5.5.3
1.項(xiàng)目構(gòu)建
1.pom依賴如下:
1
2
3
4
5
6
7
8
9
10
11
|
< dependency > < groupId >com.github.vanroy</ groupId > < artifactId >spring-boot-starter-data-jest</ artifactId > < version >3.0.0.RELEASE</ version > </ dependency > < dependency > < groupId >io.searchbox</ groupId > < artifactId >jest</ artifactId > < version >5.3.2</ version > </ dependency > |
2.配置文件
1
2
3
4
5
6
|
spring: data: jest: uri: http://127.0.0.1:9200 username: elastic password: changeme |
2.構(gòu)造查詢條件
以簡(jiǎn)單的實(shí)體類為例
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
|
package com.hfcsbc.esetl.domain; import lombok.Data; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToOne; import java.util.Date; import java.util.List; /** * Create by pengchao on 2018/2/23 */ @Document (indexName = "person" , type = "person" , shards = 1 , replicas = 0 , refreshInterval = "-1" ) @Entity @Data public class Person { @Id private Long id; private String name; @OneToOne @Field (type = FieldType.Nested) private List<Address> address; private Integer number; private Integer status; private Date birthDay; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package com.hfcsbc.esetl.domain; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; /** * Create by pengchao on 2018/2/23 */ @Entity @Data public class Address { @Id private Long id; private String name; private Integer number; } |
1.根據(jù)多個(gè)狀態(tài)查詢(類似于sql的in)
1
2
3
4
5
6
|
BoolQueryBuilder orderStatusCondition = QueryBuilders.boolQuery() .should(QueryBuilders.termQuery( "status" , 1 )) .should(QueryBuilders.termQuery( "status" , 2 )) .should(QueryBuilders.termQuery( "status" , 3 )) .should(QueryBuilders.termQuery( "status" , 4 )) .should(QueryBuilders.termQuery( "status" , 5 )); |
2.and鏈接查詢(類似于sql的and)
1
2
3
4
5
|
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery(); queryBuilder .must(queryBuilder1) .must(queryBuilder2) .must(queryBuilder3); |
3.range查詢(類似于sql的between .. and ..)
QueryBuilder rangeQuery = QueryBuilders.rangeQuery("birthDay").from(yesterday).to(today);
4.嵌套對(duì)象查詢
QueryBuilder queryBuilder = QueryBuilders.nestedQuery("nested", QueryBuilders.termQuery("address.id", 100001), ScoreMode.None);
ScoreMode: 定義other join side中score是如何被使用的。如果不關(guān)注scoring,我們只需要設(shè)置成ScoreMode.None,此種方式會(huì)忽略評(píng)分因此會(huì)更高效和節(jié)約內(nèi)存
3.獲取統(tǒng)計(jì)數(shù)據(jù)
1.非嵌套獲取數(shù)據(jù)求和
1
2
3
4
5
6
7
8
9
10
|
SumAggregationBuilder sumBuilder = AggregationBuilders.sum( "sum" ).field( "number" ); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withIndices(QUERY_INDEX) .withTypes(QUERY_TYPE) .withQuery(boolQueryBuilder) .addAggregation(sumBuilder).build(); AggregatedPage<ParkingOrder> account = (AggregatedPage<ParkingOrder>) esParkingOrderRepository.search(EsQueryBuilders.buildYesterdayArrearsSumQuery(employeeId)); int sum = account.getAggregation( "sum" , SumAggregation. class ).getSum().intValue(); |
2.嵌套數(shù)據(jù)求和
1
2
3
4
5
6
7
8
9
|
SumAggregationBuilder sumBuilder = AggregationBuilders.sum( "sum" ).field( "adress.num" ); AggregationBuilder aggregationBuilder = AggregationBuilders.nested( "nested" , "adress" ).subAggregation(sumBuilder); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withIndices(QUERY_INDEX) .withTypes(QUERY_TYPE) .withQuery(boolQueryBuilder) .addAggregation((AbstractAggregationBuilder) aggregationBuilder).build(); AggregatedPage<ParkingOrder> account = (AggregatedPage<ParkingOrder>) esParkingOrderRepository.search(EsQueryBuilders.buildYesterdayArrearsSumQuery(employeeId)); int sum = account.getAggregation( "nested" , SumAggregation. class ).getAggregation( "sum" , SumAggregation. class ).getSum().intValue(); |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://www.wisely.top/2018/02/27/spring-data-jest-elasticsarch/