基于Spring Data Jest的Elasticsearch数据统计示例
命令查询职责分离模式(CommandQueryResponsibilitySegregation,CQRS)从业务上分离修改(Command,增,删,改,会对系统状态进行修改)和查询(Query,查,不会对系统状态进行修改)的行为。从而使得逻辑更加清晰,便于对不同部分进行针对性的优化。
CQRS有以下几点有点:
1.分工明确,可以负责不同的部分;
2.将业务上的命令和查询的职责分离能够提高系统的性能、可扩展性和安全性。并且在系统的演化中能够保持高度的灵活性,能够防止出现CRUD模式中,对查询或者修改中的某一方进行改动,导致另一方出现问题的情况;
3.逻辑清晰,能够看到系统中的那些行为或者操作导致了系统的状态变化;
4.可以从数据驱动(Data-Driven)转到任务驱动(Task-Driven)以及事件驱动(Event-Driven)。
因此Command使用数据库,Query使用效率查询效率更高的Elasticsearch。
如何确保数据库和Elasticsearch的数据的一致性?
我们可以使用事件驱动(Event-Driven)即SpringData的DomainEvent同步数据,可参考文章:https://www.nhooo.com/article/135604.htm。
当老数据库有大量数据需要导入Elasticsearch时,可参考文章:https://www.nhooo.com/article/135426.htm
SpringDataElasticsearch使用的是transportclient,而Elasticsearch官网推荐使用RESTclient。阿里云的Elasticsearch使用transportclient目前还在存在问题,阿里云推荐使用RESTclient。
本示例使用的是SpringDataJest链接Elasticsearch(目前只有springboot2.0以上版本支持),Elasticsearch的版本为:5.5.3
1.项目构建
1.pom依赖如下:
com.github.vanroy spring-boot-starter-data-jest 3.0.0.RELEASE io.searchbox jest 5.3.2
2.配置文件
spring: data: jest: uri:http://127.0.0.1:9200 username:elastic password:changeme
2.构造查询条件
以简单的实体类为例
packagecom.hfcsbc.esetl.domain; importlombok.Data; importorg.springframework.data.elasticsearch.annotations.Document; importorg.springframework.data.elasticsearch.annotations.Field; importorg.springframework.data.elasticsearch.annotations.FieldType; importjavax.persistence.Entity; importjavax.persistence.Id; importjavax.persistence.OneToOne; importjava.util.Date; importjava.util.List; /** *Createbypengchaoon2018/2/23 */ @Document(indexName="person",type="person",shards=1,replicas=0,refreshInterval="-1") @Entity @Data publicclassPerson{ @Id privateLongid; privateStringname; @OneToOne @Field(type=FieldType.Nested) privateListaddress; privateIntegernumber; privateIntegerstatus; privateDatebirthDay; }
packagecom.hfcsbc.esetl.domain; importlombok.Data; importjavax.persistence.Entity; importjavax.persistence.Id; /** *Createbypengchaoon2018/2/23 */ @Entity @Data publicclassAddress{ @Id privateLongid; privateStringname; privateIntegernumber; }
1.根据多个状态查询(类似于sql的in)
BoolQueryBuilderorderStatusCondition=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)
BoolQueryBuilderqueryBuilder=QueryBuilders.boolQuery(); queryBuilder .must(queryBuilder1) .must(queryBuilder2) .must(queryBuilder3);
3.range查询(类似于sql的between..and..)
QueryBuilderrangeQuery=QueryBuilders.rangeQuery("birthDay").from(yesterday).to(today);
4.嵌套对象查询
QueryBuilderqueryBuilder=QueryBuilders.nestedQuery("nested",QueryBuilders.termQuery("address.id",100001),ScoreMode.None);
ScoreMode:定义otherjoinside中score是如何被使用的。如果不关注scoring,我们只需要设置成ScoreMode.None,此种方式会忽略评分因此会更高效和节约内存
3.获取统计数据
1.非嵌套获取数据求和
SumAggregationBuildersumBuilder=AggregationBuilders.sum("sum").field("number"); SearchQuerysearchQuery=newNativeSearchQueryBuilder() .withIndices(QUERY_INDEX) .withTypes(QUERY_TYPE) .withQuery(boolQueryBuilder) .addAggregation(sumBuilder).build(); AggregatedPageaccount=(AggregatedPage )esParkingOrderRepository.search(EsQueryBuilders.buildYesterdayArrearsSumQuery(employeeId)); intsum=account.getAggregation("sum",SumAggregation.class).getSum().intValue();
2.嵌套数据求和
SumAggregationBuildersumBuilder=AggregationBuilders.sum("sum").field("adress.num"); AggregationBuilderaggregationBuilder=AggregationBuilders.nested("nested","adress").subAggregation(sumBuilder); SearchQuerysearchQuery=newNativeSearchQueryBuilder() .withIndices(QUERY_INDEX) .withTypes(QUERY_TYPE) .withQuery(boolQueryBuilder) .addAggregation((AbstractAggregationBuilder)aggregationBuilder).build(); AggregatedPageaccount=(AggregatedPage )esParkingOrderRepository.search(EsQueryBuilders.buildYesterdayArrearsSumQuery(employeeId)); intsum=account.getAggregation("nested",SumAggregation.class).getAggregation("sum",SumAggregation.class).getSum().intValue();
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。