diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 88e9053ba..000000000 --- a/CHANGELOG +++ /dev/null @@ -1,21 +0,0 @@ -davinci 0.3.0 change log -1) add data portal -2) add metric trend chart -3) add feedback component -4) add tab component -5) add page setting -6) modify permission process -7) optimize css style -8) optimize filter -9) delete view module - - -supersonic 0.6.0 change log -1) add llm parser and llm api server -2) support fuzzy mapping -3) support query filter and domain filter in query and search -4) support standalone mode -5) add dsl query in semantic -6) code architecture adjustment in semantic and chat -7) add unit testing and integration testing -8) support dimension and metric alias \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..5ad4db1e5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,99 @@ +# SuperSonic Changelog + +- All notable changes to this project will be documented in this file. +- "Breaking Changes" describes any changes that may break existing functionality or cause + compatibility issues with previous versions. + + +## SuperSonic [0.7.0] - 2023-07-30 + +### Added + +- Add function call parser and embedding recall parser +- Add plugin management +- Add web page query and web service query +- Metric filter query support querying metrics and comparing them in different dimensions +- Support dimension value mapping +- Support dimension/metric invisible, chat filter related data +- Add user guide docs + + +### Fixed + +- Fix the data problem of getDomainList interface in standalone mode + +## SuperSonic [0.6.0] - 2023-07-16 + +### Added + +- Support llm parser and llm api server - users can query data through complex natural language. +- Support fuzzy query dimension and metric name - users can set the 'metric.dimension.threshold' + parameter to control the fuzzy threshold. +- Support query filter and domain filter in query and search - users can specify domainId and query + filter to filter the results in search and query. +- Support standalone mode - users can integrate semantic and chat services in one process for easy + management and debugging. +- Support dsl query in semantic - users can specify DSL language to query data in Semantic. In the + past, data querying was limited to struct language. +- Add unit and integration testing - add integration tests for single-turn and multi-turn + conversations, to efficiently validate the code. +- Support dimension and metric alias - users can specify one or multiple aliases to expand search + and query. +- Add scheduled semantic metadata update functionality in chat. +- Support create datasource by table name in the web page. +- Add the ability to set permissions for domain. +- Add a local/Remote implementation to the SemanticLayer interface. + +### Updated + +- Code architecture adjustment in chat. + +1) Abstracting into three modules, namely api, core, and knowledge. Providing four core interfaces: + SchemaMapper, SemanticLayer, SemanticParser, and SemanticQuery. +2) Add RuleSemanticQuery and LLMSemanticQuery implement to SemanticQuery. +3) Add all possible queries to the candidate queries, and then select the most suitable query from + the candidate queries. + +- Code architecture adjustment in semantic. + +1) Refactor semantic layer SQL parsing code through Calcite. +2) Add QueryOptimizer interface. + +- Chat config subdivided into detailed and metric scenarios - users can set different parameters in these two scenarios. + +### Fixed + +- Resolved last word not be recognized in SchemaMapper. +- Fix context inheritance problem. +- Fix the error of querying H2 database by month unit. +- Set faker user to context when authentication disable. + +## SuperSonic [0.5.0] - 2023-06-15 + +### Added +- Add the search and query feature in chat according to rules in an extensible way. +- Add semantic/chat independent service for users. +- Add Modeling Interface - users can visually define and maintain semantic models in the web page. +- Add a unified semantic parsing layer - user can query data by struct language. + +# Davinci Changelog + +## Davinci [0.3.0] - 2023-06-15 + +### Added + +- add data portal +- add metric trend chart +- add feedback component +- add tab component +- add page setting + +### Updated + +- modify permission process +- optimize css style +- optimize filter + +### Removed + +- delete view module \ No newline at end of file diff --git a/README.md b/README.md index d8ce42237..ad7ed42b7 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ English | [中文](README_CN.md) # SuperSonic (超音数) -**SuperSonic is an out-of-the-box yet highly extensible framework for building a data chatbot**. SuperSonic provides a chat interface that empowers users to query data using natural language and visualize the results with suitable charts. To enable such experience, the only thing necessary is to define logical semantic models (metrics, dimensions, relationships, etc) on top of physical data models, and no data modification or copying is required. Meanwhile SuperSonic is designed to be plugable, allowing new functionalities to be added through plugins and core components to be integrated into other systems. +**SuperSonic is an out-of-the-box yet highly extensible framework for building a data chatbot**. SuperSonic provides a chat interface that empowers users to query data using natural language and visualize the results with suitable charts. To enable such experience, the only thing necessary is to define logical semantic models (metrics, dimensions, aliases, relationships, etc) on top of physical data models, and no data modification or copying is required. Meanwhile SuperSonic is designed to be plugable, allowing new functionalities to be added through plugins and core components to be integrated into other systems. - - + ## Motivation @@ -13,9 +12,9 @@ The emergence of Large Language Models (LLMs) like ChatGPT is reshaping the way From our perspective, the key to filling the real-world gap lies in two aspects: 1. Utilize a combination of rule-based and model-based semantic parsers to deal with different scenarios -2. Introduce a semantic model layer to encapsulate underlying complexity thus simplify the semantic parsers +2. Introduce a semantic model layer to encapsulate underlying complexity thus simplify the semantic parsers -With these ideas in mind, we developed SuperSonic as a reference implementation and used it to power our real-world products. Additionally, to encourage further development of data chatbots, we decided to open source SuperSonic as an extensible framework. +With these ideas in mind, we developed SuperSonic as a practical reference implementation and used it to power our real-world products. Additionally, to encourage further development of data chatbots, we decided to open source SuperSonic as an extensible framework. ## Out-of-the-box Features @@ -29,9 +28,7 @@ With these ideas in mind, we developed SuperSonic as a reference implementation SuperSonic is composed of two layers: supersonic-chat and supersonic-semantic. The chat layer is responsible for converting **natural language query** into semantic query (also known as DSL query), whereas the semantic layer is responsible for converting DSL query into **SQL query**. The high-level architecture and main process flow is shown in below diagram: - - - + ### Chat Layer @@ -67,4 +64,12 @@ SuperSonic comes with sample semantic models as well as chat conversations that ## How to Build -Pull the source code and run script "assembly/bin/build-standalone.sh" to build packages in the standalone mode. +SuperSonic can be deployed in two modes: standalone (intended for quick demo) and distributed (intended for production). + +### Build for Standalone Mode + +Pull the source code and run script "assembly/bin/build-standalone.sh" to build a single packages. + +### Build for Distributed Mode + +Pull the source code and run scripts "assembly/bin/build-chat.sh" and "assembly/bin/build-semantic.sh" separately to build packages. diff --git a/README_CN.md b/README_CN.md index 3a4bdf4a5..f2b6e2606 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,8 +1,8 @@ # 超音数(SuperSonic) -**超音数是一个开箱即用且易于扩展的数据问答对话框架**。通过超音数的问答对话界面,用户能够使用自然语言查询数据,系统会选择合适的可视化图表呈现结果。超音数不需要修改或复制数据,只需要在物理数据库之上构建逻辑语义模型(定义指标、维度、相互间关系等),即可开启数据问答体验。与此同时,超音数被设计为可插拔式框架,允许以插件形式来扩展新功能,或者将核心组件与其他系统集成。 +**超音数是一个开箱即用且易于扩展的数据问答对话框架**。通过超音数的问答对话界面,用户能够使用自然语言查询数据,系统会选择合适的可视化图表呈现结果。超音数不需要修改或复制数据,只需要在物理数据库之上构建逻辑语义模型(定义指标、维度、别名、相互间关系等),即可开启数据问答体验。与此同时,超音数被设计为可插拔式框架,允许以插件形式来扩展新功能,或者将核心组件与其他系统集成。 - + ## 项目动机 @@ -12,7 +12,7 @@ 1. 将基于规则和基于模型的语义解析器相结合,发挥各自优势,以便处理不同的场景 2. 引入语义模型层来封装数据底层的复杂性,从而简化语义解析器的问题求解空间 -为了验证上述想法,我们开发了超音数项目,并将其应用在实际的内部产品中。与此同时,我们决定将超音数作为一个可扩展的框架开源,希望能够促进数据问答对话领域的进一步发展。 +为了落地上述想法,我们开发了超音数项目,并将其应用在实际的内部产品中。与此同时,我们决定将超音数作为一个可扩展的框架开源,希望能够促进数据问答对话领域的进一步发展。 ## 开箱即用的特性 @@ -26,7 +26,7 @@ 超音数主要分为两层:supersonic-chat and supersonic-semantic。问答层负责将自然语言查询转换为语义查询(也称为DSL查询),而语义层负责将DSL查询转换为SQL查询。超音数的整体架构和主流程如下图所示: - + ### 问答层 @@ -62,4 +62,12 @@ ## 如何构建 -下载源码包,运行脚本"assembly/bin/build-standalone.sh",将所有服务一起编译打包 \ No newline at end of file +超音数可以运行在两个模式:standalone(一般用于快速演示)和distributed(一般用于生产环境)。 + +### Standalone模式构建 + +下载源码包,运行脚本"assembly/bin/build-standalone.sh",将所有服务一起编译打包 + +### Distributed模式构建 + +下载源码包,分别运行脚本"assembly/bin/build-chat.sh"、"assembly/bin/build-semantic.sh",为问答层服务和语义层服务编译打包 \ No newline at end of file diff --git a/assembly/bin/build-ide.sh b/assembly/bin/build-ide.sh new file mode 100755 index 000000000..b2bcd0ca3 --- /dev/null +++ b/assembly/bin/build-ide.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +sbinDir=$(cd "$(dirname "$0")"; pwd) +baseDir=$(readlink -f $sbinDir/../) +buildDir=$baseDir/build + +cd $baseDir/bin +sh build-standalone.sh + +cd $buildDir +tar xvf supersonic-webapp.tar.gz +mv supersonic-webapp webapp +mv webapp ../../launchers/standalone/target/classes \ No newline at end of file diff --git a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryGroupReq.java b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryGroupReq.java index e4134274f..0940fcb5b 100644 --- a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryGroupReq.java +++ b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryGroupReq.java @@ -1,7 +1,7 @@ package com.tencent.supersonic.auth.api.authorization.request; -import com.tencent.supersonic.common.request.PageBaseReq; +import com.tencent.supersonic.common.pojo.PageBaseReq; import java.util.List; import lombok.Data; diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/application/UserServiceImpl.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/application/UserServiceImpl.java index 65f01a222..b8c4d6fb1 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/application/UserServiceImpl.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/application/UserServiceImpl.java @@ -33,14 +33,6 @@ public class UserServiceImpl implements UserService { return userRepository.getUser(name); } - public boolean checkExist(UserWithPassword user) { - UserDO userDO = getUser(user.getName()); - if (userDO == null) { - return false; - } - return userDO.getPassword().equals(user.getPassword()); - } - @Override public List getUserNames() { return getUserDOList().stream().map(UserDO::getName).collect(Collectors.toList()); diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/AuthenticationInterceptor.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/AuthenticationInterceptor.java index 2f0e12424..433a0ddd1 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/AuthenticationInterceptor.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/AuthenticationInterceptor.java @@ -4,7 +4,7 @@ import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfi import com.tencent.supersonic.auth.api.authentication.constant.UserConstants; import com.tencent.supersonic.auth.authentication.application.UserServiceImpl; import com.tencent.supersonic.auth.authentication.domain.utils.UserTokenUtils; -import com.tencent.supersonic.common.util.context.S2ThreadContext; +import com.tencent.supersonic.common.util.S2ThreadContext; import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java index c925b21bd..23a72cf49 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java @@ -6,10 +6,10 @@ import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword; import com.tencent.supersonic.auth.authentication.application.UserServiceImpl; import com.tencent.supersonic.auth.authentication.domain.utils.UserTokenUtils; -import com.tencent.supersonic.common.exception.AccessException; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.common.util.context.S2ThreadContext; -import com.tencent.supersonic.common.util.context.ThreadContext; +import com.tencent.supersonic.common.pojo.exception.AccessException; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.common.util.S2ThreadContext; +import com.tencent.supersonic.common.util.ThreadContext; import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/utils/UserTokenUtils.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/utils/UserTokenUtils.java index f25788d14..94f76b91c 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/utils/UserTokenUtils.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/utils/UserTokenUtils.java @@ -13,7 +13,7 @@ import static com.tencent.supersonic.auth.api.authentication.constant.UserConsta import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword; -import com.tencent.supersonic.common.exception.AccessException; +import com.tencent.supersonic.common.pojo.exception.AccessException; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/infrastructure/mapper/UserDOMapper.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/infrastructure/mapper/UserDOMapper.java index 8f3cf6b58..c3b5dc43e 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/infrastructure/mapper/UserDOMapper.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/infrastructure/mapper/UserDOMapper.java @@ -9,43 +9,14 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface UserDOMapper { - /** - * @mbg.generated - */ - long countByExample(UserDOExample example); - - /** - * @mbg.generated - */ - int deleteByPrimaryKey(Long id); - /** * @mbg.generated */ int insert(UserDO record); - /** - * @mbg.generated - */ - int insertSelective(UserDO record); - /** * @mbg.generated */ List selectByExample(UserDOExample example); - /** - * @mbg.generated - */ - UserDO selectByPrimaryKey(Long id); - - /** - * @mbg.generated - */ - int updateByPrimaryKeySelective(UserDO record); - - /** - * @mbg.generated - */ - int updateByPrimaryKey(UserDO record); -} \ No newline at end of file +} diff --git a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/application/AuthServiceImpl.java b/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/application/AuthServiceImpl.java index 9e7797b9f..d797b2f1e 100644 --- a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/application/AuthServiceImpl.java +++ b/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/application/AuthServiceImpl.java @@ -124,8 +124,8 @@ public class AuthServiceImpl implements AuthService { } private List getAuthGroups(QueryAuthResReq req) { - List groups = load().stream(). - filter(group -> { + List groups = load().stream() + .filter(group -> { if (!Objects.equals(group.getDomainId(), req.getDomainId())) { return false; } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SchemaMapper.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SchemaMapper.java index caf15515c..79c62f75f 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SchemaMapper.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SchemaMapper.java @@ -1,6 +1,6 @@ package com.tencent.supersonic.chat.api.component; -import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.api.pojo.QueryContext; /** * This interface defines the contract for a schema mapper that identifies references to schema @@ -11,5 +11,5 @@ import com.tencent.supersonic.chat.api.request.QueryContextReq; */ public interface SchemaMapper { - void map(QueryContextReq queryContext); + void map(QueryContext queryContext); } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticLayer.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticLayer.java index f3c2566f1..011a7d244 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticLayer.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticLayer.java @@ -2,10 +2,15 @@ package com.tencent.supersonic.chat.api.component; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.*; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.query.request.QueryDslReq; +import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import java.util.List; @@ -25,27 +30,16 @@ import java.util.List; public interface SemanticLayer { QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user); + QueryResultWithSchemaResp queryByMultiStruct(QueryMultiStructReq queryMultiStructReq, User user); + QueryResultWithSchemaResp queryByDsl(QueryDslReq queryDslReq, User user); - QueryResultWithSchemaResp queryBySql(QuerySqlReq querySqlReq, User user); - - DomainSchemaResp getDomainSchemaInfo(Long domain, Boolean cacheEnable); - - List getDomainSchemaInfo(List ids); + List getDomainSchema(); + List getDomainSchema(List ids); + DomainSchema getDomainSchema(Long domain, Boolean cacheEnable); + PageInfo getDimensionPage(PageDimensionReq pageDimensionCmd); + PageInfo getMetricPage(PageMetricReq pageMetricCmd); List getDomainListForViewer(); - List getDomainListForAdmin(); - PageInfo queryDimensionPage(PageDimensionReq pageDimensionCmd); - - PageInfo queryMetricPage(PageMetricReq pageMetricCmd); - -// PageInfo queryMetricPage(PageMetricReq pageMetricCmd); -// -// PageInfo queryDimensionPage(PageDimensionReq pageDimensionCmd); -// -// List getDomainListForAdmin(); -// -// List getDomainListForViewer(); - } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticParser.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticParser.java index 218537502..198c9ec1b 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticParser.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticParser.java @@ -2,7 +2,7 @@ package com.tencent.supersonic.chat.api.component; import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.api.pojo.QueryContext; /** * This interface defines the contract for a semantic parser that can analyze natural language query @@ -13,5 +13,5 @@ import com.tencent.supersonic.chat.api.request.QueryContextReq; */ public interface SemanticParser { - void parse(QueryContextReq queryContext, ChatContext chatContext); + void parse(QueryContext queryContext, ChatContext chatContext); } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticQuery.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticQuery.java index 88429f69e..f8ddf147a 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticQuery.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticQuery.java @@ -2,7 +2,8 @@ package com.tencent.supersonic.chat.api.component; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.response.QueryResultResp; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import org.apache.calcite.sql.parser.SqlParseException; /** * This class defines the contract for a semantic query that executes specific type of @@ -12,7 +13,7 @@ public interface SemanticQuery { String getQueryMode(); - QueryResultResp execute(User user); + QueryResult execute(User user) throws SqlParseException; SemanticParseInfo getParseInfo(); } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DomainSchema.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DomainSchema.java new file mode 100644 index 000000000..d1aeb1855 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DomainSchema.java @@ -0,0 +1,45 @@ +package com.tencent.supersonic.chat.api.pojo; + +import lombok.Data; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +@Data +public class DomainSchema { + + private SchemaElement domain; + private Set metrics = new HashSet<>(); + private Set dimensions = new HashSet<>(); + private Set dimensionValues = new HashSet<>(); + private Set entities = new HashSet<>(); + + public SchemaElement getElement(SchemaElementType elementType, long elementID) { + Optional element = Optional.empty(); + switch (elementType) { + case DOMAIN: + element = Optional.of(domain); + break; + case METRIC: + element = metrics.stream().filter(e -> e.getId() == elementID).findFirst(); + break; + case DIMENSION: + element = dimensions.stream().filter(e -> e.getId() == elementID).findFirst(); + break; + case ENTITY: + element = entities.stream().filter(e -> e.getId() == elementID).findFirst(); + break; + case VALUE: + element = dimensionValues.stream().filter(e -> e.getId() == elementID).findFirst(); + default: + } + + if (element.isPresent()) { + return element.get(); + } else { + return null; + } + } + +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryContext.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryContext.java new file mode 100644 index 000000000..ba92177af --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryContext.java @@ -0,0 +1,20 @@ +package com.tencent.supersonic.chat.api.pojo; + +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class QueryContext { + + private QueryRequest request; + private List candidateQueries = new ArrayList<>(); + private SchemaMapInfo mapInfo = new SchemaMapInfo(); + + public QueryContext(QueryRequest request) { + this.request = request; + } +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryMatchInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryMatchInfo.java deleted file mode 100644 index 7e866f050..000000000 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryMatchInfo.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.tencent.supersonic.chat.api.pojo; - -import lombok.Data; - -@Data -public class QueryMatchInfo { - - SchemaElementType elementType; - String detectWord; - private Integer count = 0; - private double maxSimilarity; -} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElement.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElement.java new file mode 100644 index 000000000..0907c25c9 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElement.java @@ -0,0 +1,56 @@ +package com.tencent.supersonic.chat.api.pojo; + +import com.google.common.base.Objects; + +import java.io.Serializable; +import java.util.List; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class SchemaElement implements Serializable { + + private Long domain; + private Long id; + private String name; + private String bizName; + private Long useCnt; + private SchemaElementType type; + private List alias; + + public SchemaElement() { + } + + public SchemaElement(Long domain, Long id, String name, String bizName, + Long useCnt, SchemaElementType type, List alias) { + this.domain = domain; + this.id = id; + this.name = name; + this.bizName = bizName; + this.useCnt = useCnt; + this.type = type; + this.alias = alias; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SchemaElement schemaElement = (SchemaElement) o; + return Objects.equal(domain, schemaElement.domain) && Objects.equal(id, + schemaElement.id) && Objects.equal(name, schemaElement.name) + && Objects.equal(bizName, schemaElement.bizName) && Objects.equal( + useCnt, schemaElement.useCnt) && Objects.equal(type, schemaElement.type); + } + + @Override + public int hashCode() { + return Objects.hashCode(domain, id, name, bizName, useCnt, type); + } +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java index 592ee3bbe..605023199 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java @@ -13,15 +13,9 @@ import lombok.ToString; @NoArgsConstructor public class SchemaElementMatch { - SchemaElementType elementType; - - int elementID; - + SchemaElement element; double similarity; - String detectWord; - String word; - Long frequency; } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java index 66f8c2ca3..588d93f02 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java @@ -7,26 +7,21 @@ import java.util.Set; public class SchemaMapInfo { - private Map> domainElementMatches = new HashMap<>(); + private Map> domainElementMatches = new HashMap<>(); - public Set getMatchedDomains() { + public Set getMatchedDomains() { return domainElementMatches.keySet(); } - public List getMatchedElements(Integer domain) { + public List getMatchedElements(Long domain) { return domainElementMatches.get(domain); } - public Map> getDomainElementMatches() { + public Map> getDomainElementMatches() { return domainElementMatches; } - public void setDomainElementMatches( - Map> domainElementMatches) { - this.domainElementMatches = domainElementMatches; - } - - public void setMatchedElements(Integer domain, List elementMatches) { + public void setMatchedElements(Long domain, List elementMatches) { domainElementMatches.put(domain, elementMatches); } } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticParseInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticParseInfo.java index 03adf3897..b0059cfc7 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticParseInfo.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticParseInfo.java @@ -1,34 +1,55 @@ package com.tencent.supersonic.chat.api.pojo; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.Order; -import com.tencent.supersonic.common.pojo.SchemaItem; - +import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import lombok.Data; @Data public class SemanticParseInfo { String queryMode; - AggregateTypeEnum aggType = AggregateTypeEnum.NONE; - Long domainId = 0L; - String domainName; + SchemaElement domain; + Set metrics = new LinkedHashSet(); + Set dimensions = new LinkedHashSet(); Long entity = 0L; - Set metrics = new LinkedHashSet(); - Set dimensions = new LinkedHashSet(); - Set dimensionFilters = new LinkedHashSet(); - Set metricFilters = new LinkedHashSet(); + AggregateTypeEnum aggType = AggregateTypeEnum.NONE; + Set dimensionFilters = new LinkedHashSet(); + Set metricFilters = new LinkedHashSet(); private Set orders = new LinkedHashSet(); private DateConf dateInfo; private Long limit; private Boolean nativeQuery = false; private Double bonus = 0d; private List elementMatches = new ArrayList<>(); - private Object info; + private Map properties; + + public Long getDomainId() { + return domain != null ? domain.getId() : 0L; + } + + public String getDomainName() { + return domain != null ? domain.getName() : "null"; + } + + public Set getMetrics() { + this.metrics = this.metrics.stream().sorted((o1, o2) -> { + int len1 = o1.getName().length(); + int len2 = o2.getName().length(); + if (len1 != len2) { + return len1 - len2; + } else { + return o1.getName().compareTo(o2.getName()); + } + }).collect(Collectors.toCollection(LinkedHashSet::new)); + return this.metrics; + } } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticSchema.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticSchema.java new file mode 100644 index 000000000..7e199f00d --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticSchema.java @@ -0,0 +1,54 @@ +package com.tencent.supersonic.chat.api.pojo; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class SemanticSchema implements Serializable { + private List domainSchemaList; + + public SemanticSchema(List domainSchemaList) { + this.domainSchemaList = domainSchemaList; + } + + public void add(DomainSchema schema) { + domainSchemaList.add(schema); + } + + public Map getDomainIdToName() { + return domainSchemaList.stream() + .collect(Collectors.toMap(a -> a.getDomain().getId(), a -> a.getDomain().getName(), (k1, k2) -> k1)); + } + + public List getDimensionValues() { + List dimensionValues = new ArrayList<>(); + domainSchemaList.stream().forEach(d -> dimensionValues.addAll(d.getDimensionValues())); + return dimensionValues; + } + + public List getDimensions() { + List dimensions = new ArrayList<>(); + domainSchemaList.stream().forEach(d -> dimensions.addAll(d.getDimensions())); + return dimensions; + } + + public List getMetrics() { + List metrics = new ArrayList<>(); + domainSchemaList.stream().forEach(d -> metrics.addAll(d.getMetrics())); + return metrics; + } + + public List getDomains() { + List domains = new ArrayList<>(); + domainSchemaList.stream().forEach(d -> domains.add(d.getDomain())); + return domains; + } + + public List getEntities() { + List entities = new ArrayList<>(); + domainSchemaList.stream().forEach(d -> entities.addAll(d.getEntities())); + return entities; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/PageQueryInfoReq.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/PageQueryInfoReq.java similarity index 91% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/PageQueryInfoReq.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/PageQueryInfoReq.java index a6b092ae1..873c9cfd6 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/PageQueryInfoReq.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/PageQueryInfoReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; +package com.tencent.supersonic.chat.api.pojo.request; import lombok.Data; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/PluginQueryReq.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/PluginQueryReq.java new file mode 100644 index 000000000..f3ba04966 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/PluginQueryReq.java @@ -0,0 +1,22 @@ +package com.tencent.supersonic.chat.api.pojo.request; + + +import lombok.Data; + +@Data +public class PluginQueryReq { + + + private String showElementId; + + //DASHBOARD WIDGET + private String showType; + + private String type; + + private String domain; + + private String pattern; + + +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryDataRequest.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryDataRequest.java new file mode 100644 index 000000000..73ef07130 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryDataRequest.java @@ -0,0 +1,24 @@ +package com.tencent.supersonic.chat.api.pojo.request; + + +import java.util.HashSet; +import java.util.Set; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.pojo.Order; +import lombok.Data; + +@Data +public class QueryDataRequest { + String queryMode; + SchemaElement domain; + Set metrics = new HashSet<>(); + Set dimensions = new HashSet<>(); + Set dimensionFilters = new HashSet<>(); + Set metricFilters = new HashSet<>(); + private Set orders = new HashSet<>(); + private DateConf dateInfo; + private Long limit; + private Boolean nativeQuery = false; +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/Filter.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryFilter.java similarity index 88% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/Filter.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryFilter.java index 5b5d7a8aa..8a2054b95 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/Filter.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryFilter.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.api.pojo; +package com.tencent.supersonic.chat.api.pojo.request; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import java.util.Objects; @@ -7,7 +7,7 @@ import lombok.ToString; @Data @ToString(callSuper = true) -public class Filter { +public class QueryFilter { private String bizName; @@ -27,7 +27,7 @@ public class Filter { if (o == null || getClass() != o.getClass()) { return false; } - Filter filter = (Filter) o; + QueryFilter filter = (QueryFilter) o; return Objects.equals(bizName, filter.bizName) && Objects.equals(name, filter.name) && operator == filter.operator && Objects.equals(value, filter.value) && Objects.equals( elementID, filter.elementID); diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryFilter.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryFilters.java similarity index 57% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryFilter.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryFilters.java index c1bb4c4ac..903288cd1 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryFilter.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryFilters.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.api.pojo; +package com.tencent.supersonic.chat.api.pojo.request; import lombok.Data; import java.util.ArrayList; @@ -7,10 +7,7 @@ import java.util.List; import java.util.Map; @Data -public class QueryFilter { - - private List filters = new ArrayList<>(); - +public class QueryFilters { + private List filters = new ArrayList<>(); private Map params = new HashMap<>(); - } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryRequest.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryRequest.java new file mode 100644 index 000000000..d51ccee2f --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/QueryRequest.java @@ -0,0 +1,15 @@ +package com.tencent.supersonic.chat.api.pojo.request; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import lombok.Data; + +@Data +public class QueryRequest { + + private String queryText; + private Integer chatId; + private Long domainId = 0L; + private User user; + private QueryFilters queryFilters; + private boolean saveAnswer = true; +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/RecommendedQuestion.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/RecommendedQuestion.java new file mode 100644 index 000000000..0aa8a6bdf --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/RecommendedQuestion.java @@ -0,0 +1,12 @@ +package com.tencent.supersonic.chat.api.pojo.request; + +import lombok.Data; +import lombok.ToString; + +@Data +@ToString +public class RecommendedQuestion { + + private String question; + +} \ No newline at end of file diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/AggregateInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/AggregateInfo.java new file mode 100644 index 000000000..96cb05e13 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/AggregateInfo.java @@ -0,0 +1,10 @@ +package com.tencent.supersonic.chat.api.pojo.response; + +import java.util.ArrayList; +import java.util.List; +import lombok.Data; + +@Data +public class AggregateInfo { + private List metricInfos = new ArrayList<>(); +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DataInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/DataInfo.java similarity index 74% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DataInfo.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/DataInfo.java index 07a452f9d..7b22daf73 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DataInfo.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/DataInfo.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.api.pojo; +package com.tencent.supersonic.chat.api.pojo.response; import lombok.Data; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DomainInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/DomainInfo.java similarity index 80% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DomainInfo.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/DomainInfo.java index 36073cf9c..2be895e86 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/DomainInfo.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/DomainInfo.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.api.pojo; +package com.tencent.supersonic.chat.api.pojo.response; import java.io.Serializable; import java.util.List; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/EntityInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/EntityInfo.java similarity index 84% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/EntityInfo.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/EntityInfo.java index 329704688..0f0039380 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/EntityInfo.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/EntityInfo.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.api.pojo; +package com.tencent.supersonic.chat.api.pojo.response; import java.util.ArrayList; import java.util.List; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/MetricInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/MetricInfo.java new file mode 100644 index 000000000..ef9264145 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/MetricInfo.java @@ -0,0 +1,14 @@ +package com.tencent.supersonic.chat.api.pojo.response; + +import java.util.Map; +import lombok.Data; + +@Data +public class MetricInfo { + + private String name; + private String value; + private String date; + private Map statistics; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/ChatQueryVO.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryResponse.java similarity index 54% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/ChatQueryVO.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryResponse.java index d32120313..2ab39fb93 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/ChatQueryVO.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryResponse.java @@ -1,11 +1,10 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; +package com.tencent.supersonic.chat.api.pojo.response; -import com.tencent.supersonic.chat.api.response.QueryResultResp; import java.util.Date; import lombok.Data; @Data -public class ChatQueryVO { +public class QueryResponse { private Long questionId; private Date createTime; @@ -13,5 +12,5 @@ public class ChatQueryVO { private Integer score; private String feedback; private String queryText; - private QueryResultResp queryResponse; + private QueryResult queryResult; } \ No newline at end of file diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/response/QueryResultResp.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryResult.java similarity index 61% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/response/QueryResultResp.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryResult.java index 6ed1fc587..3858f64f2 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/response/QueryResultResp.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryResult.java @@ -1,21 +1,21 @@ -package com.tencent.supersonic.chat.api.response; +package com.tencent.supersonic.chat.api.pojo.response; -import com.tencent.supersonic.chat.api.pojo.EntityInfo; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.semantic.api.core.pojo.QueryAuthorization; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; +import com.tencent.supersonic.common.pojo.QueryAuthorization; +import com.tencent.supersonic.common.pojo.QueryColumn; import java.util.List; import java.util.Map; import lombok.Data; @Data -public class QueryResultResp { +public class QueryResult { public EntityInfo entityInfo; + public AggregateInfo aggregateInfo; private Long queryId; private String queryMode; private String querySql; - private int queryState; + private QueryState queryState = QueryState.EMPTY; private List queryColumns; private QueryAuthorization queryAuthorization; private SemanticParseInfo chatContext; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryState.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryState.java new file mode 100644 index 000000000..30ecc1e2c --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/QueryState.java @@ -0,0 +1,8 @@ +package com.tencent.supersonic.chat.api.pojo.response; + +public enum QueryState { + SUCCESS, + SEARCH_EXCEPTION, + EMPTY, + INVALID; +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/RecommendQuestion.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/RecommendQuestion.java new file mode 100644 index 000000000..67cec7302 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/RecommendQuestion.java @@ -0,0 +1,14 @@ +package com.tencent.supersonic.chat.api.pojo.response; + +import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestion; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +@Data +@AllArgsConstructor +public class RecommendQuestion { + private Long domainId; + private List recommendedQuestions; +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/RecommendResponse.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/RecommendResponse.java new file mode 100644 index 000000000..89fd38a34 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/RecommendResponse.java @@ -0,0 +1,12 @@ +package com.tencent.supersonic.chat.api.pojo.response; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import lombok.Data; + +import java.util.List; + +@Data +public class RecommendResponse { + private List dimensions; + private List metrics; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/SearchResponse.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResponse.java similarity index 79% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/SearchResponse.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResponse.java index 7da6c4092..5f6b406ee 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/SearchResponse.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResponse.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.search; +package com.tencent.supersonic.chat.api.pojo.response; import java.util.List; import lombok.Data; @@ -6,8 +6,6 @@ import lombok.Getter; import lombok.Setter; @Data -@Setter -@Getter public class SearchResponse { private List searchResults; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/SearchResult.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResult.java similarity index 54% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/SearchResult.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResult.java index cd0641073..3c0c6a7a1 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/SearchResult.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResult.java @@ -1,7 +1,8 @@ -package com.tencent.supersonic.chat.domain.pojo.search; +package com.tencent.supersonic.chat.api.pojo.response; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import java.util.Objects; +import lombok.Builder; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -9,6 +10,7 @@ import lombok.Setter; @Data @Setter @Getter +@Builder public class SearchResult { private String recommend; @@ -17,29 +19,12 @@ public class SearchResult { private String domainName; - private Integer domainId; + private Long domainId; private SchemaElementType schemaElementType; private boolean isComplete = true; - public SearchResult(String recommend, String subRecommend, String className, Integer domainId, - SchemaElementType schemaElementType) { - this.recommend = recommend; - this.subRecommend = subRecommend; - this.domainName = className; - this.domainId = domainId; - this.schemaElementType = schemaElementType; - } - - public SearchResult(String recommend, String subRecommend, String className, Integer domainId, boolean isComplete) { - this.recommend = recommend; - this.subRecommend = subRecommend; - this.domainName = className; - this.domainId = domainId; - this.isComplete = isComplete; - } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/request/QueryContextReq.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/request/QueryContextReq.java deleted file mode 100644 index 87622822f..000000000 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/request/QueryContextReq.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.tencent.supersonic.chat.api.request; - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.QueryFilter; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -@Data -public class QueryContextReq { - - private String queryText; - private Integer chatId; - private Integer domainId = 0; - private User user; - private QueryFilter queryFilter; - private List candidateQueries = new ArrayList<>(); - private SchemaMapInfo mapInfo = new SchemaMapInfo(); - private boolean saveAnswer = true; -} diff --git a/chat/core/pom.xml b/chat/core/pom.xml index 63369ba78..f30672455 100644 --- a/chat/core/pom.xml +++ b/chat/core/pom.xml @@ -113,12 +113,6 @@ semantic-api ${project.version} - - - - - - com.tencent.supersonic semantic-query @@ -137,6 +131,12 @@ ${project.version} compile + + + com.github.xkzhangsan + xk-time + ${xk.time.version} + diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/DomainEntityService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/DomainEntityService.java deleted file mode 100644 index 41cc10d6a..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/DomainEntityService.java +++ /dev/null @@ -1,213 +0,0 @@ -package com.tencent.supersonic.chat.application; - - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.api.pojo.DataInfo; -import com.tencent.supersonic.chat.api.pojo.DomainInfo; -import com.tencent.supersonic.chat.api.pojo.EntityInfo; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatDefaultRichConfig; -import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -@Service -@Slf4j -public class DomainEntityService { - - private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - - @Autowired - private ConfigServiceImpl configService; - - public EntityInfo getEntityInfo(SemanticParseInfo parseInfo, User user) { - if (parseInfo != null && parseInfo.getDomainId() > 0) { - EntityInfo entityInfo = getEntityInfo(parseInfo.getDomainId()); - if (parseInfo.getDimensionFilters().size() <= 0) { - entityInfo.setMetrics(null); - entityInfo.setDimensions(null); - return entityInfo; - } - if (entityInfo.getDomainInfo() != null && entityInfo.getDomainInfo().getPrimaryEntityBizName() != null) { - String domainInfoPrimaryName = entityInfo.getDomainInfo().getPrimaryEntityBizName(); - String domainInfoId = ""; - for (Filter chatFilter : parseInfo.getDimensionFilters()) { - if (chatFilter != null && chatFilter.getBizName() != null && chatFilter.getBizName() - .equals(domainInfoPrimaryName)) { - if (chatFilter.getOperator().equals(FilterOperatorEnum.EQUALS)) { - domainInfoId = chatFilter.getValue().toString(); - } - if (chatFilter.getOperator().equals(FilterOperatorEnum.IN)) { - domainInfoId = ((List) chatFilter.getValue()).get(0); - } - } - } - if (!"".equals(domainInfoId)) { - try { - setMainDomain(entityInfo, parseInfo.getDomainId(), - domainInfoId, user); - - return entityInfo; - } catch (Exception e) { - log.error("setMaintDomain error {}", e); - } - } - } - } - return null; - } - - public EntityInfo getEntityInfo(Long domain) { - ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(domain); - if (Objects.isNull(chaConfigRichDesc) || Objects.isNull(chaConfigRichDesc.getChatDetailRichConfig())) { - return new EntityInfo(); - } - return getEntityInfo(chaConfigRichDesc); - } - - private EntityInfo getEntityInfo(ChatConfigRichResp chaConfigRichDesc) { - - EntityInfo entityInfo = new EntityInfo(); - EntityRichInfo entityDesc = chaConfigRichDesc.getChatDetailRichConfig().getEntity(); - if (entityDesc != null && Objects.nonNull(chaConfigRichDesc.getDomainId())) { - DomainInfo domainInfo = new DomainInfo(); - domainInfo.setItemId(Integer.valueOf(chaConfigRichDesc.getDomainId().intValue())); - domainInfo.setName(chaConfigRichDesc.getDomainName()); - domainInfo.setWords(entityDesc.getNames()); - domainInfo.setBizName(chaConfigRichDesc.getBizName()); - if (Objects.nonNull(entityDesc.getDimItem())) { - domainInfo.setPrimaryEntityBizName(entityDesc.getDimItem().getBizName()); - } - - entityInfo.setDomainInfo(domainInfo); - List dimensions = new ArrayList<>(); - List metrics = new ArrayList<>(); - - if (Objects.nonNull(chaConfigRichDesc) && Objects.nonNull(chaConfigRichDesc.getChatDetailRichConfig()) - && Objects.nonNull(chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig())) { - ChatDefaultRichConfig chatDefaultConfig = chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig(); - if(!CollectionUtils.isEmpty(chatDefaultConfig.getDimensions())){ - for (SchemaItem dimensionDesc : chatDefaultConfig.getDimensions()) { - DataInfo mainEntityDimension = new DataInfo(); - mainEntityDimension.setItemId(dimensionDesc.getId().intValue()); - mainEntityDimension.setName(dimensionDesc.getName()); - mainEntityDimension.setBizName(dimensionDesc.getBizName()); - dimensions.add(mainEntityDimension); - } - entityInfo.setDimensions(dimensions); - } - - if(!CollectionUtils.isEmpty(chatDefaultConfig.getMetrics())){ - for (SchemaItem metricDesc : chatDefaultConfig.getMetrics()) { - DataInfo dataInfo = new DataInfo(); - dataInfo.setName(metricDesc.getName()); - dataInfo.setBizName(metricDesc.getBizName()); - dataInfo.setItemId(metricDesc.getId().intValue()); - metrics.add(dataInfo); - } - entityInfo.setMetrics(metrics); - } - } - } - return entityInfo; - } - - public void setMainDomain(EntityInfo domainInfo, Long domain, String entity, User user) { - domainInfo.setEntityId(entity); - SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); - semanticParseInfo.setDomainId(Long.valueOf(domain)); - semanticParseInfo.setNativeQuery(true); - semanticParseInfo.setMetrics(getMetrics(domainInfo)); - semanticParseInfo.setDimensions(getDimensions(domainInfo)); - DateConf dateInfo = new DateConf(); - dateInfo.setUnit(1); - dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); - semanticParseInfo.setDateInfo(dateInfo); - - // add filter - Filter chatFilter = new Filter(); - chatFilter.setValue(String.valueOf(entity)); - chatFilter.setOperator(FilterOperatorEnum.EQUALS); - chatFilter.setBizName(getEntityPrimaryName(domainInfo)); - Set chatFilters = new LinkedHashSet(); - chatFilters.add(chatFilter); - semanticParseInfo.setDimensionFilters(chatFilters); - - QueryResultWithSchemaResp queryResultWithColumns = null; - try { - queryResultWithColumns = semanticLayer.queryByStruct(SchemaInfoConverter.convertTo(semanticParseInfo), - user); - } catch (Exception e) { - log.warn("setMainDomain queryByStruct error, e:", e); - } - - if (queryResultWithColumns != null) { - if (!CollectionUtils.isEmpty(queryResultWithColumns.getResultList()) - && queryResultWithColumns.getResultList().size() > 0) { - Map result = queryResultWithColumns.getResultList().get(0); - for (Map.Entry entry : result.entrySet()) { - String entryKey = getEntryKey(entry); - if (entry.getValue() == null || entryKey == null) { - continue; - } - domainInfo.getDimensions().stream().filter(i -> entryKey.equals(i.getBizName())) - .forEach(i -> i.setValue(entry.getValue().toString())); - domainInfo.getMetrics().stream().filter(i -> entryKey.equals(i.getBizName())) - .forEach(i -> i.setValue(entry.getValue().toString())); - } - } - } - } - - private Set getDimensions(EntityInfo domainInfo) { - Set dimensions = new LinkedHashSet(); - for (DataInfo mainEntityDimension : domainInfo.getDimensions()) { - SchemaItem dimension = new SchemaItem(); - dimension.setBizName(mainEntityDimension.getBizName()); - dimensions.add(dimension); - } - return dimensions; - } - - private String getEntryKey(Map.Entry entry) { - // metric parser special handle, TODO delete - String entryKey = entry.getKey(); - if (entryKey.contains("__")) { - entryKey = entryKey.split("__")[1]; - } - return entryKey; - } - - private Set getMetrics(EntityInfo domainInfo) { - Set metrics = new LinkedHashSet(); - for (DataInfo metricValue : domainInfo.getMetrics()) { - SchemaItem metric = new SchemaItem(); - metric.setBizName(metricValue.getBizName()); - metrics.add(metric); - } - return metrics; - } - - private String getEntityPrimaryName(EntityInfo domainInfo) { - return domainInfo.getDomainInfo().getPrimaryEntityBizName(); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/QueryServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/QueryServiceImpl.java deleted file mode 100644 index 4fdde6e91..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/QueryServiceImpl.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.tencent.supersonic.chat.application; - - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.*; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.application.query.QuerySelector; -import com.tencent.supersonic.chat.domain.pojo.chat.QueryData; -import com.tencent.supersonic.chat.domain.pojo.search.QueryState; -import com.tencent.supersonic.chat.domain.service.QueryService; -import com.tencent.supersonic.chat.domain.service.ChatService; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import java.util.List; -import java.util.stream.Collectors; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; - -@Service -@Component("chatQueryService") -@Primary -@Slf4j -public class QueryServiceImpl implements QueryService { - - @Autowired - private ChatService chatService; - - private List schemaMappers = ComponentFactory.getSchemaMappers(); - private List semanticParsers = ComponentFactory.getSemanticParsers(); - private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - private QuerySelector querySelector = ComponentFactory.getQuerySelector(); - - @Override - public QueryResultResp executeQuery(QueryContextReq queryCtx) throws Exception { - schemaMappers.stream().forEach(s -> s.map(queryCtx)); - - // in order to support multi-turn conversation, we need to consider chat context - ChatContext chatCtx = chatService.getOrCreateContext(queryCtx.getChatId()); - - for (SemanticParser semanticParser : semanticParsers) { - log.info("semanticParser processing:[{}]", semanticParser.getClass().getName()); - semanticParser.parse(queryCtx, chatCtx); - } - if (queryCtx.getCandidateQueries().size() > 0) { - log.info("pick before [{}]", queryCtx.getCandidateQueries().stream().collect( - Collectors.toList())); - SemanticQuery semanticQuery = querySelector.select(queryCtx.getCandidateQueries()); - log.info("pick after [{}]", semanticQuery); - - QueryResultResp queryResponse = semanticQuery.execute(queryCtx.getUser()); - if (queryResponse != null) { - // update chat context after a successful semantic query - if (queryCtx.isSaveAnswer() && queryResponse.getQueryState() == QueryState.NORMAL.getState()) { - chatService.updateContext(chatCtx, queryCtx, semanticQuery.getParseInfo()); - } - queryResponse.setChatContext(chatCtx.getParseInfo()); - chatService.addQuery(queryResponse, queryCtx, chatCtx); - return queryResponse; - } - } - - return null; - } - - @Override - public SemanticParseInfo queryContext(QueryContextReq queryCtx) { - ChatContext context = chatService.getOrCreateContext(queryCtx.getChatId()); - return context.getParseInfo(); - } - - @Override - public QueryResultResp executeDirectQuery(QueryData queryData, User user) throws Exception { - SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); - QueryResultResp queryResponse = new QueryResultResp(); - BeanUtils.copyProperties(queryData, semanticParseInfo); - QueryResultWithSchemaResp resultWithColumns = semanticLayer.queryByStruct( - SchemaInfoConverter.convertTo(semanticParseInfo), user); - queryResponse.setQueryColumns(resultWithColumns.getColumns()); - queryResponse.setQueryResults(resultWithColumns.getResultList()); - return queryResponse; - } -} - diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/RecommendServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/RecommendServiceImpl.java deleted file mode 100644 index b88ce07e4..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/RecommendServiceImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.tencent.supersonic.chat.application; - - -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.chat.domain.pojo.chat.RecommendResponse; -import com.tencent.supersonic.chat.domain.service.RecommendService; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Service; - -/*** - * Recommend Service impl - */ -@Service -public class RecommendServiceImpl implements RecommendService { - - private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - - @Override - public RecommendResponse recommend(QueryContextReq queryCtx) { - Integer domainId = queryCtx.getDomainId(); - if (Objects.isNull(domainId)) { - return new RecommendResponse(); - } - - DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo( - Long.valueOf(domainId), true); - - List dimensions = domainSchemaDesc.getDimensions().stream().map(dimSchemaDesc -> { - RecommendResponse.Item item = new RecommendResponse.Item(); - item.setDomain(domainId); - item.setName(dimSchemaDesc.getName()); - item.setBizName(dimSchemaDesc.getBizName()); - return item; - }).collect(Collectors.toList()); - - List metrics = domainSchemaDesc.getMetrics().stream().map(metricSchemaDesc -> { - RecommendResponse.Item item = new RecommendResponse.Item(); - item.setDomain(domainId); - item.setName(metricSchemaDesc.getName()); - item.setBizName(metricSchemaDesc.getBizName()); - return item; - }).collect(Collectors.toList()); - - RecommendResponse response = new RecommendResponse(); - response.setDimensions(dimensions); - response.setMetrics(metrics); - return response; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/ApplicationStartedInit.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/ApplicationStartedInit.java deleted file mode 100644 index 517851ed0..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/ApplicationStartedInit.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.tencent.supersonic.chat.application.knowledge; - -import com.tencent.supersonic.common.nlp.WordNature; -import com.tencent.supersonic.knowledge.domain.service.OnlineKnowledgeService; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.event.ApplicationStartedEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Slf4j -@Component -public class ApplicationStartedInit implements ApplicationListener { - - @Autowired - private OnlineKnowledgeService onlineKnowledgeService; - - @Autowired - private WordNatureService wordNatureService; - - - @Override - public void onApplicationEvent(ApplicationStartedEvent event) { - try { - log.info("ApplicationStartedInit start"); - - List wordNatures = wordNatureService.getAllWordNature(); - - wordNatureService.setPreWordNatures(wordNatures); - - onlineKnowledgeService.reloadAllData(wordNatures); - - log.info("ApplicationStartedInit end"); - } catch (Exception e) { - log.error("ApplicationStartedInit error", e); - } - } - - /*** - * reload knowledge task - */ - @Scheduled(cron = "${reload.knowledge.corn:0 0/1 * * * ?}") - public void reloadKnowledge() { - log.info("reloadKnowledge start"); - - try { - List wordNatures = wordNatureService.getAllWordNature(); - List preWordNatures = wordNatureService.getPreWordNatures(); - - if (CollectionUtils.isEqualCollection(wordNatures, preWordNatures)) { - log.debug("wordNatures is not change, reloadKnowledge end"); - return; - } - log.info("wordNatures is change"); - wordNatureService.setPreWordNatures(wordNatures); - onlineKnowledgeService.updateOnlineKnowledge(wordNatureService.getAllWordNature()); - wordNatureService.getCache().refresh(""); - - } catch (Exception e) { - log.error("reloadKnowledge error", e); - } - - log.info("reloadKnowledge end"); - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/NatureHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/NatureHelper.java deleted file mode 100644 index c01c8a08b..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/NatureHelper.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.tencent.supersonic.chat.application.knowledge; - -import com.hankcs.hanlp.corpus.tag.Nature; -import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper; -import com.tencent.supersonic.chat.domain.pojo.search.DomainInfoStat; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.knowledge.application.online.BaseWordNature; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * nature parse helper - */ -@Slf4j -public class NatureHelper { - - private static boolean isDomainOrEntity(Term term, Integer domain) { - return (NatureType.NATURE_SPILT + domain).equals(term.nature.toString()) || term.nature.toString() - .endsWith(NatureType.ENTITY.getType()); - } - - public static Integer getDomainByNature(Nature nature) { - if (nature.startsWith(NatureType.NATURE_SPILT)) { - String[] dimensionValues = nature.toString().split(NatureType.NATURE_SPILT); - if (StringUtils.isNumeric(dimensionValues[1])) { - return Integer.valueOf(dimensionValues[1]); - } - } - return 0; - } - - public static Integer getDomain(String nature) { - try { - String[] split = nature.split(NatureType.NATURE_SPILT); - if (split.length <= 1) { - return null; - } - return Integer.valueOf(split[1]); - } catch (NumberFormatException e) { - log.error("", e); - } - return null; - } - - public static boolean isDimensionValueClassId(String nature) { - if (StringUtils.isEmpty(nature)) { - return false; - } - if (!nature.startsWith(NatureType.NATURE_SPILT)) { - return false; - } - String[] split = nature.split(NatureType.NATURE_SPILT); - if (split.length <= 1) { - return false; - } - return !nature.endsWith(NatureType.METRIC.getType()) && !nature.endsWith(NatureType.DIMENSION.getType()) - && StringUtils.isNumeric(split[1]); - } - - public static DomainInfoStat getDomainStat(List terms) { - DomainInfoStat stat = new DomainInfoStat(); - stat.setDimensionDomainCount(getDimensionCount(terms)); - stat.setMetricDomainCount(getMetricCount(terms)); - stat.setDomainCount(getDomainCount(terms)); - stat.setDimensionValueDomainCount(getDimensionValueCount(terms)); - return stat; - } - - - private static long getDomainCount(List terms) { - return terms.stream().filter(term -> isDomainOrEntity(term, getDomainByNature(term.nature))).count(); - } - - private static long getDimensionValueCount(List terms) { - return terms.stream().filter(term -> isDimensionValueClassId(term.nature.toString())).count(); - } - - private static long getDimensionCount(List terms) { - return terms.stream().filter(term -> term.nature.startsWith(NatureType.NATURE_SPILT) && term.nature.toString() - .endsWith(NatureType.DIMENSION.getType())).count(); - } - - private static long getMetricCount(List terms) { - return terms.stream().filter(term -> term.nature.startsWith(NatureType.NATURE_SPILT) && term.nature.toString() - .endsWith(NatureType.METRIC.getType())).count(); - } - - /** - * Get the number of types of class parts of speech - * domainId -> (nature , natureCount) - * - * @param terms - * @return - */ - public static Map> getDomainToNatureStat(List terms) { - Map> domainToNature = new HashMap<>(); - terms.stream().filter( - term -> term.nature.startsWith(NatureType.NATURE_SPILT) - ).forEach(term -> { - NatureType natureType = NatureType.getNatureType(String.valueOf(term.nature)); - Integer domain = getDomain(String.valueOf(term.nature)); - - Map natureTypeMap = new HashMap<>(); - natureTypeMap.put(natureType, 1); - - Map original = domainToNature.get(domain); - if (Objects.isNull(original)) { - domainToNature.put(domain, natureTypeMap); - } else { - Integer count = original.get(natureType); - if (Objects.isNull(count)) { - count = 1; - } else { - count = count + 1; - } - original.put(natureType, count); - } - }); - return domainToNature; - } - - public static List selectPossibleDomains(List terms) { - Map> domainToNatureStat = getDomainToNatureStat(terms); - Integer maxDomainTypeSize = domainToNatureStat.entrySet().stream() - .max(Comparator.comparingInt(o -> o.getValue().size())).map(entry -> entry.getValue().size()) - .orElse(null); - if (Objects.isNull(maxDomainTypeSize) || maxDomainTypeSize == 0) { - return new ArrayList<>(); - } - return domainToNatureStat.entrySet().stream().filter(entry -> entry.getValue().size() == maxDomainTypeSize) - .map(entry -> entry.getKey()).collect(Collectors.toList()); - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/WordNatureService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/WordNatureService.java deleted file mode 100644 index c24805448..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/WordNatureService.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.tencent.supersonic.chat.application.knowledge; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import com.tencent.supersonic.knowledge.application.online.WordNatureStrategyFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - - -/** - * word nature service - **/ -@Service -@Slf4j -public class WordNatureService { - - private static final Integer META_CACHE_TIME = 5; - private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - private List preWordNatures = new ArrayList<>(); - - private LoadingCache cache = CacheBuilder.newBuilder() - .expireAfterWrite(META_CACHE_TIME, TimeUnit.MINUTES) - .build( - new CacheLoader() { - @Override - public DomainInfos load(String key) { - log.info("load getDomainSchemaInfo cache [{}]", key); - return SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>())); - } - } - ); - - public List getAllWordNature() { - SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - DomainInfos domainInfos = SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>())); - - List natures = new ArrayList<>(); - - addNatureToResult(NatureType.DIMENSION, domainInfos.getDimensions(), natures); - - addNatureToResult(NatureType.METRIC, domainInfos.getMetrics(), natures); - - addNatureToResult(NatureType.DOMAIN, domainInfos.getDomains(), natures); - - addNatureToResult(NatureType.ENTITY, domainInfos.getEntities(), natures); - - return natures; - } - - private void addNatureToResult(NatureType value, List metas, List natures) { - List natureList = WordNatureStrategyFactory.get(value).getWordNatureList(metas); - log.debug("nature type:{} , nature size:{}", value.name(), natureList.size()); - natures.addAll(natureList); - } - - public List getPreWordNatures() { - return preWordNatures; - } - - public void setPreWordNatures(List preWordNatures) { - this.preWordNatures = preWordNatures; - } - - public LoadingCache getCache() { - return cache; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/DatabaseSchemaMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/DatabaseSchemaMapper.java deleted file mode 100644 index f22f1ac2c..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/DatabaseSchemaMapper.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.tencent.supersonic.chat.application.mapper; - -import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.api.component.SchemaMapper; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.knowledge.WordNatureService; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.CollectionUtils; - -@Slf4j -public class DatabaseSchemaMapper implements SchemaMapper { - - @Override - public void map(QueryContextReq queryContext) { - - log.debug("before db mapper,mapInfo:{}", queryContext.getMapInfo()); - - List terms = HanlpHelper.getTerms(queryContext.getQueryText()); - - WordNatureService wordNatureService = ContextUtils.getBean(WordNatureService.class); - - DomainInfos domainInfos = wordNatureService.getCache().getUnchecked(""); - - detectAndAddToSchema(queryContext, terms, domainInfos.getDimensions(), - SchemaElementType.DIMENSION); - detectAndAddToSchema(queryContext, terms, domainInfos.getMetrics(), SchemaElementType.METRIC); - - log.debug("after db mapper,mapInfo:{}", queryContext.getMapInfo()); - } - - private void detectAndAddToSchema(QueryContextReq queryContext, List terms, List domains, - SchemaElementType schemaElementType) { - try { - String queryText = queryContext.getQueryText(); - - Map> domainResultSet = getResultSet(queryText, terms, domains); - - addToSchemaMapInfo(domainResultSet, queryContext.getMapInfo(), schemaElementType); - - } catch (Exception e) { - log.error("detectAndAddToSchema error", e); - } - } - - private Map> getResultSet(String queryText, List terms, List domains) { - - MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); - - Map> nameToItems = getNameToItems(domains); - - Map regOffsetToLength = terms.stream().sorted(Comparator.comparing(Term::length)) - .collect(Collectors.toMap(Term::getOffset, term -> term.word.length(), (value1, value2) -> value2)); - - Map> domainResultSet = new HashMap<>(); - for (Integer index = 0; index <= queryText.length() - 1; ) { - for (Integer i = index; i <= queryText.length(); ) { - i = mapperHelper.getStepIndex(regOffsetToLength, i); - if (i <= queryText.length()) { - String detectSegment = queryText.substring(index, i); - nameToItems.forEach( - (name, newItemDOs) -> { - if (name.contains(detectSegment) - && mapperHelper.getSimilarity(detectSegment, name) - >= mapperHelper.getMetricDimensionThresholdConfig()) { - Set preItemDOS = domainResultSet.putIfAbsent(detectSegment, newItemDOs); - if (Objects.nonNull(preItemDOS)) { - preItemDOS.addAll(newItemDOs); - } - } - } - ); - } - } - index = mapperHelper.getStepIndex(regOffsetToLength, index); - } - return domainResultSet; - } - - private Map> getNameToItems(List domains) { - return domains.stream() - .collect(Collectors.toMap(ItemDO::getName, a -> { - Set result = new HashSet<>(); - result.add(a); - return result; - }, (k1, k2) -> { - k1.addAll(k2); - return k1; - })); - } - - private void addToSchemaMapInfo(Map> mapResultRowSet, SchemaMapInfo schemaMap, - SchemaElementType schemaElementType) { - if (Objects.isNull(mapResultRowSet) || mapResultRowSet.size() <= 0) { - return; - } - MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); - - for (Map.Entry> entry : mapResultRowSet.entrySet()) { - String detectWord = entry.getKey(); - Set itemDOS = entry.getValue(); - for (ItemDO itemDO : itemDOS) { - - List elements = schemaMap.getMatchedElements(itemDO.getDomain()); - if (CollectionUtils.isEmpty(elements)) { - elements = new ArrayList<>(); - schemaMap.setMatchedElements(itemDO.getDomain(), elements); - } - Set regElementSet = elements.stream() - .filter(elementMatch -> schemaElementType.equals(elementMatch.getElementType())) - .map(elementMatch -> elementMatch.getElementID()) - .collect(Collectors.toSet()); - - if (regElementSet.contains(itemDO.getItemId())) { - continue; - } - SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() - .elementID(itemDO.getItemId()).word(itemDO.getName()).frequency(10000L) - .elementType(schemaElementType).detectWord(detectWord) - .similarity(mapperHelper.getSimilarity(detectWord, itemDO.getName())) - .build(); - log.info("schemaElementType:{},add to schema, elementMatch {}", schemaElementType, schemaElementMatch); - elements.add(schemaElementMatch); - } - } - - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapper.java deleted file mode 100644 index 13f1709b4..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapper.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.tencent.supersonic.chat.application.mapper; - -import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.api.component.SchemaMapper; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.knowledge.NatureHelper; -import com.tencent.supersonic.chat.domain.pojo.search.MatchText; -import com.tencent.supersonic.chat.domain.utils.NatureConverter; -import com.tencent.supersonic.common.nlp.MapResult; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.knowledge.application.online.BaseWordNature; -import com.tencent.supersonic.knowledge.application.online.WordNatureStrategyFactory; -import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections.CollectionUtils; - -@Slf4j -public class HanlpSchemaMapper implements SchemaMapper { - - @Override - public void map(QueryContextReq queryContext) { - - List terms = HanlpHelper.getTerms(queryContext.getQueryText()); - - terms.forEach( - item -> log.info("word:{},nature:{},frequency:{}", item.word, item.nature.toString(), - item.getFrequency()) - ); - QueryMatchStrategy matchStrategy = ContextUtils.getBean(QueryMatchStrategy.class); - - Map> matchResult = matchStrategy.match(queryContext.getQueryText(), terms, - queryContext.getDomainId()); - List matches = new ArrayList<>(); - if (Objects.nonNull(matchResult)) { - Optional> first = matchResult.entrySet().stream() - .filter(entry -> CollectionUtils.isNotEmpty(entry.getValue())) - .map(entry -> entry.getValue()).findFirst(); - if (first.isPresent()) { - matches = first.get(); - } - } - HanlpHelper.transLetterOriginal(matches); - log.info("queryContext:{},matches:{}", queryContext, matches); - - convertTermsToSchemaMapInfo(matches, queryContext.getMapInfo(), terms); - } - - - - private void convertTermsToSchemaMapInfo(List mapResults, SchemaMapInfo schemaMap, List terms) { - if (CollectionUtils.isEmpty(mapResults)) { - return; - } - - Map wordNatureToFrequency = terms.stream().collect( - Collectors.toMap(entry -> entry.getWord() + entry.getNature(), - term -> Long.valueOf(term.getFrequency()), (value1, value2) -> value2)); - - for (MapResult mapResult : mapResults) { - for (String nature : mapResult.getNatures()) { - Integer domain = NatureHelper.getDomain(nature); - if (Objects.isNull(domain)) { - continue; - } - SchemaElementType elementType = NatureConverter.convertTo(nature); - if (Objects.isNull(elementType)) { - continue; - } - - BaseWordNature baseWordNature = WordNatureStrategyFactory.get(NatureType.getNatureType(nature)); - Integer elementID = baseWordNature.getElementID(nature); - Long frequency = wordNatureToFrequency.get(mapResult.getName() + nature); - SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() - .elementType(elementType) - .elementID(elementID) - .frequency(frequency) - .word(mapResult.getName()) - .similarity(mapResult.getSimilarity()) - .detectWord(mapResult.getDetectWord()) - .build(); - - Map> domainElementMatches = schemaMap.getDomainElementMatches(); - List schemaElementMatches = domainElementMatches.putIfAbsent(domain, - new ArrayList<>()); - if (schemaElementMatches == null) { - schemaElementMatches = domainElementMatches.get(domain); - } - schemaElementMatches.add(schemaElementMatch); - } - } - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryFilterMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryFilterMapper.java deleted file mode 100644 index 5d4977a65..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryFilterMapper.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.tencent.supersonic.chat.application.mapper; - -import com.google.common.collect.Lists; -import com.tencent.supersonic.chat.api.component.SchemaMapper; -import com.tencent.supersonic.chat.api.pojo.*; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.common.constant.Constants; -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.CollectionUtils; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - - -@Slf4j -public class QueryFilterMapper implements SchemaMapper { - - private Long FREQUENCY = 9999999L; - - private double SIMILARITY = 1.0; - - @Override - public void map(QueryContextReq queryContext) { - Integer domainId = queryContext.getDomainId(); - if (domainId == null || domainId <= 0 || queryContext.getQueryFilter() == null) { - return; - } - QueryFilter queryFilter = queryContext.getQueryFilter(); - SchemaMapInfo schemaMapInfo = queryContext.getMapInfo(); - List schemaElementMatches = schemaMapInfo.getMatchedElements(domainId); - clearOtherSchemaElementMatch(domainId, schemaMapInfo); - convertFilterToSchemaMapInfo(queryFilter.getFilters(), schemaElementMatches); - } - - private void convertFilterToSchemaMapInfo(List filters, List schemaElementMatches) { - log.info("schemaElementMatches before queryFilerMapper:{}", schemaElementMatches); - if (CollectionUtils.isEmpty(schemaElementMatches)) { - schemaElementMatches = Lists.newArrayList(); - } - List words = schemaElementMatches.stream().map(SchemaElementMatch::getWord).collect(Collectors.toList()); - for (Filter filter : filters) { - SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() - .elementType(SchemaElementType.VALUE) - .elementID(filter.getElementID().intValue()) - .frequency(FREQUENCY) - .word(String.valueOf(filter.getValue())) - .similarity(SIMILARITY) - .detectWord(Constants.EMPTY) - .build(); - if (words.contains(schemaElementMatch.getWord())) { - continue; - } - schemaElementMatches.add(schemaElementMatch); - } - log.info("schemaElementMatches after queryFilerMapper:{}", schemaElementMatches); - } - - private void clearOtherSchemaElementMatch(Integer domainId, SchemaMapInfo schemaMapInfo) { - for (Map.Entry> entry : schemaMapInfo.getDomainElementMatches().entrySet()) { - if (!entry.getKey().equals(domainId)) { - entry.getValue().clear(); - } - } - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/AggregateSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/AggregateSemanticParser.java deleted file mode 100644 index 9a9940c45..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/AggregateSemanticParser.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.tencent.supersonic.chat.application.parser; - -import com.tencent.supersonic.chat.api.component.SemanticParser; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.query.EntityListFilter; -import com.tencent.supersonic.chat.application.query.MetricGroupBy; -import com.tencent.supersonic.chat.application.query.MetricOrderBy; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class AggregateSemanticParser implements SemanticParser { - - public static final Integer TOPN_LIMIT = 1000; - - private static Map aggregateRegexMap = new HashMap<>(); - - static { - aggregateRegexMap.put(AggregateTypeEnum.MAX, Pattern.compile("(?i)(最大值|最大|max|峰值|最高|最多)")); - aggregateRegexMap.put(AggregateTypeEnum.MIN, Pattern.compile("(?i)(最小值|最小|min|最低|最少)")); - aggregateRegexMap.put(AggregateTypeEnum.SUM, Pattern.compile("(?i)(汇总|总和|sum)")); - aggregateRegexMap.put(AggregateTypeEnum.AVG, Pattern.compile("(?i)(平均值|日均|平均|avg)")); - aggregateRegexMap.put(AggregateTypeEnum.TOPN, Pattern.compile("(?i)(top)")); - aggregateRegexMap.put(AggregateTypeEnum.DISTINCT, Pattern.compile("(?i)(uv)")); - aggregateRegexMap.put(AggregateTypeEnum.COUNT, Pattern.compile("(?i)(总数|pv)")); - aggregateRegexMap.put(AggregateTypeEnum.NONE, Pattern.compile("(?i)(明细)")); - } - - public static AggregateTypeEnum resolveAggregateType(String queryText) { - - Map aggregateCount = new HashMap<>(aggregateRegexMap.size()); - for (Map.Entry entry : aggregateRegexMap.entrySet()) { - Matcher matcher = entry.getValue().matcher(queryText); - int count = 0; - while (matcher.find()) { - count++; - } - if (count > 0) { - aggregateCount.put(entry.getKey(), count); - } - } - - return aggregateCount.entrySet().stream().max(Map.Entry.comparingByValue()).map(entry -> entry.getKey()) - .orElse(null); - } - - @Override - public void parse(QueryContextReq queryContext, ChatContext chatContext) { - AggregateTypeEnum aggregateType = resolveAggregateType(queryContext.getQueryText()); - - for (SemanticQuery semanticQuery : queryContext.getCandidateQueries()) { - SemanticParseInfo semanticParse = semanticQuery.getParseInfo(); - - semanticParse.setNativeQuery(getNativeQuery(aggregateType, semanticParse)); - semanticParse.setAggType(aggregateType); - if (Objects.isNull(semanticParse.getLimit()) || semanticParse.getLimit() <= 0) { - semanticParse.setLimit(Long.valueOf(TOPN_LIMIT)); - } - resetQueryModeByAggregateType(semanticParse, aggregateType); - } - } - - /** - * query mode reset by the AggregateType - * - * @param parseInfo - * @param aggregateType - */ - private void resetQueryModeByAggregateType(SemanticParseInfo parseInfo, - AggregateTypeEnum aggregateType) { - - String queryMode = parseInfo.getQueryMode(); - if (MetricGroupBy.QUERY_MODE.equals(queryMode) || MetricGroupBy.QUERY_MODE.equals(queryMode)) { - if (AggregateTypeEnum.MAX.equals(aggregateType) || AggregateTypeEnum.MIN.equals(aggregateType) - || AggregateTypeEnum.TOPN.equals(aggregateType)) { - parseInfo.setQueryMode(MetricOrderBy.QUERY_MODE); - } else { - parseInfo.setQueryMode(MetricGroupBy.QUERY_MODE); - } - log.info("queryMode mode [{}]->[{}]", queryMode, parseInfo.getQueryMode()); - } - } - - private boolean getNativeQuery(AggregateTypeEnum aggregateType, SemanticParseInfo semanticParse) { - if (AggregateTypeEnum.TOPN.equals(aggregateType)) { - return true; - } - if (EntityListFilter.QUERY_MODE.equals(semanticParse.getQueryMode()) && (semanticParse.getMetrics() == null - || semanticParse.getMetrics().isEmpty())) { - return true; - } - return semanticParse.getNativeQuery(); - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainResolver.java deleted file mode 100644 index b3ca4e295..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainResolver.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.tencent.supersonic.chat.application.parser; - - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.component.SemanticQuery; - -import java.util.Map; - -public interface DomainResolver { - - Integer resolve(Map domainQueryModes, QueryContextReq queryCtx, ChatContext chatCtx, - SchemaMapInfo schemaMap); - - boolean isDomainSwitch(ChatContext chatCtx, SemanticParseInfo semanticParseInfo); - -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainSemanticParser.java deleted file mode 100644 index b24be50fc..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainSemanticParser.java +++ /dev/null @@ -1,250 +0,0 @@ -package com.tencent.supersonic.chat.application.parser; - -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.api.component.SemanticParser; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.query.EntitySemanticQuery; -import com.tencent.supersonic.chat.application.query.MetricSemanticQuery; -import com.tencent.supersonic.chat.application.query.RuleSemanticQuery; -import com.tencent.supersonic.chat.application.query.RuleSemanticQueryManager; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigResp; -import com.tencent.supersonic.chat.domain.service.ConfigService; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import com.tencent.supersonic.chat.domain.utils.DefaultMetricUtils; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.util.context.ContextUtils; - -import java.util.*; -import java.util.stream.Collectors; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.CollectionUtils; - -@Slf4j -public class DomainSemanticParser implements SemanticParser { - - private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - - @Override - public void parse(QueryContextReq queryContext, ChatContext chatContext) { - DomainInfos domainInfosDb = SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>())); - Map domainToName = domainInfosDb.getDomainToName(); - SchemaMapInfo mapInfo = queryContext.getMapInfo(); - - // iterate all schemaElementMatches to resolve semantic query - for (Integer domainId : mapInfo.getMatchedDomains()) { - List elementMatches = mapInfo.getMatchedElements(domainId); - List queries = resolveQuery(elementMatches, queryContext); - for (RuleSemanticQuery query : queries) { - - if (useBlackItem(query, domainId)) { - log.info("useBlackItem, skip query:{}", query); - continue; - } - addCandidateQuery(queryContext, chatContext, domainId.longValue(), - domainToName.get(domainId), query); - } - } - - // if no candidates have been found yet, count in chat context and try again - if (queryContext.getCandidateQueries().size() <= 0) { - if (chatContext.getParseInfo() != null && chatContext.getParseInfo().getDomainId() > 0) { - Integer chatDomainId = Integer.valueOf(chatContext.getParseInfo().getDomainId().intValue()); - if (mapInfo.getMatchedDomains().contains(chatDomainId)) { - List elementMatches = mapInfo.getMatchedElements(chatDomainId); - - List queries = tryParseByContext(elementMatches, chatContext, queryContext); - for (RuleSemanticQuery query : queries) { - addCandidateQuery(queryContext, chatContext, chatDomainId.longValue(), - domainToName.get(chatDomainId), query); - } - } - } - } - } - - private boolean useBlackItem(RuleSemanticQuery query, Integer domainId) { - if (Objects.isNull(domainId)) { - return false; - } - ConfigService configService = ContextUtils.getBean(ConfigService.class); - ChatConfigResp chatConfigResp = configService.fetchConfigByDomainId(domainId.longValue()); - if (Objects.nonNull(chatConfigResp) && Objects.nonNull(query) && Objects.nonNull(query.getParseInfo())) { - List elementMatches = query.getParseInfo().getElementMatches(); - if (!CollectionUtils.isEmpty(elementMatches)) { - return useBlackItemInternal(elementMatches, chatConfigResp, query); - - } - } - return false; - } - - private boolean useBlackItemInternal(List elementMatches, ChatConfigResp chatConfigResp, RuleSemanticQuery query) { - if (Objects.isNull(chatConfigResp)) { - return false; - } - List blackDimIdList = new ArrayList<>(); - List blackMetricIdList = new ArrayList<>(); - if (query instanceof EntitySemanticQuery - && Objects.nonNull(chatConfigResp.getChatDetailConfig()) - && Objects.nonNull(chatConfigResp.getChatDetailConfig().getVisibility())) { - log.info("useBlackItem, handle EntitySemanticQuery blackList logic"); - blackDimIdList = chatConfigResp.getChatDetailConfig().getVisibility().getBlackDimIdList(); - blackMetricIdList = chatConfigResp.getChatDetailConfig().getVisibility().getBlackMetricIdList(); - } - - if (query instanceof MetricSemanticQuery - && Objects.nonNull(chatConfigResp.getChatAggConfig()) - && Objects.nonNull(chatConfigResp.getChatAggConfig().getVisibility())) { - log.info("useBlackItem, handle MetricSemanticQuery blackList logic"); - blackDimIdList = chatConfigResp.getChatAggConfig().getVisibility().getBlackDimIdList(); - blackMetricIdList = chatConfigResp.getChatAggConfig().getVisibility().getBlackMetricIdList(); - } - return useBlackItemWithElementMatches(elementMatches, blackDimIdList, blackMetricIdList); - } - - private boolean useBlackItemWithElementMatches(List elementMatches, List blackDimIdList, List blackMetricIdList) { - - Set dimIds = elementMatches.stream() - .filter(element -> SchemaElementType.VALUE.equals(element.getElementType()) || SchemaElementType.DIMENSION.equals(element.getElementType())) - .map(element -> Long.valueOf(element.getElementID())).collect(Collectors.toSet()); - - Set metricIds = elementMatches.stream() - .filter(element -> SchemaElementType.METRIC.equals(element.getElementType())) - .map(element -> Long.valueOf(element.getElementID())).collect(Collectors.toSet()); - - - return useBlackItemWithIds(dimIds, metricIds, blackDimIdList, blackMetricIdList); - } - - private boolean useBlackItemWithIds(Set dimIds, Set metricIds, List blackDimIdList, List blackMetricIdList) { - - if (!CollectionUtils.isEmpty(blackDimIdList) && !CollectionUtils.isEmpty(dimIds)) { - if (blackDimIdList.stream().anyMatch(dimIds::contains)) { - log.info("useBlackItem, blackDimIdList:{}", blackDimIdList.stream().filter(dimIds::contains).collect(Collectors.toList())); - return true; - } - } - if (!CollectionUtils.isEmpty(blackMetricIdList) && !CollectionUtils.isEmpty(metricIds)) { - if (blackMetricIdList.stream().anyMatch(metricIds::contains)) { - log.info("useBlackItem, blackMetricIdList:{}", blackMetricIdList.stream().filter(metricIds::contains).collect(Collectors.toList())); - return true; - } - } - return false; - } - - private void addCandidateQuery(QueryContextReq queryContext, ChatContext chatContext, - Long domainId, String domainName, RuleSemanticQuery semanticQuery) { - if (semanticQuery != null) { - DefaultMetricUtils defaultMetricUtils = ContextUtils.getBean(DefaultMetricUtils.class); - defaultMetricUtils.fillParseInfo(semanticQuery, domainId, domainName); - inheritContext(semanticQuery, chatContext); - defaultMetricUtils.fillDefaultMetric(semanticQuery.getParseInfo(), queryContext, chatContext); - queryContext.getCandidateQueries().add(semanticQuery); - } - } - - protected void inheritContext(RuleSemanticQuery semanticQuery, ChatContext chatContext) { - // is domain switch - SemanticParseInfo semanticParse = semanticQuery.getParseInfo(); - DomainResolver domainResolver = ComponentFactory.getDomainResolver(); - if (!domainResolver.isDomainSwitch(chatContext, semanticParse)) { - semanticQuery.inheritContext(chatContext); - } - } - - /** - * try to add ChatContext to SchemaMatch and look if match QueryMode - * - * @param elementMatches - * @param chatCtx - * @return - */ - private List tryParseByContext(List elementMatches, - ChatContext chatCtx, QueryContextReq queryCtx) { - if (chatCtx.getParseInfo() != null && chatCtx.getParseInfo().getEntity() > 0) { - Long entityCount = elementMatches.stream().filter(i -> SchemaElementType.ENTITY.equals(i.getElementType())) - .count(); - Long metricCount = elementMatches.stream().filter(i -> SchemaElementType.METRIC.equals(i.getElementType())) - .count(); - if (entityCount <= 0 && metricCount <= 0 && ContextHelper.hasEntityId(chatCtx)) { - // try entity parse - SchemaElementMatch entityElementMatch = SchemaElementMatch.builder() - .elementType(SchemaElementType.ENTITY).build(); - List newSchemaMatches = new ArrayList<>(); - if (!CollectionUtils.isEmpty(elementMatches)) { - newSchemaMatches.addAll(elementMatches); - } - newSchemaMatches.add(entityElementMatch); - List queries = doParseByContext(newSchemaMatches, chatCtx, queryCtx); - if (queries.size() > 0) { - return queries; - } - } - } - return doParseByContext(elementMatches, chatCtx, queryCtx); - } - - - private List doParseByContext(List elementMatches, - ChatContext chatCtx, QueryContextReq queryContext) { - SemanticParseInfo contextSemanticParse = chatCtx.getParseInfo(); - if (contextSemanticParse != null) { - List newElementMatches = new ArrayList<>(); - List> trySchemaElementTypes = new LinkedList<>(); - // try DIMENSION+METRIC+VALUE - // try DIMENSION+METRIC METRIC+VALUE DIMENSION+VALUE - // try DIMENSION METRIC VALUE single - trySchemaElementTypes.add(new ArrayList<>( - Arrays.asList(SchemaElementType.DIMENSION, SchemaElementType.METRIC, SchemaElementType.VALUE))); - trySchemaElementTypes.add( - new ArrayList<>(Arrays.asList(SchemaElementType.METRIC, SchemaElementType.VALUE))); - trySchemaElementTypes.add( - new ArrayList<>(Arrays.asList(SchemaElementType.DIMENSION, SchemaElementType.METRIC))); - trySchemaElementTypes.add( - new ArrayList<>(Arrays.asList(SchemaElementType.DIMENSION, SchemaElementType.VALUE))); - trySchemaElementTypes.add(new ArrayList<>(Arrays.asList(SchemaElementType.METRIC))); - trySchemaElementTypes.add(new ArrayList<>(Arrays.asList(SchemaElementType.VALUE))); - trySchemaElementTypes.add(new ArrayList<>(Arrays.asList(SchemaElementType.DIMENSION))); - - for (List schemaTypes : trySchemaElementTypes) { - newElementMatches.clear(); - if (!CollectionUtils.isEmpty(elementMatches)) { - newElementMatches.addAll(elementMatches); - } - ContextHelper.mergeContextSchemaElementMatch(newElementMatches, elementMatches, schemaTypes, - contextSemanticParse); - List queries = resolveQuery(newElementMatches, queryContext); - if (queries.size() > 0) { - return queries; - } - } - } - return new ArrayList<>(); - } - - private List resolveQuery(List candidateElementMatches, - QueryContextReq queryContext) { - List matchedQueries = new ArrayList<>(); - for (RuleSemanticQuery semanticQuery : RuleSemanticQueryManager.getSemanticQueries()) { - List matches = semanticQuery.match(candidateElementMatches, queryContext); - - if (matches.size() > 0) { - log.info("resolve match [{}:{}] ", semanticQuery.getQueryMode(), matches.size()); - RuleSemanticQuery query = RuleSemanticQueryManager.create(semanticQuery.getQueryMode()); - query.getParseInfo().getElementMatches().addAll(matches); - matchedQueries.add(query); - } - } - - return matchedQueries; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/HeuristicDomainResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/HeuristicDomainResolver.java deleted file mode 100644 index 1b781be17..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/HeuristicDomainResolver.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.tencent.supersonic.chat.application.parser; - -import com.tencent.supersonic.chat.api.pojo.*; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import lombok.extern.slf4j.Slf4j; - -import java.util.*; -import java.util.stream.Collectors; - -@Slf4j -public class HeuristicDomainResolver implements DomainResolver { - - protected static Integer selectDomainBySchemaElementCount(Map domainQueryModes, - SchemaMapInfo schemaMap) { - Map domainTypeMap = getDomainTypeMap(schemaMap); - if (domainTypeMap.size() == 1) { - Integer domainSelect = domainTypeMap.entrySet().stream().collect(Collectors.toList()).get(0).getKey(); - if (domainQueryModes.containsKey(domainSelect)) { - log.info("selectDomain from domainTypeMap not order [{}]", domainSelect); - return domainSelect; - } - } else { - Map.Entry maxDomain = domainTypeMap.entrySet().stream() - .filter(entry -> domainQueryModes.containsKey(entry.getKey())) - .sorted(ContextHelper.DomainStatComparator).findFirst().orElse(null); - if (maxDomain != null) { - log.info("selectDomain from domainTypeMap order [{}]", maxDomain.getKey()); - return maxDomain.getKey(); - } - } - return 0; - } - - /** - * to check can switch domain if context exit domain - * - * @return false will use context domain, true will use other domain , maybe include context domain - */ - protected static boolean isAllowSwitch(Map domainQueryModes, SchemaMapInfo schemaMap, - ChatContext chatCtx, QueryContextReq searchCtx, Integer domainId) { - if (!Objects.nonNull(domainId) || domainId <= 0) { - return true; - } - // except content domain, calculate the number of types for each domain, if numbers<=1 will not switch - Map domainTypeMap = getDomainTypeMap(schemaMap); - log.info("isAllowSwitch domainTypeMap [{}]", domainTypeMap); - long otherDomainTypeNumBigOneCount = domainTypeMap.entrySet().stream() - .filter(entry -> domainQueryModes.containsKey(entry.getKey()) && !entry.getKey().equals(domainId)) - .filter(entry -> entry.getValue().getCount() > 1).count(); - if (otherDomainTypeNumBigOneCount >= 1) { - return true; - } - // if query text only contain time , will not switch - for (SemanticQuery semanticQuery : domainQueryModes.values()) { - SemanticParseInfo semanticParseInfo = semanticQuery.getParseInfo(); - if (semanticParseInfo == null) { - continue; - } - if (searchCtx.getQueryText() != null && semanticParseInfo.getDateInfo() != null) { - if (semanticParseInfo.getDateInfo().getText() != null) { - if (semanticParseInfo.getDateInfo().getText().equalsIgnoreCase(searchCtx.getQueryText())) { - log.info("timeParseResults is not null , can not switch context , timeParseResults:{},", - semanticParseInfo.getDateInfo()); - return false; - } - } - } - } - - // if context domain not in schemaMap , will switch - if (schemaMap.getMatchedElements(domainId) == null || schemaMap.getMatchedElements(domainId).size() <= 0) { - log.info("domainId not in schemaMap "); - return true; - } - // other will not switch - return false; - } - - public static Map getDomainTypeMap(SchemaMapInfo schemaMap) { - Map domainCount = new HashMap<>(); - for (Map.Entry> entry : schemaMap.getDomainElementMatches().entrySet()) { - List schemaElementMatches = schemaMap.getMatchedElements(entry.getKey()); - if (schemaElementMatches != null && schemaElementMatches.size() > 0) { - if (!domainCount.containsKey(entry.getKey())) { - domainCount.put(entry.getKey(), new QueryMatchInfo()); - } - QueryMatchInfo queryMatchInfo = domainCount.get(entry.getKey()); - Set schemaElementTypes = new HashSet<>(); - schemaElementMatches.stream() - .forEach(schemaElementMatch -> schemaElementTypes.add(schemaElementMatch.getElementType())); - SchemaElementMatch schemaElementMatchMax = schemaElementMatches.stream() - .sorted(ContextHelper.schemaElementMatchComparatorBySimilarity).findFirst().orElse(null); - if (schemaElementMatchMax != null) { - queryMatchInfo.setMaxSimilarity(schemaElementMatchMax.getSimilarity()); - } - queryMatchInfo.setCount(schemaElementTypes.size()); - - } - } - return domainCount; - } - - @Override - public boolean isDomainSwitch(ChatContext chatCtx, SemanticParseInfo semanticParseInfo) { - Long contextDomain = chatCtx.getParseInfo().getDomainId(); - Long currentDomain = semanticParseInfo.getDomainId(); - boolean noSwitch = - currentDomain == null || contextDomain == null || contextDomain.equals(currentDomain); - log.debug("ChatContext isDomainSwitch [{}] [{}]", - semanticParseInfo.getQueryMode(), !noSwitch); - return !noSwitch; - } - - @Override - public Integer resolve(Map domainQueryModes, QueryContextReq searchCtx, - ChatContext chatCtx, SchemaMapInfo schemaMap) { - Integer selectDomain = selectDomain(domainQueryModes, searchCtx, chatCtx, schemaMap); - if (selectDomain > 0) { - log.info("selectDomain {} ", selectDomain); - return selectDomain; - } - // get the max SchemaElementType number - return selectDomainBySchemaElementCount(domainQueryModes, schemaMap); - } - - public Integer selectDomain(Map domainQueryModes, QueryContextReq searchCtx, - ChatContext chatCtx, - SchemaMapInfo schemaMap) { - // if QueryContext has domainId and in domainQueryModes - if (domainQueryModes.containsKey(searchCtx.getDomainId())) { - log.info("selectDomain from QueryContext [{}]", searchCtx.getDomainId()); - return searchCtx.getDomainId(); - } - // if ChatContext has domainId and in domainQueryModes - if (chatCtx.getParseInfo().getDomainId() > 0) { - Integer domainId = Integer.valueOf(chatCtx.getParseInfo().getDomainId().intValue()); - if (!isAllowSwitch(domainQueryModes, schemaMap, chatCtx, searchCtx, domainId)) { - log.info("selectDomain from ChatContext [{}]", domainId); - return domainId; - } - } - // default 0 - return 0; - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/LLMSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/LLMSemanticParser.java deleted file mode 100644 index b3aa00471..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/LLMSemanticParser.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.tencent.supersonic.chat.application.parser; - -import com.tencent.supersonic.chat.api.component.SemanticParser; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.knowledge.WordNatureService; -import com.tencent.supersonic.chat.application.query.LLMSemanticQuery; -import com.tencent.supersonic.chat.domain.config.LLMConfig; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.chat.domain.pojo.chat.LLMReq; -import com.tencent.supersonic.chat.domain.pojo.chat.LLMResp; -import com.tencent.supersonic.chat.domain.pojo.chat.LLMSchema; -import com.tencent.supersonic.chat.domain.utils.DslToSemanticInfo; -import com.tencent.supersonic.chat.domain.utils.SemanticSatisfactionChecker; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.common.util.json.JsonUtil; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.apache.calcite.sql.parser.SqlParseException; -import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -@Slf4j -public class LLMSemanticParser implements SemanticParser { - - private DslToSemanticInfo dslToSemanticInfo = new DslToSemanticInfo(); - - @Override - public void parse(QueryContextReq queryContext, ChatContext chatCtx) { - String queryText = queryContext.getQueryText(); - - if (SemanticSatisfactionChecker.check(queryContext)) { - log.info("There is no need parse by llm , queryText:{}", queryText); - return; - } - - try { - Integer domainId = getDomainId(queryContext, chatCtx); - LLMResp llmResp = requestLLM(queryContext, domainId); - if (Objects.isNull(llmResp)) { - return; - } - LLMSemanticQuery semanticQuery = new LLMSemanticQuery(); - SemanticParseInfo parseInfo = semanticQuery.getParseInfo(); - String sql = convertToSql(llmResp, parseInfo, domainId); - - parseInfo.setInfo(sql); - parseInfo.setDomainId(Long.valueOf(domainId)); - parseInfo.setBonus(queryText.length() * 1.0); - parseInfo.setQueryMode(LLMSemanticQuery.QUERY_MODE); - queryContext.getCandidateQueries().add(semanticQuery); - return; - } catch (Exception e) { - log.error("llm parse error , skip the parser. error:", e); - } - } - - protected String convertToSql(LLMResp llmResp, SemanticParseInfo parseInfo, Integer domainId) - throws SqlParseException { - return dslToSemanticInfo.convert(parseInfo, llmResp, domainId); - } - - protected LLMResp requestLLM(QueryContextReq queryContext, Integer domainId) { - final LLMConfig llmConfig = ContextUtils.getBean(LLMConfig.class); - - if (StringUtils.isEmpty(llmConfig.getUrl())) { - log.warn("llmConfig url is null, skip llm parser"); - return null; - } - - DomainInfos domainInfos = ContextUtils.getBean(WordNatureService.class).getCache().getUnchecked(""); - - Map domainIdToName = domainInfos.getDomains().stream() - .collect(Collectors.toMap(ItemDO::getDomain, a -> a.getName(), (k1, k2) -> k1)); - - Map itemIdToName = domainInfos.getDimensions().stream() - .filter(entry -> domainId.equals(entry.getDomain())) - .collect(Collectors.toMap(ItemDO::getItemId, ItemDO::getName, (value1, value2) -> value2)); - - String domainName = domainIdToName.get(domainId); - LLMReq llmReq = new LLMReq(); - llmReq.setQueryText(queryContext.getQueryText()); - - List matchedElements = queryContext.getMapInfo().getMatchedElements(domainId); - - Set fieldNameList = matchedElements.stream() - .filter(schemaElementMatch -> - SchemaElementType.METRIC.equals(schemaElementMatch.getElementType()) || - SchemaElementType.DIMENSION.equals(schemaElementMatch.getElementType()) || - SchemaElementType.VALUE.equals(schemaElementMatch.getElementType())) - .map(schemaElementMatch -> { - if (!SchemaElementType.VALUE.equals(schemaElementMatch.getElementType())) { - return schemaElementMatch.getWord(); - } - return itemIdToName.get(schemaElementMatch.getElementID()); - }) - .filter(name -> StringUtils.isNotEmpty(name) && !name.contains("%")) - .collect(Collectors.toSet()); - - LLMSchema llmSchema = new LLMSchema(); - llmSchema.setDomainName(domainName); - llmSchema.setFieldNameList(new ArrayList<>(fieldNameList)); - llmReq.setSchema(llmSchema); - - log.info("requestLLM request, domainId:{},llmReq:{}", domainId, llmReq); - String questUrl = llmConfig.getUrl() + llmConfig.getQueryToSqlPath(); - - RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity entity = new HttpEntity<>(JsonUtil.toString(llmReq), headers); - - ResponseEntity responseEntity = restTemplate.exchange(questUrl, HttpMethod.POST, entity, - LLMResp.class); - - log.info("requestLLM response, questUrl:{} \n entity:{} \n body:{}", questUrl, entity, - responseEntity.getBody()); - return responseEntity.getBody(); - } - - protected Integer getDomainId(QueryContextReq queryContext, ChatContext chatCtx) { - SchemaMapInfo mapInfo = queryContext.getMapInfo(); - Set matchedDomains = mapInfo.getMatchedDomains(); - Map domainQueryModes = new HashMap<>(); - for (Integer matchedDomain : matchedDomains) { - domainQueryModes.put(matchedDomain, new LLMSemanticQuery()); - } - List domainResolverList = SpringFactoriesLoader.loadFactories(DomainResolver.class, - Thread.currentThread().getContextClassLoader()); - Optional domainId = domainResolverList.stream() - .map(domainResolver -> domainResolver.resolve(domainQueryModes, queryContext, chatCtx, - queryContext.getMapInfo())).filter(d -> d > 0).findFirst(); - if (domainId.isPresent()) { - return domainId.get(); - } - return 0; - } -} - - diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParser.java deleted file mode 100644 index 4190c7012..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParser.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.tencent.supersonic.chat.application.parser; - -import com.tencent.supersonic.chat.api.component.SemanticParser; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.query.MetricSemanticQuery; -import com.tencent.supersonic.chat.application.query.RuleSemanticQuery; -import com.tencent.supersonic.chat.application.query.RuleSemanticQueryManager; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; -import java.time.LocalDate; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.Stack; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.commons.collections.CollectionUtils; -import org.apache.logging.log4j.util.Strings; - -public class TimeSemanticParser implements SemanticParser { - - private static final Pattern recentPeriodPattern = Pattern.compile( - ".*(?(近|过去)((?\\d+)|(?[一二三四五六七八九十百千万亿]+))个?(?[天周月年])).*"); - - private int zhNumParse(String zhNumStr) { - Stack stack = new Stack<>(); - String numStr = "一二三四五六七八九"; - String unitStr = "十百千万亿"; - - String[] ssArr = zhNumStr.split(""); - for (String e : ssArr) { - int numIndex = numStr.indexOf(e); - int unitIndex = unitStr.indexOf(e); - if (numIndex != -1) { - stack.push(numIndex + 1); - } else if (unitIndex != -1) { - int unitNum = (int) Math.pow(10, unitIndex + 1); - if (stack.isEmpty()) { - stack.push(unitNum); - } else { - stack.push(stack.pop() * unitNum); - } - } - } - - return stack.stream().mapToInt(s -> s).sum(); - } - - @Override - public void parse(QueryContextReq queryContext, ChatContext chatContext) { - Matcher m = recentPeriodPattern.matcher(queryContext.getQueryText()); - if (m.matches()) { - int num = 0; - String enNum = m.group("enNum"); - String zhNum = m.group("zhNum"); - if (enNum != null) { - num = Integer.parseInt(enNum); - } else if (zhNum != null) { - num = zhNumParse(zhNum); - } - if (num > 0) { - DateConf info = new DateConf(); - String zhPeriod = m.group("zhPeriod"); - int days; - switch (zhPeriod) { - case "周": - days = 7; - info.setPeriod(Constants.WEEK); - break; - case "月": - days = 30; - info.setPeriod(Constants.MONTH); - break; - case "年": - days = 365; - info.setPeriod(Constants.YEAR); - break; - default: - days = 1; - info.setPeriod(Constants.DAY); - } - days = days * num; - info.setDateMode(DateConf.DateMode.RECENT_UNITS); - String text = "近" + num + zhPeriod; - if (Strings.isNotEmpty(m.group("periodStr"))) { - text = m.group("periodStr"); - } - info.setText(text); - info.setStartDate(LocalDate.now().minusDays(days).toString()); - info.setUnit(num); - //queryContext.getParseInfo().setDateInfo(info); - for (SemanticQuery query : queryContext.getCandidateQueries()) { - if (query instanceof MetricSemanticQuery) { - query.getParseInfo().setDateInfo(info); - } - } - doParseOnlyTime(queryContext, chatContext, info); - } - } - } - - protected void doParseOnlyTime(QueryContextReq queryContext, ChatContext chatContext, DateConf info) { - if (!queryContext.getCandidateQueries().isEmpty() || chatContext.getParseInfo() == null || Objects.isNull( - info.getText())) { - return; - } - if (info.getText().equals(queryContext.getQueryText()) && queryContext.getMapInfo().getDomainElementMatches() - .isEmpty() - ) { - if (Objects.nonNull(chatContext.getParseInfo().getQueryMode()) && Objects.nonNull( - chatContext.getParseInfo().getDomainId()) && chatContext.getParseInfo().getDomainId() > 0) { - if (Objects.nonNull(chatContext.getParseInfo().getDateInfo()) && !chatContext.getParseInfo() - .getDateInfo().getPeriod().equals(info.getPeriod())) { - if (!CollectionUtils.isEmpty(chatContext.getParseInfo().getDimensions())) { - String dateField = TimeDimensionEnum.DAY.getName(); - if (Constants.MONTH.equals(chatContext.getParseInfo().getDateInfo().getPeriod())) { - dateField = TimeDimensionEnum.MONTH.getName(); - } - if (Constants.WEEK.equals(chatContext.getParseInfo().getDateInfo().getPeriod())) { - dateField = TimeDimensionEnum.WEEK.getName(); - } - Set dimensions = new HashSet<>(); - for (SchemaItem schemaItem : chatContext.getParseInfo().getDimensions()) { - if (schemaItem.getBizName().equals(dateField)) { - continue; - } - dimensions.add(schemaItem); - } - chatContext.getParseInfo().setDimensions(dimensions); - } - } - chatContext.getParseInfo().setDateInfo(info); - RuleSemanticQuery semanticQuery = RuleSemanticQueryManager.create( - chatContext.getParseInfo().getQueryMode()); - semanticQuery.setParseInfo(chatContext.getParseInfo()); - queryContext.getCandidateQueries().add(semanticQuery); - } - } - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityDetail.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityDetail.java deleted file mode 100644 index db626d7af..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityDetail.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Component; - -@Component -public class EntityDetail extends EntitySemanticQuery { - - public static String QUERY_MODE = "ENTITY_DETAIL"; - - public EntityDetail() { - super(); - queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1) - .addOption(VALUE, REQUIRED, AT_LEAST, 1); - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public void inheritContext(ChatContext chatContext) { - ContextHelper.addIfEmpty(chatContext.getParseInfo().getDimensionFilters(), - parseInfo.getDimensionFilters()); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListFilter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListFilter.java deleted file mode 100644 index aadc64412..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListFilter.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.*; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.*; -import static com.tencent.supersonic.common.constant.Constants.DAY; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatDefaultRichConfig; -import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; -import com.tencent.supersonic.chat.domain.service.ConfigService; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.Order; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; - -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Objects; -import java.util.Set; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeanUtils; -import org.springframework.stereotype.Component; - - -@Slf4j -@Component -public class EntityListFilter extends EntitySemanticQuery { - - public static String QUERY_MODE = "ENTITY_LIST_FILTER"; - private static Long entityListLimit = 200L; - - - public EntityListFilter() { - super(); - queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 1) - .addOption(ENTITY, REQUIRED, AT_LEAST, 1); - } - - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); - parseInfo.setLimit(entityListLimit); - this.fillDateEntityFilter(parseInfo); - this.addEntityDetailAndOrderByMetric(parseInfo); - this.dealNativeQuery(parseInfo, true); - } - - - private void fillDateEntityFilter(SemanticParseInfo semanticParseInfo) { - DateConf dateInfo = new DateConf(); - dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); - dateInfo.setUnit(1); - dateInfo.setPeriod(DAY); - dateInfo.setText(String.format("近1天")); - semanticParseInfo.setDateInfo(dateInfo); - } - - private void addEntityDetailAndOrderByMetric(SemanticParseInfo semanticParseInfo) { - if (semanticParseInfo.getDomainId() > 0L) { - ConfigService configService = ContextUtils.getBean(ConfigService.class); - ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo( - semanticParseInfo.getDomainId()); - if (chaConfigRichDesc != null && chaConfigRichDesc.getChatDetailRichConfig() != null - && chaConfigRichDesc.getChatDetailRichConfig().getEntity() != null) { -// SemanticParseInfo semanticParseInfo = queryContext.getParseInfo(); -// EntityRichInfo entity = chaConfigRichDesc.getChatDetailRichConfig().getEntity(); - Set dimensions = new LinkedHashSet(); -// Set primaryDimensions = this.addPrimaryDimension(entity, dimensions); - Set metrics = new LinkedHashSet(); - Set orders = new LinkedHashSet(); - ChatDefaultRichConfig chatDefaultConfig = chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig(); - if (chatDefaultConfig != null) { - chatDefaultConfig.getMetrics().stream() - .forEach(metric -> { - metrics.add(metric); - orders.add(new Order(metric.getBizName(), Constants.DESC_UPPER)); - }); - chatDefaultConfig.getDimensions().stream() -// .filter((m) -> !primaryDimensions.contains(m.getBizName())) - .forEach(dimension -> dimensions.add(dimension)); - - } - - semanticParseInfo.setDimensions(dimensions); - semanticParseInfo.setMetrics(metrics); - semanticParseInfo.setOrders(orders); - } - } - - } - - private Set addPrimaryDimension(EntityRichInfo entity, Set dimensions) { - Set primaryDimensions = new HashSet(); - DimSchemaResp dimItem = entity.getDimItem(); - if (Objects.nonNull(entity) && Objects.nonNull(dimItem)) { - SchemaItem dimension = new SchemaItem(); - BeanUtils.copyProperties(dimItem, dimension); - dimensions.add(dimension); - primaryDimensions.add(dimItem.getBizName()); - return primaryDimensions; - } else { - return primaryDimensions; - } - } - - private void dealNativeQuery(SemanticParseInfo semanticParseInfo, boolean isNativeQuery) { - if (Objects.nonNull(semanticParseInfo)) { - semanticParseInfo.setNativeQuery(isNativeQuery); - } - - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListTopN.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListTopN.java deleted file mode 100644 index aba98b7a5..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListTopN.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Component; - -@Component -public class EntityListTopN extends EntitySemanticQuery { - - public static String QUERY_MODE = "ENTITY_LIST_TOPN"; - - public EntityListTopN() { - super(); - queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1) - .setSupportOrderBy(true); - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); - ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityMetricFilter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityMetricFilter.java deleted file mode 100644 index 4139f83ea..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityMetricFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.METRIC; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Component; - -@Component -public class EntityMetricFilter extends EntitySemanticQuery { - - public static String QUERY_MODE = "ENTITY_METRIC_FILTER"; - - public EntityMetricFilter() { - super(); - queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1) - .addOption(VALUE, REQUIRED, AT_LEAST, 1); - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntitySemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntitySemanticQuery.java deleted file mode 100644 index 416af0244..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntitySemanticQuery.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; - -public abstract class EntitySemanticQuery extends RuleSemanticQuery { - - public EntitySemanticQuery() { - super(); - queryMatcher.addOption(ENTITY, REQUIRED, AT_LEAST, 1); - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/LLMSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/LLMSemanticQuery.java deleted file mode 100644 index d7a7fbbdc..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/LLMSemanticQuery.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.EntityInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.application.DomainEntityService; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -@Slf4j -public class LLMSemanticQuery implements SemanticQuery { - - public static String QUERY_MODE = "DSL"; - - private SemanticParseInfo semanticParse = new SemanticParseInfo(); - private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public QueryResultResp execute(User user) { - String queryMode = semanticParse.getQueryMode(); - - if (semanticParse.getDomainId() < 0 || StringUtils.isEmpty(queryMode)) { - // reach here some error may happen - log.error("not find QueryMode"); - throw new RuntimeException("not find QueryMode"); - } - QueryResultResp queryResponse = new QueryResultResp(); - QueryResultWithSchemaResp queryResult = semanticLayer.queryBySql( - SchemaInfoConverter.convertToQuerySqlReq(semanticParse), user); - - if (queryResult != null) { - queryResponse.setQueryAuthorization(queryResult.getQueryAuthorization()); - } - String sql = queryResult == null ? null : queryResult.getSql(); - List> resultList = queryResult == null ? new ArrayList<>() - : queryResult.getResultList(); - List columns = queryResult == null ? new ArrayList<>() : queryResult.getColumns(); - queryResponse.setQuerySql(sql); - queryResponse.setQueryResults(resultList); - queryResponse.setQueryColumns(columns); - queryResponse.setQueryMode(queryMode); - - // add domain info - EntityInfo entityInfo = ContextUtils.getBean(DomainEntityService.class) - .getEntityInfo(semanticParse, user); - queryResponse.setEntityInfo(entityInfo); - return queryResponse; - } - - @Override - public SemanticParseInfo getParseInfo() { - return semanticParse; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricCompare.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricCompare.java deleted file mode 100644 index 927b4e2c9..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricCompare.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_MOST; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.OPTIONAL; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -public class MetricCompare extends MetricSemanticQuery { - - public static String QUERY_MODE = "METRIC_COMPARE"; - public static Pattern intentWordPattern = Pattern.compile("(?i)(比较|对比)"); - - public MetricCompare() { - super(); - queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 2) - .addOption(ENTITY, OPTIONAL, AT_MOST, 1); - - queryMatcher.setSupportCompare(true); - queryMatcher.setSupportOrderBy(true); - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public List match(List candidateElementMatches, QueryContextReq queryCtx) { - if (intentWordPattern.matcher(queryCtx.getQueryText()).find()) { - return super.match(candidateElementMatches, queryCtx); - } else { - return new ArrayList<>(); - } - } - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); - ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); - mergeAppend(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); - addCompareDimension(parseInfo); - parseInfo.setBonus(2 * 1.0); - } - - private void addCompareDimension(SemanticParseInfo semanticParseInfo) { - if (!semanticParseInfo.getDimensionFilters().isEmpty()) { - Set dimensions = semanticParseInfo.getDimensions().stream().map(d -> d.getBizName()).collect( - Collectors.toSet()); - log.info("addCompareDimension before [{}]", dimensions); - semanticParseInfo.getDimensionFilters().stream().filter(d -> d.getOperator().equals(FilterOperatorEnum.IN)) - .forEach( - d -> { - if (!dimensions.contains(d.getBizName())) { - SchemaItem schemaItem = new SchemaItem(); - schemaItem.setBizName(d.getBizName()); - schemaItem.setId(d.getElementID()); - semanticParseInfo.getDimensions().add(schemaItem); - dimensions.add(d.getBizName()); - } - } - ); - log.info("addCompareDimension after [{}]", dimensions); - } - } - - private void mergeAppend(Set from, Set to) { - if (!from.isEmpty()) { - for (Filter filter : from) { - if (FilterOperatorEnum.EQUALS.equals(filter.getOperator()) || FilterOperatorEnum.IN.equals( - filter.getOperator())) { - Optional toAdd = to.stream() - .filter(t -> t.getBizName().equalsIgnoreCase(filter.getBizName())).findFirst(); - if (toAdd.isPresent()) { - if (FilterOperatorEnum.EQUALS.equals(toAdd.get().getOperator()) || FilterOperatorEnum.IN.equals( - toAdd.get().getOperator())) { - Set vals = new HashSet<>(); - if (toAdd.get().getOperator().equals(FilterOperatorEnum.IN)) { - vals.addAll((List) (toAdd.get().getValue())); - } else { - vals.add(toAdd.get().getValue()); - } - if (filter.getOperator().equals(FilterOperatorEnum.IN)) { - vals.addAll((List) (filter.getValue())); - } else { - vals.add(filter.getValue()); - } - toAdd.get().setValue(new ArrayList<>(vals)); - toAdd.get().setOperator(FilterOperatorEnum.IN); - continue; - } - } - } - to.add(filter); - } - } - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricDomain.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricDomain.java deleted file mode 100644 index ed38701dc..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricDomain.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Component; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.*; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.*; - -@Component -public class MetricDomain extends MetricSemanticQuery { - - public static String QUERY_MODE = "METRIC_DOMAIN"; - - public MetricDomain() { - super(); - queryMatcher.addOption(DOMAIN, REQUIRED, AT_LEAST, 1); - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); - ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricFilter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricFilter.java deleted file mode 100644 index a1ccd7975..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Component; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.*; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.*; - -@Component -public class MetricFilter extends MetricSemanticQuery { - - public static String QUERY_MODE = "METRIC_FILTER"; - - public MetricFilter() { - super(); - queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 1) - .addOption(ENTITY, OPTIONAL, AT_MOST, 1); - - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); - ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); - ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricGroupBy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricGroupBy.java deleted file mode 100644 index b65909e64..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricGroupBy.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Component; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.*; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.*; - -@Component -public class MetricGroupBy extends MetricSemanticQuery { - - public static String QUERY_MODE = "METRIC_GROUPBY"; - - public MetricGroupBy() { - super(); - queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1); - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); - ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); - ContextHelper.addIfEmpty(chatParseInfo.getDimensions(), parseInfo.getDimensions()); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricOrderBy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricOrderBy.java deleted file mode 100644 index 9eb671d21..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricOrderBy.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Component; - -@Component -public class MetricOrderBy extends RuleSemanticQuery { - - public static String QUERY_MODE = "METRIC_ORDERBY"; - - public MetricOrderBy() { - super(); - } - - @Override - public String getQueryMode() { - return QUERY_MODE; - } - - @Override - public void inheritContext(ChatContext chatContext) { - SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); - ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); - ContextHelper.addIfEmpty(chatParseInfo.getDimensions(), parseInfo.getDimensions()); - ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricSemanticQuery.java deleted file mode 100644 index 95797c2d7..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricSemanticQuery.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.METRIC; -import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; -import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; - -public abstract class MetricSemanticQuery extends RuleSemanticQuery { - - public MetricSemanticQuery() { - super(); - queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1); - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQuery.java deleted file mode 100644 index 93888dd12..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQuery.java +++ /dev/null @@ -1,89 +0,0 @@ - -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.*; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.application.DomainEntityService; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import lombok.ToString; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; - -import java.io.Serializable; -import java.util.*; - -@Slf4j -@ToString -public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { - - protected SemanticParseInfo parseInfo = new SemanticParseInfo(); - protected QueryMatcher queryMatcher = new QueryMatcher(); - protected SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - - public RuleSemanticQuery() { - RuleSemanticQueryManager.register(this); - } - - public List match(List candidateElementMatches, - QueryContextReq queryCtx) { - return queryMatcher.match(candidateElementMatches); - } - - public abstract void inheritContext(ChatContext chatContext); - - @Override - public QueryResultResp execute(User user) { - String queryMode = parseInfo.getQueryMode(); - - if (parseInfo.getDomainId() < 0 || StringUtils.isEmpty(queryMode)) { - // reach here some error may happen - log.error("not find QueryMode"); - throw new RuntimeException("not find QueryMode"); - } - - List semanticQueryModes = RuleSemanticQueryManager.getSemanticQueryModes(); - if (!semanticQueryModes.contains(parseInfo.getQueryMode())) { - return null; - } - - QueryResultResp queryResponse = new QueryResultResp(); - QueryResultWithSchemaResp queryResult = semanticLayer.queryByStruct( - SchemaInfoConverter.convertTo(parseInfo), user); - - - if (queryResult != null) { - queryResponse.setQueryAuthorization(queryResult.getQueryAuthorization()); - } - String sql = queryResult == null ? null : queryResult.getSql(); - List> resultList = queryResult == null ? new ArrayList<>() - : queryResult.getResultList(); - List columns = queryResult == null ? new ArrayList<>() : queryResult.getColumns(); - queryResponse.setQuerySql(sql); - queryResponse.setQueryResults(resultList); - queryResponse.setQueryColumns(columns); - queryResponse.setQueryMode(queryMode); - - // add domain info - EntityInfo entityInfo = ContextUtils.getBean(DomainEntityService.class) - .getEntityInfo(parseInfo, user); - queryResponse.setEntityInfo(entityInfo); - return queryResponse; - } - - @Override - public SemanticParseInfo getParseInfo() { - return parseInfo; - } - - public void setParseInfo(SemanticParseInfo parseInfo) { - this.parseInfo = parseInfo; - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQueryManager.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQueryManager.java deleted file mode 100644 index 74c608dec..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQueryManager.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** - * RuleSemanticQueryManager - */ -public class RuleSemanticQueryManager { - - private static Map semanticQueryMap = new ConcurrentHashMap<>(); - - public static RuleSemanticQuery create(String queryMode) { - RuleSemanticQuery semanticQuery = semanticQueryMap.get(queryMode); - if (Objects.isNull(semanticQuery)) { - throw new RuntimeException("no supported queryMode :" + queryMode); - } - try { - return semanticQuery.getClass().getDeclaredConstructor().newInstance(); - } catch (Exception e) { - throw new RuntimeException("no supported queryMode :" + queryMode); - } - } - - public static void register(RuleSemanticQuery query) { - semanticQueryMap.put(query.getQueryMode(), query); - } - - public static List getSemanticQueries() { - return new ArrayList<>(semanticQueryMap.values()); - } - - public static List getSemanticQueryModes() { - return new ArrayList<>(semanticQueryMap.keySet()); - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatAggConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatAggConfig.java similarity index 87% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatAggConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatAggConfig.java index 329dc910f..32f3ba11c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatAggConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatAggConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatAggRichConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatAggRichConfig.java similarity index 88% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatAggRichConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatAggRichConfig.java index 66b91be47..fbe4b6f96 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatAggRichConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatAggRichConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfig.java similarity index 67% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfig.java index e26fb41f6..c41c08960 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfig.java @@ -1,11 +1,13 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.enums.StatusEnum; -import com.tencent.supersonic.common.util.RecordInfo; -import java.util.List; +import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestion; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; +import com.tencent.supersonic.common.pojo.RecordInfo; import lombok.Data; import lombok.ToString; +import java.util.List; + @Data @ToString public class ChatConfig { @@ -27,6 +29,8 @@ public class ChatConfig { */ private ChatAggConfig chatAggConfig; + private List recommendedQuestions; + /** * available status */ @@ -37,4 +41,4 @@ public class ChatConfig { */ private RecordInfo recordInfo; -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigBaseReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigBaseReq.java similarity index 61% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigBaseReq.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigBaseReq.java index 4f0b1b1e3..c172bf8b4 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigBaseReq.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigBaseReq.java @@ -1,12 +1,13 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.enums.StatusEnum; - -import java.util.List; +import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestion; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; import lombok.Data; import lombok.ToString; +import java.util.List; + /** * extended information command about domain */ @@ -26,9 +27,15 @@ public class ChatConfigBaseReq { */ private ChatAggConfig chatAggConfig; + + /** + * the recommended questions about the domain + */ + private List recommendedQuestions; + /** * available status */ private StatusEnum status; -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigEditReqReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigEditReqReq.java similarity index 67% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigEditReqReq.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigEditReqReq.java index 6557385c4..441e8f59d 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigEditReqReq.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigEditReqReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigFilter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigFilter.java similarity index 65% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigFilter.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigFilter.java index 252e3dc62..721bd4ce0 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigFilter.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigFilter.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.enums.StatusEnum; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigFilterInternal.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigFilterInternal.java similarity index 72% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigFilterInternal.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigFilterInternal.java index c7ce5ed30..d6c634ca5 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigFilterInternal.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigFilterInternal.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigResp.java similarity index 61% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigResp.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigResp.java index acd1c40a5..6c7ecba88 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigResp.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigResp.java @@ -1,7 +1,11 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; + +import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestion; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; -import com.tencent.supersonic.common.enums.StatusEnum; import java.util.Date; +import java.util.List; + import lombok.Data; @Data @@ -15,6 +19,8 @@ public class ChatConfigResp { private ChatAggConfig chatAggConfig; + private List recommendedQuestions; + /** * available status */ diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigRichResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigRich.java similarity index 64% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigRichResp.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigRich.java index 84f271e23..f2913012b 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatConfigRichResp.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatConfigRich.java @@ -1,12 +1,14 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.enums.StatusEnum; +import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestion; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; import java.util.Date; import java.util.List; + import lombok.Data; @Data -public class ChatConfigRichResp { +public class ChatConfigRich { private Long id; @@ -19,6 +21,8 @@ public class ChatConfigRichResp { private ChatDetailRichConfig chatDetailRichConfig; + private List recommendedQuestions; + /** * available status */ @@ -28,4 +32,4 @@ public class ChatConfigRichResp { private String updatedBy; private Date createdAt; private Date updatedAt; -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDefaultConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDefaultConfig.java similarity index 78% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDefaultConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDefaultConfig.java index f25601e3a..c69eeade3 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDefaultConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDefaultConfig.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import lombok.Data; import java.util.ArrayList; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDefaultRichConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDefaultRichConfig.java similarity index 54% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDefaultRichConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDefaultRichConfig.java index 079ab0c92..5b63e9ee7 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDefaultRichConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDefaultRichConfig.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.common.pojo.Constants; import lombok.Data; import java.util.List; @@ -10,8 +10,9 @@ import java.util.List; @Data public class ChatDefaultRichConfig { - private List dimensions; - private List metrics; + private List dimensions; + private List metrics; + /** * default time span unit diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDetailConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDetailConfig.java similarity index 89% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDetailConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDetailConfig.java index a85a1f85d..42b6f7d98 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDetailConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDetailConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDetailRichConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDetailRichConfig.java similarity index 90% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDetailRichConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDetailRichConfig.java index 35263cdd1..e7f372baf 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ChatDetailRichConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ChatDetailRichConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/DefaultMetric.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/DefaultMetric.java similarity index 93% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/DefaultMetric.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/DefaultMetric.java index 753087740..e00e36fe5 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/DefaultMetric.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/DefaultMetric.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/DefaultMetricInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/DefaultMetricInfo.java similarity index 78% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/DefaultMetricInfo.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/DefaultMetricInfo.java index 4ba686464..227f3f679 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/DefaultMetricInfo.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/DefaultMetricInfo.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import lombok.Data; import lombok.ToString; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/Dim4Dict.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/Dim4Dict.java similarity index 87% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/Dim4Dict.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/Dim4Dict.java index de36c3994..48f364070 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/Dim4Dict.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/Dim4Dict.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import java.util.List; import lombok.AllArgsConstructor; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/Entity.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/Entity.java similarity index 88% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/Entity.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/Entity.java index d5ca4508a..26a1d415c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/Entity.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/Entity.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import java.util.List; import lombok.AllArgsConstructor; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityDetailData.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityDetailData.java similarity index 80% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityDetailData.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityDetailData.java index 4e8ef93b6..f76cfcb97 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityDetailData.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityDetailData.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import java.util.List; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityInternalDetail.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityInternalDetail.java new file mode 100644 index 000000000..0c2935a36 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityInternalDetail.java @@ -0,0 +1,14 @@ +package com.tencent.supersonic.chat.config; + + +import com.tencent.supersonic.semantic.api.model.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; +import java.util.List; +import lombok.Data; + +@Data +public class EntityInternalDetail { + + List dimensionList; + List metricList; +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityRichInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityRichInfo.java new file mode 100644 index 000000000..023b6e770 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/EntityRichInfo.java @@ -0,0 +1,16 @@ +package com.tencent.supersonic.chat.config; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; + +import java.util.List; +import lombok.Data; + +@Data +public class EntityRichInfo { + /** + * entity alias + */ + private List names; + + private SchemaElement dimItem; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/config/FunctionCallConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/FunctionCallConfig.java new file mode 100644 index 000000000..1fd4a4083 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/FunctionCallConfig.java @@ -0,0 +1,12 @@ +package com.tencent.supersonic.chat.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Data +public class FunctionCallConfig { + @Value("${functionCall.url:}") + private String url; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ItemVisibility.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ItemVisibility.java similarity index 86% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ItemVisibility.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ItemVisibility.java index b6bd242a6..e554e92ed 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ItemVisibility.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ItemVisibility.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import java.util.ArrayList; import java.util.List; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ItemVisibilityInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ItemVisibilityInfo.java similarity index 81% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ItemVisibilityInfo.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/ItemVisibilityInfo.java index a4364a0d9..7a66b15df 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/ItemVisibilityInfo.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/ItemVisibilityInfo.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import java.util.List; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeAdvancedConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/KnowledgeAdvancedConfig.java similarity index 85% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeAdvancedConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/KnowledgeAdvancedConfig.java index 931ed7de3..8ba0dabf1 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeAdvancedConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/KnowledgeAdvancedConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/KnowledgeInfo.java similarity index 82% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeInfo.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/KnowledgeInfo.java index 9481228d5..7a0686ed0 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeInfo.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/KnowledgeInfo.java @@ -1,8 +1,7 @@ -package com.tencent.supersonic.chat.domain.pojo.config; +package com.tencent.supersonic.chat.config; -import com.tencent.supersonic.common.enums.TypeEnums; +import com.tencent.supersonic.common.pojo.enums.TypeEnums; -import java.util.List; import javax.validation.constraints.NotNull; import lombok.Data; @@ -35,4 +34,4 @@ public class KnowledgeInfo { private KnowledgeAdvancedConfig knowledgeAdvancedConfig; -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/config/LLMConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/LLMConfig.java similarity index 86% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/config/LLMConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/config/LLMConfig.java index fc22c872d..c73743545 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/config/LLMConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/LLMConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.config; +package com.tencent.supersonic.chat.config; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/DomainInfos.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/DomainInfos.java deleted file mode 100644 index d6936d1c5..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/DomainInfos.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; - -import com.tencent.supersonic.common.nlp.ItemDO; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import lombok.Data; -import org.apache.commons.collections.CollectionUtils; - -/** - * DomainInfos - */ -@Data -public class DomainInfos implements Serializable { - - private List domains = new ArrayList<>(); - private List dimensions = new ArrayList<>(); - private List metrics = new ArrayList<>(); - private List entities = new ArrayList<>(); - - public Map getDomainToName() { - if (CollectionUtils.isEmpty(domains)) { - return new HashMap(); - } - return domains.stream().collect( - Collectors.toMap(ItemDO::getDomain, ItemDO::getName, (value1, value2) -> value2) - ); - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMReq.java deleted file mode 100644 index a656d69c9..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMReq.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; - -import lombok.Data; - -@Data -public class LLMReq { - - private String queryText; - private LLMSchema schema; - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMSchema.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMSchema.java deleted file mode 100644 index a94141bcc..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMSchema.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; - -import java.util.List; -import lombok.Data; - -@Data -public class LLMSchema { - - private String domainName; - - private List fieldNameList; - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/QueryData.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/QueryData.java deleted file mode 100644 index 792e1bde9..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/QueryData.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; - - -import com.tencent.supersonic.chat.api.pojo.Filter; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.Order; -import com.tencent.supersonic.common.pojo.SchemaItem; -import lombok.Data; - -@Data -public class QueryData { - - Long domainId = 0L; - Set metrics = new HashSet<>(); - Set dimensions = new HashSet<>(); - Set dimensionFilters = new HashSet<>(); - Set metricFilters = new HashSet<>(); - private Set orders = new HashSet<>(); - private DateConf dateInfo; - private Long limit; - private Boolean nativeQuery = false; - - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/RecommendResponse.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/RecommendResponse.java deleted file mode 100644 index 37365692e..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/RecommendResponse.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; - -import java.io.Serializable; -import java.util.List; -import lombok.Data; -import lombok.Getter; -import lombok.Setter; - -@Data -@Setter -@Getter -public class RecommendResponse { - - private List dimensions; - private List metrics; - - - public static class Item implements Serializable { - - private Integer domain; - private String name; - private String bizName; - - public Integer getDomain() { - return domain; - } - - public void setDomain(Integer domain) { - this.domain = domain; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getBizName() { - return bizName; - } - - public void setBizName(String bizName) { - this.bizName = bizName; - } - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/SchemaElementOption.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/SchemaElementOption.java deleted file mode 100644 index 9f1e39b8b..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/SchemaElementOption.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; - -public enum SchemaElementOption { - REQUIRED, - OPTIONAL, - UNUSED -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityInternalDetail.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityInternalDetail.java deleted file mode 100644 index 3926703a7..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityInternalDetail.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.config; - - -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import java.util.List; -import lombok.Data; - -@Data -public class EntityInternalDetail { - - List dimensionList; - List metricList; -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityRichInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityRichInfo.java deleted file mode 100644 index 4cbf8cc60..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/EntityRichInfo.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.config; - -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import java.util.List; -import lombok.Data; - -@Data -public class EntityRichInfo { - -// private Long domainId; -// private String domainName; -// private String domainBizName; - - /** - * entity alias - */ - private List names; - - private DimSchemaResp dimItem; -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/NameNature.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/NameNature.java deleted file mode 100644 index fe45d8060..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/NameNature.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.search; - -import java.io.Serializable; -import java.util.List; -import lombok.Data; -import lombok.ToString; - -@Data -@ToString -public class NameNature implements Serializable { - - private String name; - private List natures; - - public NameNature() { - } - - public NameNature(String name, List natures) { - this.name = name; - this.natures = natures; - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/QueryState.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/QueryState.java deleted file mode 100644 index 257c10416..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/QueryState.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.tencent.supersonic.chat.domain.pojo.search; - -public enum QueryState { - NORMAL(0), - SEARCH_EXCEPTION(1), - EMPTY(2), - INVALID(3); - - private int state; - - QueryState(int state) { - this.state = state; - } - - public int getState() { - return state; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatQueryRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatQueryRepository.java deleted file mode 100644 index cb5b9b4b3..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatQueryRepository.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.tencent.supersonic.chat.domain.repository; - -import com.github.pagehelper.PageInfo; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDO; -import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO; -import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq; - -public interface ChatQueryRepository { - - PageInfo getChatQuery(PageQueryInfoReq pageQueryInfoCommend, long chatId); - - void createChatQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx); - - ChatQueryDO getLastChatQuery(long chatId); - - int updateChatQuery(ChatQueryDO chatQueryDO); -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ConfigService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ConfigService.java deleted file mode 100644 index 1b1a14c66..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ConfigService.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.tencent.supersonic.chat.domain.service; - - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigBaseReq; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigEditReqReq; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilter; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichResp; - -import java.util.List; - -public interface ConfigService { - - Long addConfig(ChatConfigBaseReq extendBaseCmd, User user); - - Long editConfig(ChatConfigEditReqReq extendEditCmd, User user); - - List search(ChatConfigFilter filter, User user); - - ChatConfigRichResp getConfigRichInfo(Long domainId); - - ChatConfigResp fetchConfigByDomainId(Long domainId); - - List getAllChatRichConfig(); -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/QueryService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/QueryService.java deleted file mode 100644 index f80be7fb7..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/QueryService.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.tencent.supersonic.chat.domain.service; - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.domain.pojo.chat.QueryData; - -/*** - * QueryService for query and search - */ -public interface QueryService { - - QueryResultResp executeQuery(QueryContextReq queryCtx) throws Exception; - - SemanticParseInfo queryContext(QueryContextReq queryCtx); - - QueryResultResp executeDirectQuery(QueryData queryData, User user) throws Exception; -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/RecommendService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/RecommendService.java deleted file mode 100644 index 245f82c0a..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/RecommendService.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tencent.supersonic.chat.domain.service; - - -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.RecommendResponse; - -/*** - * Recommend Service - */ -public interface RecommendService { - - RecommendResponse recommend(QueryContextReq queryCtx); - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/SearchService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/SearchService.java deleted file mode 100644 index d99f276ed..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/SearchService.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tencent.supersonic.chat.domain.service; - -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.search.SearchResult; -import java.util.List; - -/** - * search service - */ -public interface SearchService { - - List search(QueryContextReq queryCtx); - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ContextHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ContextHelper.java deleted file mode 100644 index bc5190667..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ContextHelper.java +++ /dev/null @@ -1,263 +0,0 @@ -package com.tencent.supersonic.chat.domain.utils; - -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.pojo.QueryMatchInfo; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichResp; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import org.apache.commons.lang3.StringUtils; -import org.springframework.util.CollectionUtils; - -public class ContextHelper { - - public static Comparator> DomainStatComparator - = (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue()); - public static Comparator> SemanticQueryStatComparator - = (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue()); - /** - * similarity desc - */ - public static Comparator schemaElementMatchComparatorBySimilarity - = new Comparator() { - @Override - public int compare(SchemaElementMatch o1, SchemaElementMatch o2) { - return (int) ((o2.getSimilarity() - o1.getSimilarity()) * 100); - } - }; - - public static void updateDomain(SemanticParseInfo from, SemanticParseInfo to) { - if (from != null && from.getDomainId() != null) { - to.setDomainId(from.getDomainId()); - } - if (from != null && from.getDomainName() != null) { - to.setDomainName(from.getDomainName()); - } - } - - public static void updateEntity(SemanticParseInfo from, SemanticParseInfo to) { - if (from != null && from.getEntity() != null && from.getEntity() > 0) { - to.setEntity(from.getEntity()); - } - } - - public static void updateSemanticQuery(SemanticParseInfo from, SemanticParseInfo to) { - to.setQueryMode(from.getQueryMode()); - } - - /** - * update time if from is not null - * - * @param from - * @param to - */ - public static void updateTime(SemanticParseInfo from, SemanticParseInfo to) { - if (from != null && from.getDateInfo() != null) { - to.setDateInfo(from.getDateInfo()); - } - } - - /** - * update time if time is null and from is not null - * - * @param from - * @param to - */ - public static void updateTimeIfEmpty(SemanticParseInfo from, SemanticParseInfo to) { - if (from != null && from.getDateInfo() != null && to.getDateInfo() == null) { - to.setDateInfo(from.getDateInfo()); - } - } - - public static void updateDomainIfEmpty(SemanticParseInfo from, SemanticParseInfo to) { - if (from != null && from.getDomainId() != null && to.getDomainId() == null) { - to.setDomainId(from.getDomainId()); - } - - if (from != null && from.getDomainName() != null && to.getDomainName() == null) { - to.setDomainName(from.getDomainName()); - } - } - - /** - * add from to list if list is empty and from is not empty - * - * @param from - * @param to - */ - public static void addIfEmpty(Set from, Set to) { - if (to.isEmpty() && !from.isEmpty()) { - to.addAll(from); - } - } - - /*** - * append from to list if from is not empty - * @param from - * @param to - */ - public static void appendList(Set from, Set to) { - if (!from.isEmpty()) { - to.addAll(from); - } - } - - /** - * update list if from is not empty - * - * @param from - * @param to - */ - public static void updateList(Set from, Set to) { - if (!from.isEmpty()) { - to.clear(); - to.addAll(from); - } - } - - /** - * count desc > similarity desc - */ - public static int domainSchemaElementCountComparator(QueryMatchInfo o1, QueryMatchInfo o2) { - int difference = o1.getCount() - o2.getCount(); - if (difference == 0) { - return (int) ((o1.getMaxSimilarity() - o2.getMaxSimilarity()) * 100); - } - return difference; - } - - public static void setEntityId(Long dimensionId, String value, ChatConfigRichResp chaConfigRichDesc, - SemanticParseInfo semanticParseInfo) { - if (chaConfigRichDesc != null && chaConfigRichDesc.getChatDetailRichConfig() != null - && chaConfigRichDesc.getChatDetailRichConfig().getEntity() != null) { - DimSchemaResp dimSchemaResp = chaConfigRichDesc.getChatDetailRichConfig().getEntity().getDimItem(); - if (Objects.nonNull(dimSchemaResp) && StringUtils.isNumeric(value)) { - semanticParseInfo.setEntity(Long.valueOf(value)); - } - } - } - - - public static boolean hasEntityId(ChatContext chatCtx) { - if (chatCtx != null && chatCtx.getParseInfo() != null) { - return chatCtx.getParseInfo().getEntity() > 0; - } - return false; - } - - /*** - * merge Context SchemaElementMatch - * @param toSchemaElementMatch - * @param elementMatches - * @param schemaElementTypes - * @param contextSemanticParse - */ - public static void mergeContextSchemaElementMatch(List toSchemaElementMatch, - List elementMatches, List schemaElementTypes, - SemanticParseInfo contextSemanticParse) { - - SchemaElementMatch domainMatch = SchemaElementMatch.builder() - .elementType(SchemaElementType.DOMAIN) - .elementID(contextSemanticParse.getDomainId().intValue()) - .similarity(1.0) - .word(contextSemanticParse.getDomainName()) - .detectWord(contextSemanticParse.getDomainName()) - .build(); - toSchemaElementMatch.add(domainMatch); - - for (SchemaElementType schemaElementType : schemaElementTypes) { - switch (schemaElementType) { - case DIMENSION: - if (contextSemanticParse.getDimensions().size() > 0) { - for (SchemaItem dimension : contextSemanticParse.getDimensions()) { - addSchemaElementMatch(toSchemaElementMatch, elementMatches, SchemaElementType.DIMENSION, - dimension); - } - } - break; - case METRIC: - if (contextSemanticParse.getMetrics().size() > 0) { - for (SchemaItem metric : contextSemanticParse.getMetrics()) { - addSchemaElementMatch(toSchemaElementMatch, elementMatches, SchemaElementType.METRIC, - metric); - } - } - break; - case VALUE: - if (contextSemanticParse.getDimensionFilters().size() > 0) { - for (Filter chatFilter : contextSemanticParse.getDimensionFilters()) { - if (!isInSchemaElementMatchList(elementMatches, SchemaElementType.VALUE, - chatFilter.getValue().toString())) { - List values = new ArrayList<>(); - if (chatFilter.getOperator().equals(FilterOperatorEnum.IN)) { - values.addAll((List) chatFilter.getValue()); - } else { - values.add(chatFilter.getValue().toString()); - } - for (String value : values) { - toSchemaElementMatch.add( - getSchemaElementMatchByContext(chatFilter.getElementID().intValue(), - value, SchemaElementType.VALUE)); - } - } - } - } - break; - default: - } - } - } - - /** - * is that SchemaElementType and word in SchemaElementMatch list - * - * @param elementMatches - * @param schemaElementType - * @param word - * @return - */ - private static boolean isInSchemaElementMatchList(List elementMatches, - SchemaElementType schemaElementType, String word) { - if (CollectionUtils.isEmpty(elementMatches)) { - return false; - } - Long num = elementMatches.stream() - .filter(element -> element != null && element.getElementType().equals(schemaElementType)).count(); - return num > 0; - } - - private static void addSchemaElementMatch(List toAddSchemaElementMatch, - List elementMatches, SchemaElementType schemaElementType, SchemaItem schemaItem) { - if (Objects.isNull(schemaItem) || Objects.isNull(schemaItem.getId()) || Objects.isNull(schemaItem.getName())) { - return; - } - if (!isInSchemaElementMatchList(elementMatches, schemaElementType, schemaItem.getName())) { - toAddSchemaElementMatch.add( - getSchemaElementMatchByContext(schemaItem.getId().intValue(), schemaItem.getName(), - schemaElementType)); - } - } - - private static SchemaElementMatch getSchemaElementMatchByContext(int id, String word, - SchemaElementType schemaElementType) { - return SchemaElementMatch.builder() - .elementID(id) - .elementType(schemaElementType) - .word(word) - .detectWord(word) - .similarity(0.5) - .build(); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultMetricUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultMetricUtils.java deleted file mode 100644 index 7146d95fe..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultMetricUtils.java +++ /dev/null @@ -1,439 +0,0 @@ -package com.tencent.supersonic.chat.domain.utils; - -import static java.time.LocalDate.now; - -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.*; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.ConfigServiceImpl; -import com.tencent.supersonic.chat.application.parser.DomainResolver; -import com.tencent.supersonic.chat.application.query.*; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatDefaultRichConfig; -import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; - -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -@Slf4j -@Component -public class DefaultMetricUtils { - - @Autowired - private ConfigServiceImpl configService; - - /** - * supplementary default metric date dimension - */ - public void fillDefaultMetric(SemanticParseInfo semanticParseInfo, QueryContextReq queryContext, - ChatContext chatContext) { - String queryMode = semanticParseInfo.getQueryMode(); - if (StringUtils.isNotEmpty(queryMode)) { - Map semanticQuery = RuleSemanticQueryManager.getSemanticQueries().stream().collect(Collectors.toMap(RuleSemanticQuery::getQueryMode, Function.identity())); - RuleSemanticQuery ruleSemanticQuery = semanticQuery.get(queryMode); - if (semanticParseInfo == null) { - return; - } -// if (!EntityListFilter.QUERY_MODE.equals(queryMode)) { - boolean isFillAggDefaultMetricLogic = false; - boolean isFillDetailDimensionMetric = false; - Integer domainId = queryContext.getDomainId().intValue(); - ChatDefaultRichConfig chatDefaultConfig = null; - Boolean isDetailMode = false; - List matchedElements = queryContext.getMapInfo().getMatchedElements(domainId); - ChatConfigRichResp chaConfigRichDesc = getChatConfigRichInfo(semanticParseInfo.getDomainId()); - if (Objects.isNull(chaConfigRichDesc)) { - return; - } - if (ruleSemanticQuery instanceof MetricSemanticQuery) { - if (!CollectionUtils.isEmpty(matchedElements)) { - long metricCount = matchedElements.stream() - .filter(schemaElementMatch -> schemaElementMatch.getElementType() - .equals(SchemaElementType.METRIC)).count(); - - if (metricCount <= 0) { - if (chatContext.getParseInfo() == null - || chatContext.getParseInfo().getMetrics() == null - || chatContext.getParseInfo().getMetrics().size() <= 0) { - - log.info("isFillAggDefaultMetricLogic is true"); - isFillAggDefaultMetricLogic = true; - - } - } - } - if (Objects.nonNull(chaConfigRichDesc.getChatAggRichConfig())) { - chatDefaultConfig = chaConfigRichDesc.getChatAggRichConfig().getChatDefaultConfig(); - } - - } else if (ruleSemanticQuery instanceof EntitySemanticQuery) { - log.info("fillThemeDefaultMetricLogic for empty matchedElements "); - isFillDetailDimensionMetric = true; - dealNativeQuery(semanticParseInfo, queryContext, true); - isDetailMode = true; - if (Objects.nonNull(chaConfigRichDesc.getChatDetailRichConfig())) { - chatDefaultConfig = chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig(); - } - } - - - if (isFillAggDefaultMetricLogic) { - fillDefaultMetricAggLogic(semanticParseInfo, chaConfigRichDesc, queryContext); - } - - if (isFillDetailDimensionMetric) { - addEntityDetailDimensionMetric(semanticParseInfo, chaConfigRichDesc, queryContext, chatContext); - } - - fillDateDomain(semanticParseInfo, chatContext, chaConfigRichDesc, chatDefaultConfig, isDetailMode); -// } - defaultQueryMode(semanticParseInfo, queryContext, chatContext); - addEntityTopDimension(semanticParseInfo, chaConfigRichDesc); - } - } - - public void dealNativeQuery(SemanticParseInfo semanticParseInfo, QueryContextReq queryContext, - boolean isNativeQuery) { - if (Objects.nonNull(queryContext) && Objects.nonNull(semanticParseInfo)) { - semanticParseInfo.setNativeQuery(isNativeQuery); - } - } - - public Set addPrimaryDimension(EntityRichInfo entity, List dimensions) { - Set primaryDimensions = new HashSet<>(); - if (Objects.isNull(entity) || Objects.isNull(entity.getDimItem())) { - return primaryDimensions; - } - DimSchemaResp dimItem = entity.getDimItem(); - SchemaItem dimension = new SchemaItem(); - BeanUtils.copyProperties(dimItem, dimension); - dimensions.add(dimension); - primaryDimensions.add(dimItem.getBizName()); - return primaryDimensions; - } - - public void addEntityTopDimension(SemanticParseInfo semanticParseInfo, ChatConfigRichResp chaConfigRichDesc) { - if (!semanticParseInfo.getQueryMode().equals(EntityListTopN.QUERY_MODE) || !semanticParseInfo.getDimensions() - .isEmpty()) { - return; - } - if (semanticParseInfo.getDomainId() > 0) { - Long domainId = semanticParseInfo.getDomainId(); - if (chaConfigRichDesc == null) { - chaConfigRichDesc = getChatConfigRichInfo(domainId); - } - if (chaConfigRichDesc != null && chaConfigRichDesc.getChatDetailRichConfig() != null - && chaConfigRichDesc.getChatDetailRichConfig().getEntity() != null) { - List dimensions = new ArrayList<>(); - addPrimaryDimension(chaConfigRichDesc.getChatDetailRichConfig().getEntity(), dimensions); - semanticParseInfo.setDimensions(new HashSet<>(dimensions)); - semanticParseInfo.setLimit(1L); - } - } - } - - public void addEntityDetailDimensionMetric(SemanticParseInfo semanticParseInfo, ChatConfigRichResp chaConfigRichDesc, QueryContextReq queryContext, - ChatContext chatCtx) { - if (semanticParseInfo.getDomainId() > 0) { - Long domainId = semanticParseInfo.getDomainId(); - - if (chaConfigRichDesc != null && chaConfigRichDesc.getChatDetailRichConfig() != null) { - if (chaConfigRichDesc.getChatDetailRichConfig().getEntity() == null - || chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig() == null) { - return; - } - - List schemaElementMatches = queryContext.getMapInfo() - .getMatchedElements(domainId.intValue()); - if (CollectionUtils.isEmpty(schemaElementMatches) - || schemaElementMatches.stream().filter(s -> SchemaElementType.DIMENSION.equals(s.getElementType())).count() <= 0) { - log.info("addEntityDetailDimensionMetric catch"); - if (CollectionUtils.isEmpty(semanticParseInfo.getDimensions())) { - Set dimensions = new LinkedHashSet(); - List dimensionsConfig = chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig().getDimensions(); - if (!CollectionUtils.isEmpty(dimensionsConfig)) { - dimensionsConfig.stream().forEach(m -> dimensions.add(m)); - } - semanticParseInfo.setDimensions(dimensions); - } - - if (CollectionUtils.isEmpty(semanticParseInfo.getMetrics())) { - Set metrics = new LinkedHashSet(); - List metricsConfig = chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig().getMetrics(); - if (!CollectionUtils.isEmpty(metricsConfig)) { - metricsConfig.stream().forEach(m -> metrics.add(m)); - } - semanticParseInfo.setMetrics(metrics); - } - } - } - } - } - - public void defaultQueryMode(SemanticParseInfo semanticParseInfo, QueryContextReq queryContext, - ChatContext chatCtx) { - SchemaMapInfo schemaMap = queryContext.getMapInfo(); - if (StringUtils.isEmpty(semanticParseInfo.getQueryMode())) { - if (chatCtx.getParseInfo() != null && chatCtx.getParseInfo().getDomainId() > 0) { - // - Long domain = chatCtx.getParseInfo().getDomainId(); - String queryMode = chatCtx.getParseInfo().getQueryMode(); - if (!CollectionUtils.isEmpty(schemaMap.getMatchedDomains()) && schemaMap.getMatchedDomains() - .contains(domain.intValue())) { - List elementMatches = schemaMap.getMatchedElements(domain.intValue()); - Long filterNUm = elementMatches.stream() - .filter(e -> e.getElementType().equals(SchemaElementType.VALUE) || e.getElementType() - .equals(SchemaElementType.ID)).count(); - Long dimensionNUm = elementMatches.stream() - .filter(e -> e.getElementType().equals(SchemaElementType.DIMENSION)).count(); - Long metricrNUm = elementMatches.stream() - .filter(e -> e.getElementType().equals(SchemaElementType.METRIC)).count(); - if (filterNUm > 0 && dimensionNUm > 0 && metricrNUm > 0) { - // default as entity detail queryMode - log.info("defaultQueryMode [{}]", EntityDetail.QUERY_MODE); - semanticParseInfo.setQueryMode(EntityDetail.QUERY_MODE); - semanticParseInfo.setDomainId(domain); - return; - } - Long entityNUm = elementMatches.stream() - .filter(e -> e.getElementType().equals(SchemaElementType.ENTITY)).count(); - if (filterNUm <= 0 && dimensionNUm <= 0 && entityNUm <= 0) { - // default as metric domain - if (metricrNUm > 0 || MetricDomain.QUERY_MODE.equals(queryMode)) { - // default as entity detail queryMode - log.info("defaultQueryMode [{}]", MetricDomain.QUERY_MODE); - semanticParseInfo.setQueryMode(MetricDomain.QUERY_MODE); - semanticParseInfo.setDomainId(domain); - return; - } - } - } - if (CollectionUtils.isEmpty(schemaMap.getMatchedDomains()) && semanticParseInfo != null - && semanticParseInfo.getDateInfo() != null) { - // only query time - if (MetricDomain.QUERY_MODE.equals(queryMode)) { - // METRIC_DOMAIN context - log.info("defaultQueryMode [{}]", MetricDomain.QUERY_MODE); - semanticParseInfo.setQueryMode(MetricDomain.QUERY_MODE); - semanticParseInfo.setDomainId(domain); - return; - } - } - } - } - } - - public void fillParseInfo(SemanticQuery query, Long domainId, String domainName) { - SemanticParseInfo parseInfo = query.getParseInfo(); - parseInfo.setDomainId(domainId); - parseInfo.setDomainName(domainName); - parseInfo.setQueryMode(query.getQueryMode()); - - - SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - - DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(parseInfo.getDomainId(), true); - ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(parseInfo.getDomainId()); - Map dimensionDescMap = domainSchemaDesc.getDimensions().stream() - .collect(Collectors.toMap(DimSchemaResp::getId, Function.identity())); - Map metricDescMap = domainSchemaDesc.getMetrics().stream() - .collect(Collectors.toMap(MetricSchemaResp::getId, Function.identity())); - Map> dim2Values = new HashMap<>(); - - List elementMatches = query.getParseInfo().getElementMatches(); - for (SchemaElementMatch schemaMatch : elementMatches) { - Long elementID = Long.valueOf(schemaMatch.getElementID()); - switch (schemaMatch.getElementType()) { - case ID: - case VALUE: - if (dimensionDescMap.containsKey(elementID)) { - if (dim2Values.containsKey(elementID)) { - dim2Values.get(elementID).add(schemaMatch); - } else { - dim2Values.put(elementID, new ArrayList<>(Arrays.asList(schemaMatch))); - } - } - break; - case DIMENSION: - DimSchemaResp dimensionDesc = dimensionDescMap.get(elementID); - if (dimensionDesc != null) { - SchemaItem dimensionParseInfo = new SchemaItem(); - dimensionParseInfo.setBizName(dimensionDesc.getBizName()); - dimensionParseInfo.setName(dimensionDesc.getName()); - dimensionParseInfo.setId(dimensionDesc.getId()); - parseInfo.getDimensions().add(dimensionParseInfo); - } - break; - case METRIC: - MetricSchemaResp metricDesc = metricDescMap.get(elementID); - if (metricDesc != null) { - SchemaItem metricItem = new SchemaItem(); - metricItem.setBizName(metricDesc.getBizName()); - metricItem.setName(metricDesc.getName()); - metricItem.setId(metricDesc.getId()); - metricItem.setCreatedAt(null); - metricItem.setUpdatedAt(null); - parseInfo.getMetrics().add(metricItem); - } - break; - default: - } - } - - if (!dim2Values.isEmpty()) { - for (Map.Entry> entry : dim2Values.entrySet()) { - DimSchemaResp dimensionDesc = dimensionDescMap.get(entry.getKey()); - if (entry.getValue().size() == 1) { - SchemaElementMatch schemaMatch = entry.getValue().get(0); - Filter dimensionFilter = new Filter(); - dimensionFilter.setValue(schemaMatch.getWord()); - dimensionFilter.setBizName(dimensionDesc.getBizName()); - dimensionFilter.setName(dimensionDesc.getName()); - dimensionFilter.setOperator(FilterOperatorEnum.EQUALS); - dimensionFilter.setElementID(Long.valueOf(schemaMatch.getElementID())); - parseInfo.getDimensionFilters().add(dimensionFilter); - ContextHelper.setEntityId(entry.getKey(), schemaMatch.getWord(), chaConfigRichDesc, - parseInfo); - } else { - Filter dimensionFilter = new Filter(); - List vals = new ArrayList<>(); - entry.getValue().stream().forEach(i -> vals.add(i.getWord())); - dimensionFilter.setValue(vals); - dimensionFilter.setBizName(dimensionDesc.getBizName()); - dimensionFilter.setName(dimensionDesc.getName()); - dimensionFilter.setOperator(FilterOperatorEnum.IN); - dimensionFilter.setElementID(entry.getKey()); - parseInfo.getDimensionFilters().add(dimensionFilter); - } - } - } - } - - public void fillDateDomain(SemanticParseInfo parseInfo, ChatContext chatCtx, ChatConfigRichResp chaConfigRichDesc, - ChatDefaultRichConfig chatDefaultConfig, Boolean isDetailMode) { - //SemanticParseInfo parseInfo = queryContext.getParseInfo(); - - if (parseInfo == null || parseInfo.getDateInfo() == null) { - DomainResolver selectStrategy = ComponentFactory.getDomainResolver(); - boolean isUpdateTime = false; - if (selectStrategy.isDomainSwitch(chatCtx, parseInfo)) { - isUpdateTime = true; - } - if (chatCtx.getParseInfo() == null - || chatCtx.getParseInfo().getDateInfo() == null) { - isUpdateTime = true; - } - if (isUpdateTime && parseInfo != null && parseInfo.getDomainId() > 0) { - - fillThemeDefaultTime(chaConfigRichDesc, parseInfo, chatDefaultConfig, isDetailMode); - } - } - } - - public void fillDefaultMetricAggLogic(SemanticParseInfo semanticParseInfo, ChatConfigRichResp chaConfigRichDesc, QueryContextReq queryContext) { - //SemanticParseInfo semanticParseInfo = queryContext.getParseInfo(); - - if (Objects.isNull(chaConfigRichDesc) || Objects.isNull(chaConfigRichDesc.getChatAggRichConfig()) - || Objects.isNull(chaConfigRichDesc.getChatAggRichConfig().getChatDefaultConfig()) - || CollectionUtils.isEmpty(chaConfigRichDesc.getChatAggRichConfig().getChatDefaultConfig().getMetrics())) { - log.info("there is no defaultMetricIds info"); - return; - } - - if (queryContext.getMapInfo() == null || !queryContext.getMapInfo().getMatchedDomains() - .contains(chaConfigRichDesc.getDomainId().intValue())) { - return; - } - List schemaElementMatches = queryContext.getMapInfo() - .getMatchedElements(chaConfigRichDesc.getDomainId().intValue()); - long metricNum = schemaElementMatches.stream().filter(e -> e.getElementType().equals(SchemaElementType.METRIC)) - .count(); - long dimensionNum = schemaElementMatches.stream() - .filter(e -> e.getElementType().equals(SchemaElementType.DIMENSION)).count(); - if (metricNum <= 0 && dimensionNum <= 0) { - Set metrics = new LinkedHashSet(); - chaConfigRichDesc.getChatAggRichConfig().getChatDefaultConfig().getMetrics().stream().forEach(metric -> { - SchemaItem metricTmp = new SchemaItem(); - metricTmp.setId(metric.getId()); - metricTmp.setBizName(metric.getBizName()); - metrics.add(metricTmp); - }); - semanticParseInfo.setMetrics(metrics); - } - - if (Objects.isNull(semanticParseInfo.getDateInfo()) || Objects.isNull( - semanticParseInfo.getDateInfo().getDateMode())) { - ChatDefaultRichConfig chatDefaultConfig = chaConfigRichDesc.getChatAggRichConfig().getChatDefaultConfig(); - DateConf dateInfo = new DateConf(); - dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); - dateInfo.setUnit(chatDefaultConfig.getUnit()); - dateInfo.setPeriod(chatDefaultConfig.getPeriod()); - semanticParseInfo.setDateInfo(dateInfo); - } - - } - - public void fillThemeDefaultTime(ChatConfigRichResp chaConfigRichDesc, SemanticParseInfo semanticParseInfo, ChatDefaultRichConfig chatDefaultConfig, Boolean isDetailMode) { - if (!Objects.isNull(semanticParseInfo.getDateInfo()) && !Objects.isNull( - semanticParseInfo.getDateInfo().getDateMode())) { - return; - } - if (chaConfigRichDesc == null) { - chaConfigRichDesc = getChatConfigRichInfo(semanticParseInfo.getDomainId()); - } - if (!Objects.isNull(chaConfigRichDesc) && Objects.nonNull(chatDefaultConfig) && !CollectionUtils.isEmpty(chatDefaultConfig.getMetrics())) { - DateConf dateInfo = new DateConf(); - if (isDetailMode) { - dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); - dateInfo.setUnit(1); - dateInfo.setPeriod(Constants.DAY); - } else { - dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); - dateInfo.setUnit(chatDefaultConfig.getUnit()); - dateInfo.setPeriod(chatDefaultConfig.getPeriod()); - } - - - semanticParseInfo.setDateInfo(dateInfo); - log.info("fillThemeDefaultTime"); - } - } - - public ChatConfigRichResp getChatConfigRichInfo(Long domain) { - ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(domain); - return chaConfigRichDesc; - } - - private SchemaItem getMetric(MetricSchemaResp metricSchemaDesc) { - SchemaItem queryMeta = new SchemaItem(); - queryMeta.setId(metricSchemaDesc.getId()); - queryMeta.setBizName(metricSchemaDesc.getBizName()); - queryMeta.setName(metricSchemaDesc.getName()); - return queryMeta; - } - - private SchemaItem getDimension(DimSchemaResp dimSchemaDesc) { - SchemaItem queryMeta = new SchemaItem(); - queryMeta.setId(dimSchemaDesc.getId()); - queryMeta.setBizName(dimSchemaDesc.getBizName()); - queryMeta.setName(dimSchemaDesc.getName()); - return queryMeta; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/NatureConverter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/NatureConverter.java deleted file mode 100644 index b71e0d01f..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/NatureConverter.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.tencent.supersonic.chat.domain.utils; - -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.common.nlp.NatureType; - -/*** - * nature type to schemaType converter - */ -public class NatureConverter { - - public static SchemaElementType convertTo(String nature) { - NatureType natureType = NatureType.getNatureType(nature); - SchemaElementType result = null; - switch (natureType) { - case METRIC: - result = SchemaElementType.METRIC; - break; - case DIMENSION: - result = SchemaElementType.DIMENSION; - break; - case ENTITY: - result = SchemaElementType.ENTITY; - break; - case DOMAIN: - result = SchemaElementType.DOMAIN; - break; - case VALUE: - result = SchemaElementType.VALUE; - break; - default: - break; - } - return result; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SchemaInfoConverter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SchemaInfoConverter.java deleted file mode 100644 index a6b013cbe..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SchemaInfoConverter.java +++ /dev/null @@ -1,227 +0,0 @@ -package com.tencent.supersonic.chat.domain.utils; - -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.application.query.MetricCompare; -import com.tencent.supersonic.chat.application.query.MetricDomain; -import com.tencent.supersonic.chat.application.query.MetricFilter; -import com.tencent.supersonic.chat.application.query.MetricGroupBy; -import com.tencent.supersonic.chat.application.query.MetricOrderBy; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.enums.AggOperatorEnum; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.pojo.Aggregator; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.Order; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.semantic.api.query.pojo.Filter; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; -import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.util.Strings; -import org.springframework.beans.BeanUtils; -import org.springframework.util.CollectionUtils; - -public class SchemaInfoConverter { - - /*** - * convert to queryStructReq - * @param parseInfo - * @return - */ - public static QueryStructReq convertTo(SemanticParseInfo parseInfo) { - QueryStructReq queryStructCmd = new QueryStructReq(); - queryStructCmd.setDomainId(parseInfo.getDomainId()); - queryStructCmd.setNativeQuery(parseInfo.getNativeQuery()); - queryStructCmd.setDateInfo(parseInfo.getDateInfo()); - - List dimensionFilters = parseInfo.getDimensionFilters().stream() - .filter(chatFilter -> Strings.isNotEmpty(chatFilter.getBizName())) - .map(chatFilter -> new Filter(chatFilter.getBizName(), chatFilter.getOperator(), chatFilter.getValue())) - .collect(Collectors.toList()); - queryStructCmd.setDimensionFilters(dimensionFilters); - - List metricFilters = parseInfo.getMetricFilters().stream() - .map(chatFilter -> new Filter(chatFilter.getBizName(), chatFilter.getOperator(), chatFilter.getValue())) - .collect(Collectors.toList()); - queryStructCmd.setMetricFilters(metricFilters); - - addDateDimension(parseInfo); - List dimensions = parseInfo.getDimensions().stream().map(entry -> entry.getBizName()) - .collect(Collectors.toList()); - queryStructCmd.setGroups(dimensions); - queryStructCmd.setLimit(parseInfo.getLimit()); - Set order = getOrder(parseInfo.getOrders(), parseInfo.getAggType(), parseInfo.getMetrics()); - queryStructCmd.setOrders(new ArrayList<>(order)); - queryStructCmd.setAggregators(getAggregatorByMetric(parseInfo.getMetrics(), parseInfo.getAggType())); - return queryStructCmd; - } - - - /*** - * convert to QuerySqlReq - * @param parseInfo - * @return - */ - public static QuerySqlReq convertToQuerySqlReq(SemanticParseInfo parseInfo) { - QuerySqlReq querySqlReq = new QuerySqlReq(); - Object info = parseInfo.getInfo(); - if (Objects.nonNull(info)) { - querySqlReq.setSql(info.toString()); - } - querySqlReq.setDomainId(parseInfo.getDomainId()); - return querySqlReq; - } - - - private static List getAggregatorByMetric(Set metrics, AggregateTypeEnum aggregateType) { - List aggregators = new ArrayList<>(); - String agg = (aggregateType == null || aggregateType.equals(AggregateTypeEnum.NONE)) ? "" - : aggregateType.name(); - for (SchemaItem metric : metrics) { - aggregators.add(new Aggregator(metric.getBizName(), AggOperatorEnum.of(agg))); - } - return aggregators; - } - - private static void addDateDimension(SemanticParseInfo parseInfo) { - if (parseInfo != null) { - String queryMode = parseInfo.getQueryMode(); - if (parseInfo.getDateInfo() == null) { - return; - } - if (MetricCompare.QUERY_MODE.equals(queryMode)) { - if (parseInfo.getAggType() != null && !parseInfo.getAggType().equals(AggregateTypeEnum.NONE)) { - return; - } - } - if (parseInfo.getAggType() != null && (parseInfo.getAggType().equals(AggregateTypeEnum.MAX) - || parseInfo.getAggType().equals(AggregateTypeEnum.MIN)) && !CollectionUtils.isEmpty( - parseInfo.getDimensions())) { - return; - } - DateConf dateInfo = parseInfo.getDateInfo(); - String dateField = TimeDimensionEnum.DAY.getName(); - if (Constants.MONTH.equals(dateInfo.getPeriod())) { - dateField = TimeDimensionEnum.MONTH.getName(); - } - if (Constants.WEEK.equals(dateInfo.getPeriod())) { - dateField = TimeDimensionEnum.WEEK.getName(); - } - for (SchemaItem dimension : parseInfo.getDimensions()) { - if (dimension.getBizName().equalsIgnoreCase(dateField)) { - return; - } - } - SchemaItem dimension = new SchemaItem(); - dimension.setBizName(dateField); - - if (MetricDomain.QUERY_MODE.equals(queryMode) - || MetricGroupBy.QUERY_MODE.equals(queryMode) - || MetricFilter.QUERY_MODE.equals(queryMode) - || MetricCompare.QUERY_MODE.equals(queryMode) - || MetricOrderBy.QUERY_MODE.equals(queryMode)) { - parseInfo.getDimensions().add(dimension); - } - } - } - - public static DomainInfos convert(List domainSchemaInfos) { - DomainInfos result = new DomainInfos(); - if (CollectionUtils.isEmpty(domainSchemaInfos)) { - return result; - } - for (DomainSchemaResp domainSchemaDesc : domainSchemaInfos) { - int domain = Math.toIntExact(domainSchemaDesc.getId()); - // domain - ItemDO domainDO = new ItemDO(); - domainDO.setDomain(domain); - domainDO.setName(domainSchemaDesc.getName()); - domainDO.setItemId(domain); - result.getDomains().add(domainDO); - domainDO.setBizName(domainSchemaDesc.getBizName()); - // entity - List entityNames = domainSchemaDesc.getEntityNames(); - if (!CollectionUtils.isEmpty(entityNames)) { - for (String entityName : entityNames) { - ItemDO entity = new ItemDO(); - entity.setDomain(domain); - entity.setName(entityName); - entity.setItemId(domain); - result.getEntities().add(entity); - } - } - // metric - for (MetricSchemaResp metric : domainSchemaDesc.getMetrics()) { - ItemDO metricDO = new ItemDO(); - metricDO.setDomain(domain); - metricDO.setName(metric.getName()); - metricDO.setItemId(Math.toIntExact(metric.getId())); - metricDO.setUseCnt(metric.getUseCnt()); - metricDO.setBizName(metric.getBizName()); - result.getMetrics().add(metricDO); - - String metricAlias = metric.getAlias(); - if (StringUtils.isNotEmpty(metricAlias)) { - ItemDO aliasMetricDO = new ItemDO(); - BeanUtils.copyProperties(metricDO, aliasMetricDO); - aliasMetricDO.setName(metricAlias); - result.getMetrics().add(aliasMetricDO); - } - } - // dimension - for (DimSchemaResp dimension : domainSchemaDesc.getDimensions()) { - ItemDO dimensionDO = new ItemDO(); - dimensionDO.setDomain(domain); - dimensionDO.setName(dimension.getName()); - dimensionDO.setItemId(Math.toIntExact(dimension.getId())); - dimensionDO.setUseCnt(dimension.getUseCnt()); - dimensionDO.setBizName(dimension.getBizName()); - result.getDimensions().add(dimensionDO); - - String dimensionAlias = dimension.getAlias(); - if (StringUtils.isNotEmpty(dimensionAlias)) { - ItemDO aliasDimensionDO = new ItemDO(); - BeanUtils.copyProperties(dimensionDO, aliasDimensionDO); - aliasDimensionDO.setName(dimensionAlias); - result.getDimensions().add(aliasDimensionDO); - } - } - } - return result; - } - - public static Set getOrder(Set parseOrder, AggregateTypeEnum aggregator, Set metrics) { - if (!CollectionUtils.isEmpty(parseOrder)) { - return parseOrder; - } - Set orders = new LinkedHashSet(); - if (CollectionUtils.isEmpty(metrics)) { - return orders; - } - if ((AggregateTypeEnum.TOPN.equals(aggregator) || AggregateTypeEnum.MAX.equals(aggregator) - || AggregateTypeEnum.MIN.equals( - aggregator))) { - for (SchemaItem metric : metrics) { - Order order = new Order(); - order.setColumn(metric.getBizName()); - order.setDirection("desc"); - orders.add(order); - } - } - return orders; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SemanticSatisfactionChecker.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SemanticSatisfactionChecker.java deleted file mode 100644 index 336eb7556..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SemanticSatisfactionChecker.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.tencent.supersonic.chat.domain.utils; - - -import com.tencent.supersonic.chat.api.component.SemanticQuery; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.common.pojo.SchemaItem; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.lang3.StringUtils; -import org.springframework.util.CollectionUtils; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * utils to check current parse info is enough to query result - */ -@Slf4j -public class SemanticSatisfactionChecker { - - private static final double THRESHOLD = 0.8; - - // check all the parse info in candidate - public static boolean check(QueryContextReq queryCtx) { - for (SemanticQuery query : queryCtx.getCandidateQueries()) { - SemanticParseInfo semanticParseInfo = query.getParseInfo(); - Long domainId = semanticParseInfo.getDomainId(); - List schemaElementMatches = queryCtx.getMapInfo() - .getMatchedElements(domainId.intValue()); - if (check(queryCtx.getQueryText(), semanticParseInfo, schemaElementMatches)) { - return true; - } - } - return false; - } - - //check single parse info - private static boolean check(String text, SemanticParseInfo semanticParseInfo, - List schemaElementMatches) { - if (CollectionUtils.isEmpty(schemaElementMatches)) { - return false; - } - List detectWords = Lists.newArrayList(); - Map detectWordMap = schemaElementMatches.stream() - .collect(Collectors.toMap(SchemaElementMatch::getElementID, SchemaElementMatch::getDetectWord, - (id1, id2) -> id1)); - // get detect word in text by element id in semantic layer - Long domainId = semanticParseInfo.getDomainId(); - if (domainId != null && domainId > 0) { - for (SchemaElementMatch schemaElementMatch : schemaElementMatches) { - if (SchemaElementType.DOMAIN.equals(schemaElementMatch.getElementType())) { - detectWords.add(schemaElementMatch.getDetectWord()); - } - } - } - - for (Filter filter : semanticParseInfo.getDimensionFilters()) { - detectWords.add( - detectWordMap.getOrDefault(Optional.ofNullable(filter.getElementID()).orElse(0L).intValue(), "")); - } - for (SchemaItem schemaItem : semanticParseInfo.getMetrics()) { - detectWords.add( - detectWordMap.getOrDefault(Optional.ofNullable(schemaItem.getId()).orElse(0L).intValue(), "")); - // only first metric - break; - } - for (SchemaItem schemaItem : semanticParseInfo.getDimensions()) { - detectWords.add( - detectWordMap.getOrDefault(Optional.ofNullable(schemaItem.getId()).orElse(0L).intValue(), "")); - // only first dimension - break; - } - //compare the length between detect words and query text - String detectWordsDistinct = StringUtils.join(new HashSet<>(detectWords), ""); - int detectWordsLength = detectWordsDistinct.length(); - int queryTextLength = text.length(); - double degree = detectWordsLength * 1.0 / queryTextLength; - if (degree > THRESHOLD) { - log.info("queryMode:{} has satisfied semantic check, degree:{}, detectWords:{}, parse info:{}", - semanticParseInfo.getQueryMode(), degree, detectWordsDistinct, semanticParseInfo); - return true; - } - return false; - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatQueryDOMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatQueryDOMapper.java deleted file mode 100644 index c4c19da03..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatQueryDOMapper.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.tencent.supersonic.chat.infrastructure.mapper; - -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDO; -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDOExample; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -@Mapper -public interface ChatQueryDOMapper { - - long countByExample(ChatQueryDOExample example); - - int deleteByPrimaryKey(Long questionId); - - - int insert(ChatQueryDO record); - - int insertSelective(ChatQueryDO record); - - List selectByExampleWithBLOBs(ChatQueryDOExample example); - - List selectByExample(ChatQueryDOExample example); - - ChatQueryDO selectByPrimaryKey(Long questionId); - - int updateByPrimaryKeySelective(ChatQueryDO record); - - int updateByPrimaryKeyWithBLOBs(ChatQueryDO record); - - int updateByPrimaryKey(ChatQueryDO record); -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/LocalSemanticLayerImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/LocalSemanticLayerImpl.java deleted file mode 100644 index a3938e7e8..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/LocalSemanticLayerImpl.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.tencent.supersonic.chat.infrastructure.semantic; - -import com.github.pagehelper.PageInfo; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.domain.pojo.config.ChatAggConfig; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatDetailConfig; -import com.tencent.supersonic.chat.domain.pojo.config.ItemVisibility; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.common.util.context.S2ThreadContext; -import com.tencent.supersonic.common.util.context.ThreadContext; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.*; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; -import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; -import com.tencent.supersonic.semantic.query.domain.SchemaService; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.CollectionUtils; -import com.tencent.supersonic.semantic.query.domain.QueryService; - -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -@Slf4j -public class LocalSemanticLayerImpl implements SemanticLayer { - - private static final Cache> domainSchemaCache = - CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); - - private SchemaService schemaService; - - private S2ThreadContext s2ThreadContext; - - private DomainService domainService; - - private DimensionService dimensionService; - - private MetricService metricService; - -// public LocalSemanticLayerImpl(DomainService domainService){ -// this.domainService=domainService; -// } - - @Override - public QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user) { - deletionDuplicated(queryStructReq); - onlyQueryFirstMetric(queryStructReq); - try { - QueryService queryService = ContextUtils.getBean(QueryService.class); - QueryResultWithSchemaResp queryResultWithSchemaResp = queryService.queryByStruct(queryStructReq, user); - return queryResultWithSchemaResp; - } catch (Exception e) { - log.info("queryByStruct has an exception:{}", e.toString()); - } - return null; - } - - @Override - public QueryResultWithSchemaResp queryBySql(QuerySqlReq querySqlReq, User user) { - try { - QueryService queryService = ContextUtils.getBean(QueryService.class); - Object object = queryService.queryBySql(querySqlReq, user); - QueryResultWithSchemaResp queryResultWithSchemaResp = JsonUtil.toObject(JsonUtil.toString(object), - QueryResultWithSchemaResp.class); - return queryResultWithSchemaResp; - } catch (Exception e) { - log.info("queryByStruct has an exception:{}", e.toString()); - } - return null; - } - - - public List fetchDomainSchemaAll(List ids) { - - DomainSchemaFilterReq filter = new DomainSchemaFilterReq(); - filter.setDomainIds(ids); - User user = new User(1L, "admin", "admin", "admin@email"); - schemaService = ContextUtils.getBean(SchemaService.class); - return schemaService.fetchDomainSchema(filter, user); - } - - - @SneakyThrows - public List fetchDomainSchema(List ids, Boolean cacheEnable) { - if (cacheEnable) { - return domainSchemaCache.get(String.valueOf(ids), () -> { - List data = fetchDomainSchemaAll(ids); - fillEntityNameAndFilterBlackElement(data); - return data; - }); - } - List data = fetchDomainSchemaAll(ids); - fillEntityNameAndFilterBlackElement(data); - return data; - } - - public DomainSchemaResp getDomainSchemaInfo(Long domain, Boolean cacheEnable) { - List ids = new ArrayList<>(); - ids.add(domain); - List domainSchemaResps = fetchDomainSchema(ids, cacheEnable); - if (!CollectionUtils.isEmpty(domainSchemaResps)) { - Optional domainSchemaResp = domainSchemaResps.stream() - .filter(d -> d.getId().equals(domain)).findFirst(); - if (domainSchemaResp.isPresent()) { - DomainSchemaResp domainSchema = domainSchemaResp.get(); - return domainSchema; - } - } - return null; - } - - @Override - public List getDomainSchemaInfo(List ids) { - return fetchDomainSchema(ids, true); - } - - public DomainSchemaResp fillEntityNameAndFilterBlackElement(DomainSchemaResp domainSchemaResp) { - if (Objects.isNull(domainSchemaResp) || Objects.isNull(domainSchemaResp.getId())) { - return domainSchemaResp; - } - ChatConfigResp chatConfigResp = getConfigBaseInfo(domainSchemaResp.getId()); - - // fill entity names - fillEntityNamesInfo(domainSchemaResp, chatConfigResp); - - // filter black element - filterBlackDim(domainSchemaResp, chatConfigResp); - filterBlackMetric(domainSchemaResp, chatConfigResp); - return domainSchemaResp; - } - - public void fillEntityNameAndFilterBlackElement(List domainSchemaRespList) { - if (!CollectionUtils.isEmpty(domainSchemaRespList)) { - domainSchemaRespList.stream() - .forEach(domainSchemaResp -> fillEntityNameAndFilterBlackElement(domainSchemaResp)); - } - } - - private void filterBlackMetric(DomainSchemaResp domainSchemaResp, ChatConfigResp chatConfigResp) { - ItemVisibility visibility = generateFinalVisibility(chatConfigResp); - if (Objects.nonNull(chatConfigResp) && Objects.nonNull(visibility) - && !CollectionUtils.isEmpty(visibility.getBlackMetricIdList()) - && !CollectionUtils.isEmpty(domainSchemaResp.getMetrics())) { - List metric4Chat = domainSchemaResp.getMetrics().stream() - .filter(metric -> !visibility.getBlackMetricIdList().contains(metric.getId())) - .collect(Collectors.toList()); - domainSchemaResp.setMetrics(metric4Chat); - } - } - - private ItemVisibility generateFinalVisibility(ChatConfigResp chatConfigInfo) { - ItemVisibility visibility = new ItemVisibility(); - - ChatAggConfig chatAggConfig = chatConfigInfo.getChatAggConfig(); - ChatDetailConfig chatDetailConfig = chatConfigInfo.getChatDetailConfig(); - - // both black is exist - if (Objects.nonNull(chatAggConfig) && Objects.nonNull(chatAggConfig.getVisibility()) - && Objects.nonNull(chatDetailConfig) && Objects.nonNull(chatDetailConfig.getVisibility())) { - List blackDimIdList = new ArrayList<>(); - blackDimIdList.addAll(chatAggConfig.getVisibility().getBlackDimIdList()); - blackDimIdList.retainAll(chatDetailConfig.getVisibility().getBlackDimIdList()); - List blackMetricIdList = new ArrayList<>(); - - blackMetricIdList.addAll(chatAggConfig.getVisibility().getBlackMetricIdList()); - blackMetricIdList.retainAll(chatDetailConfig.getVisibility().getBlackMetricIdList()); - - visibility.setBlackDimIdList(blackDimIdList); - visibility.setBlackMetricIdList(blackMetricIdList); - } - return visibility; - } - - private void filterBlackDim(DomainSchemaResp domainSchemaResp, ChatConfigResp chatConfigResp) { - ItemVisibility visibility = generateFinalVisibility(chatConfigResp); - if (Objects.nonNull(chatConfigResp) && Objects.nonNull(visibility) - && !CollectionUtils.isEmpty(visibility.getBlackDimIdList()) - && !CollectionUtils.isEmpty(domainSchemaResp.getDimensions())) { - List dim4Chat = domainSchemaResp.getDimensions().stream() - .filter(dim -> !visibility.getBlackDimIdList().contains(dim.getId())) - .collect(Collectors.toList()); - domainSchemaResp.setDimensions(dim4Chat); - } - } - - private void fillEntityNamesInfo(DomainSchemaResp domainSchemaResp, ChatConfigResp chatConfigResp) { - if (Objects.nonNull(chatConfigResp) && Objects.nonNull(chatConfigResp.getChatDetailConfig()) - && Objects.nonNull(chatConfigResp.getChatDetailConfig().getEntity()) - && !CollectionUtils.isEmpty(chatConfigResp.getChatDetailConfig().getEntity().getNames())) { - domainSchemaResp.setEntityNames(chatConfigResp.getChatDetailConfig().getEntity().getNames()); - } - } - - private void deletionDuplicated(QueryStructReq queryStructReq) { - if (!CollectionUtils.isEmpty(queryStructReq.getGroups()) && queryStructReq.getGroups().size() > 1) { - Set groups = new HashSet<>(); - groups.addAll(queryStructReq.getGroups()); - queryStructReq.getGroups().clear(); - queryStructReq.getGroups().addAll(groups); - } - } - - private void onlyQueryFirstMetric(QueryStructReq queryStructReq) { - if (!CollectionUtils.isEmpty(queryStructReq.getAggregators()) && queryStructReq.getAggregators().size() > 1) { - log.info("multi metric in aggregators:{} , only query first one", queryStructReq.getAggregators()); - queryStructReq.setAggregators(queryStructReq.getAggregators().subList(0, 1)); - } - } - - public ChatConfigResp getConfigBaseInfo(Long domain) { - DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); - return defaultSemanticConfig.getConfigService().fetchConfigByDomainId(domain); - } - - @Override - public List getDomainListForViewer() { - s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class); - ThreadContext threadContext = s2ThreadContext.get(); - domainService = ContextUtils.getBean(DomainService.class); - return domainService.getDomainListForViewer(threadContext.getUserName()); - } - - @Override - public List getDomainListForAdmin() { - domainService = ContextUtils.getBean(DomainService.class); - s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class); - ThreadContext threadContext = s2ThreadContext.get(); - return domainService.getDomainListForAdmin(threadContext.getUserName()); - } - - @Override - public PageInfo queryDimensionPage(PageDimensionReq pageDimensionCmd) { - dimensionService = ContextUtils.getBean(DimensionService.class); - return dimensionService.queryDimension(pageDimensionCmd); - } - - @Override - public PageInfo queryMetricPage(PageMetricReq pageMetricCmd) { - metricService = ContextUtils.getBean(MetricService.class); - return metricService.queryMetric(pageMetricCmd); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/DomainInfoStat.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/DomainInfoStat.java similarity index 78% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/DomainInfoStat.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/mapper/DomainInfoStat.java index ba861c1a9..f65f29bef 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/DomainInfoStat.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/DomainInfoStat.java @@ -1,16 +1,21 @@ -package com.tencent.supersonic.chat.domain.pojo.search; +package com.tencent.supersonic.chat.mapper; import java.io.Serializable; +import lombok.Builder; import lombok.Data; import lombok.ToString; @Data @ToString +@Builder public class DomainInfoStat implements Serializable { private long domainCount; + private long metricDomainCount; + private long dimensionDomainCount; + private long dimensionValueDomainCount; } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/DomainWithSemanticType.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/DomainWithSemanticType.java similarity index 66% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/DomainWithSemanticType.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/mapper/DomainWithSemanticType.java index 31a115bdf..78777b937 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/DomainWithSemanticType.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/DomainWithSemanticType.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.search; +package com.tencent.supersonic.chat.mapper; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import java.io.Serializable; @@ -9,10 +9,10 @@ import lombok.ToString; @ToString public class DomainWithSemanticType implements Serializable { - private Integer domain; + private Long domain; private SchemaElementType semanticType; - public DomainWithSemanticType(Integer domain, SchemaElementType semanticType) { + public DomainWithSemanticType(Long domain, SchemaElementType semanticType) { this.domain = domain; this.semanticType = semanticType; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/FuzzyNameMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/FuzzyNameMapper.java new file mode 100644 index 000000000..cf3a6129e --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/FuzzyNameMapper.java @@ -0,0 +1,172 @@ +package com.tencent.supersonic.chat.mapper; + +import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.component.SchemaMapper; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.knowledge.service.SchemaService; +import com.tencent.supersonic.chat.api.pojo.SemanticSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.knowledge.utils.HanlpHelper; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; + +@Slf4j +public class FuzzyNameMapper implements SchemaMapper { + + @Override + public void map(QueryContext queryContext) { + + log.debug("before db mapper,mapInfo:{}", queryContext.getMapInfo()); + + List terms = HanlpHelper.getTerms(queryContext.getRequest().getQueryText()); + + SemanticSchema semanticSchema = ContextUtils.getBean(SchemaService.class).getSemanticSchema(); + + detectAndAddToSchema(queryContext, terms, semanticSchema.getDimensions(), SchemaElementType.DIMENSION); + + detectAndAddToSchema(queryContext, terms, semanticSchema.getMetrics(), SchemaElementType.METRIC); + + log.debug("after db mapper,mapInfo:{}", queryContext.getMapInfo()); + } + + private void detectAndAddToSchema(QueryContext queryContext, List terms, List domains, + SchemaElementType schemaElementType) { + try { + + Map> domainResultSet = getResultSet(queryContext, terms, domains); + + addToSchemaMapInfo(domainResultSet, queryContext.getMapInfo(), schemaElementType); + + } catch (Exception e) { + log.error("detectAndAddToSchema error", e); + } + } + + private Map> getResultSet(QueryContext queryContext, List terms, + List domains) { + + String queryText = queryContext.getRequest().getQueryText(); + + MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); + + Double metricDimensionThresholdConfig = getThreshold(queryContext, mapperHelper); + + Map> nameToItems = getNameToItems(domains); + + Map regOffsetToLength = terms.stream().sorted(Comparator.comparing(Term::length)) + .collect(Collectors.toMap(Term::getOffset, term -> term.word.length(), (value1, value2) -> value2)); + + Map> domainResultSet = new HashMap<>(); + for (Integer startIndex = 0; startIndex <= queryText.length() - 1; ) { + for (Integer endIndex = startIndex; endIndex <= queryText.length(); ) { + endIndex = mapperHelper.getStepIndex(regOffsetToLength, endIndex); + if (endIndex > queryText.length()) { + continue; + } + String detectSegment = queryText.substring(startIndex, endIndex); + + for (Entry> entry : nameToItems.entrySet()) { + String name = entry.getKey(); + Set schemaElements = entry.getValue(); + if (!name.contains(detectSegment) + || mapperHelper.getSimilarity(detectSegment, name) < metricDimensionThresholdConfig) { + continue; + } + Set preSchemaElements = domainResultSet.putIfAbsent(detectSegment, + schemaElements); + if (Objects.nonNull(preSchemaElements)) { + preSchemaElements.addAll(schemaElements); + } + } + } + startIndex = mapperHelper.getStepIndex(regOffsetToLength, startIndex); + } + return domainResultSet; + } + + private Double getThreshold(QueryContext queryContext, MapperHelper mapperHelper) { + + Double metricDimensionThresholdConfig = mapperHelper.getMetricDimensionThresholdConfig(); + Double metricDimensionMinThresholdConfig = mapperHelper.getMetricDimensionMinThresholdConfig(); + + Map> domainElementMatches = queryContext.getMapInfo() + .getDomainElementMatches(); + boolean existElement = domainElementMatches.entrySet().stream() + .anyMatch(entry -> entry.getValue().size() >= 1); + + if (!existElement) { + double halfThreshold = metricDimensionThresholdConfig / 2; + + metricDimensionThresholdConfig = halfThreshold >= metricDimensionMinThresholdConfig ? halfThreshold + : metricDimensionMinThresholdConfig; + log.info("domainElementMatches:{} , not exist Element metricDimensionThresholdConfig reduce by half:{}", + domainElementMatches, metricDimensionThresholdConfig); + } + return metricDimensionThresholdConfig; + } + + private Map> getNameToItems(List domains) { + return domains.stream().collect( + Collectors.toMap(SchemaElement::getName, a -> { + Set result = new HashSet<>(); + result.add(a); + return result; + }, (k1, k2) -> { + k1.addAll(k2); + return k1; + })); + } + + private void addToSchemaMapInfo(Map> mapResultRowSet, SchemaMapInfo schemaMap, + SchemaElementType schemaElementType) { + if (Objects.isNull(mapResultRowSet) || mapResultRowSet.size() <= 0) { + return; + } + MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); + + for (Map.Entry> entry : mapResultRowSet.entrySet()) { + String detectWord = entry.getKey(); + Set schemaElements = entry.getValue(); + for (SchemaElement schemaElement : schemaElements) { + + List elements = schemaMap.getMatchedElements(schemaElement.getDomain()); + if (CollectionUtils.isEmpty(elements)) { + elements = new ArrayList<>(); + schemaMap.setMatchedElements(schemaElement.getDomain(), elements); + } + Set regElementSet = elements.stream() + .filter(elementMatch -> schemaElementType.equals(elementMatch.getElement().getType())) + .map(elementMatch -> elementMatch.getElement().getId()) + .collect(Collectors.toSet()); + + if (regElementSet.contains(schemaElement.getId())) { + continue; + } + SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() + .element(schemaElement) + .word(schemaElement.getName()) + .detectWord(detectWord) + .frequency(10000L) + .similarity(mapperHelper.getSimilarity(detectWord, schemaElement.getName())) + .build(); + log.info("schemaElementType:{},add to schema, elementMatch {}", schemaElementType, schemaElementMatch); + elements.add(schemaElementMatch); + } + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/HanlpDictMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/HanlpDictMapper.java new file mode 100644 index 000000000..fb9c94d36 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/HanlpDictMapper.java @@ -0,0 +1,113 @@ +package com.tencent.supersonic.chat.mapper; + +import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.component.SchemaMapper; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.service.SemanticService; +import com.tencent.supersonic.chat.utils.NatureHelper; +import com.tencent.supersonic.knowledge.dictionary.builder.BaseWordBuilder; +import com.tencent.supersonic.knowledge.dictionary.MapResult; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.knowledge.dictionary.builder.WordBuilderFactory; +import com.tencent.supersonic.knowledge.utils.HanlpHelper; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; + +@Slf4j +public class HanlpDictMapper implements SchemaMapper { + + @Override + public void map(QueryContext queryContext) { + + String queryText = queryContext.getRequest().getQueryText(); + List terms = HanlpHelper.getTerms(queryText); + + for (Term term : terms) { + log.info("word:{},nature:{},frequency:{}", term.word, term.nature.toString(), term.getFrequency()); + } + Long domainId = queryContext.getRequest().getDomainId(); + + QueryMatchStrategy matchStrategy = ContextUtils.getBean(QueryMatchStrategy.class); + Map> matchResult = matchStrategy.match(queryText, terms, domainId); + + List matches = getMatches(matchResult); + + HanlpHelper.transLetterOriginal(matches); + + log.info("queryContext:{},matches:{}", queryContext, matches); + + convertTermsToSchemaMapInfo(matches, queryContext.getMapInfo(), terms); + } + + private void convertTermsToSchemaMapInfo(List mapResults, SchemaMapInfo schemaMap, List terms) { + if (CollectionUtils.isEmpty(mapResults)) { + return; + } + + Map wordNatureToFrequency = terms.stream().collect( + Collectors.toMap(entry -> entry.getWord() + entry.getNature(), + term -> Long.valueOf(term.getFrequency()), (value1, value2) -> value2)); + + for (MapResult mapResult : mapResults) { + for (String nature : mapResult.getNatures()) { + Long domainId = NatureHelper.getDomainId(nature); + if (Objects.isNull(domainId)) { + continue; + } + SchemaElementType elementType = NatureHelper.convertToElementType(nature); + if (Objects.isNull(elementType)) { + continue; + } + + SemanticService schemaService = ContextUtils.getBean(SemanticService.class); + DomainSchema domainSchema = schemaService.getDomainSchema(domainId); + + BaseWordBuilder baseWordBuilder = WordBuilderFactory.get(DictWordType.getNatureType(nature)); + Long elementID = baseWordBuilder.getElementID(nature); + Long frequency = wordNatureToFrequency.get(mapResult.getName() + nature); + + SchemaElement element = domainSchema.getElement(elementType, elementID); + if (element.getType().equals(SchemaElementType.VALUE)) { + element.setName(mapResult.getName()); + } + SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() + .element(element) + .frequency(frequency) + .word(mapResult.getName()) + .similarity(mapResult.getSimilarity()) + .detectWord(mapResult.getDetectWord()) + .build(); + + Map> domainElementMatches = schemaMap.getDomainElementMatches(); + List schemaElementMatches = domainElementMatches.putIfAbsent(domainId, + new ArrayList<>()); + if (schemaElementMatches == null) { + schemaElementMatches = domainElementMatches.get(domainId); + } + schemaElementMatches.add(schemaElementMatch); + } + } + } + + private List getMatches(Map> matchResult) { + List matches = new ArrayList<>(); + if (Objects.isNull(matchResult)) { + return matches; + } + Optional> first = matchResult.entrySet().stream() + .filter(entry -> CollectionUtils.isNotEmpty(entry.getValue())) + .map(entry -> entry.getValue()).findFirst(); + + if (first.isPresent()) { + matches = first.get(); + } + return matches; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MapperHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MapperHelper.java similarity index 92% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MapperHelper.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MapperHelper.java index 55309da3d..7fc691404 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MapperHelper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MapperHelper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.chat.application.mapper; +package com.tencent.supersonic.chat.mapper; import com.hankcs.hanlp.algorithm.EditDistance; -import com.tencent.supersonic.chat.application.knowledge.NatureHelper; +import com.tencent.supersonic.chat.utils.NatureHelper; import java.util.List; import java.util.Map; import java.util.Objects; @@ -25,6 +25,9 @@ public class MapperHelper { private Integer oneDetectionMaxSize; @Value("${metric.dimension.threshold:0.3}") private Double metricDimensionThresholdConfig; + + @Value("${metric.dimension.min.threshold:0.3}") + private Double metricDimensionMinThresholdConfig; @Value("${dimension.value.threshold:0.5}") private Double dimensionValueThresholdConfig; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchStrategy.java similarity index 51% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MatchStrategy.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchStrategy.java index 9b98f9d60..ea9db99f3 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchStrategy.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.chat.application.mapper; +package com.tencent.supersonic.chat.mapper; import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.domain.pojo.search.MatchText; -import com.tencent.supersonic.common.nlp.MapResult; +import com.tencent.supersonic.knowledge.dictionary.MapResult; + import java.util.List; import java.util.Map; @@ -11,6 +11,6 @@ import java.util.Map; */ public interface MatchStrategy { - Map> match(String text, List terms, Integer detectDomainId); + Map> match(String text, List terms, Long detectDomainId); } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/MatchText.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchText.java similarity index 68% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/MatchText.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchText.java index b4142fc20..fe5d8bdca 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/search/MatchText.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchText.java @@ -1,30 +1,19 @@ -package com.tencent.supersonic.chat.domain.pojo.search; +package com.tencent.supersonic.chat.mapper; import java.util.Objects; +import lombok.Builder; import lombok.Data; -import lombok.Getter; -import lombok.Setter; import lombok.ToString; @Data -@Setter -@Getter @ToString +@Builder public class MatchText { private String regText; private String detectSegment; - public MatchText() { - } - - - public MatchText(String regText, String detectSegment) { - this.regText = regText; - this.detectSegment = detectSegment; - } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryFilterMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryFilterMapper.java new file mode 100644 index 000000000..74f785f30 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryFilterMapper.java @@ -0,0 +1,32 @@ +package com.tencent.supersonic.chat.mapper; + +import com.tencent.supersonic.chat.api.component.SchemaMapper; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import lombok.extern.slf4j.Slf4j; +import java.util.List; +import java.util.Map; + +@Slf4j +public class QueryFilterMapper implements SchemaMapper { + + @Override + public void map(QueryContext queryContext) { + QueryRequest queryReq = queryContext.getRequest(); + Long domainId = queryReq.getDomainId(); + if (domainId == null || domainId <= 0) { + return; + } + SchemaMapInfo schemaMapInfo = queryContext.getMapInfo(); + clearOtherSchemaElementMatch(domainId, schemaMapInfo); + } + + private void clearOtherSchemaElementMatch(Long domainId, SchemaMapInfo schemaMapInfo) { + for (Map.Entry> entry : schemaMapInfo.getDomainElementMatches().entrySet()) { + if (!entry.getKey().equals(domainId)) { + entry.getValue().clear(); + } + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryMatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryMatchStrategy.java similarity index 84% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryMatchStrategy.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryMatchStrategy.java index 86a389a2f..a04ee3edd 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryMatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryMatchStrategy.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.chat.application.mapper; +package com.tencent.supersonic.chat.mapper; import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.domain.pojo.search.MatchText; -import com.tencent.supersonic.common.nlp.MapResult; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester; +import com.tencent.supersonic.knowledge.dictionary.MapResult; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.service.SearchService; + import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; @@ -32,10 +32,11 @@ public class QueryMatchStrategy implements MatchStrategy { private MapperHelper mapperHelper; @Override - public Map> match(String text, List terms, Integer detectDomainId) { - if (CollectionUtils.isEmpty(terms) || StringUtils.isEmpty(text)) { + public Map> match(String text, List terms, Long detectDomainId) { + if (Objects.isNull(terms) || StringUtils.isEmpty(text)) { return null; } + Map regOffsetToLength = terms.stream().sorted(Comparator.comparing(Term::length)) .collect(Collectors.toMap(Term::getOffset, term -> term.word.length(), (value1, value2) -> value2)); @@ -47,13 +48,17 @@ public class QueryMatchStrategy implements MatchStrategy { List detects = detect(text, regOffsetToLength, offsetList, detectDomainId); Map> result = new HashMap<>(); - MatchText matchText = new MatchText(text, text); + + MatchText matchText = MatchText.builder() + .regText(text) + .detectSegment(text) + .build(); result.put(matchText, detects); return result; } private List detect(String text, Map regOffsetToLength, List offsetList, - Integer detectDomainId) { + Long detectDomainId) { List results = Lists.newArrayList(); for (Integer index = 0; index <= text.length() - 1; ) { @@ -75,15 +80,15 @@ public class QueryMatchStrategy implements MatchStrategy { return results; } - private List detectByStep(String text, Integer detectDomainId, Integer index, Integer i, int offset) { + private List detectByStep(String text, Long detectDomainId, Integer index, Integer i, int offset) { String detectSegment = text.substring(index, i); Integer oneDetectionSize = mapperHelper.getOneDetectionSize(); // step1. pre search - LinkedHashSet mapResults = Suggester.prefixSearch(detectSegment, + LinkedHashSet mapResults = SearchService.prefixSearch(detectSegment, mapperHelper.getOneDetectionMaxSize()) .stream().collect(Collectors.toCollection(LinkedHashSet::new)); // step2. suffix search - LinkedHashSet suffixMapResults = Suggester.suffixSearch(detectSegment, oneDetectionSize) + LinkedHashSet suffixMapResults = SearchService.suffixSearch(detectSegment, oneDetectionSize) .stream().collect(Collectors.toCollection(LinkedHashSet::new)); mapResults.addAll(suffixMapResults); @@ -99,8 +104,8 @@ public class QueryMatchStrategy implements MatchStrategy { log.debug("detectDomainId:{}, before parseResults:{}", mapResults); mapResults = mapResults.stream().map(entry -> { List natures = entry.getNatures().stream().filter( - nature -> nature.startsWith(NatureType.NATURE_SPILT + detectDomainId) || (nature.startsWith( - NatureType.NATURE_SPILT)) + nature -> nature.startsWith(DictWordType.NATURE_SPILT + detectDomainId) || (nature.startsWith( + DictWordType.NATURE_SPILT)) ).collect(Collectors.toList()); entry.setNatures(natures); return entry; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/SearchMatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/SearchMatchStrategy.java similarity index 76% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/SearchMatchStrategy.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/mapper/SearchMatchStrategy.java index 38c449a8e..91c7be09b 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/SearchMatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/SearchMatchStrategy.java @@ -1,11 +1,11 @@ -package com.tencent.supersonic.chat.application.mapper; +package com.tencent.supersonic.chat.mapper; import com.google.common.collect.Lists; import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.domain.pojo.search.MatchText; -import com.tencent.supersonic.common.nlp.MapResult; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester; +import com.tencent.supersonic.knowledge.dictionary.MapResult; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.service.SearchService; + import java.util.List; import java.util.Map; import java.util.Objects; @@ -25,10 +25,10 @@ public class SearchMatchStrategy implements MatchStrategy { @Override public Map> match(String text, List originals, - Integer detectDomainId) { + Long detectDomainId) { Map regOffsetToLength = originals.stream() - .filter(entry -> !entry.nature.toString().startsWith(NatureType.NATURE_SPILT)) + .filter(entry -> !entry.nature.toString().startsWith(DictWordType.NATURE_SPILT)) .collect(Collectors.toMap(Term::getOffset, value -> value.word.length(), (value1, value2) -> value2)); @@ -52,19 +52,19 @@ public class SearchMatchStrategy implements MatchStrategy { String detectSegment = text.substring(detectIndex); if (StringUtils.isNotEmpty(detectSegment)) { - List mapResults = Suggester.prefixSearch(detectSegment); - List suffixMapResults = Suggester.suffixSearch(detectSegment, SEARCH_SIZE); + List mapResults = SearchService.prefixSearch(detectSegment); + List suffixMapResults = SearchService.suffixSearch(detectSegment, SEARCH_SIZE); mapResults.addAll(suffixMapResults); // remove entity name where search mapResults = mapResults.stream().filter(entry -> { List natures = entry.getNatures().stream() - .filter(nature -> !nature.endsWith(NatureType.ENTITY.getType())) + .filter(nature -> !nature.endsWith(DictWordType.ENTITY.getType())) .filter(nature -> { if (Objects.isNull(detectDomainId) || detectDomainId <= 0) { return true; } - if (nature.startsWith(NatureType.NATURE_SPILT + detectDomainId) - && nature.startsWith(NatureType.NATURE_SPILT)) { + if (nature.startsWith(DictWordType.NATURE_SPILT + detectDomainId) + && nature.startsWith(DictWordType.NATURE_SPILT)) { return true; } return false; @@ -75,7 +75,11 @@ public class SearchMatchStrategy implements MatchStrategy { } return true; }).collect(Collectors.toList()); - regTextMap.put(new MatchText(regText, detectSegment), mapResults); + MatchText matchText = MatchText.builder() + .regText(regText) + .detectSegment(detectSegment) + .build(); + regTextMap.put(matchText, mapResults); } } ); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/ParseMode.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/ParseMode.java new file mode 100644 index 000000000..d40c3d86f --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/ParseMode.java @@ -0,0 +1,9 @@ +package com.tencent.supersonic.chat.parser; + +public enum ParseMode { + + RULE, + EMBEDDING_RECALL, + FUNCTION_CALL; + +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/SatisfactionChecker.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/SatisfactionChecker.java new file mode 100644 index 000000000..495a73597 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/SatisfactionChecker.java @@ -0,0 +1,112 @@ +package com.tencent.supersonic.chat.parser; + + +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.DateConf; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * This checker can be used by semantic parsers to check if query intent + * has already been satisfied by current candidate queries. If so, current + * parser could be skipped. + */ +@Slf4j +public class SatisfactionChecker { + + private static final double LONG_TEXT_THRESHOLD = 0.8; + private static final double SHORT_TEXT_THRESHOLD = 0.6; + private static final int QUERY_TEXT_LENGTH_THRESHOLD = 10; + + public static final double BONUS_THRESHOLD = 100; + + // check all the parse info in candidate + public static boolean check(QueryContext queryCtx) { + for (SemanticQuery query : queryCtx.getCandidateQueries()) { + SemanticParseInfo semanticParseInfo = query.getParseInfo(); + Long domainId = semanticParseInfo.getDomainId(); + List schemaElementMatches = queryCtx.getMapInfo() + .getMatchedElements(domainId); + if (check(queryCtx.getRequest().getQueryText(), semanticParseInfo, schemaElementMatches)) { + return true; + } + } + return false; + } + + //check single parse info + private static boolean check(String text, SemanticParseInfo semanticParseInfo, + List schemaElementMatches) { + if (semanticParseInfo.getBonus() != null && semanticParseInfo.getBonus() >= BONUS_THRESHOLD) { + return true; + } + if (CollectionUtils.isEmpty(schemaElementMatches)) { + return false; + } + List detectWords = Lists.newArrayList(); + Map detectWordMap = schemaElementMatches.stream() + .collect(Collectors.toMap(m -> m.getElement().getId(), SchemaElementMatch::getDetectWord, + (id1, id2) -> id1)); + // get detect word in text by element id in semantic layer + Long domainId = semanticParseInfo.getDomainId(); + if (domainId != null && domainId > 0) { + for (SchemaElementMatch schemaElementMatch : schemaElementMatches) { + if (SchemaElementType.DOMAIN.equals(schemaElementMatch.getElement().getType())) { + detectWords.add(schemaElementMatch.getDetectWord()); + } + } + } + for (SchemaElementMatch schemaElementMatch : schemaElementMatches) { + if (SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())) { + detectWords.add(schemaElementMatch.getDetectWord()); + } + } + for (SchemaElement schemaItem : semanticParseInfo.getMetrics()) { + detectWords.add( + detectWordMap.getOrDefault(Optional.ofNullable(schemaItem.getId()).orElse(0L), "")); + // only first metric + break; + } + for (SchemaElement schemaItem : semanticParseInfo.getDimensions()) { + detectWords.add( + detectWordMap.getOrDefault(Optional.ofNullable(schemaItem.getId()).orElse(0L), "")); + // only first dimension + break; + } + String dateText = Optional.ofNullable(semanticParseInfo.getDateInfo()).orElse(new DateConf()).getText(); + if (StringUtils.isNotBlank(dateText) && !dateText.equalsIgnoreCase(Constants.NULL)) { + detectWords.add(dateText); + } + detectWords.removeIf(word -> !text.contains(word)); + //compare the length between detect words and query text + return checkThreshold(text, detectWords, semanticParseInfo); + } + + private static boolean checkThreshold(String queryText, List detectWords, SemanticParseInfo semanticParseInfo) { + String detectWordsDistinct = StringUtils.join(new HashSet<>(detectWords), ""); + int detectWordsLength = detectWordsDistinct.length(); + int queryTextLength = queryText.length(); + double degree = detectWordsLength * 1.0 / queryTextLength; + if (queryTextLength > QUERY_TEXT_LENGTH_THRESHOLD) { + if (degree < LONG_TEXT_THRESHOLD) { + return false; + } + } else if (degree < SHORT_TEXT_THRESHOLD) { + return false; + } + log.info("queryMode:{}, degree:{}, detectWords:{}, parse info:{}", + semanticParseInfo.getQueryMode(), degree, detectWordsDistinct, semanticParseInfo); + return true; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingBasedParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingBasedParser.java new file mode 100644 index 000000000..6bbdf299f --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingBasedParser.java @@ -0,0 +1,181 @@ +package com.tencent.supersonic.chat.parser.embedding; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.config.EntityRichInfo; +import com.tencent.supersonic.chat.parser.SatisfactionChecker; +import com.tencent.supersonic.chat.plugin.Plugin; +import com.tencent.supersonic.chat.plugin.PluginManager; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.service.PluginService; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.util.ContextUtils; +import java.util.*; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +@Slf4j +public class EmbeddingBasedParser implements SemanticParser { + + private final static double THRESHOLD = 0.2d; + + @Override + public void parse(QueryContext queryContext, ChatContext chatContext) { + EmbeddingConfig embeddingConfig = ContextUtils.getBean(EmbeddingConfig.class); + if (SatisfactionChecker.check(queryContext) || StringUtils.isBlank(embeddingConfig.getUrl())) { + return; + } + log.info("EmbeddingBasedParser parser query ctx: {}, chat ctx: {}", queryContext, chatContext); + for (Long domainId : getDomainMatched(queryContext)) { + String text = replaceText(queryContext, domainId); + List embeddingRetrievals = recallResult(text, hasCandidateQuery(queryContext)); + Optional pluginOptional = choosePlugin(embeddingRetrievals, domainId); + if (pluginOptional.isPresent()) { + Map embeddingRetrievalMap = embeddingRetrievals.stream() + .collect(Collectors.toMap(RecallRetrieval::getId, e -> e, (value1, value2) -> value1)); + Plugin plugin = pluginOptional.get(); + log.info("EmbeddingBasedParser text: {} domain: {} choose plugin: [{} {}]", + text, domainId, plugin.getId(), plugin.getName()); + PluginSemanticQuery pluginQuery = QueryManager.createPluginQuery(plugin.getType()); + SemanticParseInfo semanticParseInfo = buildSemanticParseInfo(queryContext, domainId, + plugin, embeddingRetrievalMap); + semanticParseInfo.setQueryMode(pluginQuery.getQueryMode()); + pluginQuery.setParseInfo(semanticParseInfo); + queryContext.getCandidateQueries().add(pluginQuery); + } + } + } + + private Set getDomainMatched(QueryContext queryContext) { + Long queryDomainId = queryContext.getRequest().getDomainId(); + if (queryDomainId != null && queryDomainId > 0) { + return Sets.newHashSet(queryDomainId); + } + return queryContext.getMapInfo().getMatchedDomains(); + } + + private SemanticParseInfo buildSemanticParseInfo(QueryContext queryContext, Long domainId, Plugin plugin, + Map embeddingRetrievalMap) { + SchemaElement schemaElement = new SchemaElement(); + schemaElement.setDomain(domainId); + schemaElement.setId(domainId); + SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); + semanticParseInfo.setDomain(schemaElement); + SchemaMapInfo schemaMapInfo = queryContext.getMapInfo(); + if (Double.parseDouble(embeddingRetrievalMap.get(plugin.getId().toString()).getDistance()) < THRESHOLD) { + semanticParseInfo.setBonus(SatisfactionChecker.BONUS_THRESHOLD); + } + Map properties = new HashMap<>(); + properties.put(Constants.CONTEXT, plugin); + semanticParseInfo.setProperties(properties); + semanticParseInfo.setElementMatches(schemaMapInfo.getMatchedElements(domainId)); + fillSemanticParseInfo(queryContext, semanticParseInfo); + setEntityId(domainId, semanticParseInfo); + return semanticParseInfo; + } + + private Optional getEntityElementId(Long domainId) { + ConfigService configService = ContextUtils.getBean(ConfigService.class); + ChatConfigRich chatConfigRich = configService.getConfigRichInfo(domainId); + EntityRichInfo entityRichInfo = chatConfigRich.getChatDetailRichConfig().getEntity(); + if (entityRichInfo != null) { + SchemaElement schemaElement = entityRichInfo.getDimItem(); + if (schemaElement != null) { + return Optional.of(schemaElement.getId()); + } + } + return Optional.empty(); + } + + private void setEntityId(Long domainId, SemanticParseInfo semanticParseInfo) { + Optional entityElementIdOptional = getEntityElementId(domainId); + if (entityElementIdOptional.isPresent()) { + Long entityElementId = entityElementIdOptional.get(); + for (QueryFilter filter : semanticParseInfo.getDimensionFilters()) { + if (entityElementId.equals(filter.getElementID())) { + String value = String.valueOf(filter.getValue()); + if (StringUtils.isNumeric(value)) { + semanticParseInfo.setEntity(Long.parseLong(value)); + } + } + } + } + } + + private Optional choosePlugin(List embeddingRetrievals, + Long domainId) { + if (CollectionUtils.isEmpty(embeddingRetrievals)) { + return Optional.empty(); + } + PluginService pluginService = ContextUtils.getBean(PluginService.class); + List plugins = pluginService.getPluginList(); + Map pluginMap = plugins.stream().collect(Collectors.toMap(Plugin::getId, p -> p)); + for (RecallRetrieval embeddingRetrieval : embeddingRetrievals) { + Plugin plugin = pluginMap.get(Long.parseLong(embeddingRetrieval.getId())); + if (!CollectionUtils.isEmpty(plugin.getDomainList()) && plugin.getDomainList().contains(domainId)) { + return Optional.of(plugin); + } + } + return Optional.empty(); + } + + public List recallResult(String embeddingText, boolean hasCandidateQuery) { + try { + PluginManager pluginManager = ContextUtils.getBean(PluginManager.class); + EmbeddingResp embeddingResp = pluginManager.recognize(embeddingText); + log.info("embedding result, text:{} embeddingResp:{}", embeddingText, embeddingResp); + List embeddingRetrievals = embeddingResp.getRetrieval(); + if(!CollectionUtils.isEmpty(embeddingRetrievals)){ + if (hasCandidateQuery) { + embeddingRetrievals = embeddingRetrievals.stream() + .filter(llmRetrieval -> Double.parseDouble(llmRetrieval.getDistance()) + Math.abs(Double.parseDouble(o.getDistance())))).collect(Collectors.toList()); + embeddingResp.setRetrieval(embeddingRetrievals); + } + return embeddingRetrievals; + } catch (Exception e) { + log.warn("get embedding result error ", e); + } + return Lists.newArrayList(); + } + + private boolean hasCandidateQuery(QueryContext queryContext) { + return !CollectionUtils.isEmpty(queryContext.getCandidateQueries()); + } + + private void fillSemanticParseInfo(QueryContext queryContext, SemanticParseInfo semanticParseInfo) { + if (queryContext.getRequest().getQueryFilters() != null) { + semanticParseInfo.getDimensionFilters() + .addAll(queryContext.getRequest().getQueryFilters().getFilters()); + } + } + + protected String replaceText(QueryContext queryContext, Long domainId) { + String text = queryContext.getRequest().getQueryText(); + List schemaElementMatches = queryContext.getMapInfo().getMatchedElements(domainId); + if (CollectionUtils.isEmpty(schemaElementMatches)) { + return text; + } + List valueSchemaElementMatches = schemaElementMatches.stream() + .filter(schemaElementMatch -> + SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())) + .collect(Collectors.toList()); + for (SchemaElementMatch schemaElementMatch : valueSchemaElementMatches) { + String detectWord = schemaElementMatch.getDetectWord(); + text = text.replace(detectWord, ""); + } + return text; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingConfig.java new file mode 100644 index 000000000..9df4c6e8b --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingConfig.java @@ -0,0 +1,26 @@ +package com.tencent.supersonic.chat.parser.embedding; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Data +public class EmbeddingConfig { + + @Value("${embedding.url:}") + private String url; + + @Value("${embedding.recognize.path:preset_query_retrival}") + private String recognizePath; + + @Value("${embedding.delete.path:preset_delete_by_ids}") + private String deletePath; + + @Value("${embedding.add.path:preset_query_add}") + private String addPath; + + @Value("${embedding.nResult:1}") + private String nResult; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingEntityResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingEntityResolver.java new file mode 100644 index 000000000..6ac6509d5 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingEntityResolver.java @@ -0,0 +1,110 @@ +package com.tencent.supersonic.chat.parser.embedding; + +import com.alibaba.fastjson.JSONObject; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.parser.function.DomainResolver; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +@Slf4j +@Component("EmbeddingEntityResolver") +public class EmbeddingEntityResolver { + + private ConfigService configService; + + public EmbeddingEntityResolver(ConfigService configService) { + this.configService = configService; + } + + public Pair getDomainEntityId(QueryContext queryCtx, ChatContext chatCtx) { + DomainResolver domainResolver = ComponentFactory.getDomainResolver(); + Long domainId = domainResolver.resolve(queryCtx, chatCtx); + ChatConfigRich chatConfigRichResp = configService.getConfigRichInfo(domainId); + SchemaElement schemaElement = chatConfigRichResp.getChatDetailRichConfig().getEntity().getDimItem(); + if (schemaElement == null) { + return Pair.of(domainId, null); + } + Long entityId = getEntityValue(domainId, schemaElement.getId(), queryCtx, chatCtx); + return Pair.of(domainId, entityId); + } + + + private Long getEntityValue(Long domainId, Long entityElementId, QueryContext queryCtx, ChatContext chatCtx) { + Long entityId = null; + QueryFilters queryFilters = queryCtx.getRequest().getQueryFilters(); + if (queryFilters != null) { + entityId = getEntityValueFromQueryFilter(queryFilters.getFilters()); + if (entityId != null) { + log.info("get entity id:{} domain id:{} from query filter :{} ", entityId, domainId, queryFilters); + return entityId; + } + } + entityId = getEntityValueFromSchemaMapInfo(domainId, queryCtx.getMapInfo(), entityElementId); + log.info("get entity id:{} from schema map Info :{} ", entityId, JSONObject.toJSONString(queryCtx.getMapInfo())); + if (entityId == null || entityId == 0) { + Long entityIdFromChat = getEntityValueFromParseInfo(chatCtx.getParseInfo(), entityElementId); + if (entityIdFromChat != null && entityIdFromChat > 0) { + entityId = entityIdFromChat; + } + } + return entityId; + } + + private Long getEntityValueFromQueryFilter(List queryFilters) { + if (CollectionUtils.isEmpty(queryFilters)) { + return null; + } + QueryFilter filter = queryFilters.get(0); + String value = String.valueOf(filter.getValue()); + if (StringUtils.isNumeric(value)) { + return Long.parseLong(value); + } + return null; + } + + private Long getEntityValueFromParseInfo(SemanticParseInfo semanticParseInfo, Long entityElementId) { + Set filters = semanticParseInfo.getDimensionFilters(); + if (CollectionUtils.isEmpty(filters)) { + return null; + } + for (QueryFilter filter : filters) { + if (entityElementId.equals(filter.getElementID())) { + String value = String.valueOf(filter.getValue()); + if (StringUtils.isNumeric(value)) { + return Long.parseLong(value); + } + } + } + return null; + } + + + private Long getEntityValueFromSchemaMapInfo(Long domainId, SchemaMapInfo schemaMapInfo, Long entityElementId) { + List schemaElementMatchList = schemaMapInfo.getMatchedElements(domainId); + if (CollectionUtils.isEmpty(schemaElementMatchList)) { + return null; + } + for (SchemaElementMatch schemaElementMatch : schemaElementMatchList) { + if (Objects.equals(schemaElementMatch.getElement().getId(), entityElementId)) { + if (StringUtils.isNumeric(schemaElementMatch.getWord())) { + return Long.parseLong(schemaElementMatch.getWord()); + } + } + + } + return null; + } + +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingResp.java new file mode 100644 index 000000000..4966514a9 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingResp.java @@ -0,0 +1,16 @@ +package com.tencent.supersonic.chat.parser.embedding; + + +import lombok.Data; + +import java.util.List; + +@Data +public class EmbeddingResp { + + private String query; + + private List retrieval; + + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/RecallRetrieval.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/RecallRetrieval.java new file mode 100644 index 000000000..64d141119 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/RecallRetrieval.java @@ -0,0 +1,17 @@ +package com.tencent.supersonic.chat.parser.embedding; + + +import lombok.Data; + +@Data +public class RecallRetrieval { + + private String id; + + private String distance; + + private String presetQuery; + + private String presetId; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/DomainMatchResult.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/DomainMatchResult.java new file mode 100644 index 000000000..bb1dfcbff --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/DomainMatchResult.java @@ -0,0 +1,9 @@ +package com.tencent.supersonic.chat.parser.function; + +import lombok.Data; + +@Data +public class DomainMatchResult { + private Integer count = 0; + private double maxSimilarity; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/DomainResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/DomainResolver.java new file mode 100644 index 000000000..4ecd3e9db --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/DomainResolver.java @@ -0,0 +1,11 @@ +package com.tencent.supersonic.chat.parser.function; + + +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; + +public interface DomainResolver { + + Long resolve(QueryContext queryContext, ChatContext chatCtx); + +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionBasedParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionBasedParser.java new file mode 100644 index 000000000..e32ccc9fd --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionBasedParser.java @@ -0,0 +1,132 @@ +package com.tencent.supersonic.chat.parser.function; + +import com.alibaba.fastjson.JSON; +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.config.FunctionCallConfig; +import com.tencent.supersonic.chat.parser.ParseMode; +import com.tencent.supersonic.chat.parser.SatisfactionChecker; +import com.tencent.supersonic.chat.plugin.Plugin; +import com.tencent.supersonic.chat.plugin.PluginManager; +import com.tencent.supersonic.chat.plugin.PluginParseResult; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; +import com.tencent.supersonic.chat.query.plugin.dsl.DSLQuery; +import com.tencent.supersonic.chat.service.PluginService; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.util.ContextUtils; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +@Slf4j +public class FunctionBasedParser implements SemanticParser { + + public static final double FUNCTION_BONUS_THRESHOLD = 200; + + @Override + public void parse(QueryContext queryCtx, ChatContext chatCtx) { + FunctionCallConfig functionCallConfig = ContextUtils.getBean(FunctionCallConfig.class); + PluginService pluginService = ContextUtils.getBean(PluginService.class); + String functionUrl = functionCallConfig.getUrl(); + + if (StringUtils.isBlank(functionUrl) || SatisfactionChecker.check(queryCtx)) { + log.info("functionUrl:{}, skip function parser, queryText:{}", functionUrl, + queryCtx.getRequest().getQueryText()); + return; + } + DomainResolver domainResolver = ComponentFactory.getDomainResolver(); + Long domainId = domainResolver.resolve(queryCtx, chatCtx); + List functionNames = getFunctionNames(domainId); + log.info("domainId:{},functionNames:{}", domainId, functionNames); + if (Objects.isNull(domainId) || domainId <= 0) { + return; + } + FunctionReq functionReq = FunctionReq.builder() + .queryText(queryCtx.getRequest().getQueryText()) + .functionNames(functionNames).build(); + + FunctionResp functionResp = requestFunction(functionUrl, functionReq); + log.info("requestFunction result:{}", functionResp.getToolSelection()); + if (Objects.isNull(functionResp) || StringUtils.isBlank(functionResp.getToolSelection())) { + return; + } + + PluginParseResult functionCallParseResult = new PluginParseResult(); + String toolSelection = functionResp.getToolSelection(); + Optional pluginOptional = pluginService.getPluginByName(toolSelection); + if (pluginOptional.isPresent()) { + toolSelection = pluginOptional.get().getType(); + functionCallParseResult.setPlugin(pluginOptional.get()); + } + PluginSemanticQuery semanticQuery = QueryManager.createPluginQuery(toolSelection); + + SemanticParseInfo parseInfo = semanticQuery.getParseInfo(); + parseInfo.getElementMatches().addAll(queryCtx.getMapInfo().getMatchedElements(domainId)); + functionCallParseResult.setRequest(queryCtx.getRequest()); + Map properties = new HashMap<>(); + properties.put(Constants.CONTEXT, functionCallParseResult); + parseInfo.setProperties(properties); + parseInfo.setBonus(FUNCTION_BONUS_THRESHOLD); + SchemaElement domain = new SchemaElement(); + domain.setDomain(domainId); + domain.setId(domainId); + parseInfo.setDomain(domain); + queryCtx.getCandidateQueries().add(semanticQuery); + } + + private List getFunctionNames(Long domainId) { + List plugins = PluginManager.getPlugins(); + Set functionNames = plugins.stream() + .filter(entry -> ParseMode.FUNCTION_CALL.equals(entry.getParseMode())) + .filter(entry -> { + if (!CollectionUtils.isEmpty(entry.getDomainList())) { + return entry.getDomainList().contains(domainId); + } + return true; + } + ).map(Plugin::getName).collect(Collectors.toSet()); + functionNames.add(DSLQuery.QUERY_MODE); + return new ArrayList<>(functionNames); + } + + public FunctionResp requestFunction(String url, FunctionReq functionReq) { + HttpHeaders headers = new HttpHeaders(); + long startTime = System.currentTimeMillis(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(JSON.toJSONString(functionReq), headers); + URI requestUrl = UriComponentsBuilder.fromHttpUrl(url).build().encode().toUri(); + RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); + try { + log.info("requestFunction functionReq:{}", functionReq); + ResponseEntity responseEntity = restTemplate.exchange(requestUrl, HttpMethod.POST, entity, + FunctionResp.class); + log.info("requestFunction responseEntity:{},cost:{}", responseEntity, + System.currentTimeMillis() - startTime); + return responseEntity.getBody(); + } catch (Exception e) { + log.error("requestFunction error", e); + } + return null; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionReq.java new file mode 100644 index 000000000..65c382cc0 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionReq.java @@ -0,0 +1,15 @@ +package com.tencent.supersonic.chat.parser.function; + +import java.util.List; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class FunctionReq { + + private String queryText; + + private List functionNames; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionResp.java new file mode 100644 index 000000000..f27021481 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionResp.java @@ -0,0 +1,10 @@ +package com.tencent.supersonic.chat.parser.function; + +import lombok.Data; + +@Data +public class FunctionResp { + + private String toolSelection; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/HeuristicDomainResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/HeuristicDomainResolver.java new file mode 100644 index 000000000..db7a486e1 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/HeuristicDomainResolver.java @@ -0,0 +1,166 @@ +package com.tencent.supersonic.chat.parser.function; + +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; + +@Slf4j +public class HeuristicDomainResolver implements DomainResolver { + + protected static Long selectDomainBySchemaElementCount(Map domainQueryModes, + SchemaMapInfo schemaMap) { + Map domainTypeMap = getDomainTypeMap(schemaMap); + if (domainTypeMap.size() == 1) { + Long domainSelect = domainTypeMap.entrySet().stream().collect(Collectors.toList()).get(0).getKey(); + if (domainQueryModes.containsKey(domainSelect)) { + log.info("selectDomain with only one domain [{}]", domainSelect); + return domainSelect; + } + } else { + Map.Entry maxDomain = domainTypeMap.entrySet().stream() + .filter(entry -> domainQueryModes.containsKey(entry.getKey())) + .sorted((o1, o2) -> { + int difference = o1.getValue().getCount() - o2.getValue().getCount(); + if (difference == 0) { + return (int) ((o1.getValue().getMaxSimilarity() + - o2.getValue().getMaxSimilarity()) * 100); + } + return difference; + }).findFirst().orElse(null); + if (maxDomain != null) { + log.info("selectDomain with multiple domains [{}]", maxDomain.getKey()); + return maxDomain.getKey(); + } + } + return 0L; + } + + /** + * to check can switch domain if context exit domain + * + * @return false will use context domain, true will use other domain , maybe include context domain + */ + protected static boolean isAllowSwitch(Map domainQueryModes, SchemaMapInfo schemaMap, + ChatContext chatCtx, QueryRequest searchCtx, Long domainId) { + if (!Objects.nonNull(domainId) || domainId <= 0) { + return true; + } + // except content domain, calculate the number of types for each domain, if numbers<=1 will not switch + Map domainTypeMap = getDomainTypeMap(schemaMap); + log.info("isAllowSwitch domainTypeMap [{}]", domainTypeMap); + long otherDomainTypeNumBigOneCount = domainTypeMap.entrySet().stream() + .filter(entry -> domainQueryModes.containsKey(entry.getKey()) && !entry.getKey().equals(domainId)) + .filter(entry -> entry.getValue().getCount() > 1).count(); + if (otherDomainTypeNumBigOneCount >= 1) { + return true; + } + // if query text only contain time , will not switch + if (!CollectionUtils.isEmpty(domainQueryModes.values())) { + for (SemanticQuery semanticQuery : domainQueryModes.values()) { + if (semanticQuery == null) { + continue; + } + SemanticParseInfo semanticParseInfo = semanticQuery.getParseInfo(); + if (semanticParseInfo == null) { + continue; + } + if (searchCtx.getQueryText() != null && semanticParseInfo.getDateInfo() != null) { + if (semanticParseInfo.getDateInfo().getText() != null) { + if (semanticParseInfo.getDateInfo().getText().equalsIgnoreCase(searchCtx.getQueryText())) { + log.info("timeParseResults is not null , can not switch context , timeParseResults:{},", + semanticParseInfo.getDateInfo()); + return false; + } + } + } + } + } + + // if context domain not in schemaMap , will switch + if (schemaMap.getMatchedElements(domainId) == null || schemaMap.getMatchedElements(domainId).size() <= 0) { + log.info("domainId not in schemaMap "); + return true; + } + // other will not switch + return false; + } + + public static Map getDomainTypeMap(SchemaMapInfo schemaMap) { + Map domainCount = new HashMap<>(); + for (Map.Entry> entry : schemaMap.getDomainElementMatches().entrySet()) { + List schemaElementMatches = schemaMap.getMatchedElements(entry.getKey()); + if (schemaElementMatches != null && schemaElementMatches.size() > 0) { + if (!domainCount.containsKey(entry.getKey())) { + domainCount.put(entry.getKey(), new DomainMatchResult()); + } + DomainMatchResult domainMatchResult = domainCount.get(entry.getKey()); + Set schemaElementTypes = new HashSet<>(); + schemaElementMatches.stream() + .forEach(schemaElementMatch -> schemaElementTypes.add( + schemaElementMatch.getElement().getType())); + SchemaElementMatch schemaElementMatchMax = schemaElementMatches.stream() + .sorted((o1, o2) -> + ((int) ((o2.getSimilarity() - o1.getSimilarity()) * 100)) + ).findFirst().orElse(null); + if (schemaElementMatchMax != null) { + domainMatchResult.setMaxSimilarity(schemaElementMatchMax.getSimilarity()); + } + domainMatchResult.setCount(schemaElementTypes.size()); + + } + } + return domainCount; + } + + + public Long resolve(QueryContext queryContext, ChatContext chatCtx) { + Long domainId = queryContext.getRequest().getDomainId(); + if (Objects.nonNull(domainId) && domainId > 0) { + return domainId; + } + SchemaMapInfo mapInfo = queryContext.getMapInfo(); + Set matchedDomains = mapInfo.getMatchedDomains(); + Map domainQueryModes = new HashMap<>(); + for (Long matchedDomain : matchedDomains) { + domainQueryModes.put(matchedDomain, null); + } + return resolve(domainQueryModes, queryContext, chatCtx, + queryContext.getMapInfo()); + } + + public Long resolve(Map domainQueryModes, QueryContext queryContext, + ChatContext chatCtx, SchemaMapInfo schemaMap) { + Long selectDomain = selectDomain(domainQueryModes, queryContext.getRequest(), chatCtx, schemaMap); + if (selectDomain > 0) { + log.info("selectDomain {} ", selectDomain); + return selectDomain; + } + // get the max SchemaElementType number + return selectDomainBySchemaElementCount(domainQueryModes, schemaMap); + } + + public Long selectDomain(Map domainQueryModes, QueryRequest queryContext, + ChatContext chatCtx, + SchemaMapInfo schemaMap) { + // if QueryContext has domainId and in domainQueryModes + if (domainQueryModes.containsKey(queryContext.getDomainId())) { + log.info("selectDomain from QueryContext [{}]", queryContext.getDomainId()); + return queryContext.getDomainId(); + } + // if ChatContext has domainId and in domainQueryModes + if (chatCtx.getParseInfo().getDomainId() > 0) { + Long domainId = chatCtx.getParseInfo().getDomainId(); + if (!isAllowSwitch(domainQueryModes, schemaMap, chatCtx, queryContext, domainId)) { + log.info("selectDomain from ChatContext [{}]", domainId); + return domainId; + } + } + // default 0 + return 0L; + } +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/AggregateTypeParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/AggregateTypeParser.java new file mode 100644 index 000000000..9302ab920 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/AggregateTypeParser.java @@ -0,0 +1,64 @@ +package com.tencent.supersonic.chat.parser.rule; + +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.tencent.supersonic.common.util.JsonUtil; +import lombok.extern.slf4j.Slf4j; + +import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.*; + +@Slf4j +public class AggregateTypeParser implements SemanticParser { + + private static final Map REGX_MAP = Stream.of( + new AbstractMap.SimpleEntry<>(MAX, Pattern.compile("(?i)(最大值|最大|max|峰值|最高|最多)")), + new AbstractMap.SimpleEntry<>(MIN, Pattern.compile("(?i)(最小值|最小|min|最低|最少)")), + new AbstractMap.SimpleEntry<>(SUM, Pattern.compile("(?i)(汇总|总和|sum)")), + new AbstractMap.SimpleEntry<>(AVG, Pattern.compile("(?i)(平均值|日均|平均|avg)")), + new AbstractMap.SimpleEntry<>(TOPN, Pattern.compile("(?i)(top)")), + new AbstractMap.SimpleEntry<>(DISTINCT, Pattern.compile("(?i)(uv)")), + new AbstractMap.SimpleEntry<>(COUNT, Pattern.compile("(?i)(总数|pv)")), + new AbstractMap.SimpleEntry<>(NONE, Pattern.compile("(?i)(明细)")) + ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + @Override + public void parse(QueryContext queryContext, ChatContext chatContext) { + for (SemanticQuery semanticQuery : queryContext.getCandidateQueries()) { + if (!AggregateTypeEnum.NONE.equals(semanticQuery.getParseInfo().getAggType())) { + continue; + } + + String queryText = queryContext.getRequest().getQueryText(); + semanticQuery.getParseInfo().setAggType(resolveAggregateType(queryText)); + } + } + + public static AggregateTypeEnum resolveAggregateType(String queryText) { + Map aggregateCount = new HashMap<>(REGX_MAP.size()); + + for (Map.Entry entry : REGX_MAP.entrySet()) { + Matcher matcher = entry.getValue().matcher(queryText); + int count = 0; + while (matcher.find()) { + count++; + } + if (count > 0) { + aggregateCount.put(entry.getKey(), count); + } + } + + return aggregateCount.entrySet().stream().max(Map.Entry.comparingByValue()) + .map(entry -> entry.getKey()).orElse(NONE); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/ContextInheritParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/ContextInheritParser.java new file mode 100644 index 000000000..073a4906c --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/ContextInheritParser.java @@ -0,0 +1,78 @@ +package com.tencent.supersonic.chat.parser.rule; + +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.query.rule.metric.MetricDomainQuery; +import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; +import com.tencent.supersonic.common.util.JsonUtil; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; + +@Slf4j +public class ContextInheritParser implements SemanticParser { + + private static final Map> MUTUAL_EXCLUSIVE_MAP = Stream.of( + new AbstractMap.SimpleEntry<>(METRIC, Arrays.asList(METRIC)), + new AbstractMap.SimpleEntry<>(DIMENSION, Arrays.asList(DIMENSION, VALUE)), + new AbstractMap.SimpleEntry<>(VALUE, Arrays.asList(VALUE, DIMENSION)), + new AbstractMap.SimpleEntry<>(ENTITY, Arrays.asList(ENTITY)), + new AbstractMap.SimpleEntry<>(DOMAIN, Arrays.asList(DOMAIN)) + ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + @Override + public void parse(QueryContext queryContext, ChatContext chatContext) { + if (!shouldInherit(queryContext, chatContext)) { + return; + } + + Long domainId = chatContext.getParseInfo().getDomainId(); + List elementMatches = queryContext.getMapInfo() + .getMatchedElements(domainId); + + List matchesToInherit = new ArrayList<>(); + for (SchemaElementMatch match : chatContext.getParseInfo().getElementMatches()) { + SchemaElementType matchType = match.getElement().getType(); + // mutual exclusive element types should not be inherited + if (!containsTypes(elementMatches, MUTUAL_EXCLUSIVE_MAP.get(matchType))) { + matchesToInherit.add(match); + } + } + elementMatches.addAll(matchesToInherit); + + List queries = RuleSemanticQuery.resolve(elementMatches, queryContext); + for (RuleSemanticQuery query : queries) { + query.fillParseInfo(domainId, chatContext); + queryContext.getCandidateQueries().add(query); + } + } + + private boolean containsTypes(List matches, List types) { + return matches.stream().anyMatch(m -> types.contains(m.getElement().getType())); + } + + protected boolean shouldInherit(QueryContext queryContext, ChatContext chatContext) { + if (queryContext.getMapInfo().getMatchedElements( + chatContext.getParseInfo().getDomainId()) == null) { + return false; + } + + // if candidates have only one MetricDomain mode and context has value filter , count in context + if (queryContext.getCandidateQueries().size() == 1 && (queryContext.getCandidateQueries() + .get(0) instanceof MetricDomainQuery) + && queryContext.getCandidateQueries().get(0).getParseInfo().getDomainId() + .equals(chatContext.getParseInfo().getDomainId()) + && !CollectionUtils.isEmpty(chatContext.getParseInfo().getDimensionFilters())) { + return true; + } else { + return queryContext.getCandidateQueries().size() == 0; + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/QueryModeParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/QueryModeParser.java new file mode 100644 index 000000000..af1d7e0f8 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/QueryModeParser.java @@ -0,0 +1,31 @@ +package com.tencent.supersonic.chat.parser.rule; + +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; + +import java.util.*; + +import com.tencent.supersonic.common.util.JsonUtil; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class QueryModeParser implements SemanticParser { + + @Override + public void parse(QueryContext queryContext, ChatContext chatContext) { + SchemaMapInfo mapInfo = queryContext.getMapInfo(); + + // iterate all schemaElementMatches to resolve semantic query + for (Long domainId : mapInfo.getMatchedDomains()) { + List elementMatches = mapInfo.getMatchedElements(domainId); + List queries = RuleSemanticQuery.resolve(elementMatches, queryContext); + + for (RuleSemanticQuery query : queries) { + query.fillParseInfo(domainId, chatContext); + queryContext.getCandidateQueries().add(query); + } + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/TimeRangeParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/TimeRangeParser.java new file mode 100644 index 000000000..fec43ee27 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/TimeRangeParser.java @@ -0,0 +1,188 @@ +package com.tencent.supersonic.chat.parser.rule; + +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.DateConf; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.xkzhangsan.time.nlp.TimeNLP; +import com.xkzhangsan.time.nlp.TimeNLPUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; + +@Slf4j +public class TimeRangeParser implements SemanticParser { + + private static final Pattern RECENT_PATTERN_CN = Pattern.compile( + ".*(?(近|过去)((?\\d+)|(?[一二三四五六七八九十百千万亿]+))个?(?[天周月年])).*"); + private static final Pattern DATE_PATTERN_NUMBER = Pattern.compile("(\\d{8})"); + private static final DateFormat DATE_FORMAT_NUMBER = new SimpleDateFormat("yyyyMMdd"); + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + @Override + public void parse(QueryContext queryContext, ChatContext chatContext) { + DateConf dateConf = parseRecent(queryContext.getRequest().getQueryText()); + if (dateConf == null) { + dateConf = parseDateNumber(queryContext.getRequest().getQueryText()); + } + if (dateConf == null) { + dateConf = parseDateCN(queryContext.getRequest().getQueryText()); + } + + if (dateConf != null) { + if (queryContext.getCandidateQueries().size() > 0) { + for (SemanticQuery query : queryContext.getCandidateQueries()) { + query.getParseInfo().setDateInfo(dateConf); + } + } else if(QueryManager.containsRuleQuery(chatContext.getParseInfo().getQueryMode())) { + RuleSemanticQuery semanticQuery = QueryManager.createRuleQuery( + chatContext.getParseInfo().getQueryMode()); + // inherit parse info from context + chatContext.getParseInfo().setDateInfo(dateConf); + semanticQuery.setParseInfo(chatContext.getParseInfo()); + queryContext.getCandidateQueries().add(semanticQuery); + } + } + } + + private DateConf parseDateCN(String queryText) { + Date startDate = null; + Date endDate; + + List times = TimeNLPUtil.parse(queryText); + if (times.size() > 0) { + startDate = times.get(0).getTime(); + }else { + return null; + } + + if (times.size() > 1) { + endDate = times.get(1).getTime(); + } else { + endDate = startDate; + } + + return getDateConf(startDate, endDate); + } + + private DateConf parseDateNumber(String queryText) { + String startDate; + String endDate = null; + + Matcher dateMatcher = DATE_PATTERN_NUMBER.matcher(queryText); + if (dateMatcher.find()) { + startDate = dateMatcher.group(); + } else { + return null; + } + if (dateMatcher.find()) { + endDate = dateMatcher.group(); + } + + endDate = endDate != null ? endDate : startDate; + + try { + return getDateConf(DATE_FORMAT_NUMBER.parse(startDate), DATE_FORMAT_NUMBER.parse(endDate)); + } catch (ParseException e) { + return null; + } + } + + private DateConf parseRecent(String queryText) { + Matcher m = RECENT_PATTERN_CN.matcher(queryText); + if (m.matches()) { + int num = 0; + String enNum = m.group("enNum"); + String zhNum = m.group("zhNum"); + if (enNum != null) { + num = Integer.parseInt(enNum); + } else if (zhNum != null) { + num = zhNumParse(zhNum); + } + if (num > 0) { + DateConf info = new DateConf(); + String zhPeriod = m.group("zhPeriod"); + int days; + switch (zhPeriod) { + case "周": + days = 7; + info.setPeriod(Constants.WEEK); + break; + case "月": + days = 30; + info.setPeriod(Constants.MONTH); + break; + case "年": + days = 365; + info.setPeriod(Constants.YEAR); + break; + default: + days = 1; + info.setPeriod(Constants.DAY); + } + days = days * num; + info.setDateMode(DateConf.DateMode.RECENT_UNITS); + String text = "近" + num + zhPeriod; + if (Strings.isNotEmpty(m.group("periodStr"))) { + text = m.group("periodStr"); + } + info.setText(text); + info.setStartDate(LocalDate.now().minusDays(days).toString()); + info.setUnit(num); + + return info; + } + } + + return null; + } + + private int zhNumParse(String zhNumStr) { + Stack stack = new Stack<>(); + String numStr = "一二三四五六七八九"; + String unitStr = "十百千万亿"; + + String[] ssArr = zhNumStr.split(""); + for (String e : ssArr) { + int numIndex = numStr.indexOf(e); + int unitIndex = unitStr.indexOf(e); + if (numIndex != -1) { + stack.push(numIndex + 1); + } else if (unitIndex != -1) { + int unitNum = (int) Math.pow(10, unitIndex + 1); + if (stack.isEmpty()) { + stack.push(unitNum); + } else { + stack.push(stack.pop() * unitNum); + } + } + } + + return stack.stream().mapToInt(s -> s).sum(); + } + + private DateConf getDateConf(Date startDate, Date endDate) { + if (startDate == null || endDate == null) { + return null; + } + + DateConf info = new DateConf(); + info.setDateMode(DateConf.DateMode.BETWEEN_CONTINUOUS); + info.setStartDate(DATE_FORMAT.format(startDate)); + info.setEndDate(DATE_FORMAT.format(endDate)); + return info; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatConfigDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatConfigDO.java similarity index 82% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatConfigDO.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatConfigDO.java index e8d700a20..25d5b526c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatConfigDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatConfigDO.java @@ -1,6 +1,7 @@ -package com.tencent.supersonic.chat.domain.dataobject; +package com.tencent.supersonic.chat.persistence.dataobject; import java.util.Date; + import lombok.Data; import lombok.ToString; @@ -20,6 +21,8 @@ public class ChatConfigDO { private String chatAggConfig; + private String recommendedQuestions; + private Integer status; /** diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatContextDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatContextDO.java similarity index 82% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatContextDO.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatContextDO.java index bb3db6dcf..7d9027485 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatContextDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatContextDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.dataobject; +package com.tencent.supersonic.chat.persistence.dataobject; import java.io.Serializable; import java.time.Instant; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatDO.java similarity index 82% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatDO.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatDO.java index 597302a56..fa1af2c11 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.dataobject; +package com.tencent.supersonic.chat.persistence.dataobject; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDO.java similarity index 89% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDO.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDO.java index c8dd559ce..600f8b87e 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.dataobject; +package com.tencent.supersonic.chat.persistence.dataobject; import java.util.Date; @@ -48,7 +48,7 @@ public class ChatQueryDO { /** * queryResponse */ - private String queryResponse; + private String queryResult; /** * return question_id @@ -165,14 +165,14 @@ public class ChatQueryDO { /** * return query_response */ - public String getQueryResponse() { - return queryResponse; + public String getQueryResult() { + return queryResult; } /** * queryResponse */ - public void setQueryResponse(String queryResponse) { - this.queryResponse = queryResponse == null ? null : queryResponse.trim(); + public void setQueryResult(String queryResult) { + this.queryResult = queryResult == null ? null : queryResult.trim(); } } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDOExample.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDOExample.java similarity index 99% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDOExample.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDOExample.java index 99d6cd109..836e6db25 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDOExample.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.dataobject; +package com.tencent.supersonic.chat.persistence.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/DimValueDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/DimValueDO.java similarity index 79% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/DimValueDO.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/DimValueDO.java index d81305cab..99e570d2c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/DimValueDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/DimValueDO.java @@ -1,10 +1,11 @@ -package com.tencent.supersonic.chat.domain.dataobject; +package com.tencent.supersonic.chat.persistence.dataobject; -import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric; -import com.tencent.supersonic.chat.domain.pojo.config.Dim4Dict; import java.util.ArrayList; import java.util.List; + +import com.tencent.supersonic.chat.config.DefaultMetric; +import com.tencent.supersonic.chat.config.Dim4Dict; import lombok.Data; import lombok.ToString; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/PluginDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/PluginDO.java new file mode 100644 index 000000000..30e6a60bf --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/PluginDO.java @@ -0,0 +1,236 @@ +package com.tencent.supersonic.chat.persistence.dataobject; + +import java.util.Date; + +public class PluginDO { + /** + * + */ + private Long id; + + /** + * DASHBOARD,WIDGET,URL + */ + private String type; + + /** + * + */ + private String domain; + + /** + * + */ + private String pattern; + + /** + * + */ + private String parseMode; + + /** + * + */ + private String name; + + /** + * + */ + private Date createdAt; + + /** + * + */ + private String createdBy; + + /** + * + */ + private Date updatedAt; + + /** + * + */ + private String updatedBy; + + /** + * + */ + private String config; + + /** + * + * @return id + */ + public Long getId() { + return id; + } + + /** + * + * @param id + */ + public void setId(Long id) { + this.id = id; + } + + /** + * DASHBOARD,WIDGET,URL + * @return type DASHBOARD,WIDGET,URL + */ + public String getType() { + return type; + } + + /** + * DASHBOARD,WIDGET,URL + * @param type DASHBOARD,WIDGET,URL + */ + public void setType(String type) { + this.type = type == null ? null : type.trim(); + } + + /** + * + * @return domain + */ + public String getDomain() { + return domain; + } + + /** + * + * @param domain + */ + public void setDomain(String domain) { + this.domain = domain == null ? null : domain.trim(); + } + + /** + * + * @return pattern + */ + public String getPattern() { + return pattern; + } + + /** + * + * @param pattern + */ + public void setPattern(String pattern) { + this.pattern = pattern == null ? null : pattern.trim(); + } + + /** + * + * @return parse_mode + */ + public String getParseMode() { + return parseMode; + } + + /** + * + * @param parseMode + */ + public void setParseMode(String parseMode) { + this.parseMode = parseMode == null ? null : parseMode.trim(); + } + + /** + * + * @return name + */ + public String getName() { + return name; + } + + /** + * + * @param name + */ + public void setName(String name) { + this.name = name == null ? null : name.trim(); + } + + /** + * + * @return created_at + */ + public Date getCreatedAt() { + return createdAt; + } + + /** + * + * @param createdAt + */ + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + /** + * + * @return created_by + */ + public String getCreatedBy() { + return createdBy; + } + + /** + * + * @param createdBy + */ + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy == null ? null : createdBy.trim(); + } + + /** + * + * @return updated_at + */ + public Date getUpdatedAt() { + return updatedAt; + } + + /** + * + * @param updatedAt + */ + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + /** + * + * @return updated_by + */ + public String getUpdatedBy() { + return updatedBy; + } + + /** + * + * @param updatedBy + */ + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy == null ? null : updatedBy.trim(); + } + + /** + * + * @return config + */ + public String getConfig() { + return config; + } + + /** + * + * @param config + */ + public void setConfig(String config) { + this.config = config == null ? null : config.trim(); + } +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/PluginDOExample.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/PluginDOExample.java new file mode 100644 index 000000000..e2c316a84 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/PluginDOExample.java @@ -0,0 +1,975 @@ +package com.tencent.supersonic.chat.persistence.dataobject; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class PluginDOExample { + /** + * s2_plugin + */ + protected String orderByClause; + + /** + * s2_plugin + */ + protected boolean distinct; + + /** + * s2_plugin + */ + protected List oredCriteria; + + /** + * s2_plugin + */ + protected Integer limitStart; + + /** + * s2_plugin + */ + protected Integer limitEnd; + + /** + * + * @mbg.generated + */ + public PluginDOExample() { + oredCriteria = new ArrayList(); + } + + /** + * + * @mbg.generated + */ + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; + } + + /** + * + * @mbg.generated + */ + public String getOrderByClause() { + return orderByClause; + } + + /** + * + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + + /** + * + * @mbg.generated + */ + public boolean isDistinct() { + return distinct; + } + + /** + * + * @mbg.generated + */ + public List getOredCriteria() { + return oredCriteria; + } + + /** + * + * @mbg.generated + */ + public void or(Criteria criteria) { + oredCriteria.add(criteria); + } + + /** + * + * @mbg.generated + */ + public Criteria or() { + Criteria criteria = createCriteriaInternal(); + oredCriteria.add(criteria); + return criteria; + } + + /** + * + * @mbg.generated + */ + public Criteria createCriteria() { + Criteria criteria = createCriteriaInternal(); + if (oredCriteria.size() == 0) { + oredCriteria.add(criteria); + } + return criteria; + } + + /** + * + * @mbg.generated + */ + protected Criteria createCriteriaInternal() { + Criteria criteria = new Criteria(); + return criteria; + } + + /** + * + * @mbg.generated + */ + public void clear() { + oredCriteria.clear(); + orderByClause = null; + distinct = false; + } + + /** + * + * @mbg.generated + */ + public void setLimitStart(Integer limitStart) { + this.limitStart=limitStart; + } + + /** + * + * @mbg.generated + */ + public Integer getLimitStart() { + return limitStart; + } + + /** + * + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd=limitEnd; + } + + /** + * + * @mbg.generated + */ + public Integer getLimitEnd() { + return limitEnd; + } + + /** + * s2_plugin null + */ + protected abstract static class GeneratedCriteria { + protected List criteria; + + protected GeneratedCriteria() { + super(); + criteria = new ArrayList(); + } + + public boolean isValid() { + return criteria.size() > 0; + } + + public List getAllCriteria() { + return criteria; + } + + public List getCriteria() { + return criteria; + } + + protected void addCriterion(String condition) { + if (condition == null) { + throw new RuntimeException("Value for condition cannot be null"); + } + criteria.add(new Criterion(condition)); + } + + protected void addCriterion(String condition, Object value, String property) { + if (value == null) { + throw new RuntimeException("Value for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value)); + } + + protected void addCriterion(String condition, Object value1, Object value2, String property) { + if (value1 == null || value2 == null) { + throw new RuntimeException("Between values for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value1, value2)); + } + + public Criteria andIdIsNull() { + addCriterion("id is null"); + return (Criteria) this; + } + + public Criteria andIdIsNotNull() { + addCriterion("id is not null"); + return (Criteria) this; + } + + public Criteria andIdEqualTo(Long value) { + addCriterion("id =", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotEqualTo(Long value) { + addCriterion("id <>", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThan(Long value) { + addCriterion("id >", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThanOrEqualTo(Long value) { + addCriterion("id >=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThan(Long value) { + addCriterion("id <", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThanOrEqualTo(Long value) { + addCriterion("id <=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdIn(List values) { + addCriterion("id in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdNotIn(List values) { + addCriterion("id not in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdBetween(Long value1, Long value2) { + addCriterion("id between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andIdNotBetween(Long value1, Long value2) { + addCriterion("id not between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andTypeIsNull() { + addCriterion("type is null"); + return (Criteria) this; + } + + public Criteria andTypeIsNotNull() { + addCriterion("type is not null"); + return (Criteria) this; + } + + public Criteria andTypeEqualTo(String value) { + addCriterion("type =", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotEqualTo(String value) { + addCriterion("type <>", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeGreaterThan(String value) { + addCriterion("type >", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeGreaterThanOrEqualTo(String value) { + addCriterion("type >=", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLessThan(String value) { + addCriterion("type <", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLessThanOrEqualTo(String value) { + addCriterion("type <=", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLike(String value) { + addCriterion("type like", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotLike(String value) { + addCriterion("type not like", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeIn(List values) { + addCriterion("type in", values, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotIn(List values) { + addCriterion("type not in", values, "type"); + return (Criteria) this; + } + + public Criteria andTypeBetween(String value1, String value2) { + addCriterion("type between", value1, value2, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotBetween(String value1, String value2) { + addCriterion("type not between", value1, value2, "type"); + return (Criteria) this; + } + + public Criteria andDomainIsNull() { + addCriterion("domain is null"); + return (Criteria) this; + } + + public Criteria andDomainIsNotNull() { + addCriterion("domain is not null"); + return (Criteria) this; + } + + public Criteria andDomainEqualTo(String value) { + addCriterion("domain =", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainNotEqualTo(String value) { + addCriterion("domain <>", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainGreaterThan(String value) { + addCriterion("domain >", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainGreaterThanOrEqualTo(String value) { + addCriterion("domain >=", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainLessThan(String value) { + addCriterion("domain <", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainLessThanOrEqualTo(String value) { + addCriterion("domain <=", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainLike(String value) { + addCriterion("domain like", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainNotLike(String value) { + addCriterion("domain not like", value, "domain"); + return (Criteria) this; + } + + public Criteria andDomainIn(List values) { + addCriterion("domain in", values, "domain"); + return (Criteria) this; + } + + public Criteria andDomainNotIn(List values) { + addCriterion("domain not in", values, "domain"); + return (Criteria) this; + } + + public Criteria andDomainBetween(String value1, String value2) { + addCriterion("domain between", value1, value2, "domain"); + return (Criteria) this; + } + + public Criteria andDomainNotBetween(String value1, String value2) { + addCriterion("domain not between", value1, value2, "domain"); + return (Criteria) this; + } + + public Criteria andPatternIsNull() { + addCriterion("pattern is null"); + return (Criteria) this; + } + + public Criteria andPatternIsNotNull() { + addCriterion("pattern is not null"); + return (Criteria) this; + } + + public Criteria andPatternEqualTo(String value) { + addCriterion("pattern =", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternNotEqualTo(String value) { + addCriterion("pattern <>", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternGreaterThan(String value) { + addCriterion("pattern >", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternGreaterThanOrEqualTo(String value) { + addCriterion("pattern >=", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternLessThan(String value) { + addCriterion("pattern <", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternLessThanOrEqualTo(String value) { + addCriterion("pattern <=", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternLike(String value) { + addCriterion("pattern like", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternNotLike(String value) { + addCriterion("pattern not like", value, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternIn(List values) { + addCriterion("pattern in", values, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternNotIn(List values) { + addCriterion("pattern not in", values, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternBetween(String value1, String value2) { + addCriterion("pattern between", value1, value2, "pattern"); + return (Criteria) this; + } + + public Criteria andPatternNotBetween(String value1, String value2) { + addCriterion("pattern not between", value1, value2, "pattern"); + return (Criteria) this; + } + + public Criteria andParseModeIsNull() { + addCriterion("parse_mode is null"); + return (Criteria) this; + } + + public Criteria andParseModeIsNotNull() { + addCriterion("parse_mode is not null"); + return (Criteria) this; + } + + public Criteria andParseModeEqualTo(String value) { + addCriterion("parse_mode =", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeNotEqualTo(String value) { + addCriterion("parse_mode <>", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeGreaterThan(String value) { + addCriterion("parse_mode >", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeGreaterThanOrEqualTo(String value) { + addCriterion("parse_mode >=", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeLessThan(String value) { + addCriterion("parse_mode <", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeLessThanOrEqualTo(String value) { + addCriterion("parse_mode <=", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeLike(String value) { + addCriterion("parse_mode like", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeNotLike(String value) { + addCriterion("parse_mode not like", value, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeIn(List values) { + addCriterion("parse_mode in", values, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeNotIn(List values) { + addCriterion("parse_mode not in", values, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeBetween(String value1, String value2) { + addCriterion("parse_mode between", value1, value2, "parseMode"); + return (Criteria) this; + } + + public Criteria andParseModeNotBetween(String value1, String value2) { + addCriterion("parse_mode not between", value1, value2, "parseMode"); + return (Criteria) this; + } + + public Criteria andNameIsNull() { + addCriterion("name is null"); + return (Criteria) this; + } + + public Criteria andNameIsNotNull() { + addCriterion("name is not null"); + return (Criteria) this; + } + + public Criteria andNameEqualTo(String value) { + addCriterion("name =", value, "name"); + return (Criteria) this; + } + + public Criteria andNameNotEqualTo(String value) { + addCriterion("name <>", value, "name"); + return (Criteria) this; + } + + public Criteria andNameGreaterThan(String value) { + addCriterion("name >", value, "name"); + return (Criteria) this; + } + + public Criteria andNameGreaterThanOrEqualTo(String value) { + addCriterion("name >=", value, "name"); + return (Criteria) this; + } + + public Criteria andNameLessThan(String value) { + addCriterion("name <", value, "name"); + return (Criteria) this; + } + + public Criteria andNameLessThanOrEqualTo(String value) { + addCriterion("name <=", value, "name"); + return (Criteria) this; + } + + public Criteria andNameLike(String value) { + addCriterion("name like", value, "name"); + return (Criteria) this; + } + + public Criteria andNameNotLike(String value) { + addCriterion("name not like", value, "name"); + return (Criteria) this; + } + + public Criteria andNameIn(List values) { + addCriterion("name in", values, "name"); + return (Criteria) this; + } + + public Criteria andNameNotIn(List values) { + addCriterion("name not in", values, "name"); + return (Criteria) this; + } + + public Criteria andNameBetween(String value1, String value2) { + addCriterion("name between", value1, value2, "name"); + return (Criteria) this; + } + + public Criteria andNameNotBetween(String value1, String value2) { + addCriterion("name not between", value1, value2, "name"); + return (Criteria) this; + } + + public Criteria andCreatedAtIsNull() { + addCriterion("created_at is null"); + return (Criteria) this; + } + + public Criteria andCreatedAtIsNotNull() { + addCriterion("created_at is not null"); + return (Criteria) this; + } + + public Criteria andCreatedAtEqualTo(Date value) { + addCriterion("created_at =", value, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtNotEqualTo(Date value) { + addCriterion("created_at <>", value, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtGreaterThan(Date value) { + addCriterion("created_at >", value, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtGreaterThanOrEqualTo(Date value) { + addCriterion("created_at >=", value, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtLessThan(Date value) { + addCriterion("created_at <", value, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtLessThanOrEqualTo(Date value) { + addCriterion("created_at <=", value, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtIn(List values) { + addCriterion("created_at in", values, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtNotIn(List values) { + addCriterion("created_at not in", values, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtBetween(Date value1, Date value2) { + addCriterion("created_at between", value1, value2, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedAtNotBetween(Date value1, Date value2) { + addCriterion("created_at not between", value1, value2, "createdAt"); + return (Criteria) this; + } + + public Criteria andCreatedByIsNull() { + addCriterion("created_by is null"); + return (Criteria) this; + } + + public Criteria andCreatedByIsNotNull() { + addCriterion("created_by is not null"); + return (Criteria) this; + } + + public Criteria andCreatedByEqualTo(String value) { + addCriterion("created_by =", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByNotEqualTo(String value) { + addCriterion("created_by <>", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByGreaterThan(String value) { + addCriterion("created_by >", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByGreaterThanOrEqualTo(String value) { + addCriterion("created_by >=", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByLessThan(String value) { + addCriterion("created_by <", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByLessThanOrEqualTo(String value) { + addCriterion("created_by <=", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByLike(String value) { + addCriterion("created_by like", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByNotLike(String value) { + addCriterion("created_by not like", value, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByIn(List values) { + addCriterion("created_by in", values, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByNotIn(List values) { + addCriterion("created_by not in", values, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByBetween(String value1, String value2) { + addCriterion("created_by between", value1, value2, "createdBy"); + return (Criteria) this; + } + + public Criteria andCreatedByNotBetween(String value1, String value2) { + addCriterion("created_by not between", value1, value2, "createdBy"); + return (Criteria) this; + } + + public Criteria andUpdatedAtIsNull() { + addCriterion("updated_at is null"); + return (Criteria) this; + } + + public Criteria andUpdatedAtIsNotNull() { + addCriterion("updated_at is not null"); + return (Criteria) this; + } + + public Criteria andUpdatedAtEqualTo(Date value) { + addCriterion("updated_at =", value, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtNotEqualTo(Date value) { + addCriterion("updated_at <>", value, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtGreaterThan(Date value) { + addCriterion("updated_at >", value, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtGreaterThanOrEqualTo(Date value) { + addCriterion("updated_at >=", value, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtLessThan(Date value) { + addCriterion("updated_at <", value, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtLessThanOrEqualTo(Date value) { + addCriterion("updated_at <=", value, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtIn(List values) { + addCriterion("updated_at in", values, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtNotIn(List values) { + addCriterion("updated_at not in", values, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtBetween(Date value1, Date value2) { + addCriterion("updated_at between", value1, value2, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedAtNotBetween(Date value1, Date value2) { + addCriterion("updated_at not between", value1, value2, "updatedAt"); + return (Criteria) this; + } + + public Criteria andUpdatedByIsNull() { + addCriterion("updated_by is null"); + return (Criteria) this; + } + + public Criteria andUpdatedByIsNotNull() { + addCriterion("updated_by is not null"); + return (Criteria) this; + } + + public Criteria andUpdatedByEqualTo(String value) { + addCriterion("updated_by =", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByNotEqualTo(String value) { + addCriterion("updated_by <>", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByGreaterThan(String value) { + addCriterion("updated_by >", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByGreaterThanOrEqualTo(String value) { + addCriterion("updated_by >=", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByLessThan(String value) { + addCriterion("updated_by <", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByLessThanOrEqualTo(String value) { + addCriterion("updated_by <=", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByLike(String value) { + addCriterion("updated_by like", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByNotLike(String value) { + addCriterion("updated_by not like", value, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByIn(List values) { + addCriterion("updated_by in", values, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByNotIn(List values) { + addCriterion("updated_by not in", values, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByBetween(String value1, String value2) { + addCriterion("updated_by between", value1, value2, "updatedBy"); + return (Criteria) this; + } + + public Criteria andUpdatedByNotBetween(String value1, String value2) { + addCriterion("updated_by not between", value1, value2, "updatedBy"); + return (Criteria) this; + } + } + + /** + * s2_plugin + */ + public static class Criteria extends GeneratedCriteria { + + protected Criteria() { + super(); + } + } + + /** + * s2_plugin null + */ + public static class Criterion { + private String condition; + + private Object value; + + private Object secondValue; + + private boolean noValue; + + private boolean singleValue; + + private boolean betweenValue; + + private boolean listValue; + + private String typeHandler; + + public String getCondition() { + return condition; + } + + public Object getValue() { + return value; + } + + public Object getSecondValue() { + return secondValue; + } + + public boolean isNoValue() { + return noValue; + } + + public boolean isSingleValue() { + return singleValue; + } + + public boolean isBetweenValue() { + return betweenValue; + } + + public boolean isListValue() { + return listValue; + } + + public String getTypeHandler() { + return typeHandler; + } + + protected Criterion(String condition) { + super(); + this.condition = condition; + this.typeHandler = null; + this.noValue = true; + } + + protected Criterion(String condition, Object value, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.typeHandler = typeHandler; + if (value instanceof List) { + this.listValue = true; + } else { + this.singleValue = true; + } + } + + protected Criterion(String condition, Object value) { + this(condition, value, null); + } + + protected Criterion(String condition, Object value, Object secondValue, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.secondValue = secondValue; + this.typeHandler = typeHandler; + this.betweenValue = true; + } + + protected Criterion(String condition, Object value, Object secondValue) { + this(condition, value, secondValue, null); + } + } +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/QueryDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/QueryDO.java similarity index 92% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/QueryDO.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/QueryDO.java index 4564714b0..4f9dc0eec 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/QueryDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/QueryDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.dataobject; +package com.tencent.supersonic.chat.persistence.dataobject; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatConfigMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatConfigMapper.java similarity index 62% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatConfigMapper.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatConfigMapper.java index 4e4583725..6b3c6802c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatConfigMapper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatConfigMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.chat.infrastructure.mapper; +package com.tencent.supersonic.chat.persistence.mapper; -import com.tencent.supersonic.chat.domain.dataobject.ChatConfigDO; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilterInternal; +import com.tencent.supersonic.chat.config.ChatConfigFilterInternal; +import com.tencent.supersonic.chat.persistence.dataobject.ChatConfigDO; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatContextMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatContextMapper.java similarity index 65% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatContextMapper.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatContextMapper.java index 5a37fdba2..391ab3b76 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatContextMapper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatContextMapper.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.chat.infrastructure.mapper; +package com.tencent.supersonic.chat.persistence.mapper; -import com.tencent.supersonic.chat.domain.dataobject.ChatContextDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatContextDO; import org.apache.ibatis.annotations.Mapper; @Mapper diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatMapper.java similarity index 65% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatMapper.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatMapper.java index 5c7627158..870ac6076 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatMapper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.chat.infrastructure.mapper; +package com.tencent.supersonic.chat.persistence.mapper; -import com.tencent.supersonic.chat.domain.dataobject.ChatDO; -import com.tencent.supersonic.chat.domain.dataobject.QueryDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.persistence.dataobject.QueryDO; import java.util.List; import org.apache.ibatis.annotations.Mapper; @@ -12,8 +12,6 @@ public interface ChatMapper { List getAll(String creator); - List queryInfo(String userName, long chatId); - Boolean updateChatName(Long chatId, String chatName, String lastTime, String creator); Boolean updateLastQuestion(Long chatId, String lastQuestion, String lastTime); @@ -24,5 +22,4 @@ public interface ChatMapper { Boolean deleteChat(Long chatId, String userName); - Long createQuery(QueryDO queryDO); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatQueryDOMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatQueryDOMapper.java new file mode 100644 index 000000000..8eb2f1b98 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatQueryDOMapper.java @@ -0,0 +1,18 @@ +package com.tencent.supersonic.chat.persistence.mapper; + +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDOExample; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface ChatQueryDOMapper { + + int insert(ChatQueryDO record); + + List selectByExampleWithBLOBs(ChatQueryDOExample example); + + int updateByPrimaryKeyWithBLOBs(ChatQueryDO record); + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/PluginDOMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/PluginDOMapper.java new file mode 100644 index 000000000..426be06d8 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/PluginDOMapper.java @@ -0,0 +1,70 @@ +package com.tencent.supersonic.chat.persistence.mapper; + + +import com.tencent.supersonic.chat.persistence.dataobject.PluginDO; +import com.tencent.supersonic.chat.persistence.dataobject.PluginDOExample; +import org.apache.ibatis.annotations.Mapper; +import java.util.List; + +@Mapper +public interface PluginDOMapper { + /** + * + * @mbg.generated + */ + long countByExample(PluginDOExample example); + + /** + * + * @mbg.generated + */ + int deleteByPrimaryKey(Long id); + + /** + * + * @mbg.generated + */ + int insert(PluginDO record); + + /** + * + * @mbg.generated + */ + int insertSelective(PluginDO record); + + /** + * + * @mbg.generated + */ + List selectByExampleWithBLOBs(PluginDOExample example); + + /** + * + * @mbg.generated + */ + List selectByExample(PluginDOExample example); + + /** + * + * @mbg.generated + */ + PluginDO selectByPrimaryKey(Long id); + + /** + * + * @mbg.generated + */ + int updateByPrimaryKeySelective(PluginDO record); + + /** + * + * @mbg.generated + */ + int updateByPrimaryKeyWithBLOBs(PluginDO record); + + /** + * + * @mbg.generated + */ + int updateByPrimaryKey(PluginDO record); +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatConfigRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatConfigRepository.java similarity index 51% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatConfigRepository.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatConfigRepository.java index 8a7e83e6c..33de13ec6 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatConfigRepository.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatConfigRepository.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.chat.domain.repository; +package com.tencent.supersonic.chat.persistence.repository; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfig; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilter; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigResp; +import com.tencent.supersonic.chat.config.ChatConfig; +import com.tencent.supersonic.chat.config.ChatConfigFilter; +import com.tencent.supersonic.chat.config.ChatConfigResp; + import java.util.List; - public interface ChatConfigRepository { Long createConfig(ChatConfig chaConfig); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatContextRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatContextRepository.java similarity index 76% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatContextRepository.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatContextRepository.java index fd035d972..53a534d31 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatContextRepository.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatContextRepository.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.repository; +package com.tencent.supersonic.chat.persistence.repository; import com.tencent.supersonic.chat.api.pojo.ChatContext; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatQueryRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatQueryRepository.java new file mode 100644 index 000000000..4b818c464 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatQueryRepository.java @@ -0,0 +1,20 @@ +package com.tencent.supersonic.chat.persistence.repository; + +import com.github.pagehelper.PageInfo; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResponse; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; + +public interface ChatQueryRepository { + + PageInfo getChatQuery(PageQueryInfoReq pageQueryInfoCommend, long chatId); + + void createChatQuery(QueryResult queryResult, QueryRequest queryContext, ChatContext chatCtx); + + ChatQueryDO getLastChatQuery(long chatId); + + int updateChatQuery(ChatQueryDO chatQueryDO); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatRepository.java similarity index 71% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatRepository.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatRepository.java index da1990ed0..54ee6ad53 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatRepository.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/ChatRepository.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.chat.domain.repository; +package com.tencent.supersonic.chat.persistence.repository; -import com.tencent.supersonic.chat.domain.dataobject.ChatDO; -import com.tencent.supersonic.chat.domain.dataobject.QueryDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.persistence.dataobject.QueryDO; import java.util.List; public interface ChatRepository { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/PluginRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/PluginRepository.java new file mode 100644 index 000000000..4e434c376 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/PluginRepository.java @@ -0,0 +1,22 @@ +package com.tencent.supersonic.chat.persistence.repository; + +import com.tencent.supersonic.chat.persistence.dataobject.PluginDO; +import com.tencent.supersonic.chat.persistence.dataobject.PluginDOExample; + +import java.util.List; + +public interface PluginRepository { + List getPlugins(); + + List fetchPluginDOs(String queryText, String type); + + void createPlugin(PluginDO pluginDO); + + void updatePlugin(PluginDO pluginDO); + + PluginDO getPlugin(Long id); + + List query(PluginDOExample pluginDOExample); + + void deletePlugin(Long id); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatConfigRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatConfigRepositoryImpl.java similarity index 58% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatConfigRepositoryImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatConfigRepositoryImpl.java index 3fd2a1e2d..cec064a1f 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatConfigRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatConfigRepositoryImpl.java @@ -1,16 +1,16 @@ -package com.tencent.supersonic.chat.infrastructure.repository; +package com.tencent.supersonic.chat.persistence.repository.impl; -import com.tencent.supersonic.chat.domain.dataobject.ChatConfigDO; -import com.tencent.supersonic.chat.domain.pojo.config.*; -import com.tencent.supersonic.chat.domain.repository.ChatConfigRepository; -import com.tencent.supersonic.chat.domain.utils.ChatConfigUtils; -import com.tencent.supersonic.chat.infrastructure.mapper.ChatConfigMapper; +import com.tencent.supersonic.chat.config.ChatConfig; +import com.tencent.supersonic.chat.config.ChatConfigFilter; +import com.tencent.supersonic.chat.config.ChatConfigFilterInternal; +import com.tencent.supersonic.chat.config.ChatConfigResp; +import com.tencent.supersonic.chat.persistence.dataobject.ChatConfigDO; +import com.tencent.supersonic.chat.persistence.repository.ChatConfigRepository; +import com.tencent.supersonic.chat.utils.ChatConfigHelper; +import com.tencent.supersonic.chat.persistence.mapper.ChatConfigMapper; import java.util.ArrayList; import java.util.List; -import java.util.Objects; - -import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Repository; @@ -20,25 +20,25 @@ import org.springframework.util.CollectionUtils; @Primary public class ChatConfigRepositoryImpl implements ChatConfigRepository { - private final ChatConfigUtils chatConfigUtils; + private final ChatConfigHelper chatConfigHelper; private final ChatConfigMapper chatConfigMapper; - public ChatConfigRepositoryImpl(ChatConfigUtils chatConfigUtils, + public ChatConfigRepositoryImpl(ChatConfigHelper chatConfigHelper, ChatConfigMapper chatConfigMapper) { - this.chatConfigUtils = chatConfigUtils; + this.chatConfigHelper = chatConfigHelper; this.chatConfigMapper = chatConfigMapper; } @Override public Long createConfig(ChatConfig chaConfig) { - ChatConfigDO chaConfigDO = chatConfigUtils.chatConfig2DO(chaConfig); + ChatConfigDO chaConfigDO = chatConfigHelper.chatConfig2DO(chaConfig); chatConfigMapper.addConfig(chaConfigDO); return chaConfigDO.getId(); } @Override public Long updateConfig(ChatConfig chaConfig) { - ChatConfigDO chaConfigDO = chatConfigUtils.chatConfig2DO(chaConfig); + ChatConfigDO chaConfigDO = chatConfigHelper.chatConfig2DO(chaConfig); return chatConfigMapper.editConfig(chaConfigDO); @@ -53,7 +53,7 @@ public class ChatConfigRepositoryImpl implements ChatConfigRepository { List chaConfigDOList = chatConfigMapper.search(filterInternal); if (!CollectionUtils.isEmpty(chaConfigDOList)) { chaConfigDOList.stream().forEach(chaConfigDO -> - chaConfigDescriptorList.add(chatConfigUtils.chatConfigDO2Descriptor(chaConfigDO.getDomainId(), chaConfigDO))); + chaConfigDescriptorList.add(chatConfigHelper.chatConfigDO2Descriptor(chaConfigDO.getDomainId(), chaConfigDO))); } return chaConfigDescriptorList; } @@ -61,7 +61,7 @@ public class ChatConfigRepositoryImpl implements ChatConfigRepository { @Override public ChatConfigResp getConfigByDomainId(Long domainId) { ChatConfigDO chaConfigPO = chatConfigMapper.fetchConfigByDomainId(domainId); - return chatConfigUtils.chatConfigDO2Descriptor(domainId, chaConfigPO); + return chatConfigHelper.chatConfigDO2Descriptor(domainId, chaConfigPO); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatContextRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatContextRepositoryImpl.java similarity index 78% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatContextRepositoryImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatContextRepositoryImpl.java index 54ab46a83..56a70f5ba 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatContextRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatContextRepositoryImpl.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.chat.infrastructure.repository; +package com.tencent.supersonic.chat.persistence.repository.impl; import com.google.gson.Gson; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.domain.dataobject.ChatContextDO; -import com.tencent.supersonic.chat.domain.repository.ChatContextRepository; -import com.tencent.supersonic.chat.infrastructure.mapper.ChatContextMapper; -import com.tencent.supersonic.common.util.json.JsonUtil; +import com.tencent.supersonic.chat.persistence.dataobject.ChatContextDO; +import com.tencent.supersonic.chat.persistence.mapper.ChatContextMapper; +import com.tencent.supersonic.chat.persistence.repository.ChatContextRepository; +import com.tencent.supersonic.common.util.JsonUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Repository; @@ -64,14 +64,6 @@ public class ChatContextRepositoryImpl implements ChatContextRepository { chatContextDO.setUser(chatContext.getUser()); if (chatContext.getParseInfo() != null) { Gson g = new Gson(); - chatContext.getParseInfo().getDimensions().stream().forEach(d -> { - d.setUpdatedAt(null); - d.setCreatedAt(null); - }); - chatContext.getParseInfo().getMetrics().stream().forEach(d -> { - d.setUpdatedAt(null); - d.setCreatedAt(null); - }); chatContextDO.setSemanticParse(g.toJson(chatContext.getParseInfo())); } return chatContextDO; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatQueryRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatQueryRepositoryImpl.java similarity index 56% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatQueryRepositoryImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatQueryRepositoryImpl.java index 7b1e273d3..a5e87980b 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatQueryRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatQueryRepositoryImpl.java @@ -1,19 +1,19 @@ -package com.tencent.supersonic.chat.infrastructure.repository; +package com.tencent.supersonic.chat.persistence.repository.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDO; -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDOExample; -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDOExample.Criteria; -import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO; -import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq; -import com.tencent.supersonic.chat.domain.repository.ChatQueryRepository; -import com.tencent.supersonic.chat.infrastructure.mapper.ChatQueryDOMapper; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.common.util.mybatis.PageUtils; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDOExample; +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDOExample.Criteria; +import com.tencent.supersonic.chat.api.pojo.response.QueryResponse; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; +import com.tencent.supersonic.chat.persistence.mapper.ChatQueryDOMapper; +import com.tencent.supersonic.chat.persistence.repository.ChatQueryRepository; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.common.util.PageUtils; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -35,7 +35,7 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { } @Override - public PageInfo getChatQuery(PageQueryInfoReq pageQueryInfoCommend, long chatId) { + public PageInfo getChatQuery(PageQueryInfoReq pageQueryInfoCommend, long chatId) { ChatQueryDOExample example = new ChatQueryDOExample(); example.setOrderByClause("question_id desc"); Criteria criteria = example.createCriteria(); @@ -46,7 +46,7 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { pageQueryInfoCommend.getPageSize()) .doSelectPageInfo(() -> chatQueryDOMapper.selectByExampleWithBLOBs(example)); - PageInfo chatQueryVOPageInfo = PageUtils.pageInfo2PageInfoVo(pageInfo); + PageInfo chatQueryVOPageInfo = PageUtils.pageInfo2PageInfoVo(pageInfo); chatQueryVOPageInfo.setList( pageInfo.getList().stream().map(this::convertTo) .sorted(Comparator.comparingInt(o -> o.getQuestionId().intValue())) @@ -54,28 +54,28 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { return chatQueryVOPageInfo; } - private ChatQueryVO convertTo(ChatQueryDO chatQueryDO) { - ChatQueryVO chatQueryVO = new ChatQueryVO(); - BeanUtils.copyProperties(chatQueryDO, chatQueryVO); - QueryResultResp queryResponse = JsonUtil.toObject(chatQueryDO.getQueryResponse(), QueryResultResp.class); - queryResponse.setQueryId(chatQueryDO.getQuestionId()); - chatQueryVO.setQueryResponse(queryResponse); - return chatQueryVO; + private QueryResponse convertTo(ChatQueryDO chatQueryDO) { + QueryResponse queryResponse = new QueryResponse(); + BeanUtils.copyProperties(chatQueryDO, queryResponse); + QueryResult queryResult = JsonUtil.toObject(chatQueryDO.getQueryResult(), QueryResult.class); + queryResult.setQueryId(chatQueryDO.getQuestionId()); + queryResponse.setQueryResult(queryResult); + return queryResponse; } @Override - public void createChatQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx) { + public void createChatQuery(QueryResult queryResult, QueryRequest queryRequest, ChatContext chatCtx) { ChatQueryDO chatQueryDO = new ChatQueryDO(); - chatQueryDO.setChatId(Long.valueOf(queryContext.getChatId())); + chatQueryDO.setChatId(Long.valueOf(queryRequest.getChatId())); chatQueryDO.setCreateTime(new java.util.Date()); - chatQueryDO.setUserName(queryContext.getUser().getName()); - chatQueryDO.setQueryState(queryResponse.getQueryState()); - chatQueryDO.setQueryText(queryContext.getQueryText()); - chatQueryDO.setQueryResponse(JsonUtil.toString(queryResponse)); + chatQueryDO.setUserName(queryRequest.getUser().getName()); + chatQueryDO.setQueryState(queryResult.getQueryState().ordinal()); + chatQueryDO.setQueryText(queryRequest.getQueryText()); + chatQueryDO.setQueryResult(JsonUtil.toString(queryResult)); chatQueryDOMapper.insert(chatQueryDO); - ChatQueryDO lastChatQuery = getLastChatQuery(queryContext.getChatId()); + ChatQueryDO lastChatQuery = getLastChatQuery(queryRequest.getChatId()); Long queryId = lastChatQuery.getQuestionId(); - queryResponse.setQueryId(queryId); + queryResult.setQueryId(queryId); } @Override diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatRepositoryImpl.java similarity index 80% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatRepositoryImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatRepositoryImpl.java index e40d2ff85..ce7c4249c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatRepositoryImpl.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.chat.infrastructure.repository; +package com.tencent.supersonic.chat.persistence.repository.impl; -import com.tencent.supersonic.chat.domain.dataobject.ChatDO; -import com.tencent.supersonic.chat.domain.dataobject.QueryDO; -import com.tencent.supersonic.chat.domain.repository.ChatRepository; -import com.tencent.supersonic.chat.infrastructure.mapper.ChatMapper; +import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.persistence.dataobject.QueryDO; +import com.tencent.supersonic.chat.persistence.repository.ChatRepository; +import com.tencent.supersonic.chat.persistence.mapper.ChatMapper; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Primary; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/PluginRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/PluginRepositoryImpl.java new file mode 100644 index 000000000..3538bb632 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/PluginRepositoryImpl.java @@ -0,0 +1,80 @@ +package com.tencent.supersonic.chat.persistence.repository.impl; + +import com.tencent.supersonic.chat.persistence.dataobject.PluginDO; +import com.tencent.supersonic.chat.persistence.dataobject.PluginDOExample; +import com.tencent.supersonic.chat.persistence.mapper.PluginDOMapper; +import com.tencent.supersonic.chat.persistence.repository.PluginRepository; +import com.tencent.supersonic.common.util.ContextUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.stereotype.Repository; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Repository +@Slf4j +public class PluginRepositoryImpl implements PluginRepository { + + private PluginDOMapper pluginDOMapper; + + public PluginRepositoryImpl(PluginDOMapper pluginDOMapper) { + this.pluginDOMapper = pluginDOMapper; + } + + @Override + public List getPlugins() { + return pluginDOMapper.selectByExampleWithBLOBs(new PluginDOExample()); + } + + @Override + public List fetchPluginDOs(String queryText, String type) { + + List pluginDOList = new ArrayList<>(); + + PluginRepository pluginRepository = ContextUtils.getBean(PluginRepository.class); + List pluginDOS = pluginRepository.getPlugins(); + + for (PluginDO pluginDO : pluginDOS) { + String pattern = pluginDO.getPattern(); + if (Strings.isNotEmpty(pattern)) { + + Pattern pluginPattern = Pattern.compile(pattern); + Matcher pluginMatcher = pluginPattern.matcher(queryText); + if (pluginMatcher.find()) { + log.info("pluginMatcher.find() is true, queryText:{}", queryText); + log.info("pluginDO:{}", pluginDO); + pluginDOList.add(pluginDO); + } + } + } + return pluginDOList; + } + + @Override + public void createPlugin(PluginDO pluginDO) { + pluginDOMapper.insert(pluginDO); + } + + @Override + public void updatePlugin(PluginDO pluginDO){ + pluginDOMapper.updateByPrimaryKeyWithBLOBs(pluginDO); + } + + @Override + public PluginDO getPlugin(Long id) { + return pluginDOMapper.selectByPrimaryKey(id); + } + + @Override + public List query(PluginDOExample pluginDOExample){ + return pluginDOMapper.selectByExampleWithBLOBs(pluginDOExample); + } + + @Override + public void deletePlugin(Long id){ + pluginDOMapper.deleteByPrimaryKey(id); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/Plugin.java b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/Plugin.java new file mode 100644 index 000000000..469e11bfc --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/Plugin.java @@ -0,0 +1,37 @@ +package com.tencent.supersonic.chat.plugin; + + +import com.tencent.supersonic.chat.parser.ParseMode; +import com.tencent.supersonic.common.pojo.RecordInfo; +import lombok.Data; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Data +public class Plugin extends RecordInfo { + + private Long id; + + //plugin type WEB_PAGE WEB_SERVICE + private String type; + + private List domainList; + + //description, for parsing + private String pattern; + + //parse + private ParseMode parseMode; + + private String name; + + //config for different plugin type + private String config; + + public List getPatterns() { + return Stream.of(getPattern().split("\\|")).collect(Collectors.toList()); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginManager.java b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginManager.java new file mode 100644 index 000000000..57540ebb5 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginManager.java @@ -0,0 +1,176 @@ +package com.tencent.supersonic.chat.plugin; + +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.tencent.supersonic.chat.parser.ParseMode; +import com.tencent.supersonic.chat.parser.embedding.EmbeddingConfig; +import com.tencent.supersonic.chat.parser.embedding.EmbeddingResp; +import com.tencent.supersonic.chat.parser.embedding.RecallRetrieval; +import com.tencent.supersonic.chat.plugin.event.PluginAddEvent; +import com.tencent.supersonic.chat.plugin.event.PluginUpdateEvent; +import com.tencent.supersonic.chat.service.PluginService; +import com.tencent.supersonic.common.util.ContextUtils; +import java.net.URI; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.context.event.EventListener; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +@Slf4j +@Component +public class PluginManager { + + private static Map internalPluginMap = new ConcurrentHashMap<>(); + + private EmbeddingConfig embeddingConfig; + + private RestTemplate restTemplate; + + public PluginManager(EmbeddingConfig embeddingConfig, RestTemplate restTemplate) { + this.embeddingConfig = embeddingConfig; + this.restTemplate = restTemplate; + } + + public static List getPlugins() { + PluginService pluginService = ContextUtils.getBean(PluginService.class); + List pluginList = pluginService.getPluginList(); + pluginList.addAll(internalPluginMap.values()); + return new ArrayList<>(pluginList); + } + + @EventListener + public void addPlugin(PluginAddEvent pluginAddEvent) { + Plugin plugin = pluginAddEvent.getPlugin(); + if (ParseMode.EMBEDDING_RECALL.equals(plugin.getParseMode())) { + requestEmbeddingPluginAdd(convert(Lists.newArrayList(plugin))); + } + } + + @EventListener + public void updatePlugin(PluginUpdateEvent pluginUpdateEvent) { + Plugin oldPlugin = pluginUpdateEvent.getOldPlugin(); + Plugin newPlugin = pluginUpdateEvent.getNewPlugin(); + if (ParseMode.EMBEDDING_RECALL.equals(oldPlugin.getParseMode())) { + requestEmbeddingPluginDelete(getEmbeddingId(Lists.newArrayList(oldPlugin))); + } + if (ParseMode.EMBEDDING_RECALL.equals(newPlugin.getParseMode())) { + requestEmbeddingPluginAdd(convert(Lists.newArrayList(newPlugin))); + } + } + + @EventListener + public void delPlugin(PluginAddEvent pluginAddEvent) { + Plugin plugin = pluginAddEvent.getPlugin(); + if (ParseMode.EMBEDDING_RECALL.equals(plugin.getParseMode())) { + requestEmbeddingPluginDelete(getEmbeddingId(Lists.newArrayList(plugin))); + } + + } + + public void requestEmbeddingPluginDelete(Set ids) { + if(CollectionUtils.isEmpty(ids)){ + return; + } + doRequest(embeddingConfig.getDeletePath(), JSONObject.toJSONString(ids)); + } + + + public void requestEmbeddingPluginAdd(List> maps) { + if(CollectionUtils.isEmpty(maps)){ + return; + } + doRequest(embeddingConfig.getAddPath(), JSONObject.toJSONString(maps)); + } + + public void doRequest(String path, String jsonBody) { + String url = embeddingConfig.getUrl()+ path; + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setLocation(URI.create(url)); + URI requestUrl = UriComponentsBuilder + .fromHttpUrl(url).build().encode().toUri(); + HttpEntity entity = new HttpEntity<>(jsonBody, headers); + log.info("[embedding] equest body :{}, url:{}", jsonBody, url); + ResponseEntity responseEntity = + restTemplate.exchange(requestUrl, HttpMethod.POST, entity, new ParameterizedTypeReference() {}); + log.info("[embedding] result body:{}", responseEntity); + } + + public void requestEmbeddingPluginAddALL(List plugins) { + plugins = plugins.stream() + .filter(plugin -> ParseMode.EMBEDDING_RECALL.equals(plugin.getParseMode())) + .collect(Collectors.toList()); + requestEmbeddingPluginAdd(convert(plugins)); + } + + public EmbeddingResp recognize(String embeddingText) { + String url = embeddingConfig.getUrl()+ embeddingConfig.getRecognizePath() + "?n_results=" + embeddingConfig.getNResult(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setLocation(URI.create(url)); + URI requestUrl = UriComponentsBuilder + .fromHttpUrl(url).build().encode().toUri(); + String jsonBody = JSONObject.toJSONString(Lists.newArrayList(embeddingText)); + HttpEntity entity = new HttpEntity<>(jsonBody, headers); + log.info("[embedding] request body:{}, url:{}", jsonBody, url); + ResponseEntity> embeddingResponseEntity = + restTemplate.exchange(requestUrl, HttpMethod.POST, entity, new ParameterizedTypeReference>() {}); + log.info("[embedding] recognize result body:{}",embeddingResponseEntity); + List embeddingResps = embeddingResponseEntity.getBody(); + if(CollectionUtils.isNotEmpty(embeddingResps)){ + for (EmbeddingResp embeddingResp : embeddingResps) { + List embeddingRetrievals = embeddingResp.getRetrieval(); + for (RecallRetrieval embeddingRetrieval : embeddingRetrievals) { + embeddingRetrieval.setId(getPluginIdFromEmbeddingId(embeddingRetrieval.getId())); + } + } + return embeddingResps.get(0); + } + throw new RuntimeException("get embedding result failed"); + } + + public List> convert(List plugins){ + List> maps = Lists.newArrayList(); + for(Plugin plugin : plugins){ + List patterns = plugin.getPatterns(); + int num = 0; + for(String pattern : patterns){ + Map map = new HashMap<>(); + map.put("preset_query_id", generateUniqueEmbeddingId(num, plugin.getId())); + map.put("preset_query", pattern); + maps.add(map); + num++; + } + } + return maps; + } + + private Set getEmbeddingId(List plugins) { + Set embeddingIdSet = new HashSet<>(); + for (Map map : convert(plugins)) { + embeddingIdSet.addAll(map.keySet()); + } + return embeddingIdSet; + } + + //num can not bigger than 100 + private String generateUniqueEmbeddingId(int num, Long pluginId) { + if (num < 10) { + return String.format("%s00%s", pluginId, num); + } else { + return String.format("%s0%s", pluginId, num); + } + } + + private String getPluginIdFromEmbeddingId(String id) { + return String.valueOf(Integer.parseInt(id) / 1000); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginParseResult.java b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginParseResult.java new file mode 100644 index 000000000..ba7a4a9c7 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginParseResult.java @@ -0,0 +1,11 @@ +package com.tencent.supersonic.chat.plugin; + +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import lombok.Data; + +@Data +public class PluginParseResult { + + private Plugin plugin; + private QueryRequest request; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginAddEvent.java b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginAddEvent.java new file mode 100644 index 000000000..4aafc787a --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginAddEvent.java @@ -0,0 +1,18 @@ +package com.tencent.supersonic.chat.plugin.event; + +import com.tencent.supersonic.chat.plugin.Plugin; +import org.springframework.context.ApplicationEvent; + +public class PluginAddEvent extends ApplicationEvent { + + private Plugin plugin; + + public PluginAddEvent(Object source, Plugin plugin) { + super(source); + this.plugin = plugin; + } + + public Plugin getPlugin() { + return plugin; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginDelEvent.java b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginDelEvent.java new file mode 100644 index 000000000..0dd0d4520 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginDelEvent.java @@ -0,0 +1,18 @@ +package com.tencent.supersonic.chat.plugin.event; + +import com.tencent.supersonic.chat.plugin.Plugin; +import org.springframework.context.ApplicationEvent; + +public class PluginDelEvent extends ApplicationEvent { + + private Plugin plugin; + + public PluginDelEvent(Object source, Plugin plugin) { + super(source); + this.plugin = plugin; + } + + public Plugin getPlugin() { + return plugin; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginUpdateEvent.java b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginUpdateEvent.java new file mode 100644 index 000000000..2d2086f87 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/event/PluginUpdateEvent.java @@ -0,0 +1,26 @@ +package com.tencent.supersonic.chat.plugin.event; + +import com.tencent.supersonic.chat.plugin.Plugin; +import org.springframework.context.ApplicationEvent; + +public class PluginUpdateEvent extends ApplicationEvent { + + private Plugin oldPlugin; + + private Plugin newPlugin; + + public PluginUpdateEvent(Object source, Plugin oldPlugin, Plugin newPlugin) { + super(source); + this.oldPlugin = oldPlugin; + this.newPlugin = newPlugin; + } + + public Plugin getOldPlugin() { + return oldPlugin; + } + + public Plugin getNewPlugin() { + return newPlugin; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/HeuristicQuerySelector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/HeuristicQuerySelector.java similarity index 84% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/query/HeuristicQuerySelector.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/HeuristicQuerySelector.java index 9e2ffd615..82ef74840 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/HeuristicQuerySelector.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/HeuristicQuerySelector.java @@ -1,15 +1,16 @@ -package com.tencent.supersonic.chat.application.query; +package com.tencent.supersonic.chat.query; import com.tencent.supersonic.chat.api.component.SemanticQuery; import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; @Slf4j public class HeuristicQuerySelector implements QuerySelector { @@ -18,13 +19,10 @@ public class HeuristicQuerySelector implements QuerySelector { public SemanticQuery select(List candidateQueries) { double maxScore = 0; SemanticQuery pickedQuery = null; - + if (CollectionUtils.isNotEmpty(candidateQueries) && candidateQueries.size() == 1) { + return candidateQueries.get(0); + } for (SemanticQuery query : candidateQueries) { - if (query instanceof LLMSemanticQuery) { - log.info("force to use LLM if existed"); - return query; - } - SemanticParseInfo semanticParse = query.getParseInfo(); double score = computeScore(semanticParse); if (score > maxScore) { @@ -43,7 +41,7 @@ public class HeuristicQuerySelector implements QuerySelector { Map maxSimilarityMatch = new HashMap<>(); for (SchemaElementMatch match : semanticParse.getElementMatches()) { - SchemaElementType type = match.getElementType(); + SchemaElementType type = match.getElement().getType(); if (!maxSimilarityMatch.containsKey(type) || match.getSimilarity() > maxSimilarityMatch.get(type).getSimilarity()) { maxSimilarityMatch.put(type, match); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/QueryManager.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/QueryManager.java new file mode 100644 index 000000000..4cd897fb3 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/QueryManager.java @@ -0,0 +1,64 @@ +package com.tencent.supersonic.chat.query; + +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; +import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +public class QueryManager { + + private static Map ruleQueryMap = new ConcurrentHashMap<>(); + private static Map pluginQueryMap = new ConcurrentHashMap<>(); + + public static void register(SemanticQuery query) { + if (query instanceof RuleSemanticQuery) { + ruleQueryMap.put(query.getQueryMode(), (RuleSemanticQuery) query); + } else if (query instanceof PluginSemanticQuery) { + pluginQueryMap.put(query.getQueryMode(), (PluginSemanticQuery) query); + } + } + + public static RuleSemanticQuery createRuleQuery(String queryMode) { + RuleSemanticQuery semanticQuery = ruleQueryMap.get(queryMode); + if (Objects.isNull(semanticQuery)) { + throw new RuntimeException("no supported queryMode :" + queryMode); + } + try { + return semanticQuery.getClass().getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new RuntimeException("no supported queryMode :" + queryMode); + } + } + + public static PluginSemanticQuery createPluginQuery(String queryMode) { + PluginSemanticQuery semanticQuery = pluginQueryMap.get(queryMode); + if (Objects.isNull(semanticQuery)) { + throw new RuntimeException("no supported queryMode :" + queryMode); + } + try { + return semanticQuery.getClass().getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new RuntimeException("no supported queryMode :" + queryMode); + } + } + + public static boolean containsRuleQuery(String queryMode) { + if (queryMode == null) { + return false; + } + return ruleQueryMap.containsKey(queryMode); + } + + public static List getRuleQueries() { + return new ArrayList<>(ruleQueryMap.values()); + } + + public static List getPluginQueryModes() { + return new ArrayList<>(pluginQueryMap.keySet()); + } + +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QuerySelector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/QuerySelector.java similarity index 84% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QuerySelector.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/QuerySelector.java index e84b43586..dcc8ae79c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QuerySelector.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/QuerySelector.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.application.query; +package com.tencent.supersonic.chat.query; import com.tencent.supersonic.chat.api.component.SemanticQuery; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/PluginSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/PluginSemanticQuery.java new file mode 100644 index 000000000..da2b48072 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/PluginSemanticQuery.java @@ -0,0 +1,21 @@ +package com.tencent.supersonic.chat.query.plugin; + +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class PluginSemanticQuery implements SemanticQuery { + + protected SemanticParseInfo parseInfo = new SemanticParseInfo(); + + public void setParseInfo(SemanticParseInfo parseInfo) { + this.parseInfo = parseInfo; + } + + public SemanticParseInfo getParseInfo() { + return parseInfo; + } + + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/WebBase.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/WebBase.java new file mode 100644 index 000000000..a9aec8bf4 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/WebBase.java @@ -0,0 +1,22 @@ +package com.tencent.supersonic.chat.query.plugin; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class WebBase { + + private String url; + + //key, id of schema element + private Map params = new HashMap<>(); + + //key, value of shcema element + private Map valueParams = new HashMap<>(); + + //only forward + private Map forwardParam = new HashMap<>(); + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/DSLBuilder.java similarity index 53% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfo.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/DSLBuilder.java index 339cc608c..69f4a6bd7 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfo.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/DSLBuilder.java @@ -1,32 +1,38 @@ -package com.tencent.supersonic.chat.domain.utils; +package com.tencent.supersonic.chat.query.plugin.dsl; import static java.time.LocalDate.now; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.application.knowledge.WordNatureService; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.chat.domain.pojo.chat.LLMResp; -import com.tencent.supersonic.common.nlp.ItemDO; +import com.tencent.supersonic.chat.api.pojo.SemanticSchema; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.calcite.SqlParseUtils; import com.tencent.supersonic.common.util.calcite.SqlParserInfo; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; +import com.tencent.supersonic.knowledge.service.SchemaService; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.apache.calcite.sql.parser.SqlParseException; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @Slf4j -public class DslToSemanticInfo { +public class DSLBuilder { - protected static final String SUB_TABLE = " ( select * from t_{0} where {1} >= ''{2}'' and {1} <= ''{3}'' ) as t_sub_{0}"; + public static final String COMMA_WRAPPER = "'%s'"; + public static final String SPACE_WRAPPER = " %s "; + protected static final String SUB_TABLE = " ( select * from t_{0} where {1} >= ''{2}'' and {1} <= ''{3}'' {4} ) as t_sub_{0}"; - public String convert(SemanticParseInfo parseInfo, LLMResp llmResp, Integer domainId) throws SqlParseException { + public String build(QueryFilters queryFilters, SemanticParseInfo parseInfo, LLMResp llmResp, Long domainId) + throws SqlParseException { String sqlOutput = llmResp.getSqlOutput(); String domainName = llmResp.getDomainName(); @@ -46,10 +52,12 @@ public class DslToSemanticInfo { // 2. replace the llm dsl, such as replace fieldName and tableName. log.info("sqlParseInfo:{} ,domainName:{},domainId:{}", sqlParseInfo, domainName, domainId); - DomainInfos domainInfos = ContextUtils.getBean(WordNatureService.class).getCache().getUnchecked(""); - List fieldList = domainInfos.getMetrics(); - fieldList.addAll(domainInfos.getDimensions()); - Map fieldToBizName = getMapInfo(domainId, fieldList); + SemanticSchema semanticSchema = ContextUtils.getBean(SchemaService.class).getSemanticSchema(); + List dbAllFields = new ArrayList<>(); + dbAllFields.addAll(semanticSchema.getMetrics()); + dbAllFields.addAll(semanticSchema.getDimensions()); + + Map fieldToBizName = getMapInfo(domainId, dbAllFields); for (String fieldName : allFields) { String fieldBizName = fieldToBizName.get(fieldName); @@ -74,21 +82,43 @@ public class DslToSemanticInfo { TimeDimensionEnum timeDimension = TimeDimensionEnum.valueOf(period); String dayField = timeDimension.getName(); - String subTable = MessageFormat.format(SUB_TABLE, domainId, dayField, startDate, endDate); + String queryFilter = getQueryFilter(queryFilters); + + String subTable = MessageFormat.format(SUB_TABLE, domainId, dayField, startDate, endDate, queryFilter); String querySql = sqlOutput.replaceAll(tableName, subTable); log.info("querySql:{},sqlOutput:{},dateInfo:{}", querySql, sqlOutput, dateInfo); return querySql; } - protected String extraConvert(String sqlOutput, Integer domainId) throws SqlParseException { + private String getQueryFilter(QueryFilters queryFilters) { + String queryFilter = ""; + if (Objects.isNull(queryFilters) || CollectionUtils.isEmpty(queryFilters.getFilters())) { + return queryFilter; + } + List filters = queryFilters.getFilters(); + for (QueryFilter filter : filters) { + queryFilter = getSpaceWrap(queryFilter) + "and" + getSpaceWrap(filter.getBizName()) + getSpaceWrap( + filter.getOperator().getValue()) + getCommaWrap(filter.getValue().toString()); + } + return queryFilter; + } + + protected String extraConvert(String sqlOutput, Long domainId) throws SqlParseException { return SqlParseUtils.addAliasToSql(sqlOutput); } - protected Map getMapInfo(Integer domainId, List metrics) { + protected Map getMapInfo(Long domainId, List metrics) { return metrics.stream().filter(entry -> entry.getDomain().equals(domainId)) - .collect(Collectors.toMap(ItemDO::getName, a -> a.getBizName(), (k1, k2) -> k1)); + .collect(Collectors.toMap(SchemaElement::getName, a -> a.getBizName(), (k1, k2) -> k1)); } + private String getCommaWrap(String value) { + return String.format(COMMA_WRAPPER, value); + } + + private String getSpaceWrap(String value) { + return String.format(SPACE_WRAPPER, value); + } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/DSLQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/DSLQuery.java new file mode 100644 index 000000000..16d1de9d9 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/DSLQuery.java @@ -0,0 +1,205 @@ +package com.tencent.supersonic.chat.query.plugin.dsl; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.SemanticSchema; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; +import com.tencent.supersonic.chat.api.pojo.response.EntityInfo; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.config.LLMConfig; +import com.tencent.supersonic.chat.plugin.PluginParseResult; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; +import com.tencent.supersonic.chat.query.plugin.dsl.LLMReq.ElementValue; +import com.tencent.supersonic.chat.service.SemanticService; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.chat.utils.QueryReqBuilder; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.knowledge.service.SchemaService; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.calcite.sql.parser.SqlParseException; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +public class DSLQuery extends PluginSemanticQuery { + + public static final String QUERY_MODE = "DSL"; + private DSLBuilder dslBuilder = new DSLBuilder(); + + protected SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + + public DSLQuery() { + QueryManager.register(this); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + + @Override + public QueryResult execute(User user) { + PluginParseResult functionCallParseResult = (PluginParseResult) parseInfo.getProperties() + .get(Constants.CONTEXT); + Long domainId = parseInfo.getDomainId(); + LLMResp llmResp = requestLLM(functionCallParseResult, domainId); + if (Objects.isNull(llmResp)) { + return null; + } + String querySql = convertToSql(functionCallParseResult.getRequest().getQueryFilters(), llmResp, parseInfo, + domainId); + QueryResult queryResult = new QueryResult(); + + long startTime = System.currentTimeMillis(); + QueryResultWithSchemaResp queryResp = semanticLayer.queryByDsl( + QueryReqBuilder.buildDslReq(querySql, domainId), user); + log.info("queryByDsl cost:{},querySql:{}", System.currentTimeMillis() - startTime, querySql); + + if (queryResp != null) { + queryResult.setQueryAuthorization(queryResp.getQueryAuthorization()); + } + String resultQql = queryResp == null ? null : queryResp.getSql(); + List> resultList = queryResp == null ? new ArrayList<>() + : queryResp.getResultList(); + List columns = queryResp == null ? new ArrayList<>() : queryResp.getColumns(); + queryResult.setQuerySql(resultQql); + queryResult.setQueryResults(resultList); + queryResult.setQueryColumns(columns); + queryResult.setQueryMode(QUERY_MODE); + queryResult.setQueryState(QueryState.SUCCESS); + + // add domain info + EntityInfo entityInfo = ContextUtils.getBean(SemanticService.class) + .getEntityInfo(parseInfo, user); + queryResult.setEntityInfo(entityInfo); + parseInfo.setProperties(null); + return queryResult; + } + + + protected String convertToSql(QueryFilters queryFilters, LLMResp llmResp, SemanticParseInfo parseInfo, + Long domainId) { + try { + return dslBuilder.build(queryFilters, parseInfo, llmResp, domainId); + } catch (SqlParseException e) { + log.error("convertToSql error", e); + } + return null; + } + + protected LLMResp requestLLM(PluginParseResult parseResult, Long domainId) { + long startTime = System.currentTimeMillis(); + String queryText = parseResult.getRequest().getQueryText(); + final LLMConfig llmConfig = ContextUtils.getBean(LLMConfig.class); + + if (StringUtils.isEmpty(llmConfig.getUrl())) { + log.warn("llmConfig url is null, skip llm parser"); + return null; + } + + SemanticSchema semanticSchema = ContextUtils.getBean(SchemaService.class).getSemanticSchema(); + Map domainIdToName = semanticSchema.getDomainIdToName(); + + LLMReq llmReq = new LLMReq(); + llmReq.setQueryText(queryText); + LLMReq.LLMSchema llmSchema = new LLMReq.LLMSchema(); + llmSchema.setDomainName(domainIdToName.get(domainId)); + List fieldNameList = getFieldNameList(domainId, semanticSchema); + llmSchema.setFieldNameList(fieldNameList); + llmReq.setSchema(llmSchema); + List linking = new ArrayList<>(); + linking.addAll(getValueList(domainId, semanticSchema)); + llmReq.setLinking(linking); + + log.info("requestLLM request, domainId:{},llmReq:{}", domainId, llmReq); + String questUrl = llmConfig.getUrl() + llmConfig.getQueryToSqlPath(); + + RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); + + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(JsonUtil.toString(llmReq), headers); + ResponseEntity responseEntity = restTemplate.exchange(questUrl, HttpMethod.POST, entity, + LLMResp.class); + + log.info("requestLLM response,cost:{}, questUrl:{} \n entity:{} \n body:{}", + System.currentTimeMillis() - startTime, questUrl, entity, responseEntity.getBody()); + return responseEntity.getBody(); + } catch (Exception e) { + log.error("requestLLM error", e); + } + return null; + } + + private List getValueList(Long domainId, SemanticSchema semanticSchema) { + Map itemIdToName = semanticSchema.getDimensions().stream() + .filter(entry -> domainId.equals(entry.getDomain())) + .collect(Collectors.toMap(SchemaElement::getId, SchemaElement::getName, (value1, value2) -> value2)); + + List matchedElements = parseInfo.getElementMatches(); + Set valueMatches = matchedElements.stream() + .filter(schemaElementMatch -> SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())) + .map(elementMatch -> + { + ElementValue elementValue = new ElementValue(); + elementValue.setFieldName(itemIdToName.get(elementMatch.getElement().getId())); + elementValue.setFieldValue(elementMatch.getWord()); + return elementValue; + } + ) + .collect(Collectors.toSet()); + return new ArrayList<>(valueMatches); + } + + private List getFieldNameList(Long domainId, SemanticSchema semanticSchema) { + Map itemIdToName = semanticSchema.getDimensions().stream() + .filter(entry -> domainId.equals(entry.getDomain())) + .collect(Collectors.toMap(SchemaElement::getId, SchemaElement::getName, (value1, value2) -> value2)); + + List matchedElements = parseInfo.getElementMatches(); + Set fieldNameList = matchedElements.stream() + .filter(schemaElementMatch -> { + SchemaElementType elementType = schemaElementMatch.getElement().getType(); + return SchemaElementType.METRIC.equals(elementType) || + SchemaElementType.DIMENSION.equals(elementType) || + SchemaElementType.VALUE.equals(elementType); + }) + .map(schemaElementMatch -> { + SchemaElementType elementType = schemaElementMatch.getElement().getType(); + + if (!SchemaElementType.VALUE.equals(elementType)) { + return schemaElementMatch.getWord(); + } + return itemIdToName.get(schemaElementMatch.getElement().getId()); + }) + .filter(name -> StringUtils.isNotEmpty(name) && !name.contains("%")) + .collect(Collectors.toSet()); + return new ArrayList<>(fieldNameList); + } + + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/LLMReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/LLMReq.java new file mode 100644 index 000000000..c78ceafc3 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/LLMReq.java @@ -0,0 +1,32 @@ +package com.tencent.supersonic.chat.query.plugin.dsl; + +import java.util.List; +import lombok.Data; + +@Data +public class LLMReq { + + private String queryText; + + private LLMSchema schema; + + private List linking; + + @Data + public static class ElementValue { + + private String fieldName; + + private String fieldValue; + + } + + @Data + public static class LLMSchema { + + private String domainName; + + private List fieldNameList; + + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/LLMResp.java similarity index 83% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMResp.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/LLMResp.java index b750161bf..80273fab8 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMResp.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/dsl/LLMResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.pojo.chat; +package com.tencent.supersonic.chat.query.plugin.dsl; import java.util.List; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webpage/WebPageQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webpage/WebPageQuery.java new file mode 100644 index 000000000..7c981d808 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webpage/WebPageQuery.java @@ -0,0 +1,108 @@ +package com.tencent.supersonic.chat.query.plugin.webpage; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.response.EntityInfo; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.plugin.Plugin; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; +import com.tencent.supersonic.chat.query.plugin.WebBase; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.service.SemanticService; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.common.util.JsonUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +public class WebPageQuery extends PluginSemanticQuery { + + public static String QUERY_MODE = "WEB_PAGE"; + + public WebPageQuery() { + QueryManager.register(this); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + + @Override + public QueryResult execute(User user) { + ConfigService configService = ContextUtils.getBean(ConfigService.class); + QueryResult queryResult = new QueryResult(); + queryResult.setQueryMode(QUERY_MODE); + Map properties = parseInfo.getProperties(); + Plugin plugin = (Plugin) properties.get(Constants.CONTEXT); + WebPageResponse webPageResponse = buildResponse(plugin); + queryResult.setResponse(webPageResponse); + if (parseInfo.getDomainId() != null && parseInfo.getDomainId() > 0 + && parseInfo.getEntity() != null && parseInfo.getEntity() > 0) { + ChatConfigRich chatConfigRichResp = configService.getConfigRichInfo(parseInfo.getDomainId()); + updateSemanticParse(chatConfigRichResp, parseInfo.getEntity()); + EntityInfo entityInfo = ContextUtils.getBean(SemanticService.class).getEntityInfo(parseInfo, user); + queryResult.setEntityInfo(entityInfo); + } else { + queryResult.setEntityInfo(null); + } + queryResult.setQueryState(QueryState.SUCCESS); + return queryResult; + } + + private void updateSemanticParse(ChatConfigRich chatConfigRichResp, Long entityId) { + parseInfo.setEntity(entityId); + SchemaElement domain = new SchemaElement(); + domain.setId(chatConfigRichResp.getDomainId()); + domain.setName(chatConfigRichResp.getDomainName()); + parseInfo.setDomain(domain); + } + + protected WebPageResponse buildResponse(Plugin plugin) { + WebPageResponse webPageResponse = new WebPageResponse(); + webPageResponse.setName(plugin.getName()); + webPageResponse.setPluginId(plugin.getId()); + webPageResponse.setPluginType(plugin.getType()); + WebBase webPage = JsonUtil.toObject(plugin.getConfig(), WebBase.class); + fillWebPage(webPage); + webPageResponse.setWebPage(webPage); + return webPageResponse; + } + + private void fillWebPage(WebBase webPage) { + List schemaElementMatchList = parseInfo.getElementMatches(); + Map elementValueMap = new HashMap<>(); + if (!CollectionUtils.isEmpty(schemaElementMatchList) && !CollectionUtils.isEmpty(webPage.getParams()) ) { + schemaElementMatchList.stream() + .filter(schemaElementMatch -> + SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())) + .sorted(Comparator.comparingDouble(SchemaElementMatch::getSimilarity)) + .forEach(schemaElementMatch -> + elementValueMap.put(String.valueOf(schemaElementMatch.getElement().getId()), + schemaElementMatch.getWord())); + } + if (!CollectionUtils.isEmpty(parseInfo.getDimensionFilters())) { + parseInfo.getDimensionFilters().forEach( + filter -> elementValueMap.put(String.valueOf(filter.getElementID()), filter.getValue()) + ); + } + Map params = webPage.getParams(); + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + String elementId = String.valueOf(entry.getValue()); + Object elementValue = elementValueMap.get(elementId); + webPage.getValueParams().put(key, elementValue); + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webpage/WebPageResponse.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webpage/WebPageResponse.java new file mode 100644 index 000000000..6c75a37f9 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webpage/WebPageResponse.java @@ -0,0 +1,22 @@ +package com.tencent.supersonic.chat.query.plugin.webpage; + +import com.tencent.supersonic.chat.query.plugin.WebBase; +import lombok.Data; +import java.util.List; + +@Data +public class WebPageResponse { + + private Long pluginId; + + private String pluginType; + + private String name; + + private String description; + + private WebBase webPage; + + private List moreWebPage; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webservice/WebServiceQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webservice/WebServiceQuery.java new file mode 100644 index 000000000..d9ebe1f95 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webservice/WebServiceQuery.java @@ -0,0 +1,85 @@ +package com.tencent.supersonic.chat.query.plugin.webservice; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.plugin.Plugin; +import com.tencent.supersonic.chat.plugin.PluginParseResult; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; +import com.tencent.supersonic.chat.query.plugin.WebBase; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.common.util.*; + +import java.util.List; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.apache.calcite.sql.parser.SqlParseException; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +public class WebServiceQuery extends PluginSemanticQuery { + + public static String QUERY_MODE = "WEB_SERVICE"; + + private S2ThreadContext s2ThreadContext; + + public WebServiceQuery() { + QueryManager.register(this); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + + @Override + public QueryResult execute(User user) throws SqlParseException { + QueryResult queryResult = new QueryResult(); + queryResult.setQueryMode(QUERY_MODE); + Map properties = parseInfo.getProperties(); + PluginParseResult pluginParseResult = (PluginParseResult) properties.get(Constants.CONTEXT); + WebServiceResponse webServiceResponse = buildResponse(pluginParseResult); + Object object = webServiceResponse.getResult(); + Map data=JsonUtil.toMap(JsonUtil.toString(object),String.class,Object.class); + queryResult.setQueryResults((List>) data.get("resultList")); + queryResult.setQueryColumns((List) data.get("columns")); + //queryResult.setResponse(webServiceResponse); + queryResult.setQueryState(QueryState.SUCCESS); + parseInfo.setProperties(null); + return queryResult; + } + + protected WebServiceResponse buildResponse(PluginParseResult pluginParseResult) { + WebServiceResponse webServiceResponse = new WebServiceResponse(); + Plugin plugin = pluginParseResult.getPlugin(); + WebBase webBase = JsonUtil.toObject(plugin.getConfig(), WebBase.class); + webServiceResponse.setWebBase(webBase); + //http todo + s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class); + String authHeader = s2ThreadContext.get().getToken(); + log.info("authHeader:{}", authHeader); + try { + Map headers = new HashMap<>(); + headers.put("Authorization", authHeader); + Map params = new HashMap<>(); + params.put("queryText", pluginParseResult.getRequest().getQueryText()); + HttpClientResult httpClientResult = HttpClientUtils.doGet(webBase.getUrl(), headers, params); + log.info(" response body:{}", httpClientResult.getContent()); + Map result = JsonUtil.toMap(JsonUtil.toString(httpClientResult.getContent()), String.class, Object.class); + log.info(" result:{}", result); + Map data = JsonUtil.toMap(JsonUtil.toString(result.get("data")), String.class, Object.class); + log.info(" data:{}", data); + webServiceResponse.setResult(data); + } catch (Exception e) { + log.info("Exception:{}", e.getMessage()); + } + return webServiceResponse; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webservice/WebServiceResponse.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webservice/WebServiceResponse.java new file mode 100644 index 000000000..4c3995745 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/plugin/webservice/WebServiceResponse.java @@ -0,0 +1,15 @@ +package com.tencent.supersonic.chat.query.plugin.webservice; + +import com.tencent.supersonic.chat.query.plugin.WebBase; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +@Data +public class WebServiceResponse { + + private WebBase webBase; + + private Object result; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatchOption.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/QueryMatchOption.java similarity index 73% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatchOption.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/QueryMatchOption.java index e740a0c44..3f611c27a 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatchOption.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/QueryMatchOption.java @@ -1,16 +1,15 @@ -package com.tencent.supersonic.chat.application.query; +package com.tencent.supersonic.chat.query.rule; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import lombok.Data; @Data public class QueryMatchOption { - private SchemaElementOption schemaElementOption; + private OptionType schemaElementOption; private RequireNumberType requireNumberType; private Integer requireNumber; - public static QueryMatchOption build(SchemaElementOption schemaElementOption, + public static QueryMatchOption build(OptionType schemaElementOption, RequireNumberType requireNumberType, Integer requireNumber) { QueryMatchOption queryMatchOption = new QueryMatchOption(); queryMatchOption.requireNumber = requireNumber; @@ -21,7 +20,7 @@ public class QueryMatchOption { public static QueryMatchOption optional() { QueryMatchOption queryMatchOption = new QueryMatchOption(); - queryMatchOption.setSchemaElementOption(SchemaElementOption.OPTIONAL); + queryMatchOption.setSchemaElementOption(OptionType.OPTIONAL); queryMatchOption.setRequireNumber(0); queryMatchOption.setRequireNumberType(RequireNumberType.AT_LEAST); return queryMatchOption; @@ -29,7 +28,7 @@ public class QueryMatchOption { public static QueryMatchOption unused() { QueryMatchOption queryMatchOption = new QueryMatchOption(); - queryMatchOption.setSchemaElementOption(SchemaElementOption.UNUSED); + queryMatchOption.setSchemaElementOption(OptionType.UNUSED); queryMatchOption.setRequireNumber(0); queryMatchOption.setRequireNumberType(RequireNumberType.EQUAL); return queryMatchOption; @@ -39,5 +38,8 @@ public class QueryMatchOption { AT_MOST, AT_LEAST, EQUAL } + public enum OptionType { + REQUIRED, OPTIONAL, UNUSED + } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatcher.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/QueryMatcher.java similarity index 58% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatcher.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/QueryMatcher.java index 109982ebf..ce74dd3a7 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatcher.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/QueryMatcher.java @@ -1,10 +1,12 @@ -package com.tencent.supersonic.chat.application.query; +package com.tencent.supersonic.chat.query.rule; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; - +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -13,6 +15,7 @@ import java.util.Map; import java.util.Objects; import lombok.Data; import lombok.ToString; +import org.springframework.util.CollectionUtils; @Data @ToString @@ -23,6 +26,8 @@ public class QueryMatcher { private boolean supportOrderBy; private List orderByTypes = Arrays.asList(AggregateTypeEnum.MAX, AggregateTypeEnum.MIN, AggregateTypeEnum.TOPN); + private Long FREQUENCY = 9999999L; + private double SIMILARITY = 1.0; public QueryMatcher() { for (SchemaElementType type : SchemaElementType.values()) { @@ -34,7 +39,7 @@ public class QueryMatcher { } } - public QueryMatcher addOption(SchemaElementType type, SchemaElementOption option, + public QueryMatcher addOption(SchemaElementType type, QueryMatchOption.OptionType option, QueryMatchOption.RequireNumberType requireNumberType, Integer requireNumber) { elementOptionMap.put(type, QueryMatchOption.build(option, requireNumberType, requireNumber)); return this; @@ -47,12 +52,12 @@ public class QueryMatcher { * @return a list of all matched schema elements, * empty list if no matches can be found */ - public List match(List candidateElementMatches) { + public List match(List candidateElementMatches, QueryFilters queryFilters) { List elementMatches = new ArrayList<>(); - + List schemaElementMatchWithQueryFilter = addSchemaElementMatch(candidateElementMatches, queryFilters); HashMap schemaElementTypeCount = new HashMap<>(); - for (SchemaElementMatch schemaElementMatch : candidateElementMatches) { - SchemaElementType schemaElementType = schemaElementMatch.getElementType(); + for (SchemaElementMatch schemaElementMatch : schemaElementMatchWithQueryFilter) { + SchemaElementType schemaElementType = schemaElementMatch.getElement().getType(); if (schemaElementTypeCount.containsKey(schemaElementType)) { schemaElementTypeCount.put(schemaElementType, schemaElementTypeCount.get(schemaElementType) + 1); } else { @@ -70,10 +75,10 @@ public class QueryMatcher { } // add element match if its element type is not declared as unused - for (SchemaElementMatch elementMatch : candidateElementMatches) { - QueryMatchOption elementOption = elementOptionMap.get(elementMatch.getElementType()); + for (SchemaElementMatch elementMatch : schemaElementMatchWithQueryFilter) { + QueryMatchOption elementOption = elementOptionMap.get(elementMatch.getElement().getType()); if (Objects.nonNull(elementOption) && !elementOption.getSchemaElementOption() - .equals(SchemaElementOption.UNUSED)) { + .equals(QueryMatchOption.OptionType.UNUSED)) { elementMatches.add(elementMatch); } } @@ -81,6 +86,32 @@ public class QueryMatcher { return elementMatches; } + private List addSchemaElementMatch(List candidateElementMatches, QueryFilters queryFilter) { + List schemaElementMatchWithQueryFilter = new ArrayList<>(candidateElementMatches); + if (queryFilter == null || CollectionUtils.isEmpty(queryFilter.getFilters())) { + return schemaElementMatchWithQueryFilter; + } + QueryMatchOption queryMatchOption = elementOptionMap.get(SchemaElementType.VALUE); + if (queryMatchOption != null && QueryMatchOption.OptionType.REQUIRED.equals(queryMatchOption.getSchemaElementOption())) { + for (QueryFilter filter : queryFilter.getFilters()) { + SchemaElement element = SchemaElement.builder() + .id(filter.getElementID()) + .name(String.valueOf(filter.getValue())) + .type(SchemaElementType.VALUE) + .build(); + SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() + .element(element) + .frequency(FREQUENCY) + .word(String.valueOf(filter.getValue())) + .similarity(SIMILARITY) + .detectWord(Constants.EMPTY) + .build(); + schemaElementMatchWithQueryFilter.add(schemaElementMatch); + } + } + return schemaElementMatchWithQueryFilter; + } + private int getCount(HashMap schemaElementTypeCount, SchemaElementType schemaElementType) { if (schemaElementTypeCount.containsKey(schemaElementType)) { @@ -91,7 +122,7 @@ public class QueryMatcher { private boolean isMatch(QueryMatchOption queryMatchOption, int count) { // check if required but empty - if (queryMatchOption.getSchemaElementOption().equals(SchemaElementOption.REQUIRED) && count <= 0) { + if (queryMatchOption.getSchemaElementOption().equals(QueryMatchOption.OptionType.REQUIRED) && count <= 0) { return false; } if (queryMatchOption.getRequireNumberType().equals(QueryMatchOption.RequireNumberType.AT_LEAST) @@ -102,7 +133,6 @@ public class QueryMatcher { && count > queryMatchOption.getRequireNumber()) { return false; } - return true; } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/RuleSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/RuleSemanticQuery.java new file mode 100644 index 000000000..173eb2b6e --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/RuleSemanticQuery.java @@ -0,0 +1,233 @@ + +package com.tencent.supersonic.chat.query.rule; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.response.EntityInfo; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.service.SemanticService; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.chat.utils.QueryReqBuilder; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.*; + +@Slf4j +@ToString +public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { + + protected SemanticParseInfo parseInfo = new SemanticParseInfo(); + protected QueryMatcher queryMatcher = new QueryMatcher(); + protected SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + + public RuleSemanticQuery() { + QueryManager.register(this); + } + + public List match(List candidateElementMatches, + QueryContext queryCtx) { + return queryMatcher.match(candidateElementMatches, queryCtx.getRequest().getQueryFilters()); + } + + public void fillParseInfo(Long domainId, ChatContext chatContext){ + parseInfo.setQueryMode(getQueryMode()); + + ConfigService configService = ContextUtils.getBean(ConfigService.class); + ChatConfigRich chatConfig = configService.getConfigRichInfo(domainId); + + SemanticService schemaService = ContextUtils.getBean(SemanticService.class); + DomainSchema domainSchema = schemaService.getDomainSchema(domainId); + + fillSchemaElement(parseInfo, domainSchema, chatConfig); + // inherit date info from context + if (parseInfo.getDateInfo() == null && chatContext.getParseInfo().getDateInfo() != null) { + parseInfo.setDateInfo(chatContext.getParseInfo().getDateInfo()); + } + } + + private void fillSchemaElement(SemanticParseInfo parseInfo, DomainSchema domainSchema, ChatConfigRich chaConfigRich) { + parseInfo.setDomain(domainSchema.getDomain()); + + Map> dim2Values = new HashMap<>(); + for (SchemaElementMatch schemaMatch : parseInfo.getElementMatches()) { + SchemaElement element = schemaMatch.getElement(); + switch (element.getType()) { + case ID: + case VALUE: + SchemaElement dimElement = domainSchema.getElement(SchemaElementType.DIMENSION, element.getId()); + if (dimElement != null) { + if (dim2Values.containsKey(element.getId())) { + dim2Values.get(element.getId()).add(schemaMatch); + } else { + dim2Values.put(element.getId(), new ArrayList<>(Arrays.asList(schemaMatch))); + } + } + break; + case DIMENSION: + parseInfo.getDimensions().add(element); + break; + case METRIC: + parseInfo.getMetrics().add(element); + break; + default: + } + } + + if (!dim2Values.isEmpty()) { + for (Map.Entry> entry : dim2Values.entrySet()) { + SchemaElement dimension = domainSchema.getElement(SchemaElementType.DIMENSION, entry.getKey()); + + if (entry.getValue().size() == 1) { + SchemaElementMatch schemaMatch = entry.getValue().get(0); + QueryFilter dimensionFilter = new QueryFilter(); + dimensionFilter.setValue(schemaMatch.getWord()); + dimensionFilter.setBizName(dimension.getBizName()); + dimensionFilter.setName(dimension.getName()); + dimensionFilter.setOperator(FilterOperatorEnum.EQUALS); + dimensionFilter.setElementID(schemaMatch.getElement().getId()); + parseInfo.getDimensionFilters().add(dimensionFilter); + setEntityId(schemaMatch.getWord(), chaConfigRich, parseInfo); + } else { + QueryFilter dimensionFilter = new QueryFilter(); + List vals = new ArrayList<>(); + entry.getValue().stream().forEach(i -> vals.add(i.getWord())); + dimensionFilter.setValue(vals); + dimensionFilter.setBizName(dimension.getBizName()); + dimensionFilter.setName(dimension.getName()); + dimensionFilter.setOperator(FilterOperatorEnum.IN); + dimensionFilter.setElementID(entry.getKey()); + parseInfo.getDimensionFilters().add(dimensionFilter); + } + } + } + } + + public void setEntityId(String value, ChatConfigRich chaConfigRichDesc, + SemanticParseInfo semanticParseInfo) { + if (chaConfigRichDesc != null && chaConfigRichDesc.getChatDetailRichConfig() != null + && chaConfigRichDesc.getChatDetailRichConfig().getEntity() != null) { + SchemaElement dimSchemaResp = chaConfigRichDesc.getChatDetailRichConfig().getEntity().getDimItem(); + if (Objects.nonNull(dimSchemaResp) && StringUtils.isNumeric(value)) { + semanticParseInfo.setEntity(Long.valueOf(value)); + } + } + } + + @Override + public QueryResult execute(User user) { + String queryMode = parseInfo.getQueryMode(); + + if (parseInfo.getDomainId() < 0 || StringUtils.isEmpty(queryMode) + || !QueryManager.containsRuleQuery(queryMode)) { + // reach here some error may happen + log.error("not find QueryMode"); + throw new RuntimeException("not find QueryMode"); + } + + QueryResult queryResult = new QueryResult(); + QueryResultWithSchemaResp queryResp = semanticLayer.queryByStruct( + convertQueryStruct(), user); + + if (queryResp != null) { + queryResult.setQueryAuthorization(queryResp.getQueryAuthorization()); + } + String sql = queryResp == null ? null : queryResp.getSql(); + List> resultList = queryResp == null ? new ArrayList<>() + : queryResp.getResultList(); + List columns = queryResp == null ? new ArrayList<>() : queryResp.getColumns(); + queryResult.setQuerySql(sql); + queryResult.setQueryResults(resultList); + queryResult.setQueryColumns(columns); + queryResult.setQueryMode(queryMode); + queryResult.setQueryState(QueryState.SUCCESS); + + // add domain info + EntityInfo entityInfo = ContextUtils.getBean(SemanticService.class) + .getEntityInfo(parseInfo, user); + queryResult.setEntityInfo(entityInfo); + return queryResult; + } + + public QueryResult multiStructExecute(User user) { + String queryMode = parseInfo.getQueryMode(); + + if (parseInfo.getDomainId() < 0 || StringUtils.isEmpty(queryMode) + || !QueryManager.containsRuleQuery(queryMode)) { + // reach here some error may happen + log.error("not find QueryMode"); + throw new RuntimeException("not find QueryMode"); + } + + QueryResult queryResult = new QueryResult(); + QueryMultiStructReq queryMultiStructReq = convertQueryMultiStruct(); + QueryResultWithSchemaResp queryResp = semanticLayer.queryByMultiStruct(queryMultiStructReq, user); + if (queryResp != null) { + queryResult.setQueryAuthorization(queryResp.getQueryAuthorization()); + } + String sql = queryResp == null ? null : queryResp.getSql(); + List> resultList = queryResp == null ? new ArrayList<>() + : queryResp.getResultList(); + List columns = queryResp == null ? new ArrayList<>() : queryResp.getColumns(); + queryResult.setQuerySql(sql); + queryResult.setQueryResults(resultList); + queryResult.setQueryColumns(columns); + queryResult.setQueryMode(queryMode); + queryResult.setQueryState(QueryState.SUCCESS); + + // add domain info + EntityInfo entityInfo = ContextUtils.getBean(SemanticService.class) + .getEntityInfo(parseInfo, user); + queryResult.setEntityInfo(entityInfo); + return queryResult; + } + + @Override + public SemanticParseInfo getParseInfo() { + return parseInfo; + } + + public void setParseInfo(SemanticParseInfo parseInfo) { + this.parseInfo = parseInfo; + } + + public static List resolve(List candidateElementMatches, + QueryContext queryContext) { + List matchedQueries = new ArrayList<>(); + for (RuleSemanticQuery semanticQuery : QueryManager.getRuleQueries()) { + List matches = semanticQuery.match(candidateElementMatches, queryContext); + + if (matches.size() > 0) { + RuleSemanticQuery query = QueryManager.createRuleQuery(semanticQuery.getQueryMode()); + query.getParseInfo().getElementMatches().addAll(matches); + matchedQueries.add(query); + } + } + + return matchedQueries; + } + + protected QueryStructReq convertQueryStruct() { + return QueryReqBuilder.buildStructReq(parseInfo); + } + + protected QueryMultiStructReq convertQueryMultiStruct() { + return QueryReqBuilder.buildMultiStructReq(parseInfo); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityDetailQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityDetailQuery.java new file mode 100644 index 000000000..6ca497420 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityDetailQuery.java @@ -0,0 +1,25 @@ +package com.tencent.supersonic.chat.query.rule.entity; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; + +import org.springframework.stereotype.Component; + +@Component +public class EntityDetailQuery extends EntitySemanticQuery { + + public static final String QUERY_MODE = "ENTITY_DETAIL"; + + public EntityDetailQuery() { + super(); + queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1) + .addOption(VALUE, REQUIRED, AT_LEAST, 1); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityFilterQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityFilterQuery.java new file mode 100644 index 000000000..5899d9ccb --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityFilterQuery.java @@ -0,0 +1,27 @@ +package com.tencent.supersonic.chat.query.rule.entity; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + + +@Slf4j +@Component +public class EntityFilterQuery extends EntityListQuery { + + public static final String QUERY_MODE = "ENTITY_LIST_FILTER"; + + public EntityFilterQuery() { + super(); + queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 1); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityListQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityListQuery.java new file mode 100644 index 000000000..45398e1aa --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityListQuery.java @@ -0,0 +1,53 @@ +package com.tencent.supersonic.chat.query.rule.entity; + +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.config.ChatDefaultRichConfig; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.Order; +import com.tencent.supersonic.common.util.ContextUtils; + +import java.util.LinkedHashSet; +import java.util.Set; + +public abstract class EntityListQuery extends EntitySemanticQuery{ + + @Override + public void fillParseInfo(Long domainId, ChatContext chatContext){ + super.fillParseInfo(domainId, chatContext); + this.addEntityDetailAndOrderByMetric(parseInfo); + } + + private void addEntityDetailAndOrderByMetric(SemanticParseInfo parseInfo) { + if (parseInfo.getDomainId() > 0L) { + ConfigService configService = ContextUtils.getBean(ConfigService.class); + ChatConfigRich chaConfigRichDesc = configService.getConfigRichInfo( + parseInfo.getDomainId()); + if (chaConfigRichDesc != null && chaConfigRichDesc.getChatDetailRichConfig() != null + && chaConfigRichDesc.getChatDetailRichConfig().getEntity() != null) { + Set dimensions = new LinkedHashSet(); + Set metrics = new LinkedHashSet(); + Set orders = new LinkedHashSet(); + ChatDefaultRichConfig chatDefaultConfig = chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig(); + if (chatDefaultConfig != null) { + chatDefaultConfig.getMetrics().stream() + .forEach(metric -> { + metrics.add(metric); + orders.add(new Order(metric.getBizName(), Constants.DESC_UPPER)); + }); + chatDefaultConfig.getDimensions().stream() + .forEach(dimension -> dimensions.add(dimension)); + + } + + parseInfo.setDimensions(dimensions); + parseInfo.setMetrics(metrics); + parseInfo.setOrders(orders); + } + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntitySemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntitySemanticQuery.java new file mode 100644 index 000000000..50981348e --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntitySemanticQuery.java @@ -0,0 +1,105 @@ +package com.tencent.supersonic.chat.query.rule.entity; + +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.config.ChatConfigResp; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.config.ChatDefaultRichConfig; +import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.util.ContextUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; + +@Slf4j +public abstract class EntitySemanticQuery extends RuleSemanticQuery { + + private static final Long ENTITY_MAX_RESULTS = 500L; + + public EntitySemanticQuery() { + super(); + queryMatcher.addOption(ENTITY, REQUIRED, AT_LEAST, 1); + } + + @Override + public List match(List candidateElementMatches, + QueryContext queryCtx) { + candidateElementMatches = filterElementMatches(candidateElementMatches); + return super.match(candidateElementMatches, queryCtx); + } + + private List filterElementMatches(List candidateElementMatches) { + List filteredMatches = new ArrayList<>(); + if (CollectionUtils.isEmpty(candidateElementMatches) + || Objects.isNull(candidateElementMatches.get(0).getElement().getDomain())) { + return candidateElementMatches; + } + + Long domainId = candidateElementMatches.get(0).getElement().getDomain(); + ConfigService configService = ContextUtils.getBean(ConfigService.class); + ChatConfigResp chatConfig = configService.fetchConfigByDomainId(domainId); + + List blackDimIdList = new ArrayList<>(); + List blackMetricIdList = new ArrayList<>(); + if (Objects.nonNull(chatConfig.getChatDetailConfig()) + && Objects.nonNull(chatConfig.getChatDetailConfig().getVisibility())) { + blackDimIdList = chatConfig.getChatDetailConfig().getVisibility().getBlackDimIdList(); + blackMetricIdList = chatConfig.getChatDetailConfig().getVisibility().getBlackMetricIdList(); + } + + for (SchemaElementMatch schemaElementMatch : candidateElementMatches) { + + SchemaElementType type = schemaElementMatch.getElement().getType(); + if (SchemaElementType.DIMENSION.equals(type) || SchemaElementType.VALUE.equals(type)) { + if (!blackDimIdList.contains(schemaElementMatch.getElement().getId())) { + filteredMatches.add(schemaElementMatch); + } + } else if (SchemaElementType.METRIC.equals(type)) { + if (!blackMetricIdList.contains(schemaElementMatch.getElement().getId())) { + filteredMatches.add(schemaElementMatch); + } + } else { + filteredMatches.add(schemaElementMatch); + } + } + return filteredMatches; + } + + @Override + public void fillParseInfo(Long domainId, ChatContext chatContext) { + super.fillParseInfo(domainId, chatContext); + + parseInfo.setNativeQuery(true); + parseInfo.setLimit(ENTITY_MAX_RESULTS); + if (parseInfo.getDateInfo() == null) { + ConfigService configService = ContextUtils.getBean(ConfigService.class); + ChatConfigRich chatConfig = configService.getConfigRichInfo(parseInfo.getDomainId()); + ChatDefaultRichConfig defaultConfig = chatConfig.getChatDetailRichConfig().getChatDefaultConfig(); + + int unit = 1; + if (Objects.nonNull(defaultConfig) && Objects.nonNull(defaultConfig.getUnit())) { + unit = defaultConfig.getUnit(); + } + String date = LocalDate.now().plusDays(-unit).toString(); + DateConf dateInfo = new DateConf(); + dateInfo.setDateMode(DateConf.DateMode.BETWEEN_CONTINUOUS); + dateInfo.setStartDate(date); + dateInfo.setEndDate(date); + + parseInfo.setDateInfo(dateInfo); + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityTopNQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityTopNQuery.java new file mode 100644 index 000000000..ae0d34e61 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/entity/EntityTopNQuery.java @@ -0,0 +1,25 @@ +package com.tencent.supersonic.chat.query.rule.entity; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; + +import org.springframework.stereotype.Component; + +@Component +public class EntityTopNQuery extends EntityListQuery { + + public static final String QUERY_MODE = "ENTITY_LIST_TOPN"; + + public EntityTopNQuery() { + super(); + queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1) + .setSupportOrderBy(true); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricDomainQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricDomainQuery.java new file mode 100644 index 000000000..badc4aa2b --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricDomainQuery.java @@ -0,0 +1,45 @@ +package com.tencent.supersonic.chat.query.rule.metric; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.response.AggregateInfo; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.service.SemanticService; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import java.util.Objects; +import org.springframework.stereotype.Component; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.OPTIONAL; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.*; + +@Component +public class MetricDomainQuery extends MetricSemanticQuery { + + public static final String QUERY_MODE = "METRIC_DOMAIN"; + + public MetricDomainQuery() { + super(); + queryMatcher.addOption(DOMAIN, OPTIONAL, AT_MOST, 1); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + + @Override + public QueryResult execute(User user) { + QueryResult queryResult = super.execute(user); + if (!Objects.isNull(queryResult)) { + QueryResultWithSchemaResp queryResp = new QueryResultWithSchemaResp(); + queryResp.setColumns(queryResult.getQueryColumns()); + queryResp.setResultList(queryResult.getQueryResults()); + AggregateInfo aggregateInfo = ContextUtils.getBean(SemanticService.class) + .getAggregateInfo(user, parseInfo, queryResp); + queryResult.setAggregateInfo(aggregateInfo); + } + return queryResult; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricFilterQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricFilterQuery.java new file mode 100644 index 000000000..bb6125f47 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricFilterQuery.java @@ -0,0 +1,97 @@ +package com.tencent.supersonic.chat.query.rule.metric; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.response.AggregateInfo; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.service.SemanticService; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import com.tencent.supersonic.semantic.api.query.pojo.Filter; +import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import java.util.*; +import java.util.stream.Collectors; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.OPTIONAL; + +@Slf4j +@Component +public class MetricFilterQuery extends MetricSemanticQuery { + + public static final String QUERY_MODE = "METRIC_FILTER"; + + public MetricFilterQuery() { + super(); + queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 1) + .addOption(ENTITY, OPTIONAL, AT_MOST, 1); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + + @Override + public QueryResult execute(User user) { + if (!isMultiStructQuery()) { + QueryResult queryResult = super.execute(user); + if (Objects.nonNull(queryResult)) { + QueryResultWithSchemaResp queryResp = new QueryResultWithSchemaResp(); + queryResp.setColumns(queryResult.getQueryColumns()); + queryResp.setResultList(queryResult.getQueryResults()); + AggregateInfo aggregateInfo = ContextUtils.getBean(SemanticService.class) + .getAggregateInfo(user,parseInfo,queryResp); + queryResult.setAggregateInfo(aggregateInfo); + } + return queryResult; + } + return super.multiStructExecute(user); + } + + protected boolean isMultiStructQuery() { + Set filterBizName = new HashSet<>(); + parseInfo.getDimensionFilters().forEach(filter -> + filterBizName.add(filter.getBizName())); + return filterBizName.size() > 1; + } + + @Override + protected QueryStructReq convertQueryStruct() { + QueryStructReq queryStructReq = super.convertQueryStruct(); + addDimension(queryStructReq, true); + return queryStructReq; + } + + @Override + protected QueryMultiStructReq convertQueryMultiStruct() { + QueryMultiStructReq queryMultiStructReq = super.convertQueryMultiStruct(); + for (QueryStructReq queryStructReq : queryMultiStructReq.getQueryStructReqs()) { + addDimension(queryStructReq, false); + } + return queryMultiStructReq; + } + + private void addDimension(QueryStructReq queryStructReq, boolean onlyOperateInFilter) { + if (!queryStructReq.getDimensionFilters().isEmpty()) { + List dimensions = queryStructReq.getGroups(); + log.info("addDimension before [{}]", queryStructReq.getGroups()); + List filters = new ArrayList<>(queryStructReq.getDimensionFilters()); + if (onlyOperateInFilter) { + filters = filters.stream().filter(filter + -> filter.getOperator().equals(FilterOperatorEnum.IN)).collect(Collectors.toList()); + } + filters.forEach(d -> { + if (!dimensions.contains(d.getBizName())) { + dimensions.add(d.getBizName()); + }}); + queryStructReq.setGroups(dimensions); + log.info("addDimension after [{}]", queryStructReq.getGroups()); + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricGroupByQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricGroupByQuery.java new file mode 100644 index 000000000..82571a6d1 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricGroupByQuery.java @@ -0,0 +1,26 @@ +package com.tencent.supersonic.chat.query.rule.metric; + +import org.springframework.stereotype.Component; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.OPTIONAL; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; + +@Component +public class MetricGroupByQuery extends MetricSemanticQuery { + + public static final String QUERY_MODE = "METRIC_GROUPBY"; + + public MetricGroupByQuery() { + super(); + queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1); + queryMatcher.addOption(VALUE, OPTIONAL, AT_LEAST, 0); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricSemanticQuery.java new file mode 100644 index 000000000..177123be8 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricSemanticQuery.java @@ -0,0 +1,105 @@ +package com.tencent.supersonic.chat.query.rule.metric; + +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.config.ChatConfigResp; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.config.ChatDefaultRichConfig; +import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.util.ContextUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.METRIC; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; + +@Slf4j +public abstract class MetricSemanticQuery extends RuleSemanticQuery { + + private static final Long METRIC_MAX_RESULTS = 365L; + + public MetricSemanticQuery() { + super(); + queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1); + } + + @Override + public List match(List candidateElementMatches, + QueryContext queryCtx) { + candidateElementMatches = filterElementMatches(candidateElementMatches); + return super.match(candidateElementMatches, queryCtx); + } + + private List filterElementMatches(List candidateElementMatches) { + List filteredMatches = new ArrayList<>(); + if (CollectionUtils.isEmpty(candidateElementMatches) + || Objects.isNull(candidateElementMatches.get(0).getElement().getDomain())) { + return candidateElementMatches; + } + + Long domainId = candidateElementMatches.get(0).getElement().getDomain(); + ConfigService configService = ContextUtils.getBean(ConfigService.class); + ChatConfigResp chatConfig = configService.fetchConfigByDomainId(domainId); + + List blackDimIdList = new ArrayList<>(); + List blackMetricIdList = new ArrayList<>(); + if (Objects.nonNull(chatConfig.getChatAggConfig()) + && Objects.nonNull(chatConfig.getChatAggConfig().getVisibility())) { + blackDimIdList = chatConfig.getChatAggConfig().getVisibility().getBlackDimIdList(); + blackMetricIdList = chatConfig.getChatAggConfig().getVisibility().getBlackMetricIdList(); + } + + for (SchemaElementMatch schemaElementMatch : candidateElementMatches) { + SchemaElementType type = schemaElementMatch.getElement().getType(); + + if (SchemaElementType.DIMENSION.equals(type) || SchemaElementType.VALUE.equals(type)) { + if (!blackDimIdList.contains(schemaElementMatch.getElement().getId())) { + filteredMatches.add(schemaElementMatch); + } + } else if (SchemaElementType.METRIC.equals(type)) { + if (!blackMetricIdList.contains(schemaElementMatch.getElement().getId())) { + filteredMatches.add(schemaElementMatch); + } + } else { + filteredMatches.add(schemaElementMatch); + } + } + return filteredMatches; + } + + @Override + public void fillParseInfo(Long domainId, ChatContext chatContext){ + super.fillParseInfo(domainId, chatContext); + + parseInfo.setLimit(METRIC_MAX_RESULTS); + if (parseInfo.getDateInfo() == null) { + ConfigService configService = ContextUtils.getBean(ConfigService.class); + ChatConfigRich chatConfig = configService.getConfigRichInfo(parseInfo.getDomainId()); + ChatDefaultRichConfig defaultConfig = chatConfig.getChatAggRichConfig().getChatDefaultConfig(); + + int unit = 1; + if (Objects.nonNull(defaultConfig) && Objects.nonNull(defaultConfig.getUnit())) { + unit = defaultConfig.getUnit(); + } + String startDate = LocalDate.now().plusDays(-unit).toString(); + String endDate = LocalDate.now().plusDays(-1).toString(); + DateConf dateInfo = new DateConf(); + dateInfo.setDateMode(DateConf.DateMode.BETWEEN_CONTINUOUS); + dateInfo.setStartDate(startDate); + dateInfo.setEndDate(endDate); + + parseInfo.setDateInfo(dateInfo); + } + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricTopNQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricTopNQuery.java new file mode 100644 index 000000000..196e8e70a --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricTopNQuery.java @@ -0,0 +1,64 @@ +package com.tencent.supersonic.chat.query.rule.metric; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.DIMENSION; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.OPTIONAL; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; +import static com.tencent.supersonic.common.pojo.Constants.DESC_UPPER; + +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.common.pojo.Order; +import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Component +public class MetricTopNQuery extends MetricSemanticQuery { + + public static final String QUERY_MODE = "METRIC_ORDERBY"; + private static final Long ORDERBY_MAX_RESULTS = 3L; + private static final Pattern INTENT_PATTERN = Pattern.compile("(.*)(最大|最高|最多)(.*)"); + + public MetricTopNQuery() { + super(); + queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1); + queryMatcher.addOption(VALUE, OPTIONAL, AT_LEAST, 0); + queryMatcher.setSupportOrderBy(true); + } + + @Override + public List match(List candidateElementMatches, + QueryContext queryCtx) { + Matcher matcher = INTENT_PATTERN.matcher(queryCtx.getRequest().getQueryText()); + if (matcher.matches()) { + return super.match(candidateElementMatches, queryCtx); + } + return new ArrayList<>(); + } + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + + @Override + public void fillParseInfo(Long domainId, ChatContext chatContext){ + super.fillParseInfo(domainId, chatContext); + + parseInfo.setLimit(ORDERBY_MAX_RESULTS); + parseInfo.setBonus(2.0); + parseInfo.setAggType(AggregateTypeEnum.SUM); + + SchemaElement metric = parseInfo.getMetrics().iterator().next(); + parseInfo.getOrders().add(new Order(metric.getBizName(), DESC_UPPER)); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatConfigController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatConfigController.java index 07658f701..d1ece0e2f 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatConfigController.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatConfigController.java @@ -4,18 +4,14 @@ import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigBaseReq; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigEditReqReq; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilter; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichResp; -import com.tencent.supersonic.chat.domain.service.ConfigService; +import com.tencent.supersonic.chat.config.*; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.chat.service.ConfigService; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -69,12 +65,12 @@ public class ChatConfigController { @GetMapping("/richDesc/{domainId}") - public ChatConfigRichResp getDomainExtendRichInfo(@PathVariable("domainId") Long domainId) { + public ChatConfigRich getDomainExtendRichInfo(@PathVariable("domainId") Long domainId) { return configService.getConfigRichInfo(domainId); } @GetMapping("/richDesc/all") - public List getAllChatRichConfig() { + public List getAllChatRichConfig() { return configService.getAllChatRichConfig(); } @@ -88,27 +84,25 @@ public class ChatConfigController { public List getDomainList() { return semanticLayer.getDomainListForAdmin(); - //return defaultSemanticUtils.getDomainListForAdmin(); } @GetMapping("/domainList/view") public List getDomainListForViewer() { return semanticLayer.getDomainListForViewer(); - //return defaultSemanticUtils.getDomainListForViewer(); } @PostMapping("/dimension/page") - public PageInfo queryDimension(@RequestBody PageDimensionReq pageDimensionCmd, - HttpServletRequest request, - HttpServletResponse response) { - return semanticLayer.queryDimensionPage(pageDimensionCmd); + public PageInfo getDimension(@RequestBody PageDimensionReq pageDimensionCmd, + HttpServletRequest request, + HttpServletResponse response) { + return semanticLayer.getDimensionPage(pageDimensionCmd); } @PostMapping("/metric/page") - public PageInfo queryMetric(@RequestBody PageMetricReq pageMetrricCmd, - HttpServletRequest request, - HttpServletResponse response) { - return semanticLayer.queryMetricPage(pageMetrricCmd); + public PageInfo getMetric(@RequestBody PageMetricReq pageMetrricCmd, + HttpServletRequest request, + HttpServletResponse response) { + return semanticLayer.getMetricPage(pageMetrricCmd); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatController.java index f56131f90..85b0ea412 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatController.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatController.java @@ -3,10 +3,10 @@ package com.tencent.supersonic.chat.rest; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.chat.domain.dataobject.ChatDO; -import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO; -import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq; -import com.tencent.supersonic.chat.domain.service.ChatService; +import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResponse; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; +import com.tencent.supersonic.chat.service.ChatService; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -68,13 +68,12 @@ public class ChatController { } @PostMapping("/pageQueryInfo") - public PageInfo pageQueryInfo(@RequestBody PageQueryInfoReq pageQueryInfoCommend, - @RequestParam(value = "chatId") long chatId, - HttpServletRequest request, - HttpServletResponse response) { - pageQueryInfoCommend.setUserName(UserHolder.findUser(request, response).getName()); - return chatService.queryInfo(pageQueryInfoCommend, chatId); + public PageInfo pageQueryInfo(@RequestBody PageQueryInfoReq pageQueryInfoCommand, + @RequestParam(value = "chatId") long chatId, + HttpServletRequest request, + HttpServletResponse response) { + pageQueryInfoCommand.setUserName(UserHolder.findUser(request, response).getName()); + return chatService.queryInfo(pageQueryInfoCommand, chatId); } - } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatQueryController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatQueryController.java index 9ffd97e18..0356e27ef 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatQueryController.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/ChatQueryController.java @@ -2,10 +2,10 @@ package com.tencent.supersonic.chat.rest; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.QueryData; -import com.tencent.supersonic.chat.domain.service.QueryService; -import com.tencent.supersonic.chat.domain.service.SearchService; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.request.QueryDataRequest; +import com.tencent.supersonic.chat.service.QueryService; +import com.tencent.supersonic.chat.service.SearchService; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; @@ -31,28 +31,28 @@ public class ChatQueryController { @PostMapping("search") - public Object search(@RequestBody QueryContextReq queryCtx, HttpServletRequest request, - HttpServletResponse response) { + public Object search(@RequestBody QueryRequest queryCtx, HttpServletRequest request, + HttpServletResponse response) { queryCtx.setUser(UserHolder.findUser(request, response)); return searchService.search(queryCtx); } @PostMapping("query") - public Object query(@RequestBody QueryContextReq queryCtx, HttpServletRequest request, HttpServletResponse response) + public Object query(@RequestBody QueryRequest queryCtx, HttpServletRequest request, HttpServletResponse response) throws Exception { queryCtx.setUser(UserHolder.findUser(request, response)); return queryService.executeQuery(queryCtx); } @PostMapping("queryContext") - public Object queryContext(@RequestBody QueryContextReq queryCtx, HttpServletRequest request, - HttpServletResponse response) throws Exception { + public Object queryContext(@RequestBody QueryRequest queryCtx, HttpServletRequest request, + HttpServletResponse response) throws Exception { queryCtx.setUser(UserHolder.findUser(request, response)); return queryService.queryContext(queryCtx); } @PostMapping("queryData") - public Object queryData(@RequestBody QueryData queryData, HttpServletRequest request, HttpServletResponse response) + public Object queryData(@RequestBody QueryDataRequest queryData, HttpServletRequest request, HttpServletResponse response) throws Exception { return queryService.executeDirectQuery(queryData, UserHolder.findUser(request, response)); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/DictController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/DictionaryController.java similarity index 80% rename from chat/core/src/main/java/com/tencent/supersonic/chat/rest/DictController.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/rest/DictionaryController.java index 1df4b3861..09fb97995 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/DictController.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/DictionaryController.java @@ -3,13 +3,15 @@ package com.tencent.supersonic.chat.rest; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.chat.application.knowledge.DictApplicationService; -import com.tencent.supersonic.knowledge.domain.pojo.DictTaskFilter; -import com.tencent.supersonic.knowledge.domain.pojo.DimValue2DictCommand; -import com.tencent.supersonic.knowledge.domain.pojo.DimValueDictInfo; +import com.tencent.supersonic.chat.service.DictionaryService; +import com.tencent.supersonic.knowledge.dictionary.DictTaskFilter; +import com.tencent.supersonic.knowledge.dictionary.DimValue2DictCommand; +import com.tencent.supersonic.knowledge.dictionary.DimValueDictInfo; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -20,13 +22,10 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/chat/dict") -public class DictController { +public class DictionaryController { - private final DictApplicationService dictApplicationService; - - public DictController(DictApplicationService dictApplicationService) { - this.dictApplicationService = dictApplicationService; - } + @Autowired + private DictionaryService dictApplicationService; /** * addDictInfo diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/PluginController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/PluginController.java new file mode 100644 index 000000000..c47444f6e --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/PluginController.java @@ -0,0 +1,57 @@ +package com.tencent.supersonic.chat.rest; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; +import com.tencent.supersonic.chat.api.pojo.request.PluginQueryReq; +import com.tencent.supersonic.chat.plugin.Plugin; +import com.tencent.supersonic.chat.service.PluginService; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +@RestController +@RequestMapping("/api/chat/plugin") +public class PluginController { + + private PluginService pluginService; + + public PluginController(PluginService pluginService) { + this.pluginService = pluginService; + } + + @PostMapping + public boolean createPlugin(@RequestBody Plugin plugin, + HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse) { + User user = UserHolder.findUser(httpServletRequest, httpServletResponse); + pluginService.createPlugin(plugin, user); + return true; + } + + @PutMapping + public boolean updatePlugin(@RequestBody Plugin plugin, + HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse) { + User user = UserHolder.findUser(httpServletRequest, httpServletResponse); + pluginService.updatePlugin(plugin, user); + return true; + } + + @DeleteMapping("/{id}") + public boolean deletePlugin(@PathVariable("id") Long id) { + pluginService.deletePlugin(id); + return true; + } + + @RequestMapping("/getPluginList") + public List getPluginList() { + return pluginService.getPluginList(); + } + + @PostMapping("/query") + List query(PluginQueryReq pluginQueryReq) { + return pluginService.queryWithAuthCheck(pluginQueryReq); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/RecommendController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/RecommendController.java index 0ceaefa13..7118c20b6 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/RecommendController.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/RecommendController.java @@ -1,15 +1,18 @@ package com.tencent.supersonic.chat.rest; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.service.RecommendService; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.RecommendQuestion; +import com.tencent.supersonic.chat.api.pojo.response.RecommendResponse; +import com.tencent.supersonic.chat.service.RecommendService; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; /** * recommend controller @@ -22,11 +25,31 @@ public class RecommendController { private RecommendService recommendService; @GetMapping("recommend/{domainId}") - public Object recommend(@PathVariable("domainId") Integer domainId, HttpServletRequest request, - HttpServletResponse response) { - QueryContextReq queryCtx = new QueryContextReq(); + public RecommendResponse recommend(@PathVariable("domainId") Long domainId, + @RequestParam(value = "limit", required = false) Long limit, + HttpServletRequest request, + HttpServletResponse response) { + QueryRequest queryCtx = new QueryRequest(); queryCtx.setUser(UserHolder.findUser(request, response)); queryCtx.setDomainId(domainId); - return recommendService.recommend(queryCtx); + return recommendService.recommend(queryCtx, limit); + } + + @GetMapping("recommend/metric/{domainId}") + public RecommendResponse recommendMetricMode(@PathVariable("domainId") Long domainId, + @RequestParam(value = "limit", required = false) Long limit, + HttpServletRequest request, + HttpServletResponse response) { + QueryRequest queryCtx = new QueryRequest(); + queryCtx.setUser(UserHolder.findUser(request, response)); + queryCtx.setDomainId(domainId); + return recommendService.recommendMetricMode(queryCtx, limit); + } + + @GetMapping("recommend/question") + public List recommendQuestion(@RequestParam(value = "domainId", required = false) Long domainId, + HttpServletRequest request, + HttpServletResponse response) { + return recommendService.recommendQuestion(domainId); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ChatService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/ChatService.java similarity index 59% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ChatService.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/service/ChatService.java index 531232822..590eec797 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ChatService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/ChatService.java @@ -1,15 +1,15 @@ -package com.tencent.supersonic.chat.domain.service; +package com.tencent.supersonic.chat.service; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.domain.dataobject.ChatDO; -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDO; -import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO; -import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResponse; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; import java.util.List; public interface ChatService { @@ -25,7 +25,7 @@ public interface ChatService { public void updateContext(ChatContext chatCtx); - public void updateContext(ChatContext chatCtx, QueryContextReq queryCtx, SemanticParseInfo semanticParseInfo); + public void updateContext(ChatContext chatCtx, QueryContext queryCtx, SemanticParseInfo semanticParseInfo); public void switchContext(ChatContext chatCtx); @@ -41,9 +41,9 @@ public interface ChatService { Boolean deleteChat(Long chatId, String userName); - PageInfo queryInfo(PageQueryInfoReq pageQueryInfoCommend, long chatId); + PageInfo queryInfo(PageQueryInfoReq pageQueryInfoCommend, long chatId); - public void addQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx); + public void addQuery(QueryResult queryResult, QueryContext queryContext, ChatContext chatCtx); public ChatQueryDO getLastQuery(long chatId); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/ConfigService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/ConfigService.java new file mode 100644 index 000000000..d211d2580 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/ConfigService.java @@ -0,0 +1,22 @@ +package com.tencent.supersonic.chat.service; + + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.config.*; + +import java.util.List; + +public interface ConfigService { + + Long addConfig(ChatConfigBaseReq extendBaseCmd, User user); + + Long editConfig(ChatConfigEditReqReq extendEditCmd, User user); + + List search(ChatConfigFilter filter, User user); + + ChatConfigRich getConfigRichInfo(Long domainId); + + ChatConfigResp fetchConfigByDomainId(Long domainId); + + List getAllChatRichConfig(); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/DictionaryService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/DictionaryService.java new file mode 100644 index 000000000..5ef1adec9 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/DictionaryService.java @@ -0,0 +1,21 @@ +package com.tencent.supersonic.chat.service; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.knowledge.dictionary.DictConfig; +import com.tencent.supersonic.knowledge.dictionary.DictTaskFilter; +import com.tencent.supersonic.knowledge.dictionary.DimValue2DictCommand; +import com.tencent.supersonic.knowledge.dictionary.DimValueDictInfo; + +import java.util.List; + +public interface DictionaryService { + Long addDictTask(DimValue2DictCommand dimValue2DictCommend, User user); + + Long deleteDictTask(DimValue2DictCommand dimValue2DictCommend, User user); + + List searchDictTaskList(DictTaskFilter filter, User user); + + DictConfig getDictInfoByDomainId(Long domainId); + + String getDictRootPath(); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/PluginService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/PluginService.java new file mode 100644 index 000000000..3d749e335 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/PluginService.java @@ -0,0 +1,28 @@ +package com.tencent.supersonic.chat.service; + + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.plugin.Plugin; +import com.tencent.supersonic.chat.api.pojo.request.PluginQueryReq; + +import java.util.List; +import java.util.Optional; + +public interface PluginService { + + void createPlugin(Plugin plugin, User user); + + void updatePlugin(Plugin plugin, User user); + + void deletePlugin(Long id); + + List getPluginList(); + + List fetchPluginDOs(String queryText, String type); + + List query(PluginQueryReq pluginQueryReq); + + Optional getPluginByName(String name); + + List queryWithAuthCheck(PluginQueryReq pluginQueryReq); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/QueryService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/QueryService.java new file mode 100644 index 000000000..b13d5d893 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/QueryService.java @@ -0,0 +1,20 @@ +package com.tencent.supersonic.chat.service; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.request.QueryDataRequest; +import org.apache.calcite.sql.parser.SqlParseException; + +/*** + * QueryService for query and search + */ +public interface QueryService { + + QueryResult executeQuery(QueryRequest queryCtx) throws Exception; + + SemanticParseInfo queryContext(QueryRequest queryCtx); + + QueryResult executeDirectQuery(QueryDataRequest queryData, User user) throws SqlParseException; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/RecommendService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/RecommendService.java new file mode 100644 index 000000000..8e8aff45c --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/RecommendService.java @@ -0,0 +1,20 @@ +package com.tencent.supersonic.chat.service; + + +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.RecommendQuestion; +import com.tencent.supersonic.chat.api.pojo.response.RecommendResponse; + +import java.util.List; + +/*** + * Recommend Service + */ +public interface RecommendService { + + RecommendResponse recommend(QueryRequest queryCtx, Long limit); + + RecommendResponse recommendMetricMode(QueryRequest queryCtx, Long limit); + + List recommendQuestion(Long domainId); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/SearchService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/SearchService.java new file mode 100644 index 000000000..2460ef1e6 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/SearchService.java @@ -0,0 +1,14 @@ +package com.tencent.supersonic.chat.service; + +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.SearchResult; +import java.util.List; + +/** + * search service + */ +public interface SearchService { + + List search(QueryRequest queryCtx); + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/SemanticService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/SemanticService.java new file mode 100644 index 000000000..fdac19b67 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/SemanticService.java @@ -0,0 +1,430 @@ +package com.tencent.supersonic.chat.service; + + +import static com.tencent.supersonic.common.pojo.Constants.DAY; +import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT; +import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT_INT; +import static com.tencent.supersonic.common.pojo.Constants.MONTH; +import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT; +import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT_INT; +import static com.tencent.supersonic.common.pojo.Constants.TIMES_FORMAT; +import static com.tencent.supersonic.common.pojo.Constants.TIME_FORMAT; +import static com.tencent.supersonic.common.pojo.Constants.WEEK; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.response.AggregateInfo; +import com.tencent.supersonic.chat.api.pojo.response.DataInfo; +import com.tencent.supersonic.chat.api.pojo.response.DomainInfo; +import com.tencent.supersonic.chat.api.pojo.response.EntityInfo; +import com.tencent.supersonic.chat.api.pojo.response.MetricInfo; +import com.tencent.supersonic.chat.config.ChatAggConfig; +import com.tencent.supersonic.chat.config.ChatConfigResp; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.config.ChatDefaultRichConfig; +import com.tencent.supersonic.chat.config.ChatDetailConfig; +import com.tencent.supersonic.chat.config.EntityRichInfo; +import com.tencent.supersonic.chat.config.ItemVisibility; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.chat.utils.QueryReqBuilder; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.pojo.DateConf.DateMode; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum; +import com.tencent.supersonic.common.pojo.enums.RatioOverType; +import com.tencent.supersonic.common.util.DateUtils; +import com.tencent.supersonic.knowledge.service.SchemaService; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Service +@Slf4j +public class SemanticService { + + @Autowired + private SchemaService schemaService; + @Autowired + private ConfigService configService; + + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + + public DomainSchema getDomainSchema(Long id) { + DomainSchema domainSchema = schemaService.getDomainSchema(id); + if (!Objects.isNull(domainSchema) && !Objects.isNull(domainSchema.getDomain())) { + ChatConfigResp chaConfigInfo = + configService.fetchConfigByDomainId(domainSchema.getDomain().getId()); + // filter dimensions in blacklist + filterBlackDim(domainSchema, chaConfigInfo); + // filter metrics in blacklist + filterBlackMetric(domainSchema, chaConfigInfo); + } + + return domainSchema; + } + + public EntityInfo getEntityInfo(SemanticParseInfo parseInfo, User user) { + if (parseInfo != null && parseInfo.getDomainId() > 0) { + EntityInfo entityInfo = getEntityInfo(parseInfo.getDomainId()); + if (parseInfo.getDimensionFilters().size() <= 0) { + entityInfo.setMetrics(null); + entityInfo.setDimensions(null); + return entityInfo; + } + if (entityInfo.getDomainInfo() != null && entityInfo.getDomainInfo().getPrimaryEntityBizName() != null) { + String domainInfoPrimaryName = entityInfo.getDomainInfo().getPrimaryEntityBizName(); + String domainInfoId = ""; + for (QueryFilter chatFilter : parseInfo.getDimensionFilters()) { + if (chatFilter != null && chatFilter.getBizName() != null && chatFilter.getBizName() + .equals(domainInfoPrimaryName)) { + if (chatFilter.getOperator().equals(FilterOperatorEnum.EQUALS)) { + domainInfoId = chatFilter.getValue().toString(); + } + } + } + if (!"".equals(domainInfoId)) { + try { + setMainDomain(entityInfo, parseInfo.getDomainId(), + domainInfoId, user); + + return entityInfo; + } catch (Exception e) { + log.error("setMaintDomain error {}", e); + } + } + } + } + return null; + } + + public EntityInfo getEntityInfo(Long domain) { + ChatConfigRich chaConfigRichDesc = configService.getConfigRichInfo(domain); + if (Objects.isNull(chaConfigRichDesc) || Objects.isNull(chaConfigRichDesc.getChatDetailRichConfig())) { + return new EntityInfo(); + } + return getEntityInfo(chaConfigRichDesc); + } + + private EntityInfo getEntityInfo(ChatConfigRich chaConfigRichDesc) { + + EntityInfo entityInfo = new EntityInfo(); + EntityRichInfo entityDesc = chaConfigRichDesc.getChatDetailRichConfig().getEntity(); + if (entityDesc != null && Objects.nonNull(chaConfigRichDesc.getDomainId())) { + DomainInfo domainInfo = new DomainInfo(); + domainInfo.setItemId(chaConfigRichDesc.getDomainId().intValue()); + domainInfo.setName(chaConfigRichDesc.getDomainName()); + domainInfo.setWords(entityDesc.getNames()); + domainInfo.setBizName(chaConfigRichDesc.getBizName()); + if (Objects.nonNull(entityDesc.getDimItem())) { + domainInfo.setPrimaryEntityBizName(entityDesc.getDimItem().getBizName()); + } + + entityInfo.setDomainInfo(domainInfo); + List dimensions = new ArrayList<>(); + List metrics = new ArrayList<>(); + + if (Objects.nonNull(chaConfigRichDesc) && Objects.nonNull(chaConfigRichDesc.getChatDetailRichConfig()) + && Objects.nonNull(chaConfigRichDesc.getChatDetailRichConfig().getChatDefaultConfig())) { + ChatDefaultRichConfig chatDefaultConfig = chaConfigRichDesc.getChatDetailRichConfig() + .getChatDefaultConfig(); + if (!CollectionUtils.isEmpty(chatDefaultConfig.getDimensions())) { + for (SchemaElement dimensionDesc : chatDefaultConfig.getDimensions()) { + DataInfo mainEntityDimension = new DataInfo(); + mainEntityDimension.setItemId(dimensionDesc.getId().intValue()); + mainEntityDimension.setName(dimensionDesc.getName()); + mainEntityDimension.setBizName(dimensionDesc.getBizName()); + dimensions.add(mainEntityDimension); + } + entityInfo.setDimensions(dimensions); + } + + if (!CollectionUtils.isEmpty(chatDefaultConfig.getMetrics())) { + for (SchemaElement metricDesc : chatDefaultConfig.getMetrics()) { + DataInfo dataInfo = new DataInfo(); + dataInfo.setName(metricDesc.getName()); + dataInfo.setBizName(metricDesc.getBizName()); + dataInfo.setItemId(metricDesc.getId().intValue()); + metrics.add(dataInfo); + } + entityInfo.setMetrics(metrics); + } + } + } + return entityInfo; + } + + public void setMainDomain(EntityInfo domainInfo, Long domain, String entity, User user) { + DomainSchema domainSchema = schemaService.getDomainSchema(domain); + + domainInfo.setEntityId(entity); + SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); + semanticParseInfo.setDomain(domainSchema.getDomain()); + semanticParseInfo.setNativeQuery(true); + semanticParseInfo.setMetrics(getMetrics(domainInfo)); + semanticParseInfo.setDimensions(getDimensions(domainInfo)); + DateConf dateInfo = new DateConf(); + dateInfo.setUnit(1); + dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); + semanticParseInfo.setDateInfo(dateInfo); + + // add filter + QueryFilter chatFilter = new QueryFilter(); + chatFilter.setValue(String.valueOf(entity)); + chatFilter.setOperator(FilterOperatorEnum.EQUALS); + chatFilter.setBizName(getEntityPrimaryName(domainInfo)); + Set chatFilters = new LinkedHashSet(); + chatFilters.add(chatFilter); + semanticParseInfo.setDimensionFilters(chatFilters); + + QueryResultWithSchemaResp queryResultWithColumns = null; + try { + queryResultWithColumns = semanticLayer.queryByStruct(QueryReqBuilder.buildStructReq(semanticParseInfo), + user); + } catch (Exception e) { + log.warn("setMainDomain queryByStruct error, e:", e); + } + + if (queryResultWithColumns != null) { + if (!CollectionUtils.isEmpty(queryResultWithColumns.getResultList()) + && queryResultWithColumns.getResultList().size() > 0) { + Map result = queryResultWithColumns.getResultList().get(0); + for (Map.Entry entry : result.entrySet()) { + String entryKey = getEntryKey(entry); + if (entry.getValue() == null || entryKey == null) { + continue; + } + domainInfo.getDimensions().stream().filter(i -> entryKey.equals(i.getBizName())) + .forEach(i -> i.setValue(entry.getValue().toString())); + domainInfo.getMetrics().stream().filter(i -> entryKey.equals(i.getBizName())) + .forEach(i -> i.setValue(entry.getValue().toString())); + } + } + } + } + + private Set getDimensions(EntityInfo domainInfo) { + Set dimensions = new LinkedHashSet(); + for (DataInfo mainEntityDimension : domainInfo.getDimensions()) { + SchemaElement dimension = new SchemaElement(); + dimension.setBizName(mainEntityDimension.getBizName()); + dimensions.add(dimension); + } + return dimensions; + } + + private String getEntryKey(Map.Entry entry) { + // metric parser special handle, TODO delete + String entryKey = entry.getKey(); + if (entryKey.contains("__")) { + entryKey = entryKey.split("__")[1]; + } + return entryKey; + } + + private Set getMetrics(EntityInfo domainInfo) { + Set metrics = new LinkedHashSet(); + for (DataInfo metricValue : domainInfo.getMetrics()) { + SchemaElement metric = new SchemaElement(); + metric.setBizName(metricValue.getBizName()); + metrics.add(metric); + } + return metrics; + } + + private String getEntityPrimaryName(EntityInfo domainInfo) { + return domainInfo.getDomainInfo().getPrimaryEntityBizName(); + } + + private void filterBlackMetric(DomainSchema domainSchema, ChatConfigResp chaConfigInfo) { + ItemVisibility visibility = generateFinalVisibility(chaConfigInfo); + if (Objects.nonNull(chaConfigInfo) && Objects.nonNull(visibility) + && !CollectionUtils.isEmpty(visibility.getBlackMetricIdList()) + && !CollectionUtils.isEmpty(domainSchema.getMetrics())) { + Set metric4Chat = domainSchema.getMetrics().stream() + .filter(metric -> !visibility.getBlackMetricIdList().contains(metric.getId())) + .collect(Collectors.toSet()); + domainSchema.setMetrics(metric4Chat); + } + } + + private void filterBlackDim(DomainSchema domainSchema, ChatConfigResp chatConfigInfo) { + ItemVisibility visibility = generateFinalVisibility(chatConfigInfo); + if (Objects.nonNull(chatConfigInfo) && Objects.nonNull(visibility) + && !CollectionUtils.isEmpty(visibility.getBlackDimIdList()) + && !CollectionUtils.isEmpty(domainSchema.getDimensions())) { + Set dim4Chat = domainSchema.getDimensions().stream() + .filter(dim -> !visibility.getBlackDimIdList().contains(dim.getId())) + .collect(Collectors.toSet()); + domainSchema.setDimensions(dim4Chat); + } + } + + private ItemVisibility generateFinalVisibility(ChatConfigResp chatConfigInfo) { + ItemVisibility visibility = new ItemVisibility(); + + ChatAggConfig chatAggConfig = chatConfigInfo.getChatAggConfig(); + ChatDetailConfig chatDetailConfig = chatConfigInfo.getChatDetailConfig(); + + // both black is exist + if (Objects.nonNull(chatAggConfig) && Objects.nonNull(chatAggConfig.getVisibility()) + && Objects.nonNull(chatDetailConfig) && Objects.nonNull(chatDetailConfig.getVisibility())) { + List blackDimIdList = new ArrayList<>(); + blackDimIdList.addAll(chatAggConfig.getVisibility().getBlackDimIdList()); + blackDimIdList.retainAll(chatDetailConfig.getVisibility().getBlackDimIdList()); + List blackMetricIdList = new ArrayList<>(); + + blackMetricIdList.addAll(chatAggConfig.getVisibility().getBlackMetricIdList()); + blackMetricIdList.retainAll(chatDetailConfig.getVisibility().getBlackMetricIdList()); + + visibility.setBlackDimIdList(blackDimIdList); + visibility.setBlackMetricIdList(blackMetricIdList); + } + return visibility; + } + + public AggregateInfo getAggregateInfo(User user, SemanticParseInfo semanticParseInfo, + QueryResultWithSchemaResp result) { + if (CollectionUtils.isEmpty(semanticParseInfo.getMetrics())) { + return new AggregateInfo(); + } + List resultMetricNames = result.getColumns().stream().map(c -> c.getNameEn()) + .collect(Collectors.toList()); + Optional ratioMetric = semanticParseInfo.getMetrics().stream() + .filter(m -> resultMetricNames.contains(m.getBizName())).findFirst(); + if (ratioMetric.isPresent()) { + AggregateInfo aggregateInfo = new AggregateInfo(); + MetricInfo metricInfo = new MetricInfo(); + metricInfo.setStatistics(new HashMap<>()); + String dateField = QueryReqBuilder.getDateField(semanticParseInfo.getDateInfo()); + + Optional lastDayOp = result.getResultList().stream() + .map(r -> r.get(dateField).toString()) + .sorted(Comparator.reverseOrder()).findFirst(); + if (lastDayOp.isPresent()) { + Optional> lastValue = result.getResultList().stream() + .filter(r -> r.get(dateField).toString().equals(lastDayOp.get())).findFirst(); + if (lastValue.isPresent()) { + metricInfo.setValue(lastValue.get().get(ratioMetric.get().getBizName()).toString()); + } + metricInfo.setDate(lastValue.get().get(dateField).toString()); + } + try { + queryRatio(user, semanticParseInfo, ratioMetric.get(), AggOperatorEnum.RATIO_ROLL, + result, metricInfo); + queryRatio(user, semanticParseInfo, ratioMetric.get(), AggOperatorEnum.RATIO_OVER, + result, metricInfo); + aggregateInfo.getMetricInfos().add(metricInfo); + } catch (Exception e) { + log.error("queryRatio error {}", e); + } + return aggregateInfo; + } + return new AggregateInfo(); + } + + private void queryRatio(User user, SemanticParseInfo semanticParseInfo, SchemaElement metric, + AggOperatorEnum aggOperatorEnum, QueryResultWithSchemaResp results, MetricInfo metricInfo) { + QueryStructReq queryStructReq = QueryReqBuilder.buildStructRatioReq(semanticParseInfo, metric, aggOperatorEnum); + DateConf dateInfo = semanticParseInfo.getDateInfo(); + String dateField = QueryReqBuilder.getDateField(dateInfo); + + queryStructReq.setGroups(new ArrayList<>(Arrays.asList(dateField))); + queryStructReq.setDateInfo(getRatioDateConf(aggOperatorEnum, semanticParseInfo, results)); + QueryResultWithSchemaResp queryResp = semanticLayer.queryByStruct(queryStructReq, user); + if (Objects.nonNull(queryResp) && !CollectionUtils.isEmpty(queryResp.getResultList())) { + + Map result = queryResp.getResultList().get(0); + Optional valueColumn = queryResp.getColumns().stream() + .filter(c -> c.getNameEn().equals(metric.getBizName())).findFirst(); + + if (valueColumn.isPresent()) { + String ratio = ""; + if (Objects.nonNull(result.get(valueColumn.get().getNameEn()))) { + ratio = String.format("%.2f", + (Double.valueOf(result.get(valueColumn.get().getNameEn()).toString()) * 100)) + "%"; + } + String statisticsRollName = RatioOverType.DAY_ON_DAY.getShowName(); + String statisticsOverName = RatioOverType.WEEK_ON_DAY.getShowName(); + if (MONTH.equals(dateInfo.getPeriod())) { + statisticsRollName = RatioOverType.MONTH_ON_MONTH.getShowName(); + statisticsOverName = RatioOverType.YEAR_ON_MONTH.getShowName(); + } + if (WEEK.equals(dateInfo.getPeriod())) { + statisticsRollName = RatioOverType.WEEK_ON_WEEK.getShowName(); + statisticsOverName = RatioOverType.MONTH_ON_WEEK.getShowName(); + } + metricInfo.getStatistics().put(aggOperatorEnum.equals(AggOperatorEnum.RATIO_ROLL) ? statisticsRollName + : statisticsOverName, + ratio); + } + metricInfo.setName(metric.getName()); + } + } + + private DateConf getRatioDateConf(AggOperatorEnum aggOperatorEnum, SemanticParseInfo semanticParseInfo, + QueryResultWithSchemaResp results) { + String dateField = QueryReqBuilder.getDateField(semanticParseInfo.getDateInfo()); + Optional lastDayOp = results.getResultList().stream() + .map(r -> r.get(dateField).toString()) + .sorted(Comparator.reverseOrder()).findFirst(); + if (lastDayOp.isPresent()) { + String lastDay = lastDayOp.get(); + DateConf dateConf = new DateConf(); + dateConf.setPeriod(semanticParseInfo.getDateInfo().getPeriod()); + dateConf.setDateMode(DateMode.LIST_DISCRETE); + List dayList = new ArrayList<>(); + dayList.add(lastDay); + String start = ""; + if (DAY.equalsIgnoreCase(semanticParseInfo.getDateInfo().getPeriod())) { + DateTimeFormatter formatter = DateUtils.getDateFormatter(lastDay, + new String[]{DAY_FORMAT, DAY_FORMAT_INT}); + LocalDate end = LocalDate.parse(lastDay, formatter); + start = aggOperatorEnum.equals(AggOperatorEnum.RATIO_ROLL) ? end.minusDays(1).format(formatter) + : end.minusWeeks(1).format(formatter); + } + if (WEEK.equalsIgnoreCase(semanticParseInfo.getDateInfo().getPeriod())) { + DateTimeFormatter formatter = DateUtils.getTimeFormatter(lastDay, + new String[]{TIMES_FORMAT, DAY_FORMAT, TIME_FORMAT, DAY_FORMAT_INT}); + LocalDateTime end = LocalDateTime.parse(lastDay, formatter); + start = aggOperatorEnum.equals(AggOperatorEnum.RATIO_ROLL) ? end.minusWeeks(1).format(formatter) + : end.minusMonths(1).with(DayOfWeek.MONDAY).format(formatter); + } + if (MONTH.equalsIgnoreCase(semanticParseInfo.getDateInfo().getPeriod())) { + DateTimeFormatter formatter = DateUtils.getDateFormatter(lastDay, + new String[]{MONTH_FORMAT, MONTH_FORMAT_INT}); + YearMonth end = YearMonth.parse(lastDay, formatter); + start = aggOperatorEnum.equals(AggOperatorEnum.RATIO_ROLL) ? end.minusMonths(1).format(formatter) + : end.minusYears(1).format(formatter); + } + dayList.add(start); + dateConf.setDateList(dayList); + return dateConf; + + } + return semanticParseInfo.getDateInfo(); + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ChatServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ChatServiceImpl.java similarity index 76% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/ChatServiceImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ChatServiceImpl.java index 1ae1e4cbd..9a61e618c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ChatServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ChatServiceImpl.java @@ -1,24 +1,25 @@ -package com.tencent.supersonic.chat.application; +package com.tencent.supersonic.chat.service.impl; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.domain.dataobject.ChatDO; -import com.tencent.supersonic.chat.domain.dataobject.ChatQueryDO; -import com.tencent.supersonic.chat.domain.dataobject.QueryDO; -import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO; -import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq; -import com.tencent.supersonic.chat.domain.repository.ChatContextRepository; -import com.tencent.supersonic.chat.domain.repository.ChatQueryRepository; -import com.tencent.supersonic.chat.domain.repository.ChatRepository; -import com.tencent.supersonic.chat.domain.service.ChatService; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import com.tencent.supersonic.chat.persistence.dataobject.QueryDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResponse; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; +import com.tencent.supersonic.chat.persistence.repository.ChatContextRepository; +import com.tencent.supersonic.chat.persistence.repository.ChatQueryRepository; +import com.tencent.supersonic.chat.persistence.repository.ChatRepository; + import java.text.SimpleDateFormat; import java.util.List; import java.util.Objects; +import com.tencent.supersonic.chat.service.ChatService; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; @@ -68,9 +69,10 @@ public class ChatServiceImpl implements ChatService { } @Override - public void updateContext(ChatContext chatCtx, QueryContextReq queryCtx, SemanticParseInfo semanticParseInfo) { + public void updateContext(ChatContext chatCtx, QueryContext queryCtx, + SemanticParseInfo semanticParseInfo) { chatCtx.setParseInfo(semanticParseInfo); - chatCtx.setQueryText(queryCtx.getQueryText()); + chatCtx.setQueryText(queryCtx.getRequest().getQueryText()); updateContext(chatCtx); } @@ -124,15 +126,15 @@ public class ChatServiceImpl implements ChatService { } @Override - public PageInfo queryInfo(PageQueryInfoReq pageQueryInfoCommend, long chatId) { + public PageInfo queryInfo(PageQueryInfoReq pageQueryInfoCommend, long chatId) { return chatQueryRepository.getChatQuery(pageQueryInfoCommend, chatId); } @Override - public void addQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx) { - chatQueryRepository.createChatQuery(queryResponse, queryContext, chatCtx); - chatRepository.updateLastQuestion(chatCtx.getChatId().longValue(), queryContext.getQueryText(), - getCurrentTime()); + public void addQuery(QueryResult queryResult, QueryContext queryContext, ChatContext chatCtx) { + chatQueryRepository.createChatQuery(queryResult, queryContext.getRequest(), chatCtx); + chatRepository.updateLastQuestion(chatCtx.getChatId().longValue(), + queryContext.getRequest().getQueryText(), getCurrentTime()); } @Override diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ConfigServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ConfigServiceImpl.java similarity index 55% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/ConfigServiceImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ConfigServiceImpl.java index 4a21a7e0f..3c1a762f3 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ConfigServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ConfigServiceImpl.java @@ -1,19 +1,18 @@ -package com.tencent.supersonic.chat.application; +package com.tencent.supersonic.chat.service.impl; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.domain.pojo.config.*; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.chat.domain.repository.ChatConfigRepository; -import com.tencent.supersonic.chat.domain.service.ConfigService; -import com.tencent.supersonic.chat.domain.utils.ChatConfigUtils; -import com.tencent.supersonic.common.util.json.JsonUtil; +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.config.*; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.service.SemanticService; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.chat.persistence.repository.ChatConfigRepository; +import com.tencent.supersonic.chat.utils.ChatConfigHelper; +import com.tencent.supersonic.common.util.JsonUtil; import java.util.ArrayList; import java.util.List; @@ -24,7 +23,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; -import org.springframework.context.annotation.Lazy; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -34,14 +33,17 @@ import org.springframework.util.CollectionUtils; public class ConfigServiceImpl implements ConfigService { private final ChatConfigRepository chatConfigRepository; - private final ChatConfigUtils chatConfigUtils; + private final ChatConfigHelper chatConfigHelper; + @Autowired + private SemanticService semanticService; + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); public ConfigServiceImpl(ChatConfigRepository chatConfigRepository, - ChatConfigUtils chatConfigUtils) { + ChatConfigHelper chatConfigHelper) { this.chatConfigRepository = chatConfigRepository; - this.chatConfigUtils = chatConfigUtils; + this.chatConfigHelper = chatConfigHelper; } @Override @@ -49,7 +51,7 @@ public class ConfigServiceImpl implements ConfigService { log.info("[create domain extend] object:{}", JsonUtil.toString(configBaseCmd, true)); duplicateCheck(configBaseCmd.getDomainId()); permissionCheckLogic(configBaseCmd.getDomainId(), user.getName()); - ChatConfig chaConfig = chatConfigUtils.newChatConfig(configBaseCmd, user); + ChatConfig chaConfig = chatConfigHelper.newChatConfig(configBaseCmd, user); Long id = chatConfigRepository.createConfig(chaConfig); return id; } @@ -72,7 +74,7 @@ public class ConfigServiceImpl implements ConfigService { throw new RuntimeException("editConfig, id and domainId are not allowed to be empty at the same time"); } permissionCheckLogic(configEditCmd.getDomainId(), user.getName()); - ChatConfig chaConfig = chatConfigUtils.editChatConfig(configEditCmd, user); + ChatConfig chaConfig = chatConfigHelper.editChatConfig(configEditCmd, user); chatConfigRepository.updateConfig(chaConfig); return configEditCmd.getId(); } @@ -101,11 +103,11 @@ public class ConfigServiceImpl implements ConfigService { private ItemVisibilityInfo fetchVisibilityDescByConfig(ItemVisibility visibility, - DomainSchemaResp domainSchemaDesc) { + DomainSchema domainSchema) { ItemVisibilityInfo itemVisibilityDesc = new ItemVisibilityInfo(); - List dimIdAllList = chatConfigUtils.generateAllDimIdList(domainSchemaDesc); - List metricIdAllList = chatConfigUtils.generateAllMetricIdList(domainSchemaDesc); + List dimIdAllList = chatConfigHelper.generateAllDimIdList(domainSchema); + List metricIdAllList = chatConfigHelper.generateAllMetricIdList(domainSchema); List blackDimIdList = new ArrayList<>(); List blackMetricIdList = new ArrayList<>(); @@ -117,114 +119,124 @@ public class ConfigServiceImpl implements ConfigService { blackMetricIdList.addAll(visibility.getBlackMetricIdList()); } } - List whiteMetricIdList = metricIdAllList.stream().filter(id -> !blackMetricIdList.contains(id)) + List whiteMetricIdList = metricIdAllList.stream() + .filter(id -> !blackMetricIdList.contains(id) && metricIdAllList.contains(id)) .collect(Collectors.toList()); - List whiteDimIdList = dimIdAllList.stream().filter(id -> !blackDimIdList.contains(id)) + List whiteDimIdList = dimIdAllList.stream() + .filter(id -> !blackDimIdList.contains(id) && dimIdAllList.contains(id)) .collect(Collectors.toList()); itemVisibilityDesc.setBlackDimIdList(blackDimIdList); itemVisibilityDesc.setBlackMetricIdList(blackMetricIdList); - itemVisibilityDesc.setWhiteDimIdList(whiteDimIdList); - itemVisibilityDesc.setWhiteMetricIdList(whiteMetricIdList); + itemVisibilityDesc.setWhiteDimIdList(Objects.isNull(whiteDimIdList) ? new ArrayList<>() : whiteDimIdList); + itemVisibilityDesc.setWhiteMetricIdList(Objects.isNull(whiteMetricIdList) ? new ArrayList<>() : whiteMetricIdList); return itemVisibilityDesc; } @Override - public ChatConfigRichResp getConfigRichInfo(Long domainId) { - ChatConfigRichResp chatConfigRichResp = new ChatConfigRichResp(); + public ChatConfigRich getConfigRichInfo(Long domainId) { + ChatConfigRich chatConfigRich = new ChatConfigRich(); ChatConfigResp chatConfigResp = chatConfigRepository.getConfigByDomainId(domainId); if (Objects.isNull(chatConfigResp)) { log.info("there is no chatConfigDesc for domainId:{}", domainId); - return chatConfigRichResp; + return chatConfigRich; } - BeanUtils.copyProperties(chatConfigResp, chatConfigRichResp); + BeanUtils.copyProperties(chatConfigResp, chatConfigRich); - SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - DomainSchemaResp domainSchemaInfo = semanticLayer.getDomainSchemaInfo(domainId, false); - chatConfigRichResp.setBizName(domainSchemaInfo.getBizName()); - chatConfigRichResp.setDomainName(domainSchemaInfo.getName()); + DomainSchema domainSchema = semanticService.getDomainSchema(domainId); + chatConfigRich.setBizName(domainSchema.getDomain().getBizName()); + chatConfigRich.setDomainName(domainSchema.getDomain().getName()); - chatConfigRichResp.setChatAggRichConfig(fillChatAggRichConfig(domainSchemaInfo, chatConfigResp)); - chatConfigRichResp.setChatDetailRichConfig(fillChatDetailRichConfig(domainSchemaInfo, chatConfigRichResp, chatConfigResp)); + chatConfigRich.setChatAggRichConfig(fillChatAggRichConfig(domainSchema, chatConfigResp)); + chatConfigRich.setChatDetailRichConfig(fillChatDetailRichConfig(domainSchema, chatConfigRich, chatConfigResp)); - return chatConfigRichResp; + return chatConfigRich; } - private ChatDetailRichConfig fillChatDetailRichConfig(DomainSchemaResp domainSchemaInfo, ChatConfigRichResp chatConfigRichResp, ChatConfigResp chatConfigResp) { + private ChatDetailRichConfig fillChatDetailRichConfig(DomainSchema domainSchema, ChatConfigRich chatConfigRich, ChatConfigResp chatConfigResp) { if (Objects.isNull(chatConfigResp) || Objects.isNull(chatConfigResp.getChatDetailConfig())) { return null; } ChatDetailRichConfig detailRichConfig = new ChatDetailRichConfig(); ChatDetailConfig chatDetailConfig = chatConfigResp.getChatDetailConfig(); - - detailRichConfig.setVisibility(fetchVisibilityDescByConfig(chatDetailConfig.getVisibility(), domainSchemaInfo)); - detailRichConfig.setKnowledgeInfos(fillKnowledgeBizName(chatDetailConfig.getKnowledgeInfos(), domainSchemaInfo)); + ItemVisibilityInfo itemVisibilityInfo = fetchVisibilityDescByConfig(chatDetailConfig.getVisibility(), domainSchema); + detailRichConfig.setVisibility(itemVisibilityInfo); + detailRichConfig.setKnowledgeInfos(fillKnowledgeBizName(chatDetailConfig.getKnowledgeInfos(), domainSchema)); detailRichConfig.setGlobalKnowledgeConfig(chatDetailConfig.getGlobalKnowledgeConfig()); - detailRichConfig.setChatDefaultConfig(fetchDefaultConfig(chatDetailConfig.getChatDefaultConfig(), domainSchemaInfo)); + detailRichConfig.setChatDefaultConfig(fetchDefaultConfig(chatDetailConfig.getChatDefaultConfig(), domainSchema, itemVisibilityInfo)); - detailRichConfig.setEntity(generateRichEntity(chatDetailConfig.getEntity(), domainSchemaInfo)); + detailRichConfig.setEntity(generateRichEntity(chatDetailConfig.getEntity(), domainSchema)); return detailRichConfig; } - private EntityRichInfo generateRichEntity(Entity entity, DomainSchemaResp domainSchemaInfo) { + private EntityRichInfo generateRichEntity(Entity entity, DomainSchema domainSchema) { EntityRichInfo entityRichInfo = new EntityRichInfo(); if (Objects.isNull(entity) || Objects.isNull(entity.getEntityId())) { return entityRichInfo; } BeanUtils.copyProperties(entity, entityRichInfo); - Map dimIdAndRespPair = domainSchemaInfo.getDimensions().stream() - .collect(Collectors.toMap(DimSchemaResp::getId, Function.identity())); + Map dimIdAndRespPair = domainSchema.getDimensions().stream() + .collect(Collectors.toMap(SchemaElement::getId, Function.identity(), (k1, k2) -> k1)); entityRichInfo.setDimItem(dimIdAndRespPair.get(entity.getEntityId())); return entityRichInfo; } - private ChatAggRichConfig fillChatAggRichConfig(DomainSchemaResp domainSchemaInfo, ChatConfigResp chatConfigResp) { + private ChatAggRichConfig fillChatAggRichConfig(DomainSchema domainSchema, ChatConfigResp chatConfigResp) { if (Objects.isNull(chatConfigResp) || Objects.isNull(chatConfigResp.getChatAggConfig())) { return null; } ChatAggConfig chatAggConfig = chatConfigResp.getChatAggConfig(); ChatAggRichConfig chatAggRichConfig = new ChatAggRichConfig(); - - chatAggRichConfig.setVisibility(fetchVisibilityDescByConfig(chatAggConfig.getVisibility(), domainSchemaInfo)); - chatAggRichConfig.setKnowledgeInfos(fillKnowledgeBizName(chatAggConfig.getKnowledgeInfos(), domainSchemaInfo)); + ItemVisibilityInfo itemVisibilityInfo = fetchVisibilityDescByConfig(chatAggConfig.getVisibility(), domainSchema); + chatAggRichConfig.setVisibility(itemVisibilityInfo); + chatAggRichConfig.setKnowledgeInfos(fillKnowledgeBizName(chatAggConfig.getKnowledgeInfos(), domainSchema)); chatAggRichConfig.setGlobalKnowledgeConfig(chatAggConfig.getGlobalKnowledgeConfig()); - chatAggRichConfig.setChatDefaultConfig(fetchDefaultConfig(chatAggConfig.getChatDefaultConfig(), domainSchemaInfo)); + chatAggRichConfig.setChatDefaultConfig(fetchDefaultConfig(chatAggConfig.getChatDefaultConfig(), domainSchema, itemVisibilityInfo)); return chatAggRichConfig; } - private ChatDefaultRichConfig fetchDefaultConfig(ChatDefaultConfig chatDefaultConfig, DomainSchemaResp domainSchemaInfo) { + private ChatDefaultRichConfig fetchDefaultConfig(ChatDefaultConfig chatDefaultConfig, DomainSchema domainSchema, ItemVisibilityInfo itemVisibilityInfo) { ChatDefaultRichConfig defaultRichConfig = new ChatDefaultRichConfig(); if (Objects.isNull(chatDefaultConfig)) { return defaultRichConfig; } BeanUtils.copyProperties(chatDefaultConfig, defaultRichConfig); - Map dimIdAndRespPair = domainSchemaInfo.getDimensions().stream() - .collect(Collectors.toMap(DimSchemaResp::getId, Function.identity())); + Map dimIdAndRespPair = domainSchema.getDimensions().stream() + .collect(Collectors.toMap(SchemaElement::getId, Function.identity(), (k1, k2) -> k1)); - Map metricIdAndRespPair = domainSchemaInfo.getMetrics().stream() - .collect(Collectors.toMap(MetricSchemaResp::getId, Function.identity())); + Map metricIdAndRespPair = domainSchema.getMetrics().stream() + .collect(Collectors.toMap(SchemaElement::getId, Function.identity(), (k1, k2) -> k1)); - List dimensions = new ArrayList<>(); - List metrics = new ArrayList<>(); + List dimensions = new ArrayList<>(); + List metrics = new ArrayList<>(); if (!CollectionUtils.isEmpty(chatDefaultConfig.getDimensionIds())) { - chatDefaultConfig.getDimensionIds().stream().forEach(dimId -> { - DimSchemaResp dimSchemaResp = dimIdAndRespPair.get(dimId); - SchemaItem dimSchema = new SchemaItem(); - BeanUtils.copyProperties(dimSchemaResp, dimSchema); - dimensions.add(dimSchema); - }); + chatDefaultConfig.getDimensionIds().stream() + .filter(dimId -> dimIdAndRespPair.containsKey(dimId) && itemVisibilityInfo.getWhiteDimIdList().contains(dimId)) + .forEach(dimId -> { + SchemaElement dimSchemaResp = dimIdAndRespPair.get(dimId); + if (Objects.nonNull(dimSchemaResp)) { + SchemaElement dimSchema = new SchemaElement(); + BeanUtils.copyProperties(dimSchemaResp, dimSchema); + dimensions.add(dimSchema); + } + + }); } if (!CollectionUtils.isEmpty(chatDefaultConfig.getMetricIds())) { - chatDefaultConfig.getMetricIds().stream().forEach(metricId -> { - MetricSchemaResp metricSchemaResp = metricIdAndRespPair.get(metricId); - SchemaItem metricSchema = new SchemaItem(); - BeanUtils.copyProperties(metricSchemaResp, metricSchema); - metrics.add(metricSchema); - }); + chatDefaultConfig.getMetricIds().stream() + .filter(metricId -> metricIdAndRespPair.containsKey(metricId) && itemVisibilityInfo.getWhiteMetricIdList().contains(metricId)) + .forEach(metricId -> { + SchemaElement metricSchemaResp = metricIdAndRespPair.get(metricId); + if (Objects.nonNull(metricSchemaResp)) { + SchemaElement metricSchema = new SchemaElement(); + BeanUtils.copyProperties(metricSchemaResp, metricSchema); + metrics.add(metricSchema); + } + }); } defaultRichConfig.setDimensions(dimensions); @@ -234,15 +246,15 @@ public class ConfigServiceImpl implements ConfigService { private List fillKnowledgeBizName(List knowledgeInfos, - DomainSchemaResp domainSchemaInfo) { + DomainSchema domainSchema) { if (CollectionUtils.isEmpty(knowledgeInfos)) { return new ArrayList<>(); } - Map dimIdAndRespPair = domainSchemaInfo.getDimensions().stream() - .collect(Collectors.toMap(DimSchemaResp::getId, Function.identity())); + Map dimIdAndRespPair = domainSchema.getDimensions().stream() + .collect(Collectors.toMap(SchemaElement::getId, Function.identity(),(k1, k2) -> k1)); knowledgeInfos.stream().forEach(knowledgeInfo -> { if (Objects.nonNull(knowledgeInfo)) { - DimSchemaResp dimSchemaResp = dimIdAndRespPair.get(knowledgeInfo.getItemId()); + SchemaElement dimSchemaResp = dimIdAndRespPair.get(knowledgeInfo.getItemId()); if (Objects.nonNull(dimSchemaResp)) { knowledgeInfo.setBizName(dimSchemaResp.getBizName()); } @@ -252,11 +264,11 @@ public class ConfigServiceImpl implements ConfigService { } @Override - public List getAllChatRichConfig() { - List chatConfigRichInfoList = new ArrayList<>(); + public List getAllChatRichConfig() { + List chatConfigRichInfoList = new ArrayList<>(); List domainRespList = semanticLayer.getDomainListForAdmin(); domainRespList.stream().forEach(domainResp -> { - ChatConfigRichResp chatConfigRichInfo = getConfigRichInfo(domainResp.getId()); + ChatConfigRich chatConfigRichInfo = getConfigRichInfo(domainResp.getId()); if (Objects.nonNull(chatConfigRichInfo)) { chatConfigRichInfoList.add(chatConfigRichInfo); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/DictApplicationService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/DictionaryServiceImpl.java similarity index 63% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/DictApplicationService.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/DictionaryServiceImpl.java index a125eecb1..60fdf6f7c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/DictApplicationService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/DictionaryServiceImpl.java @@ -1,22 +1,23 @@ -package com.tencent.supersonic.chat.application.knowledge; +package com.tencent.supersonic.chat.service.impl; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.domain.dataobject.DimValueDO; -import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric; -import com.tencent.supersonic.chat.domain.pojo.config.Dim4Dict; -import com.tencent.supersonic.chat.domain.utils.DictMetaUtils; -import com.tencent.supersonic.chat.domain.utils.DictQueryUtils; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.enums.TaskStatusEnum; -import com.tencent.supersonic.knowledge.domain.FileHandler; -import com.tencent.supersonic.knowledge.domain.converter.DictTaskConverter; -import com.tencent.supersonic.knowledge.domain.dataobject.DimValueDictTaskPO; -import com.tencent.supersonic.knowledge.domain.pojo.DictConfig; -import com.tencent.supersonic.knowledge.domain.pojo.DictTaskFilter; -import com.tencent.supersonic.knowledge.domain.pojo.DictUpdateMode; -import com.tencent.supersonic.knowledge.domain.pojo.DimValue2DictCommand; -import com.tencent.supersonic.knowledge.domain.pojo.DimValueDictInfo; -import com.tencent.supersonic.knowledge.domain.repository.DictRepository; +import com.tencent.supersonic.chat.config.DefaultMetric; +import com.tencent.supersonic.chat.config.Dim4Dict; +import com.tencent.supersonic.chat.persistence.dataobject.DimValueDO; +import com.tencent.supersonic.chat.service.DictionaryService; +import com.tencent.supersonic.chat.utils.DictMetaHelper; +import com.tencent.supersonic.chat.utils.DictQueryHelper; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; +import com.tencent.supersonic.knowledge.dictionary.FileHandler; +import com.tencent.supersonic.knowledge.persistence.dataobject.DictTaskDO; +import com.tencent.supersonic.knowledge.utils.DictTaskConverter; +import com.tencent.supersonic.knowledge.dictionary.DictConfig; +import com.tencent.supersonic.knowledge.dictionary.DictTaskFilter; +import com.tencent.supersonic.knowledge.dictionary.DictUpdateMode; +import com.tencent.supersonic.knowledge.dictionary.DimValue2DictCommand; +import com.tencent.supersonic.knowledge.dictionary.DimValueDictInfo; +import com.tencent.supersonic.knowledge.persistence.repository.DictRepository; import java.util.List; import java.util.Map; import java.util.Objects; @@ -27,10 +28,10 @@ import org.springframework.util.CollectionUtils; @Slf4j @Service -public class DictApplicationService { +public class DictionaryServiceImpl implements DictionaryService { - private final DictMetaUtils metaUtils; - private final DictQueryUtils dictQueryUtils; + private final DictMetaHelper metaUtils; + private final DictQueryHelper dictQueryHelper; private final FileHandler fileHandler; private final DictRepository dictRepository; @Value("${dict.flush.enable:true}") @@ -38,14 +39,13 @@ public class DictApplicationService { @Value("${dict.file.type:txt}") private String dictFileType; private String dimValue = "DimValue_%d_%d"; - private String dateTimeFormatter = "yyyyMMddHHmmss"; - public DictApplicationService(DictMetaUtils metaUtils, - DictQueryUtils dictQueryUtils, - FileHandler fileHandler, - DictRepository dictRepository) { + public DictionaryServiceImpl(DictMetaHelper metaUtils, + DictQueryHelper dictQueryHelper, + FileHandler fileHandler, + DictRepository dictRepository) { this.metaUtils = metaUtils; - this.dictQueryUtils = dictQueryUtils; + this.dictQueryHelper = dictQueryHelper; this.fileHandler = fileHandler; this.dictRepository = dictRepository; } @@ -54,10 +54,10 @@ public class DictApplicationService { if (!dictFlushEnable) { return 0L; } - DimValueDictTaskPO dimValueDictTaskPO = DictTaskConverter.generateDimValueDictTaskPO(dimValue2DictCommend, + DictTaskDO dictTaskDO = DictTaskConverter.generateDimValueDictTaskPO(dimValue2DictCommend, user); - log.info("[addDictTask] dimValueDictTaskPO:{}", dimValueDictTaskPO); - dictRepository.createDimValueDictTask(dimValueDictTaskPO); + log.info("[addDictTask] dictTaskDO:{}", dictTaskDO); + dictRepository.createDimValueDictTask(dictTaskDO); TaskStatusEnum finalStatus = TaskStatusEnum.SUCCESS; try { //1. construct internal dictionary requirements @@ -68,7 +68,7 @@ public class DictApplicationService { Long domainId = dimValueDO.getDomainId(); DefaultMetric defaultMetricDesc = dimValueDO.getDefaultMetricDescList().get(0); for (Dim4Dict dim4Dict : dimValueDO.getDimensions()) { - List data = dictQueryUtils.fetchDimValueSingle(domainId, defaultMetricDesc, dim4Dict, user); + List data = dictQueryHelper.fetchDimValueSingle(domainId, defaultMetricDesc, dim4Dict, user); //3. local file changes String fileName = String.format(dimValue + Constants.DOT + dictFileType, domainId, dim4Dict.getDimId()); @@ -79,7 +79,8 @@ public class DictApplicationService { log.warn("addDictInfo exception:", e); finalStatus = TaskStatusEnum.ERROR; } - dictRepository.updateDictTaskStatus(finalStatus.getCode(), dimValueDictTaskPO); + dictRepository.updateDictTaskStatus(finalStatus.getCode(), + dictTaskDO); return 1L; } @@ -113,7 +114,6 @@ public class DictApplicationService { return fileHandler.getDictRootPath(); } - public List searchDictTaskList(DictTaskFilter filter, User user) { return dictRepository.searchDictTaskList(filter); } @@ -121,4 +121,4 @@ public class DictApplicationService { public DictConfig getDictInfoByDomainId(Long domainId) { return dictRepository.getDictInfoByDomainId(domainId); } -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/PluginServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/PluginServiceImpl.java new file mode 100644 index 000000000..d8f87a51e --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/PluginServiceImpl.java @@ -0,0 +1,175 @@ +package com.tencent.supersonic.chat.service.impl; + +import com.google.common.collect.Lists; +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.plugin.Plugin; +import com.tencent.supersonic.chat.api.pojo.request.PluginQueryReq; +import com.tencent.supersonic.chat.persistence.dataobject.PluginDO; +import com.tencent.supersonic.chat.persistence.dataobject.PluginDOExample; +import com.tencent.supersonic.chat.persistence.repository.PluginRepository; +import com.tencent.supersonic.chat.parser.ParseMode; +import com.tencent.supersonic.chat.plugin.event.PluginAddEvent; +import com.tencent.supersonic.chat.plugin.event.PluginDelEvent; +import com.tencent.supersonic.chat.plugin.event.PluginUpdateEvent; +import com.tencent.supersonic.chat.service.PluginService; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +public class PluginServiceImpl implements PluginService { + + private PluginRepository pluginRepository; + + private ApplicationEventPublisher publisher; + + public PluginServiceImpl(PluginRepository pluginRepository, + ApplicationEventPublisher publisher) { + this.pluginRepository = pluginRepository; + this.publisher = publisher; + } + + @Override + public void createPlugin(Plugin plugin, User user){ + PluginDO pluginDO = convert(plugin, user); + pluginRepository.createPlugin(pluginDO); + publisher.publishEvent(new PluginAddEvent(this, plugin)); + } + + @Override + public void updatePlugin(Plugin plugin, User user){ + Long id = plugin.getId(); + PluginDO pluginDO = pluginRepository.getPlugin(id); + Plugin oldPlugin = convert(pluginDO); + convert(plugin, pluginDO, user); + pluginRepository.updatePlugin(pluginDO); + publisher.publishEvent(new PluginUpdateEvent(this, oldPlugin, plugin)); + } + + @Override + public void deletePlugin(Long id){ + PluginDO pluginDO = pluginRepository.getPlugin(id); + if (pluginDO != null) { + pluginRepository.deletePlugin(id); + publisher.publishEvent(new PluginDelEvent(this, convert(pluginDO))); + } + } + + + @Override + public List getPluginList() { + List plugins = Lists.newArrayList(); + List pluginDOS = pluginRepository.getPlugins(); + if(CollectionUtils.isEmpty(pluginDOS)){ + return plugins; + } + return pluginDOS.stream().map(this::convert).collect(Collectors.toList()); + } + + @Override + public List fetchPluginDOs(String queryText, String type) { + List pluginDOS = pluginRepository.fetchPluginDOs(queryText,type); + return convertList(pluginDOS); + } + + + @Override + public List query(PluginQueryReq pluginQueryReq) { + PluginDOExample pluginDOExample = new PluginDOExample(); + pluginDOExample.createCriteria(); + if (StringUtils.isNotBlank(pluginQueryReq.getType())) { + pluginDOExample.getOredCriteria().get(0).andTypeEqualTo(pluginQueryReq.getType()); + } + if (StringUtils.isNotBlank(pluginQueryReq.getDomain())) { + pluginDOExample.getOredCriteria().get(0).andDomainLike('%' + pluginQueryReq.getDomain() + '%'); + } + List pluginDOS = pluginRepository.query(pluginDOExample); + if (StringUtils.isNotBlank(pluginQueryReq.getPattern())) { + pluginDOS = pluginDOS.stream().filter(pluginDO -> + pluginDO.getPattern().contains(pluginQueryReq.getPattern()) || + (pluginDO.getName()!=null && pluginDO.getName().contains(pluginQueryReq.getPattern()))) + .collect(Collectors.toList()); + } + return convertList(pluginDOS); + } + + @Override + public Optional getPluginByName(String name) { + return getPluginList().stream() + .filter(plugin -> plugin.getName().equalsIgnoreCase(name)) + .findFirst(); + } + + @Override + public List queryWithAuthCheck(PluginQueryReq pluginQueryReq) { + return authCheck(query(pluginQueryReq)); + } + + private List authCheck(List plugins) { + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + List domainIdAuthorized = semanticLayer.getDomainListForAdmin().stream() + .map(DomainResp::getId).collect(Collectors.toList()); + plugins = plugins.stream().filter(plugin -> { + if (CollectionUtils.isEmpty(plugin.getDomainList())) { + return false; + } + for (Long domainId : plugin.getDomainList()) { + if (domainIdAuthorized.contains(domainId)) { + return true; + } + } + return false; + }).collect(Collectors.toList()); + return plugins; + } + + public Plugin convert(PluginDO pluginDO){ + Plugin plugin = new Plugin(); + BeanUtils.copyProperties(pluginDO,plugin); + plugin.setParseMode(ParseMode.valueOf(pluginDO.getParseMode())); + if (pluginDO.getDomain() != null) { + plugin.setDomainList(Arrays.stream(pluginDO.getDomain().split(",")) + .map(Long::parseLong).collect(Collectors.toList())); + } + return plugin; + } + + public PluginDO convert(Plugin plugin, User user){ + PluginDO pluginDO = new PluginDO(); + BeanUtils.copyProperties(plugin,pluginDO); + pluginDO.setCreatedAt(new Date()); + pluginDO.setCreatedBy(user.getName()); + pluginDO.setUpdatedAt(new Date()); + pluginDO.setUpdatedBy(user.getName()); + pluginDO.setDomain(StringUtils.join(plugin.getDomainList(), ",")); + pluginDO.setParseMode(plugin.getParseMode().name()); + return pluginDO; + } + + public PluginDO convert(Plugin plugin, PluginDO pluginDO, User user){ + BeanUtils.copyProperties(plugin,pluginDO); + pluginDO.setUpdatedAt(new Date()); + pluginDO.setUpdatedBy(user.getName()); + pluginDO.setDomain(StringUtils.join(plugin.getDomainList(), ",")); + pluginDO.setParseMode(plugin.getParseMode().name()); + return pluginDO; + } + + public List convertList(List pluginDOS){ + if(!CollectionUtils.isEmpty(pluginDOS)){ + return pluginDOS.stream().map(this::convert).collect(Collectors.toList()); + } + return Lists.newArrayList(); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/QueryServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/QueryServiceImpl.java new file mode 100644 index 000000000..ae4e51ae0 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/QueryServiceImpl.java @@ -0,0 +1,94 @@ +package com.tencent.supersonic.chat.service.impl; + + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.*; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.query.QuerySelector; +import com.tencent.supersonic.chat.api.pojo.request.QueryDataRequest; +import com.tencent.supersonic.chat.query.QueryManager; +import com.tencent.supersonic.chat.service.ChatService; +import com.tencent.supersonic.chat.service.QueryService; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import java.util.List; +import java.util.stream.Collectors; + +import com.tencent.supersonic.common.util.JsonUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.calcite.sql.parser.SqlParseException; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + +@Service +@Component("chatQueryService") +@Primary +@Slf4j +public class QueryServiceImpl implements QueryService { + + @Autowired + private ChatService chatService; + + private List schemaMappers = ComponentFactory.getSchemaMappers(); + private List semanticParsers = ComponentFactory.getSemanticParsers(); + private QuerySelector querySelector = ComponentFactory.getQuerySelector(); + + @Override + public QueryResult executeQuery(QueryRequest queryReq) throws Exception { + QueryContext queryCtx = new QueryContext(queryReq); + // in order to support multi-turn conversation, chat context is needed + ChatContext chatCtx = chatService.getOrCreateContext(queryReq.getChatId()); + + schemaMappers.stream().forEach(mapper -> { + mapper.map(queryCtx); + log.info("{} result:{}", mapper.getClass().getSimpleName(), JsonUtil.toString(queryCtx)); + }); + + semanticParsers.stream().forEach(parser -> { + parser.parse(queryCtx, chatCtx); + log.info("{} result:{}", parser.getClass().getSimpleName(), JsonUtil.toString(queryCtx)); + }); + + QueryResult queryResult = null; + if (queryCtx.getCandidateQueries().size() > 0) { + log.info("pick before [{}]", queryCtx.getCandidateQueries().stream().collect( + Collectors.toList())); + SemanticQuery semanticQuery = querySelector.select(queryCtx.getCandidateQueries()); + log.info("pick after [{}]", semanticQuery); + + queryResult = semanticQuery.execute(queryReq.getUser()); + if (queryResult != null) { + // update chat context after a successful semantic query + if (queryReq.isSaveAnswer() && QueryState.SUCCESS.equals(queryResult.getQueryState())) { + chatService.updateContext(chatCtx, queryCtx, semanticQuery.getParseInfo()); + } + queryResult.setChatContext(chatCtx.getParseInfo()); + chatService.addQuery(queryResult, queryCtx, chatCtx); + } + } + + return queryResult; + } + + @Override + public SemanticParseInfo queryContext(QueryRequest queryCtx) { + ChatContext context = chatService.getOrCreateContext(queryCtx.getChatId()); + return context.getParseInfo(); + } + + @Override + public QueryResult executeDirectQuery(QueryDataRequest queryData, User user) throws SqlParseException { + SemanticQuery semanticQuery = QueryManager.createRuleQuery(queryData.getQueryMode()); + BeanUtils.copyProperties(queryData, semanticQuery.getParseInfo()); + return semanticQuery.execute(user); + } + +} + diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/RecommendServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/RecommendServiceImpl.java new file mode 100644 index 000000000..ab314f84a --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/RecommendServiceImpl.java @@ -0,0 +1,131 @@ +package com.tencent.supersonic.chat.service.impl; + + +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.RecommendQuestion; +import com.tencent.supersonic.chat.config.ChatConfigFilter; +import com.tencent.supersonic.chat.config.ChatConfigResp; +import com.tencent.supersonic.chat.config.ChatConfigRich; +import com.tencent.supersonic.chat.api.pojo.response.RecommendResponse; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.service.RecommendService; +import com.tencent.supersonic.chat.service.SemanticService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +/*** + * Recommend Service impl + */ +@Service +@Slf4j +public class RecommendServiceImpl implements RecommendService { + + @Autowired + private ConfigService configService; + @Autowired + private SemanticService semanticService; + + @Override + public RecommendResponse recommend(QueryRequest queryCtx, Long limit) { + if (Objects.isNull(limit) || limit <= 0) { + limit = Long.MAX_VALUE; + } + log.debug("limit:{}", limit); + Long domainId = queryCtx.getDomainId(); + if (Objects.isNull(domainId)) { + return new RecommendResponse(); + } + + DomainSchema domainSchema = semanticService.getDomainSchema(domainId); + + List dimensions = domainSchema.getDimensions().stream() + .filter(dim -> Objects.nonNull(dim) && Objects.nonNull(dim.getUseCnt())) + .sorted(Comparator.comparing(SchemaElement::getUseCnt).reversed()) + .limit(limit) + .map(dimSchemaDesc -> { + SchemaElement item = new SchemaElement(); + item.setDomain(domainId); + item.setName(dimSchemaDesc.getName()); + item.setBizName(dimSchemaDesc.getBizName()); + item.setId(dimSchemaDesc.getId()); + return item; + }).collect(Collectors.toList()); + + List metrics = domainSchema.getMetrics().stream() + .filter(metric -> Objects.nonNull(metric) && Objects.nonNull(metric.getUseCnt())) + .sorted(Comparator.comparing(SchemaElement::getUseCnt).reversed()) + .limit(limit) + .map(metricSchemaDesc -> { + SchemaElement item = new SchemaElement(); + item.setDomain(domainId); + item.setName(metricSchemaDesc.getName()); + item.setBizName(metricSchemaDesc.getBizName()); + item.setId(metricSchemaDesc.getId()); + return item; + }).collect(Collectors.toList()); + + RecommendResponse response = new RecommendResponse(); + response.setDimensions(dimensions); + response.setMetrics(metrics); + return response; + } + + @Override + public RecommendResponse recommendMetricMode(QueryRequest queryCtx, Long limit) { + RecommendResponse recommendResponse = recommend(queryCtx, limit); + // filter black Item + if (Objects.isNull(recommendResponse)) { + return recommendResponse; + } + + ChatConfigRich chatConfigRich = configService.getConfigRichInfo(Long.valueOf(queryCtx.getDomainId())); + if (Objects.nonNull(chatConfigRich) && Objects.nonNull(chatConfigRich.getChatAggRichConfig()) + && Objects.nonNull(chatConfigRich.getChatAggRichConfig().getVisibility())) { + List blackMetricIdList = chatConfigRich.getChatAggRichConfig().getVisibility().getBlackMetricIdList(); + List metrics = filterBlackItem(recommendResponse.getMetrics(), blackMetricIdList); + recommendResponse.setMetrics(metrics); + + List blackDimIdList = chatConfigRich.getChatAggRichConfig().getVisibility().getBlackDimIdList(); + List dimensions = filterBlackItem(recommendResponse.getDimensions(), blackDimIdList); + recommendResponse.setDimensions(dimensions); + } + + return recommendResponse; + } + + @Override + public List recommendQuestion(Long domainId) { + List recommendQuestions = new ArrayList<>(); + ChatConfigFilter chatConfigFilter = new ChatConfigFilter(); + chatConfigFilter.setDomainId(domainId); + List chatConfigRespList = configService.search(chatConfigFilter, null); + if (!CollectionUtils.isEmpty(chatConfigRespList)) { + chatConfigRespList.stream().forEach(chatConfigResp -> { + if (Objects.nonNull(chatConfigResp) && !CollectionUtils.isEmpty(chatConfigResp.getRecommendedQuestions())) { + recommendQuestions.add(new RecommendQuestion(chatConfigResp.getDomainId(), chatConfigResp.getRecommendedQuestions())); + } + }); + return recommendQuestions; + } + return new ArrayList<>(); + } + + private List filterBlackItem(List itemList, List blackDimIdList) { + if (CollectionUtils.isEmpty(blackDimIdList) || CollectionUtils.isEmpty(itemList)) { + return itemList; + } + + return itemList.stream().filter(dim -> !blackDimIdList.contains(dim.getId())).collect(Collectors.toList()); + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/SearchServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/SearchServiceImpl.java similarity index 54% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/SearchServiceImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/SearchServiceImpl.java index 47ba6529a..745c1c337 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/SearchServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/SearchServiceImpl.java @@ -1,27 +1,26 @@ -package com.tencent.supersonic.chat.application; +package com.tencent.supersonic.chat.service.impl; import com.google.common.collect.Lists; import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.pojo.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.knowledge.NatureHelper; -import com.tencent.supersonic.chat.application.knowledge.WordNatureService; -import com.tencent.supersonic.chat.application.mapper.SearchMatchStrategy; -import com.tencent.supersonic.chat.domain.pojo.search.DomainInfoStat; -import com.tencent.supersonic.chat.domain.pojo.search.DomainWithSemanticType; -import com.tencent.supersonic.chat.domain.pojo.search.MatchText; -import com.tencent.supersonic.chat.domain.pojo.search.SearchResult; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.chat.domain.service.ChatService; -import com.tencent.supersonic.chat.domain.service.SearchService; -import com.tencent.supersonic.chat.domain.utils.NatureConverter; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.MapResult; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; +import com.tencent.supersonic.chat.api.pojo.SemanticSchema; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.SearchResult; +import com.tencent.supersonic.chat.mapper.DomainInfoStat; +import com.tencent.supersonic.chat.mapper.DomainWithSemanticType; +import com.tencent.supersonic.chat.mapper.MatchText; +import com.tencent.supersonic.chat.mapper.SearchMatchStrategy; +import com.tencent.supersonic.chat.service.ChatService; +import com.tencent.supersonic.chat.service.SearchService; +import com.tencent.supersonic.chat.utils.NatureHelper; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.MapResult; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.service.SchemaService; +import com.tencent.supersonic.knowledge.utils.HanlpHelper; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; @@ -34,7 +33,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -49,27 +47,27 @@ import org.springframework.stereotype.Service; public class SearchServiceImpl implements SearchService { private static final int RESULT_SIZE = 10; - @Autowired - private WordNatureService wordNatureService; + private SchemaService schemaService; @Autowired private ChatService chatService; @Autowired private SearchMatchStrategy searchMatchStrategy; @Override - public List search(QueryContextReq queryCtx) { + public List search(QueryRequest queryCtx) { String queryText = queryCtx.getQueryText(); // 1.get meta info - DomainInfos domainInfosDb = wordNatureService.getCache().getUnchecked(""); + SemanticSchema semanticSchemaDb = schemaService.getSemanticSchema(); + List metricsDb = semanticSchemaDb.getMetrics(); + final Map domainToName = semanticSchemaDb.getDomainIdToName(); - List metricsDb = domainInfosDb.getMetrics(); - final Map domainToName = domainInfosDb.getDomainToName(); // 2.detect by segment List originals = HanlpHelper.getTerms(queryText); Map> regTextMap = searchMatchStrategy.match(queryText, originals, queryCtx.getDomainId()); regTextMap.entrySet().stream().forEach(m -> HanlpHelper.transLetterOriginal(m.getValue())); + // 3.get the most matching data Optional>> mostSimilarSearchResult = regTextMap.entrySet() .stream() @@ -78,9 +76,9 @@ public class SearchServiceImpl implements SearchService { entry1.getKey().getDetectSegment().length() >= entry2.getKey().getDetectSegment().length() ? entry1 : entry2); log.debug("mostSimilarSearchResult:{}", mostSimilarSearchResult); + // 4.optimize the results after the query if (!mostSimilarSearchResult.isPresent()) { - log.info("unable to find any information through search , queryCtx:{}", queryCtx); return Lists.newArrayList(); } Map.Entry> searchTextEntry = mostSimilarSearchResult.get(); @@ -89,7 +87,7 @@ public class SearchServiceImpl implements SearchService { Set searchResults = new LinkedHashSet(); DomainInfoStat domainStat = NatureHelper.getDomainStat(originals); - List possibleDomains = getPossibleDomains(queryCtx, originals, domainStat, queryCtx.getDomainId()); + List possibleDomains = getPossibleDomains(queryCtx, originals, domainStat, queryCtx.getDomainId()); // 4.1 priority dimension metric boolean existMetricAndDimension = searchMetricAndDimension(new HashSet<>(possibleDomains), domainToName, @@ -101,22 +99,26 @@ public class SearchServiceImpl implements SearchService { log.debug("possibleDomains:{},natureToNameMap:{}", possibleDomains, natureToNameMap); for (Map.Entry natureToNameEntry : natureToNameMap.entrySet()) { - searchDimensionValue(metricsDb, domainToName, domainStat.getMetricDomainCount(), searchResults, - existMetricAndDimension, matchText, natureToNameMap, natureToNameEntry, queryCtx.getQueryFilter()); + + Set searchResultSet = searchDimensionValue(metricsDb, domainToName, + domainStat.getMetricDomainCount(), existMetricAndDimension, + matchText, natureToNameMap, natureToNameEntry, queryCtx.getQueryFilters()); + + searchResults.addAll(searchResultSet); } return searchResults.stream().limit(RESULT_SIZE).collect(Collectors.toList()); } - private List getPossibleDomains(QueryContextReq queryCtx, List originals, - DomainInfoStat domainStat, Integer webDomainId) { + private List getPossibleDomains(QueryRequest queryCtx, List originals, + DomainInfoStat domainStat, Long webDomainId) { if (Objects.nonNull(webDomainId) && webDomainId > 0) { - List result = new ArrayList<>(); + List result = new ArrayList<>(); result.add(webDomainId); return result; } - List possibleDomains = NatureHelper.selectPossibleDomains(originals); + List possibleDomains = NatureHelper.selectPossibleDomains(originals); Long contextDomain = chatService.getContextDomain(queryCtx.getChatId()); @@ -124,8 +126,8 @@ public class SearchServiceImpl implements SearchService { // If nothing is recognized or only metric are present, then add the contextDomain. if (nothingOrOnlyMetric(domainStat) && effectiveDomain(contextDomain)) { - List result = new ArrayList<>(); - result.add(Math.toIntExact(contextDomain)); + List result = new ArrayList<>(); + result.add(contextDomain); return result; } return possibleDomains; @@ -140,77 +142,91 @@ public class SearchServiceImpl implements SearchService { return Objects.nonNull(contextDomain) && contextDomain > 0; } - private void searchDimensionValue(List metricsDb, - Map domainToName, - long metricDomainCount, - Set searchResults, - boolean existMetricAndDimension, - MatchText matchText, - Map natureToNameMap, - Map.Entry natureToNameEntry, - QueryFilter queryFilter) { + private Set searchDimensionValue(List metricsDb, + Map domainToName, + long metricDomainCount, + boolean existMetricAndDimension, + MatchText matchText, + Map natureToNameMap, + Map.Entry natureToNameEntry, + QueryFilters queryFilters) { + + Set searchResults = new LinkedHashSet(); String nature = natureToNameEntry.getKey(); String wordName = natureToNameEntry.getValue(); - Integer domain = NatureHelper.getDomain(nature); - SchemaElementType schemaElementType = NatureConverter.convertTo(nature); + Long domainId = NatureHelper.getDomainId(nature); + SchemaElementType schemaElementType = NatureHelper.convertToElementType(nature); if (SchemaElementType.ENTITY.equals(schemaElementType)) { - return; + return searchResults; } // If there are no metric/dimension, complete the metric information + SearchResult searchResult = SearchResult.builder() + .domainId(domainId) + .domainName(domainToName.get(domainId)) + .recommend(matchText.getRegText() + wordName) + .schemaElementType(schemaElementType) + .subRecommend(wordName) + .build(); if (metricDomainCount <= 0 && !existMetricAndDimension) { - if (filterByQueryFilter(matchText.getRegText(), queryFilter)) { - return; + if (filterByQueryFilter(wordName, queryFilters)) { + return searchResults; } - searchResults.add( - new SearchResult(matchText.getRegText() + wordName, wordName, domainToName.get(domain), domain, - schemaElementType)); - int metricSize = RESULT_SIZE / (natureToNameMap.entrySet().size()); - if (metricSize <= 1) { - metricSize = 1; - } - List metrics = filerMetricsByDomain(metricsDb, domain).stream().limit(metricSize).collect( - Collectors.toList()); + searchResults.add(searchResult); + int metricSize = getMetricSize(natureToNameMap); + List metrics = filerMetricsByDomain(metricsDb, domainId, metricSize); + for (String metric : metrics) { - String subRecommend = matchText.getRegText() + wordName + NatureType.SPACE + metric; - searchResults.add( - new SearchResult(subRecommend, wordName + NatureType.SPACE + metric, domainToName.get(domain), - domain, false)); + SearchResult result = SearchResult.builder() + .domainId(domainId) + .domainName(domainToName.get(domainId)) + .recommend(matchText.getRegText() + wordName + DictWordType.SPACE + metric) + .subRecommend(wordName + DictWordType.SPACE + metric) + .isComplete(false) + .build(); + searchResults.add(result); } } else { - searchResults.add( - new SearchResult(matchText.getRegText() + wordName, wordName, domainToName.get(domain), domain, - schemaElementType)); + searchResults.add(searchResult); } + return searchResults; } - private boolean filterByQueryFilter(String regText, QueryFilter queryFilter) { - if (queryFilter == null || CollectionUtils.isEmpty(queryFilter.getFilters())) { + private int getMetricSize(Map natureToNameMap) { + int metricSize = RESULT_SIZE / (natureToNameMap.entrySet().size()); + if (metricSize <= 1) { + metricSize = 1; + } + return metricSize; + } + + private boolean filterByQueryFilter(String wordName, QueryFilters queryFilters) { + if (queryFilters == null || CollectionUtils.isEmpty(queryFilters.getFilters())) { return false; } - List filters = queryFilter.getFilters(); - for (Filter filter : filters) { - if (regText.equalsIgnoreCase(String.valueOf(filter.getValue()))) { + List filters = queryFilters.getFilters(); + for (QueryFilter filter : filters) { + if (wordName.equalsIgnoreCase(String.valueOf(filter.getValue()))) { return false; } } return true; } - protected List filerMetricsByDomain(List metricsDb, Integer domain) { + protected List filerMetricsByDomain(List metricsDb, Long domain, int metricSize) { if (CollectionUtils.isEmpty(metricsDb)) { return Lists.newArrayList(); } return metricsDb.stream() .filter(mapDO -> Objects.nonNull(mapDO) && domain.equals(mapDO.getDomain())) - .sorted(Comparator.comparing(ItemDO::getUseCnt).reversed()) + .sorted(Comparator.comparing(SchemaElement::getUseCnt).reversed()) .flatMap(entry -> { List result = new ArrayList<>(); result.add(entry.getName()); return result.stream(); }) - .collect(Collectors.toList()); + .limit(metricSize).collect(Collectors.toList()); } /*** @@ -219,7 +235,7 @@ public class SearchServiceImpl implements SearchService { * @return */ private Map getNatureToNameMap(Map.Entry> recommendTextListEntry, - Set possibleDomains) { + Set possibleDomains) { List recommendValues = recommendTextListEntry.getValue(); return recommendValues.stream() .flatMap(entry -> entry.getNatures().stream() @@ -227,21 +243,21 @@ public class SearchServiceImpl implements SearchService { if (CollectionUtils.isEmpty(possibleDomains)) { return true; } - Integer domain = NatureHelper.getDomain(nature); + Long domain = NatureHelper.getDomainId(nature); return possibleDomains.contains(domain); }) .map(nature -> { - WordNature posDO = new WordNature(); + DictWord posDO = new DictWord(); posDO.setWord(entry.getName()); posDO.setNature(nature); return posDO; } )).sorted(Comparator.comparingInt(a -> a.getWord().length())) - .collect(Collectors.toMap(WordNature::getNature, WordNature::getWord, (value1, value2) -> value1, + .collect(Collectors.toMap(DictWord::getNature, DictWord::getWord, (value1, value2) -> value1, LinkedHashMap::new)); } - private boolean searchMetricAndDimension(Set possibleDomains, Map domainToName, + private boolean searchMetricAndDimension(Set possibleDomains, Map domainToName, Map.Entry> searchTextEntry, Set searchResults) { boolean existMetric = false; @@ -251,27 +267,35 @@ public class SearchServiceImpl implements SearchService { for (MapResult mapResult : mapResults) { List dimensionMetricClassIds = mapResult.getNatures().stream() - .map(nature -> new DomainWithSemanticType(NatureHelper.getDomain(nature), - NatureConverter.convertTo(nature))) + .map(nature -> new DomainWithSemanticType(NatureHelper.getDomainId(nature), + NatureHelper.convertToElementType(nature))) .filter(entry -> matchCondition(entry, possibleDomains)).collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(dimensionMetricClassIds)) { - for (DomainWithSemanticType domainWithSemanticType : dimensionMetricClassIds) { - existMetric = true; - Integer domain = domainWithSemanticType.getDomain(); - SchemaElementType semanticType = domainWithSemanticType.getSemanticType(); - searchResults.add( - new SearchResult(matchText.getRegText() + mapResult.getName(), mapResult.getName(), - domainToName.get(domain), domain, semanticType)); - } + if (CollectionUtils.isEmpty(dimensionMetricClassIds)) { + continue; } - log.info("parseResult:{},dimensionMetricClassIds:{},possibleDomains:{}", mapResult, - dimensionMetricClassIds, possibleDomains); + for (DomainWithSemanticType domainWithSemanticType : dimensionMetricClassIds) { + existMetric = true; + Long domainId = domainWithSemanticType.getDomain(); + SchemaElementType semanticType = domainWithSemanticType.getSemanticType(); + + SearchResult searchResult = SearchResult.builder() + .domainId(domainId) + .domainName(domainToName.get(domainId)) + .recommend(matchText.getRegText() + mapResult.getName()) + .subRecommend(mapResult.getName()) + .schemaElementType(semanticType) + .build(); + + searchResults.add(searchResult); + } + log.info("parseResult:{},dimensionMetricClassIds:{},possibleDomains:{}", mapResult, dimensionMetricClassIds, + possibleDomains); } return existMetric; } - private boolean matchCondition(DomainWithSemanticType entry, Set possibleDomains) { + private boolean matchCondition(DomainWithSemanticType entry, Set possibleDomains) { if (!(SchemaElementType.METRIC.equals(entry.getSemanticType()) || SchemaElementType.DIMENSION.equals( entry.getSemanticType()))) { return false; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/CacheUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/CacheUtils.java new file mode 100644 index 000000000..1062f27eb --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/CacheUtils.java @@ -0,0 +1,24 @@ +package com.tencent.supersonic.chat.utils; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; + +import java.util.concurrent.TimeUnit; + +public class CacheUtils { + private static final Cache cache = Caffeine.newBuilder() + .expireAfterWrite(1200, TimeUnit.SECONDS) + .expireAfterAccess(1200, TimeUnit.SECONDS) + .maximumSize(1000) + .build(); + public static void put(QueryContext queryContext, ChatContext chatCtx, Object v){ + String key=chatCtx.getUser()+"_"+chatCtx.getChatId()+"_"+queryContext.getRequest().getQueryText(); + cache.put(key,v); + } + public static Object get(QueryContext queryContext,ChatContext chatCtx){ + String key=chatCtx.getUser()+"_"+chatCtx.getChatId()+"_"+queryContext.getRequest().getQueryText(); + return cache.getIfPresent(key); + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ChatConfigUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ChatConfigHelper.java similarity index 57% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ChatConfigUtils.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/utils/ChatConfigHelper.java index e52274def..28a2f59bb 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ChatConfigUtils.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ChatConfigHelper.java @@ -1,19 +1,18 @@ -package com.tencent.supersonic.chat.domain.utils; +package com.tencent.supersonic.chat.utils; -import static com.tencent.supersonic.common.constant.Constants.ADMIN_LOWER; +import static com.tencent.supersonic.common.pojo.Constants.ADMIN_LOWER; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.domain.pojo.config.*; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.chat.domain.dataobject.ChatConfigDO; -import com.tencent.supersonic.common.enums.StatusEnum; -import com.tencent.supersonic.common.util.RecordInfo; -import com.tencent.supersonic.common.util.json.JsonUtil; +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestion; +import com.tencent.supersonic.chat.config.*; +import com.tencent.supersonic.chat.persistence.dataobject.ChatConfigDO; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; +import com.tencent.supersonic.common.pojo.RecordInfo; +import com.tencent.supersonic.common.util.JsonUtil; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -28,7 +27,7 @@ import org.springframework.util.CollectionUtils; @Component @Slf4j -public class ChatConfigUtils { +public class ChatConfigHelper { public ChatConfig newChatConfig(ChatConfigBaseReq extendBaseCmd, User user) { ChatConfig chatConfig = new ChatConfig(); @@ -54,63 +53,21 @@ public class ChatConfigUtils { return chatConfig; } - - public List generateDimDesc(List dimIds, DomainSchemaResp domainSchemaDesc) { - List dimSchemaDescList = new ArrayList<>(); - if (Objects.nonNull(domainSchemaDesc) && !CollectionUtils.isEmpty(domainSchemaDesc.getDimensions())) { - dimSchemaDescList = domainSchemaDesc.getDimensions().stream() - .filter(dimSchemaDesc -> dimIds.contains(dimSchemaDesc.getId())) - .collect(Collectors.toList()); - } - return dimSchemaDescList; - } - - public List generateMetricDesc(List metricIds, DomainSchemaResp domainSchemaDesc) { - List metricSchemaDescList = new ArrayList<>(); - if (Objects.nonNull(domainSchemaDesc) && !CollectionUtils.isEmpty(domainSchemaDesc.getMetrics())) { - metricSchemaDescList = domainSchemaDesc.getMetrics().stream() - .filter(metricSchemaDesc -> metricIds.contains(metricSchemaDesc.getId())) - .collect(Collectors.toList()); - } - return metricSchemaDescList; - } - - public EntityInternalDetail generateEntityDetailData(EntityDetailData detailData, - DomainSchemaResp domainSchemaDesc) { - EntityInternalDetail entityInternalDetailDesc = new EntityInternalDetail(); - if (Objects.isNull(detailData)) { - return entityInternalDetailDesc; - } - entityInternalDetailDesc.setDimensionList(generateDimDesc(detailData.getDimensionIds(), domainSchemaDesc)); - entityInternalDetailDesc.setMetricList(generateMetricDesc(detailData.getMetricIds(), domainSchemaDesc)); - - return entityInternalDetailDesc; - } - - public Map generateMetricIdAndDescPair(List metricIds, - DomainSchemaResp domainSchemaDesc) { - Map metricIdAndDescPair = new HashMap<>(); - List metricDescList = generateMetricDesc(metricIds, domainSchemaDesc); - - metricDescList.stream().forEach(metricDesc -> metricIdAndDescPair.put(metricDesc.getId(), metricDesc)); - return metricIdAndDescPair; - } - - public List generateAllDimIdList(DomainSchemaResp domainSchemaDesc) { - if (Objects.isNull(domainSchemaDesc) || CollectionUtils.isEmpty(domainSchemaDesc.getDimensions())) { + public List generateAllDimIdList(DomainSchema domainSchema) { + if (Objects.isNull(domainSchema) || CollectionUtils.isEmpty(domainSchema.getDimensions())) { return new ArrayList<>(); } - Map> dimIdAndDescPair = domainSchemaDesc.getDimensions() - .stream().collect(Collectors.groupingBy(DimSchemaResp::getId)); + Map> dimIdAndDescPair = domainSchema.getDimensions() + .stream().collect(Collectors.groupingBy(SchemaElement::getId)); return new ArrayList<>(dimIdAndDescPair.keySet()); } - public List generateAllMetricIdList(DomainSchemaResp domainSchemaDesc) { - if (Objects.isNull(domainSchemaDesc) || CollectionUtils.isEmpty(domainSchemaDesc.getMetrics())) { + public List generateAllMetricIdList(DomainSchema domainSchema) { + if (Objects.isNull(domainSchema) || CollectionUtils.isEmpty(domainSchema.getMetrics())) { return new ArrayList<>(); } - Map> metricIdAndDescPair = domainSchemaDesc.getMetrics() - .stream().collect(Collectors.groupingBy(MetricSchemaResp::getId)); + Map> metricIdAndDescPair = domainSchema.getMetrics() + .stream().collect(Collectors.groupingBy(SchemaElement::getId)); return new ArrayList<>(metricIdAndDescPair.keySet()); } @@ -120,6 +77,7 @@ public class ChatConfigUtils { chatConfigDO.setChatAggConfig(JsonUtil.toString(chatConfig.getChatAggConfig())); chatConfigDO.setChatDetailConfig(JsonUtil.toString(chatConfig.getChatDetailConfig())); + chatConfigDO.setRecommendedQuestions(JsonUtil.toString(chatConfig.getRecommendedQuestions())); if (Objects.isNull(chatConfig.getStatus())) { chatConfigDO.setStatus(null); @@ -147,6 +105,7 @@ public class ChatConfigUtils { chatConfigDescriptor.setChatDetailConfig(JsonUtil.toObject(chatConfigDO.getChatDetailConfig(), ChatDetailConfig.class)); chatConfigDescriptor.setChatAggConfig(JsonUtil.toObject(chatConfigDO.getChatAggConfig(), ChatAggConfig.class)); + chatConfigDescriptor.setRecommendedQuestions(JsonUtil.toList(chatConfigDO.getRecommendedQuestions(), RecommendedQuestion.class)); chatConfigDescriptor.setStatusEnum(StatusEnum.of(chatConfigDO.getStatus())); chatConfigDescriptor.setCreatedBy(chatConfigDO.getCreatedBy()); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ComponentFactory.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ComponentFactory.java similarity index 92% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ComponentFactory.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/utils/ComponentFactory.java index 6fcdcb4ed..7fa7a9164 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ComponentFactory.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ComponentFactory.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.domain.utils; +package com.tencent.supersonic.chat.utils; import com.tencent.supersonic.chat.api.component.SchemaMapper; import com.tencent.supersonic.chat.api.component.SemanticLayer; @@ -8,8 +8,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import com.tencent.supersonic.chat.application.parser.DomainResolver; -import com.tencent.supersonic.chat.application.query.QuerySelector; +import com.tencent.supersonic.chat.parser.function.DomainResolver; +import com.tencent.supersonic.chat.query.QuerySelector; import org.apache.commons.collections.CollectionUtils; import org.springframework.core.io.support.SpringFactoriesLoader; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictMetaUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictMetaHelper.java similarity index 72% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictMetaUtils.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictMetaHelper.java index 122103051..ae8abf276 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictMetaUtils.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictMetaHelper.java @@ -1,17 +1,16 @@ -package com.tencent.supersonic.chat.domain.utils; +package com.tencent.supersonic.chat.utils; -import static com.tencent.supersonic.common.constant.Constants.DAY; -import static com.tencent.supersonic.common.constant.Constants.UNDERLINE; +import static com.tencent.supersonic.common.pojo.Constants.DAY; +import static com.tencent.supersonic.common.pojo.Constants.UNDERLINE; import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.application.ConfigServiceImpl; -import com.tencent.supersonic.chat.domain.pojo.config.*; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.chat.domain.dataobject.DimValueDO; -import com.tencent.supersonic.knowledge.domain.pojo.DictUpdateMode; -import com.tencent.supersonic.knowledge.domain.pojo.DimValue2DictCommand; +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.config.*; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.persistence.dataobject.DimValueDO; +import com.tencent.supersonic.knowledge.dictionary.DictUpdateMode; +import com.tencent.supersonic.knowledge.dictionary.DimValue2DictCommand; import java.util.ArrayList; import java.util.HashMap; @@ -30,20 +29,14 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @Component -public class DictMetaUtils { +public class DictMetaHelper { @Autowired - private ConfigServiceImpl configService; - + private ConfigService configService; @Value("${model.internal.metric.suffix:internal_cnt}") private String internalMetricNameSuffix; private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - public DictMetaUtils() { - - } - - public List generateDimValueInfo(DimValue2DictCommand dimValue2DictCommend) { List dimValueDOList = new ArrayList<>(); DictUpdateMode updateMode = dimValue2DictCommend.getUpdateMode(); @@ -54,13 +47,13 @@ public class DictMetaUtils { dimValueDOList = generateDimValueInfoByDomain(domainIds); break; case OFFLINE_FULL: - List domainSchemaDescList = semanticLayer.getDomainSchemaInfo(new ArrayList<>()); + List domainSchemaDescList = semanticLayer.getDomainSchema(); if (CollectionUtils.isEmpty(domainSchemaDescList)) { break; } - Map domainIdAndDescPair = domainSchemaDescList.stream() - .collect(Collectors.toMap(DomainSchemaResp::getId, domainSchemaDesc -> domainSchemaDesc)); + Map domainIdAndDescPair = domainSchemaDescList.stream() + .collect(Collectors.toMap(a -> a.getDomain().getId(), schema -> schema, (k1, k2) -> k1)); if (!CollectionUtils.isEmpty(domainIdAndDescPair)) { domainIds.addAll(domainIdAndDescPair.keySet()); dimValueDOList = generateDimValueInfoByDomain(domainIds); @@ -85,22 +78,22 @@ public class DictMetaUtils { return dimValueDOList; } - List domainSchemaDescList = semanticLayer.getDomainSchemaInfo(new ArrayList<>()); + List domainSchemaDescList = semanticLayer.getDomainSchema(); if (CollectionUtils.isEmpty(domainSchemaDescList)) { return dimValueDOList; } - Map domainIdAndDescPair = domainSchemaDescList.stream() - .collect(Collectors.toMap(DomainSchemaResp::getId, domainSchemaDesc -> domainSchemaDesc)); + Map domainIdAndDescPair = domainSchemaDescList.stream() + .collect(Collectors.toMap(a -> a.getDomain().getId(), a -> a, (k1, k2) -> k1)); for (Long domainId : domainAndDimMap.keySet()) { if (!domainIdAndDescPair.containsKey(domainId)) { continue; } - Map dimIdAndDescPairAll; + Map dimIdAndDescPairAll; dimIdAndDescPairAll = domainIdAndDescPair.get(domainId).getDimensions().stream() - .collect(Collectors.toMap(DimSchemaResp::getId, dimSchemaDesc -> dimSchemaDesc)); + .collect(Collectors.toMap(SchemaElement::getId, dimSchemaDesc -> dimSchemaDesc, (k1, k2) -> k1)); List dimIdReq = domainAndDimMap.get(domainId); - Map dimIdAndDescPairReq = new HashMap<>(); + Map dimIdAndDescPairReq = new HashMap<>(); for (Long dimId : dimIdReq) { if (dimIdAndDescPairAll.containsKey(dimId)) { dimIdAndDescPairReq.put(dimId, dimIdAndDescPairAll.get(dimId)); @@ -114,15 +107,15 @@ public class DictMetaUtils { private List generateDimValueInfoByDomain(Set domainIds) { List dimValueDOList = new ArrayList<>(); - List domainSchemaDescList = semanticLayer.getDomainSchemaInfo(new ArrayList<>(domainIds)); + List domainSchemaDescList = semanticLayer.getDomainSchema(new ArrayList<>(domainIds)); if (CollectionUtils.isEmpty(domainSchemaDescList)) { return dimValueDOList; } domainSchemaDescList.forEach(domainSchemaDesc -> { - Map dimIdAndDescPair = domainSchemaDesc.getDimensions().stream() - .collect(Collectors.toMap(DimSchemaResp::getId, dimSchemaDesc -> dimSchemaDesc)); - fillDimValueDOList(dimValueDOList, domainSchemaDesc.getId(), dimIdAndDescPair); + Map dimIdAndDescPair = domainSchemaDesc.getDimensions().stream() + .collect(Collectors.toMap(SchemaElement::getId, dimSchemaDesc -> dimSchemaDesc, (k1, k2) -> k1)); + fillDimValueDOList(dimValueDOList, domainSchemaDesc.getDomain().getId(), dimIdAndDescPair); }); @@ -130,8 +123,8 @@ public class DictMetaUtils { } private void fillDimValueDOList(List dimValueDOList, Long domainId, - Map dimIdAndDescPair) { - ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(domainId); + Map dimIdAndDescPair) { + ChatConfigRich chaConfigRichDesc = configService.getConfigRichInfo(domainId); if (Objects.nonNull(chaConfigRichDesc) && Objects.nonNull(chaConfigRichDesc.getChatAggRichConfig())) { ChatDefaultRichConfig chatDefaultConfig = chaConfigRichDesc.getChatAggRichConfig().getChatDefaultConfig(); @@ -147,7 +140,7 @@ public class DictMetaUtils { } private void fillKnowledgeDimValue(List knowledgeInfos, ChatDefaultRichConfig chatDefaultConfig, - List dimValueDOList, Map dimIdAndDescPair, Long domainId) { + List dimValueDOList, Map dimIdAndDescPair, Long domainId) { if (!CollectionUtils.isEmpty(knowledgeInfos)) { List dimensions = new ArrayList<>(); List defaultMetricDescList = new ArrayList<>(); @@ -156,18 +149,18 @@ public class DictMetaUtils { && dimIdAndDescPair.containsKey(knowledgeInfo.getItemId())) .forEach(knowledgeInfo -> { if (dimIdAndDescPair.containsKey(knowledgeInfo.getItemId())) { - DimSchemaResp dimensionDesc = dimIdAndDescPair.get(knowledgeInfo.getItemId()); + SchemaElement dimensionDesc = dimIdAndDescPair.get(knowledgeInfo.getItemId()); //default cnt if (Objects.isNull(chatDefaultConfig) || CollectionUtils.isEmpty(chatDefaultConfig.getMetrics())) { - String datasourceBizName = dimensionDesc.getDatasourceBizName(); + String datasourceBizName = dimensionDesc.getBizName(); if (Strings.isNotEmpty(datasourceBizName)) { String internalMetricName = datasourceBizName + UNDERLINE + internalMetricNameSuffix; defaultMetricDescList.add(new DefaultMetric(internalMetricName, 2, DAY)); } } else { - SchemaItem schemaItem = chatDefaultConfig.getMetrics().get(0); + SchemaElement schemaItem = chatDefaultConfig.getMetrics().get(0); defaultMetricDescList.add(new DefaultMetric(schemaItem.getBizName(), chatDefaultConfig.getUnit(), chatDefaultConfig.getPeriod())); } @@ -193,11 +186,4 @@ public class DictMetaUtils { } } } - - private boolean isVisibleDim(KnowledgeInfo knowledgeInfo, ItemVisibilityInfo itemVisibilityDesc) { - if (Objects.isNull(itemVisibilityDesc) || CollectionUtils.isEmpty(itemVisibilityDesc.getBlackDimIdList())) { - return true; - } - return !itemVisibilityDesc.getBlackDimIdList().contains(knowledgeInfo.getItemId()); - } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictQueryUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictQueryHelper.java similarity index 89% rename from chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictQueryUtils.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictQueryHelper.java index 2b6c2610f..fe7bae341 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictQueryUtils.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictQueryHelper.java @@ -1,21 +1,21 @@ -package com.tencent.supersonic.chat.domain.utils; +package com.tencent.supersonic.chat.utils; -import static com.tencent.supersonic.common.constant.Constants.AND_UPPER; -import static com.tencent.supersonic.common.constant.Constants.APOSTROPHE; -import static com.tencent.supersonic.common.constant.Constants.COMMA; -import static com.tencent.supersonic.common.constant.Constants.UNDERLINE_DOUBLE; +import static com.tencent.supersonic.common.pojo.Constants.AND_UPPER; +import static com.tencent.supersonic.common.pojo.Constants.APOSTROPHE; +import static com.tencent.supersonic.common.pojo.Constants.COMMA; +import static com.tencent.supersonic.common.pojo.Constants.UNDERLINE_DOUBLE; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.chat.config.DefaultMetric; +import com.tencent.supersonic.chat.config.Dim4Dict; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import com.tencent.supersonic.semantic.api.query.pojo.Filter; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric; -import com.tencent.supersonic.chat.domain.pojo.config.Dim4Dict; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.enums.AggOperatorEnum; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum; import com.tencent.supersonic.common.pojo.Aggregator; import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.Order; @@ -36,21 +36,19 @@ import org.springframework.util.CollectionUtils; @Slf4j @Component -public class DictQueryUtils { +public class DictQueryHelper { - Long frequencyMax = 99999999L; + private static final Long MAX_FREQUENCY = 99999999L; private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); @Value("${dimension.multi.value.split:#}") private String dimMultiValueSplit; - @Value("${dimension.value.show:50}") private Integer printDataShow; - @Value("${dimension.max.limit:3000000}") private Long dimMaxLimit; public List fetchDimValueSingle(Long domainId, DefaultMetric defaultMetricDesc, Dim4Dict dim4Dict, - User user) { + User user) { List data = new ArrayList<>(); QueryStructReq queryStructCmd = generateQueryStructCmd(domainId, defaultMetricDesc, dim4Dict); try { @@ -119,8 +117,8 @@ public class DictQueryUtils { private void constructDataLines(Map valueAndFrequencyPair, String nature, List data) { valueAndFrequencyPair.forEach((dimValue, metric) -> { - if (metric > frequencyMax) { - metric = frequencyMax; + if (metric > MAX_FREQUENCY) { + metric = MAX_FREQUENCY; } data.add(String.format("%s %s %s", dimValue, nature, metric)); }); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/NatureHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/NatureHelper.java new file mode 100644 index 000000000..e928b566b --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/NatureHelper.java @@ -0,0 +1,166 @@ +package com.tencent.supersonic.chat.utils; + +import com.hankcs.hanlp.corpus.tag.Nature; +import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.mapper.DomainInfoStat; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +/** + * nature parse helper + */ +@Slf4j +public class NatureHelper { + + public static SchemaElementType convertToElementType(String nature) { + DictWordType dictWordType = DictWordType.getNatureType(nature); + SchemaElementType result = null; + switch (dictWordType) { + case METRIC: + result = SchemaElementType.METRIC; + break; + case DIMENSION: + result = SchemaElementType.DIMENSION; + break; + case ENTITY: + result = SchemaElementType.ENTITY; + break; + case DOMAIN: + result = SchemaElementType.DOMAIN; + break; + case VALUE: + result = SchemaElementType.VALUE; + break; + default: + break; + } + return result; + } + + private static boolean isDomainOrEntity(Term term, Integer domain) { + return (DictWordType.NATURE_SPILT + domain).equals(term.nature.toString()) || term.nature.toString() + .endsWith(DictWordType.ENTITY.getType()); + } + + public static Integer getDomainByNature(Nature nature) { + if (nature.startsWith(DictWordType.NATURE_SPILT)) { + String[] dimensionValues = nature.toString().split(DictWordType.NATURE_SPILT); + if (StringUtils.isNumeric(dimensionValues[1])) { + return Integer.valueOf(dimensionValues[1]); + } + } + return 0; + } + + public static Long getDomainId(String nature) { + try { + String[] split = nature.split(DictWordType.NATURE_SPILT); + if (split.length <= 1) { + return null; + } + return Long.valueOf(split[1]); + } catch (NumberFormatException e) { + log.error("", e); + } + return null; + } + + public static boolean isDimensionValueClassId(String nature) { + if (StringUtils.isEmpty(nature)) { + return false; + } + if (!nature.startsWith(DictWordType.NATURE_SPILT)) { + return false; + } + String[] split = nature.split(DictWordType.NATURE_SPILT); + if (split.length <= 1) { + return false; + } + return !nature.endsWith(DictWordType.METRIC.getType()) && !nature.endsWith(DictWordType.DIMENSION.getType()) + && StringUtils.isNumeric(split[1]); + } + + public static DomainInfoStat getDomainStat(List terms) { + return DomainInfoStat.builder() + .domainCount(getDomainCount(terms)) + .dimensionDomainCount(getDimensionCount(terms)) + .metricDomainCount(getMetricCount(terms)) + .dimensionValueDomainCount(getDimensionValueCount(terms)) + .build(); + } + + + private static long getDomainCount(List terms) { + return terms.stream().filter(term -> isDomainOrEntity(term, getDomainByNature(term.nature))).count(); + } + + private static long getDimensionValueCount(List terms) { + return terms.stream().filter(term -> isDimensionValueClassId(term.nature.toString())).count(); + } + + private static long getDimensionCount(List terms) { + return terms.stream().filter(term -> term.nature.startsWith(DictWordType.NATURE_SPILT) && term.nature.toString() + .endsWith(DictWordType.DIMENSION.getType())).count(); + } + + private static long getMetricCount(List terms) { + return terms.stream().filter(term -> term.nature.startsWith(DictWordType.NATURE_SPILT) && term.nature.toString() + .endsWith(DictWordType.METRIC.getType())).count(); + } + + /** + * Get the number of types of class parts of speech + * domainId -> (nature , natureCount) + * + * @param terms + * @return + */ + public static Map> getDomainToNatureStat(List terms) { + Map> domainToNature = new HashMap<>(); + terms.stream().filter( + term -> term.nature.startsWith(DictWordType.NATURE_SPILT) + ).forEach(term -> { + DictWordType dictWordType = DictWordType.getNatureType(String.valueOf(term.nature)); + Long domain = getDomainId(String.valueOf(term.nature)); + + Map natureTypeMap = new HashMap<>(); + natureTypeMap.put(dictWordType, 1); + + Map original = domainToNature.get(domain); + if (Objects.isNull(original)) { + domainToNature.put(domain, natureTypeMap); + } else { + Integer count = original.get(dictWordType); + if (Objects.isNull(count)) { + count = 1; + } else { + count = count + 1; + } + original.put(dictWordType, count); + } + }); + return domainToNature; + } + + public static List selectPossibleDomains(List terms) { + Map> domainToNatureStat = getDomainToNatureStat(terms); + Integer maxDomainTypeSize = domainToNatureStat.entrySet().stream() + .max(Comparator.comparingInt(o -> o.getValue().size())).map(entry -> entry.getValue().size()) + .orElse(null); + if (Objects.isNull(maxDomainTypeSize) || maxDomainTypeSize == 0) { + return new ArrayList<>(); + } + return domainToNatureStat.entrySet().stream().filter(entry -> entry.getValue().size() == maxDomainTypeSize) + .map(entry -> entry.getKey()).collect(Collectors.toList()); + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/QueryReqBuilder.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/QueryReqBuilder.java new file mode 100644 index 000000000..44a1875e8 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/QueryReqBuilder.java @@ -0,0 +1,178 @@ +package com.tencent.supersonic.chat.utils; + +import com.google.common.collect.Lists; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.query.rule.metric.MetricDomainQuery; +import com.tencent.supersonic.chat.query.rule.metric.MetricFilterQuery; +import com.tencent.supersonic.chat.query.rule.metric.MetricGroupByQuery; +import com.tencent.supersonic.common.pojo.Aggregator; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.pojo.Order; +import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum; +import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; +import com.tencent.supersonic.semantic.api.query.pojo.Filter; +import com.tencent.supersonic.semantic.api.query.request.QueryDslReq; +import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.beans.BeanUtils; +import org.springframework.util.CollectionUtils; + +@Slf4j +public class QueryReqBuilder { + + public static QueryStructReq buildStructReq(SemanticParseInfo parseInfo) { + QueryStructReq queryStructCmd = new QueryStructReq(); + queryStructCmd.setDomainId(parseInfo.getDomainId()); + queryStructCmd.setNativeQuery(parseInfo.getNativeQuery()); + queryStructCmd.setDateInfo(parseInfo.getDateInfo()); + + List dimensionFilters = parseInfo.getDimensionFilters().stream() + .filter(chatFilter -> Strings.isNotEmpty(chatFilter.getBizName())) + .map(chatFilter -> new Filter(chatFilter.getBizName(), chatFilter.getOperator(), chatFilter.getValue())) + .collect(Collectors.toList()); + queryStructCmd.setDimensionFilters(dimensionFilters); + + List metricFilters = parseInfo.getMetricFilters().stream() + .map(chatFilter -> new Filter(chatFilter.getBizName(), chatFilter.getOperator(), chatFilter.getValue())) + .collect(Collectors.toList()); + queryStructCmd.setMetricFilters(metricFilters); + + addDateDimension(parseInfo); + List dimensions = parseInfo.getDimensions().stream().map(entry -> entry.getBizName()) + .collect(Collectors.toList()); + queryStructCmd.setGroups(dimensions); + queryStructCmd.setLimit(parseInfo.getLimit()); + Set order = getOrder(parseInfo.getOrders(), parseInfo.getAggType(), parseInfo.getMetrics()); + queryStructCmd.setOrders(new ArrayList<>(order)); + queryStructCmd.setAggregators(getAggregatorByMetric(parseInfo.getMetrics(), parseInfo.getAggType())); + return queryStructCmd; + } + + public static QueryMultiStructReq buildMultiStructReq(SemanticParseInfo parseInfo) { + QueryStructReq queryStructReq = buildStructReq(parseInfo); + QueryMultiStructReq queryMultiStructReq = new QueryMultiStructReq(); + List queryStructReqs = Lists.newArrayList(); + for (Filter dimensionFilter : queryStructReq.getDimensionFilters()) { + QueryStructReq req = new QueryStructReq(); + BeanUtils.copyProperties(queryStructReq, req); + req.setDimensionFilters(Lists.newArrayList(dimensionFilter)); + queryStructReqs.add(req); + } + queryMultiStructReq.setQueryStructReqs(queryStructReqs); + return queryMultiStructReq; + } + + /** + * convert to QueryDslReq + * @param querySql + * @param domainId + * @return + */ + public static QueryDslReq buildDslReq(String querySql,Long domainId) { + QueryDslReq queryDslReq = new QueryDslReq(); + if (Objects.nonNull(querySql)) { + queryDslReq.setSql(querySql); + } + queryDslReq.setDomainId(domainId); + return queryDslReq; + } + + + private static List getAggregatorByMetric(Set metrics, AggregateTypeEnum aggregateType) { + List aggregators = new ArrayList<>(); + String agg = (aggregateType == null || aggregateType.equals(AggregateTypeEnum.NONE)) ? "" + : aggregateType.name(); + for (SchemaElement metric : metrics) { + aggregators.add(new Aggregator(metric.getBizName(), AggOperatorEnum.of(agg))); + } + return aggregators; + } + + private static void addDateDimension(SemanticParseInfo parseInfo) { + if (parseInfo != null) { + String queryMode = parseInfo.getQueryMode(); + if (parseInfo.getDateInfo() == null) { + return; + } + if (parseInfo.getAggType() != null && (parseInfo.getAggType().equals(AggregateTypeEnum.MAX) + || parseInfo.getAggType().equals(AggregateTypeEnum.MIN)) && !CollectionUtils.isEmpty( + parseInfo.getDimensions())) { + return; + } + DateConf dateInfo = parseInfo.getDateInfo(); + String dateField = getDateField(dateInfo); + + for (SchemaElement dimension : parseInfo.getDimensions()) { + if (dimension.getBizName().equalsIgnoreCase(dateField)) { + return; + } + } + SchemaElement dimension = new SchemaElement(); + dimension.setBizName(dateField); + + if (MetricDomainQuery.QUERY_MODE.equals(queryMode) + || MetricGroupByQuery.QUERY_MODE.equals(queryMode) + || MetricFilterQuery.QUERY_MODE.equals(queryMode) + ) { + parseInfo.getDimensions().add(dimension); + } + } + } + + public static Set getOrder(Set parseOrder, AggregateTypeEnum aggregator, Set metrics) { + if (!CollectionUtils.isEmpty(parseOrder)) { + return parseOrder; + } + Set orders = new LinkedHashSet(); + if (CollectionUtils.isEmpty(metrics)) { + return orders; + } + if ((AggregateTypeEnum.TOPN.equals(aggregator) || AggregateTypeEnum.MAX.equals(aggregator) + || AggregateTypeEnum.MIN.equals( + aggregator))) { + for (SchemaElement metric : metrics) { + Order order = new Order(); + order.setColumn(metric.getBizName()); + order.setDirection("desc"); + orders.add(order); + } + } + return orders; + } + + public static String getDateField(DateConf dateConf) { + if(Objects.isNull(dateConf)) { + return ""; + } + String dateField = TimeDimensionEnum.DAY.getName(); + if (Constants.MONTH.equals(dateConf.getPeriod())) { + dateField = TimeDimensionEnum.MONTH.getName(); + } + if (Constants.WEEK.equals(dateConf.getPeriod())) { + dateField = TimeDimensionEnum.WEEK.getName(); + } + return dateField; + } + + public static QueryStructReq buildStructRatioReq(SemanticParseInfo parseInfo,SchemaElement metric,AggOperatorEnum aggOperatorEnum) { + QueryStructReq queryStructCmd = buildStructReq(parseInfo); + queryStructCmd.setNativeQuery(false); + queryStructCmd.setOrders(new ArrayList<>()); + List aggregators = new ArrayList<>(); + Aggregator ratioRoll = new Aggregator(metric.getBizName(), aggOperatorEnum); + aggregators.add(ratioRoll); + queryStructCmd.setAggregators(aggregators); + return queryStructCmd; + } +} diff --git a/chat/core/src/main/python/llm/few_shot_example/sql_exampler.py b/chat/core/src/main/python/llm/few_shot_example/sql_exampler.py deleted file mode 100644 index 31facf03b..000000000 --- a/chat/core/src/main/python/llm/few_shot_example/sql_exampler.py +++ /dev/null @@ -1,147 +0,0 @@ -examplars= [ - { - "table_name":"内容库产品", - "fields_list":"""["部门", "模块", "用户名", "访问次数", "访问人数", "访问时长"]""", - "question":"比较jerry和tom在内容库的访问次数", - "analysis": """让我们一步一步地思考。在问题“比较jerry和tom在内容库的访问次数“中,我们被问: -“内容库的访问次数”,所以我们需要column=[访问次数] -”比较jerry和tom“,所以我们需要column=[用户名] -基于table和columns,可能的cell values 是 = ['jerry', 'tom']。""", - "schema_links":"""["访问次数", "用户名", "'jerry'", "'tom'"]""", - "sql":"""select 用户名, 访问次数 from 内容库产品 where 用户名 in ('jerry', 'tom')""" - }, - { - "table_name":"内容库产品", - "fields_list":"""["部门", "模块", "用户名", "访问次数", "访问人数", "访问时长"]""", - "question":"内容库近12个月访问人数 按部门", - "analysis": """让我们一步一步地思考。在问题“内容库近12个月访问人数 按部门“中,我们被问: -“内容库近12个月访问人数”,所以我们需要column=[访问人数] -”按部门“,所以我们需要column=[部门] -基于table和columns,可能的cell values 是 = []。""", - "schema_links":"""["访问人数", "部门"]""", - "sql":"""select 部门, sum(访问人数) from 内容库产品 where 部门 group by 部门""" - }, - { - "table_name":"内容库产品", - "fields_list":"""["部门", "模块", "用户名", "访问次数", "访问人数", "访问时长"]""", - "question":"内容库编辑部、美术部的访问时长", - "analysis": """让我们一步一步地思考。在问题“内容库编辑部、美术部的访问时长“中,我们被问: -“访问时长”,所以我们需要column=[访问时长] -”内容库编辑部、美术部“,所以我们需要column=[部门] -基于table和columns,可能的cell values 是 = ['编辑部', '美术部']。""", - "schema_links":"""["访问时长", "部门", "'编辑部'", "'美术部'"]""", - "sql":"""select 部门, 访问时长 from 内容库产品 where 部门 in ('编辑部', '美术部')""" - }, - { - "table_name":"精选", - "fields_list":"""['归属系', '付费模式', '结算播放份额', '付费用户结算播放份额']""", - "question":"近3天飞天系结算播放份额", - "analysis": """让我们一步一步地思考。在问题“近3天飞天系结算播放份额“中,我们被问: -“结算播放份额”,所以我们需要column=[结算播放份额] -”飞天系“,所以我们需要column=[归属系] -基于table和columns,可能的cell values 是 = ['飞天系']。""", - "schema_links":"""["结算播放份额", "归属系", "'飞天系'"]""", - "sql":"""select 归属系, 结算播放份额 from 精选 where 归属系 in ('飞天系')""" - }, - { - "table_name":"歌曲库", - "fields_list":"""['歌曲ID', '歌曲MID', '歌曲名', '歌曲版本', '歌曲类型', '翻唱类型', '结算播放量', '运营播放量', '付费用户结算播放量', '历史累计结算播放量', '运营搜播量', '结算搜播量', '运营完播量', '运营推播量', '近7日复播率', '日均搜播量']""", - "question":"对比近3天翻唱版和纯音乐的歌曲播放量", - "analysis": """让我们一步一步地思考。在问题“对比近3天翻唱版和纯音乐的歌曲播放量“中,我们被问: -“歌曲播放量”,所以我们需要column=[结算播放量] -”翻唱版和纯音乐“,所以我们需要column=[歌曲类型] -基于table和columns,可能的cell values 是 = ['翻唱版', '纯音乐']。""", - "schema_links":"""["结算播放量", "歌曲类型", "'翻唱版'", "'纯音乐'"]""", - "sql":"""select 歌曲类型, 结算播放量 from 歌曲库 where 歌曲类型 in ('翻唱版', '纯音乐')""" - }, - { - "table_name":"艺人库", - "fields_list":"""['上下架状态', '歌手名', '歌手等级', '歌手类型', '歌手来源', '活跃区域', '年龄', '歌手才能', '歌手风格', '粉丝数', '在架歌曲数', '有播放量歌曲数']""", - "question":"对比一下流得滑、锅富程、章雪友的粉丝数", - "analysis": """让我们一步一步地思考。在问题“对比一下流得滑、锅富程、章雪友的粉丝数“中,我们被问: -“粉丝数”,所以我们需要column=[粉丝数] -”流得滑、锅富程、章雪友“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['流得滑', '锅富程', '章雪友']。""", - "schema_links":"""["粉丝数", "歌手名", "'流得滑'", "'锅富程'", "'章雪友'"]""", - "sql":"""select 歌手名, 粉丝数 from 艺人库 where 歌手名 in ('流得滑', '锅富程', '章雪友')""" - }, - { - "table_name":"歌曲库", - "fields_list":"""['歌曲ID', '歌曲MID', '歌曲名', '歌曲版本', '歌曲类型', '翻唱类型', '结算播放量', '运营播放量', '付费用户结算播放量', '历史累计结算播放量', '运营搜播量', '结算搜播量', '运营完播量', '运营推播量', '近7日复播率', '日均搜播量']""", - "question":"播放量大于1万的歌曲有多少", - "analysis": """让我们一步一步地思考。在问题“播放量大于1万的歌曲有多少“中,我们被问: -“歌曲有多少”,所以我们需要column=[歌曲名] -”播放量大于1万“,所以我们需要column=[结算播放量] -基于table和columns,可能的cell values 是 = [10000]。""", - "schema_links":"""["歌曲名", "结算播放量", 10000]""", - "sql":"""select 歌曲名 from 歌曲库 where 结算播放量 > 10000""" - }, - { - "table_name":"内容库产品", - "fields_list":"""['用户名', '部门', '模块', '访问时长', '访问次数', '访问人数']""", - "question":"内容库访问时长小于1小时,且来自美术部的用户是哪些", - "analysis": """让我们一步一步地思考。在问题“内容库访问时长小于1小时,且来自美术部的用户是哪些“中,我们被问: -“用户是哪些”,所以我们需要column=[用户名] -”美术部的“,所以我们需要column=[部门] -”访问时长小于1小时“,所以我们需要column=[访问时长] -基于table和columns,可能的cell values 是 = ['美术部', 1]。""", - "schema_links":"""["用户名", "部门", "访问时长", "'美术部'", 1]""", - "sql":"""select 用户名 from 内容库产品 where 部门 = '美术部' and 访问时长 < 1""" - }, - { - "table_name":"内容库产品", - "fields_list":"""['用户名', '部门', '模块', '访问次数', '访问人数', '访问时长']""", - "question":"内容库pv最高的用户有哪些", - "analysis": """让我们一步一步地思考。在问题“内容库pv最高的用户有哪些“中,我们被问: -“用户有哪些”,所以我们需要column=[用户名] -”pv最高的“,所以我们需要column=[访问次数] -基于table和columns,可能的cell values 是 = []。""", - "schema_links":"""["用户名", "访问次数"]""", - "sql":"""select 用户名 from 内容库产品 order by 访问次数 desc limit 10""" - }, - { - "table_name":"艺人库", - "fields_list":"""['歌手名', '歌手等级', '歌手类型', '歌手来源', '结算播放量', '运营播放量', '历史累计结算播放量', '有播放量歌曲数', '历史累计运营播放量', '付费用户结算播放量', '结算播放量占比', '运营播放份额', '完播量']""", - "question":"近90天袁呀味播放量平均值是多少", - "analysis": """让我们一步一步地思考。在问题“近90天袁呀味播放量平均值是多少“中,我们被问: -“播放量平均值是多少”,所以我们需要column=[结算播放量] -”袁呀味“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['袁呀味']。""", - "schema_links":"""["结算播放量", "歌手名", "'袁呀味'"]""", - "sql":"""select avg(结算播放量) from 艺人库 where 歌手名 = '袁呀味'""" - }, - { - "table_name":"艺人库", - "fields_list":"""['歌手名', '歌手等级', '歌手类型', '歌手来源', '结算播放量', '运营播放量', '历史累计结算播放量', '有播放量歌曲数', '历史累计运营播放量', '付费用户结算播放量', '结算播放量占比', '运营播放份额', '完播量']""", - "question":"周浅近7天结算播放量总和是多少", - "analysis": """让我们一步一步地思考。在问题“周浅近7天结算播放量总和是多少“中,我们被问: -“结算播放量总和是多少”,所以我们需要column=[结算播放量] -”周浅“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['周浅']。""", - "schema_links":"""["结算播放量", "歌手名", "'周浅'"]""", - "sql":"""select sum(结算播放量) from 艺人库 where 歌手名 = '周浅'""" - }, - { - "table_name":"内容库产品", - "fields_list":"""['部门', '模块', '用户名', '访问次数', '访问人数', '访问时长']""", - "question":"内容库访问次数大于1k的部门是哪些", - "analysis": """让我们一步一步地思考。在问题“内容库访问次数大于1k的部门是哪些“中,我们被问: -“部门是哪些”,所以我们需要column=[部门] -”访问次数大于1k的“,所以我们需要column=[访问次数] -基于table和columns,可能的cell values 是 = [1000]。""", - "schema_links":"""["部门", "访问次数", 1000]""", - "sql":"""select 部门 from 内容库产品 where 访问次数 > 1000""" - }, - { - "table_name":"歌曲库", - "fields_list":"""['歌曲ID', '歌曲MID', '歌曲名', '歌曲版本', '歌曲类型', '翻唱类型', '结算播放量', '运营播放量', '付费用户结算播放量', '历史累计结算播放量', '运营搜播量', '结算搜播量', '运营完播量', '运营推播量', '近7日复播率', '日均搜播量']""", - "question":"陈易迅唱的所有的播放量大于20k的雇佣者有哪些", - "analysis": """让我们一步一步地思考。在问题“陈易迅唱的所有的播放量大于20k的雇佣者有哪些“中,我们被问: -“雇佣者有哪些”,所以我们需要column=[歌曲名] -”播放量大于20k的“,所以我们需要column=[结算播放量] -”陈易迅唱的“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = [20000, '陈易迅']。""", - "schema_links":"""["歌曲名", "结算播放量", "歌手名", 20000, "'陈易迅'"]""", - "sql":"""select 歌曲名 from 歌曲库 where 结算播放量 > 20000 and 歌手名 = '陈易迅'""" - } -] \ No newline at end of file diff --git a/chat/core/src/main/resources/mapper/ChatConfigMapper.xml b/chat/core/src/main/resources/mapper/ChatConfigMapper.xml index 64e43a3c6..55eb670a4 100644 --- a/chat/core/src/main/resources/mapper/ChatConfigMapper.xml +++ b/chat/core/src/main/resources/mapper/ChatConfigMapper.xml @@ -3,14 +3,15 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + + type="com.tencent.supersonic.chat.persistence.dataobject.ChatConfigDO"> + @@ -19,15 +20,15 @@ insert into s2_chat_config ( - domain_id, `chat_detail_config`, chat_agg_config, status, created_by, updated_by, created_at, updated_at + domain_id, `chat_detail_config`, chat_agg_config, recommended_questions, status, created_by, updated_by, created_at, updated_at ) values ( - #{domainId}, #{chatDetailConfig}, #{chatAggConfig}, #{status}, #{createdBy}, #{updatedBy}, #{createdAt}, #{updatedAt} + #{domainId}, #{chatDetailConfig}, #{chatAggConfig}, #{recommendedQuestions}, #{status}, #{createdBy}, #{updatedBy}, #{createdAt}, #{updatedAt} ) @@ -42,6 +43,9 @@ chat_agg_config = #{chatAggConfig} , + + recommended_questions = #{recommendedQuestions} , + status = #{status} , diff --git a/chat/core/src/main/resources/mapper/ChatContextMapper.xml b/chat/core/src/main/resources/mapper/ChatContextMapper.xml index 1c3291d5e..2a8834627 100644 --- a/chat/core/src/main/resources/mapper/ChatContextMapper.xml +++ b/chat/core/src/main/resources/mapper/ChatContextMapper.xml @@ -3,10 +3,10 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + + type="com.tencent.supersonic.chat.persistence.dataobject.ChatContextDO"> @@ -20,7 +20,7 @@ from s2_chat_context where chat_id=#{chatId} limit 1 - + insert into s2_chat_context (chat_id,user,query_text,semantic_parse) values (#{chatId}, #{user},#{queryText}, #{semanticParse}) diff --git a/chat/core/src/main/resources/mapper/ChatMapper.xml b/chat/core/src/main/resources/mapper/ChatMapper.xml index b2f737d72..bda458423 100644 --- a/chat/core/src/main/resources/mapper/ChatMapper.xml +++ b/chat/core/src/main/resources/mapper/ChatMapper.xml @@ -3,9 +3,9 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + - + @@ -45,7 +45,7 @@ where chat_id = #{chatId} - + insert into s2_chat (chat_name, create_time, last_time, creator, last_question, is_delete, is_top) values (#{chatName}, #{createTime}, #{lastTime}, #{creator}, #{lastQuestion}, #{isDelete}, #{isTop}) @@ -59,7 +59,7 @@ - + @@ -83,14 +83,14 @@ - + update s2_chat_query set score=#{score}, feedback=#{feedback} where question_id = #{id} - insert into s2_chat_query (question_id, create_time, user_name, question, query_result, time, state, data_content, name, query_type, diff --git a/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml b/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml index 3d2501968..3c0b5bf81 100644 --- a/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml +++ b/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml @@ -1,7 +1,7 @@ - - + + @@ -10,9 +10,9 @@ - + - + @@ -49,7 +49,7 @@ query_text, query_response - select distinct @@ -65,7 +65,7 @@ order by ${orderByClause} - select distinct @@ -94,17 +94,17 @@ delete from s2_chat_query where question_id = #{questionId,jdbcType=BIGINT} - + insert into s2_chat_query (question_id, create_time, user_name, query_state, chat_id, score, feedback, query_text, query_response ) values (#{questionId,jdbcType=BIGINT}, #{createTime,jdbcType=TIMESTAMP}, #{userName,jdbcType=VARCHAR}, #{queryState,jdbcType=INTEGER}, #{chatId,jdbcType=BIGINT}, #{score,jdbcType=INTEGER}, - #{feedback,jdbcType=VARCHAR}, #{queryText,jdbcType=LONGVARCHAR}, #{queryResponse,jdbcType=LONGVARCHAR} + #{feedback,jdbcType=VARCHAR}, #{queryText,jdbcType=LONGVARCHAR}, #{queryResult,jdbcType=LONGVARCHAR} ) - + insert into s2_chat_query @@ -131,7 +131,7 @@ query_text, - + query_response, @@ -160,18 +160,18 @@ #{queryText,jdbcType=LONGVARCHAR}, - - #{queryResponse,jdbcType=LONGVARCHAR}, + + #{queryResult,jdbcType=LONGVARCHAR}, - select count(*) from s2_chat_query - + update s2_chat_query @@ -195,13 +195,13 @@ query_text = #{queryText,jdbcType=LONGVARCHAR}, - - query_response = #{queryResponse,jdbcType=LONGVARCHAR}, + + query_response = #{queryResult,jdbcType=LONGVARCHAR}, where question_id = #{questionId,jdbcType=BIGINT} - + update s2_chat_query set create_time = #{createTime,jdbcType=TIMESTAMP}, user_name = #{userName,jdbcType=VARCHAR}, @@ -210,10 +210,10 @@ score = #{score,jdbcType=INTEGER}, feedback = #{feedback,jdbcType=VARCHAR}, query_text = #{queryText,jdbcType=LONGVARCHAR}, - query_response = #{queryResponse,jdbcType=LONGVARCHAR} + query_response = #{queryResult,jdbcType=LONGVARCHAR} where question_id = #{questionId,jdbcType=BIGINT} - + update s2_chat_query set create_time = #{createTime,jdbcType=TIMESTAMP}, user_name = #{userName,jdbcType=VARCHAR}, diff --git a/chat/core/src/main/resources/mapper/PluginDOMapper.xml b/chat/core/src/main/resources/mapper/PluginDOMapper.xml new file mode 100644 index 000000000..0fe6e3f5e --- /dev/null +++ b/chat/core/src/main/resources/mapper/PluginDOMapper.xml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + id, type, domain, pattern, parse_mode, name, created_at, created_by, updated_at, + updated_by + + + config + + + + + + delete from s2_plugin + where id = #{id,jdbcType=BIGINT} + + + insert into s2_plugin (id, type, domain, + pattern, parse_mode, name, + created_at, created_by, updated_at, + updated_by, config) + values (#{id,jdbcType=BIGINT}, #{type,jdbcType=VARCHAR}, #{domain,jdbcType=VARCHAR}, + #{pattern,jdbcType=VARCHAR}, #{parseMode,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, + #{createdAt,jdbcType=TIMESTAMP}, #{createdBy,jdbcType=VARCHAR}, #{updatedAt,jdbcType=TIMESTAMP}, + #{updatedBy,jdbcType=VARCHAR}, #{config,jdbcType=LONGVARCHAR}) + + + insert into s2_plugin + + + id, + + + type, + + + domain, + + + pattern, + + + parse_mode, + + + name, + + + created_at, + + + created_by, + + + updated_at, + + + updated_by, + + + config, + + + + + #{id,jdbcType=BIGINT}, + + + #{type,jdbcType=VARCHAR}, + + + #{domain,jdbcType=VARCHAR}, + + + #{pattern,jdbcType=VARCHAR}, + + + #{parseMode,jdbcType=VARCHAR}, + + + #{name,jdbcType=VARCHAR}, + + + #{createdAt,jdbcType=TIMESTAMP}, + + + #{createdBy,jdbcType=VARCHAR}, + + + #{updatedAt,jdbcType=TIMESTAMP}, + + + #{updatedBy,jdbcType=VARCHAR}, + + + #{config,jdbcType=LONGVARCHAR}, + + + + + + update s2_plugin + + + type = #{type,jdbcType=VARCHAR}, + + + domain = #{domain,jdbcType=VARCHAR}, + + + pattern = #{pattern,jdbcType=VARCHAR}, + + + parse_mode = #{parseMode,jdbcType=VARCHAR}, + + + name = #{name,jdbcType=VARCHAR}, + + + created_at = #{createdAt,jdbcType=TIMESTAMP}, + + + created_by = #{createdBy,jdbcType=VARCHAR}, + + + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + + + updated_by = #{updatedBy,jdbcType=VARCHAR}, + + + config = #{config,jdbcType=LONGVARCHAR}, + + + where id = #{id,jdbcType=BIGINT} + + + update s2_plugin + set type = #{type,jdbcType=VARCHAR}, + domain = #{domain,jdbcType=VARCHAR}, + pattern = #{pattern,jdbcType=VARCHAR}, + parse_mode = #{parseMode,jdbcType=VARCHAR}, + name = #{name,jdbcType=VARCHAR}, + created_at = #{createdAt,jdbcType=TIMESTAMP}, + created_by = #{createdBy,jdbcType=VARCHAR}, + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + updated_by = #{updatedBy,jdbcType=VARCHAR}, + config = #{config,jdbcType=LONGVARCHAR} + where id = #{id,jdbcType=BIGINT} + + + update s2_plugin + set type = #{type,jdbcType=VARCHAR}, + domain = #{domain,jdbcType=VARCHAR}, + pattern = #{pattern,jdbcType=VARCHAR}, + parse_mode = #{parseMode,jdbcType=VARCHAR}, + name = #{name,jdbcType=VARCHAR}, + created_at = #{createdAt,jdbcType=TIMESTAMP}, + created_by = #{createdBy,jdbcType=VARCHAR}, + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + updated_by = #{updatedBy,jdbcType=VARCHAR} + where id = #{id,jdbcType=BIGINT} + + \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapperTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapperTest.java deleted file mode 100644 index 217cb9582..000000000 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapperTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.tencent.supersonic.chat.application.mapper; - -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.test.context.ContextTest; -import org.junit.jupiter.api.Test; - -/** - * HanlpSchemaMapperTest - */ -class HanlpSchemaMapperTest extends ContextTest { - - @Test - void map() { - QueryContextReq queryContext = new QueryContextReq(); - queryContext.setChatId(1); - queryContext.setDomainId(2); - queryContext.setQueryText("supersonic按部门访问次数"); - HanlpSchemaMapper hanlpSchemaMapper = new HanlpSchemaMapper(); - hanlpSchemaMapper.map(queryContext); - } -} \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParserTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeRangeParserTest.java similarity index 54% rename from chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParserTest.java rename to chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeRangeParserTest.java index 14b67ec23..23d916e33 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParserTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeRangeParserTest.java @@ -1,19 +1,21 @@ package com.tencent.supersonic.chat.application.parser; import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.QueryContext; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.parser.rule.TimeRangeParser; import org.junit.jupiter.api.Test; -class TimeSemanticParserTest { +class TimeRangeParserTest { // private HeuristicQuerySelector voteStrategy = new HeuristicQuerySelector() { // @Override // public void init(List semanticParsers) { -// List queryMode = new ArrayList<>(Arrays.asList(EntityDetail.QUERY_MODE)); +// List queryMode = new ArrayList<>(Arrays.asList(EntityDetailQuery.QUERY_MODE)); // for(SemanticParser semanticParser : semanticParsers) { -// if(semanticParser.getName().equals(TimeSemanticParser.PARSER_MODE)) { +// if(semanticParser.getName().equals(TimeRangeParser.PARSER_MODE)) { // semanticParser.getQueryModes().clear(); // semanticParser.getQueryModes().addAll(queryMode); // } @@ -23,17 +25,17 @@ class TimeSemanticParserTest { @Test void parse() { - TimeSemanticParser timeSemanticParser = new TimeSemanticParser(); + TimeRangeParser timeRangeParser = new TimeRangeParser(); - QueryContextReq queryContext = new QueryContextReq(); + QueryRequest queryRequest = new QueryRequest(); ChatContext chatCtx = new ChatContext(); SchemaMapInfo schemaMap = new SchemaMapInfo(); - queryContext.setQueryText("supersonic最近30天访问次数"); - //voteStrategy.init(new ArrayList<>(Arrays.asList(timeSemanticParser))); - timeSemanticParser.parse(queryContext, chatCtx); + queryRequest.setQueryText("supersonic最近30天访问次数"); + //voteStrategy.init(new ArrayList<>(Arrays.asList(timeRangeParser))); + timeRangeParser.parse(new QueryContext(queryRequest), chatCtx); - //DateConf dateInfo = queryContext.getParseInfo(timeSemanticParser.getQueryModes().get(0)) + //DateConf dateInfo = queryContext.getParseInfo(timeRangeParser.getQueryModes().get(0)) // .getDateInfo(); //System.out.println(dateInfo); diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateSemanticParserTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateTypeParserTest.java similarity index 85% rename from chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateSemanticParserTest.java rename to chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateTypeParserTest.java index cc996969f..2677ef2e8 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateSemanticParserTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateTypeParserTest.java @@ -2,15 +2,15 @@ package com.tencent.supersonic.chat.application.parser.aggregate; import static org.junit.Assert.assertEquals; -import com.tencent.supersonic.chat.application.parser.AggregateSemanticParser; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; +import com.tencent.supersonic.chat.parser.rule.AggregateTypeParser; +import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; import org.junit.jupiter.api.Test; -class AggregateSemanticParserTest { +class AggregateTypeParserTest { @Test void getAggregateParser() { - AggregateSemanticParser aggregateParser = new AggregateSemanticParser(); + AggregateTypeParser aggregateParser = new AggregateTypeParser(); AggregateTypeEnum aggregateType = aggregateParser.resolveAggregateType("supsersonic产品访问次数最大值"); assertEquals(aggregateType, AggregateTypeEnum.MAX); diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/HanlpDictMapperTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/HanlpDictMapperTest.java new file mode 100644 index 000000000..470215470 --- /dev/null +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/HanlpDictMapperTest.java @@ -0,0 +1,22 @@ +package com.tencent.supersonic.chat.mapper; + +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.test.context.ContextTest; +import org.junit.jupiter.api.Test; + +/** + * HanlpDictMapperTest + */ +class HanlpDictMapperTest extends ContextTest { + + @Test + void map() { + QueryRequest queryRequest = new QueryRequest(); + queryRequest.setChatId(1); + queryRequest.setDomainId(2L); + queryRequest.setQueryText("supersonic按部门访问次数"); + HanlpDictMapper hanlpDictMapper = new HanlpDictMapper(); + hanlpDictMapper.map(new QueryContext(queryRequest)); + } +} \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/application/mapper/match/QueryMatchStrategyTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/match/QueryMatchStrategyTest.java similarity index 80% rename from chat/core/src/test/java/com/tencent/supersonic/chat/application/mapper/match/QueryMatchStrategyTest.java rename to chat/core/src/test/java/com/tencent/supersonic/chat/mapper/match/QueryMatchStrategyTest.java index 7a8856b47..c32ee810b 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/application/mapper/match/QueryMatchStrategyTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/match/QueryMatchStrategyTest.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.application.mapper.match; +package com.tencent.supersonic.chat.mapper.match; import com.tencent.supersonic.chat.test.context.ContextTest; import org.junit.jupiter.api.Test; diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java index 5ca6ebceb..c1d81d250 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java @@ -1,16 +1,15 @@ package com.tencent.supersonic.chat.test.context; -import com.tencent.supersonic.chat.domain.utils.ComponentFactory; -import com.tencent.supersonic.chat.infrastructure.mapper.ChatContextMapper; -import com.tencent.supersonic.chat.infrastructure.repository.ChatContextRepositoryImpl; -import com.tencent.supersonic.chat.infrastructure.semantic.RemoteSemanticLayerImpl; +import com.tencent.supersonic.chat.persistence.repository.impl.ChatContextRepositoryImpl; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.chat.persistence.mapper.ChatContextMapper; +import com.tencent.supersonic.knowledge.semantic.RemoteSemanticLayer; import com.tencent.supersonic.chat.test.ChatBizLauncher; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; -import com.tencent.supersonic.semantic.query.domain.QueryService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.query.service.QueryService; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.test.context.SpringBootTest; @@ -25,7 +24,7 @@ import org.springframework.web.client.RestTemplate; @MockBean(DomainService.class) @MockBean(ChatContextMapper.class) @MockBean(RestTemplate.class) -@MockBean(RemoteSemanticLayerImpl.class) +@MockBean(RemoteSemanticLayer.class) @MockBean(ComponentFactory.class) //@MybatisTest //@AutoConfigureMybatis diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/MockBeansConfiguration.java b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/MockBeansConfiguration.java index 81b75e7be..e79eaf500 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/MockBeansConfiguration.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/MockBeansConfiguration.java @@ -6,28 +6,21 @@ import static org.mockito.Mockito.when; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.domain.service.QueryService; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.chat.application.ConfigServiceImpl; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigResp; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichResp; -import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric; -import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetricInfo; -import com.tencent.supersonic.chat.domain.pojo.config.EntityInternalDetail; -import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; -import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.chat.domain.service.ChatService; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.chat.infrastructure.mapper.ChatContextMapper; -import com.tencent.supersonic.chat.infrastructure.repository.ChatContextRepositoryImpl; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; +import com.tencent.supersonic.chat.config.*; +import com.tencent.supersonic.chat.persistence.repository.impl.ChatContextRepositoryImpl; +import com.tencent.supersonic.chat.service.QueryService; +import com.tencent.supersonic.semantic.api.model.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; +import com.tencent.supersonic.chat.service.impl.ConfigServiceImpl; +import com.tencent.supersonic.chat.service.ChatService; +import com.tencent.supersonic.chat.persistence.mapper.ChatContextMapper; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -47,7 +40,7 @@ public class MockBeansConfiguration { public static void buildHttpSemanticServiceImpl(SemanticLayer httpSemanticLayer, List dimensionDescs, List metricDescs) { - ChatConfigRichResp chaConfigRichDesc = new ChatConfigRichResp(); + ChatConfigRich chaConfigRichDesc = new ChatConfigRich(); DefaultMetric defaultMetricDesc = new DefaultMetric(); defaultMetricDesc.setUnit(3); defaultMetricDesc.setPeriod(Constants.DAY); @@ -79,10 +72,6 @@ public class MockBeansConfiguration { domainSchemaDesc.setDimensions(dimensionDescs); domainSchemaDesc.setMetrics(metricDescs); // when(httpSemanticLayer.getDomainSchemaInfo(anyLong())).thenReturn(domainSchemaDesc); - - DomainInfos domainInfos = new DomainInfos(); - when(SchemaInfoConverter.convert(httpSemanticLayer.getDomainSchemaInfo(anyList()))).thenReturn(domainInfos); - } public static void getDomainExtendMock(ConfigServiceImpl configService) { @@ -125,10 +114,6 @@ public class MockBeansConfiguration { public ChatContextRepositoryImpl getChatContextRepository() { return Mockito.mock(ChatContextRepositoryImpl.class); } -// @Bean -// public SemanticLayer getSemanticService() { -// return Mockito.mock(HttpSemanticServiceImpl.class); -// } @Bean public QueryService getQueryService() { diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/QueryServiceImplTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/QueryServiceImplTest.java deleted file mode 100644 index 9506aa6f4..000000000 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/QueryServiceImplTest.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.tencent.supersonic.chat.test.context; - -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper; -import com.tencent.supersonic.chat.application.mapper.QueryMatchStrategy; -import com.tencent.supersonic.chat.application.parser.DomainSemanticParser; -import com.tencent.supersonic.chat.domain.service.ChatService; -import com.tencent.supersonic.chat.test.ChatBizLauncher; -import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Bean; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = ChatBizLauncher.class) -public class QueryServiceImplTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(QueryServiceImplTest.class); - -// @MockBean -// private QueryService queryService; - - //private SemanticLayer semanticLayer = mock(SemanticLayer.class); - -// @MockBean -// private DefaultSemanticLayerImpl semanticLayer; - //SemanticLayer - @Autowired - public QueryMatchStrategy queryMatchStrategy; - @Autowired(required = false) - public Suggester suggester; - @MockBean - private SemanticLayer semanticLayer;//= ComponentFactory.getSemanticLayer(); - -// @Before -// public void setUp() { -// //List getDomainSchemaInfo(List ids) -// List domainSchemaRespList=MockUtils.getChatContext(); -// Mockito.when(semanticLayer.getDomainSchemaInfo(Mockito.anyList())).thenReturn(domainSchemaRespList); -// } - @MockBean - private DomainSemanticParser domainSemanticParser; - @MockBean - private HanlpSchemaMapper hanlpSchemaMapper; - @MockBean - private ChatService chatService; - -//// @Autowired(required = false) -//// private ChatService chatService; - - //private SemanticLayer semanticLayer ; - - @Test - public void test() throws Exception { - QueryContextReq queryContextReq = getQueryContextReq("超音数访问次数"); - //hanlpSchemaMapper.map(queryContextReq); -// List terms = HanlpHelper.getSegment().seg(queryContextReq.getQueryText().toLowerCase()).stream() -// .collect(Collectors.toList()); -// LOGGER.info("terms::::{}",terms); -// MockUtils.putSuggester(); -// List matches = queryMatchStrategy.match(queryContextReq.getQueryText(), terms, queryContextReq.getDomainId()); -// HanlpHelper.transLetterOriginal(matches); -// HanlpSchemaMapperHelper.convertTermsToSchemaMapInfo(matches, queryContextReq.getMapInfo()); - HanlpSchemaMapper hanlpSchemaMapper = new HanlpSchemaMapper(); - hanlpSchemaMapper.map(queryContextReq); - //QueryContextReq queryContextReq=MockUtils.getQueryContextReq("METRIC_FILTER"); - LOGGER.info("QueryContextReq::::{}", queryContextReq.getMapInfo().getMatchedDomains()); - LOGGER.info("QueryContextReq::::{}", queryContextReq.getMapInfo().getDomainElementMatches()); - LOGGER.info("QueryContextReq::::{}", queryContextReq); - -// //chatService=new ChatServiceImpl(); -// ChatContext chatCtx = chatService.getOrCreateContext(queryContextReq.getChatId()); -// if (chatCtx == null) { -// chatCtx=new ChatContext(); -// chatCtx.setChatId(queryContextReq.getChatId()); -// } -// LOGGER.info("chatService::::{}",chatService); -// LOGGER.info("ChatContext::::{}",chatCtx); - ChatContext chatCtx = new ChatContext();//MockUtils.getChatContext1(); - //semanticLayer = ComponentFactory.getSemanticLayer(); -// DomainSemanticParser domainSemanticParser=new DomainSemanticParser(); -// domainSemanticParser.parse(queryContextReq,chatCtx); - - //DomainSemanticParser - - //domainSemanticParser=new DomainSemanticParser(); - LOGGER.info("domainSemanticParser::::{}", domainSemanticParser); - //SemanticLayer semanticLayer= mock(SemanticLayer.class); - //List domainSchemaRespList=MockUtils.getChatContext(); - -// //SemanticLayer semanticLayer = mock(SemanticLayer.class); -// when(semanticLayer.getDomainSchemaInfo(Mockito.anyList())).thenReturn(domainSchemaRespList); -// domainSemanticParser.parse(queryContextReq,chatCtx); -// LOGGER.info("QueryContextReq::::{}",queryContextReq); -// TimeSemanticParser timeSemanticParser=new TimeSemanticParser(); -// timeSemanticParser.parse(queryContextReq,chatCtx); -// AggregateSemanticParser aggregateSemanticParser=new AggregateSemanticParser(); -// aggregateSemanticParser.parse(queryContextReq,chatCtx); -// //PickStrategy pickStrategy = ComponentFactory.getPickStrategy(); -// LOGGER.info("pickStrategy::::{}",pickStrategy); -// pickStrategy=new ScoreBasedPickStrategy(); -// SemanticParseInfo semanticParse = pickStrategy.pick(queryContextReq, chatCtx); -// LOGGER.info("semanticParse::::{}",semanticParse); - //SemanticQueryExecutorHelper semanticQueryExecutorHelper=new SemanticQueryExecutorHelper(); - //semanticQueryExecutorHelper.execute(queryContextReq.getParseInfo(),queryContextReq.getUser()); -// LOGGER.info("queryContextReq::::{}",queryContextReq.getMapInfo().getMatchedDomains()); -// LOGGER.info("queryContextReq::::{}",queryContextReq.getMapInfo().getDomainElementMatches()); -// LOGGER.info("queryContextReq::::{}",queryContextReq.getCandidateParseInfos()); -// LOGGER.info("queryContextReq::::{}",queryContextReq.getDomainId()); - -// List queryExecutors = ComponentFactory.getQueryExecutors(); -// QueryResultResp queryResponse=new QueryResultResp(); -// for (QueryExecutor executor : queryExecutors) { -// queryResponse = executor.execute(semanticParse, queryContextReq.getUser()); -// if (queryResponse != null) { -// // update chat context after a successful semantic query -// if (queryContextReq.isSaveAnswer() && queryResponse.getQueryState() == QueryState.NORMAL.getState()) { -// chatService.updateContext(chatCtx, queryContextReq, semanticParse); -// } -// queryResponse.setChatContext(chatCtx.getParseInfo()); -// chatService.addQuery(queryResponse, queryContextReq, chatCtx); -// break; -// } -// } - - //assertThat(found.getName()).isEqualTo(name); - } - - public QueryContextReq getQueryContextReq(String query) { - QueryContextReq queryContextReq = new QueryContextReq(); - queryContextReq.setQueryText(query);//"alice的访问次数" - queryContextReq.setChatId(1); - queryContextReq.setUser(new User(1L, "admin", "admin", "admin@email")); - return queryContextReq; - } - - @TestConfiguration - static class EmployeeServiceImplTestContextConfiguration { - - @Bean - public QueryMatchStrategy queryMatchStrategyService() { - return new QueryMatchStrategy(); - } -// @Bean -// public SemanticLayer querySemanticLayer() { -// return new DefaultSemanticLayerImpl(); -// } - //@Bean - //public DomainSemanticParser queryDomainSemanticParser() { - // return new DomainSemanticParser(); - //} - -// @Bean -// public RestTemplate getRestTemplate(){ -// return new RestTemplate(); -// } -// -// @Bean -// public DefaultSemanticInternalUtils getUtils(){ -// return new DefaultSemanticInternalUtils(); -// } - - } -} diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/SemanticParseObjectHelper.java b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/SemanticParseObjectHelper.java index ad0e0b887..16fad98df 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/SemanticParseObjectHelper.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/SemanticParseObjectHelper.java @@ -1,12 +1,13 @@ package com.tencent.supersonic.chat.test.context; import com.google.gson.Gson; -import com.tencent.supersonic.chat.api.pojo.Filter; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; +import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; + import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; @@ -31,9 +32,9 @@ public class SemanticParseObjectHelper { private static SemanticParseInfo getSemanticParseInfo(SemanticParseJson semanticParseJson) { Long domain = semanticParseJson.getDomain(); - Set dimensionList = new LinkedHashSet(); - Set metricList = new LinkedHashSet(); - Set chatFilters = new LinkedHashSet(); + Set dimensionList = new LinkedHashSet(); + Set metricList = new LinkedHashSet(); + Set chatFilters = new LinkedHashSet(); if (semanticParseJson.getFilter() != null && semanticParseJson.getFilter().size() > 0) { for (List filter : semanticParseJson.getFilter()) { @@ -52,7 +53,6 @@ public class SemanticParseObjectHelper { semanticParseInfo.setDimensionFilters(chatFilters); semanticParseInfo.setAggType(semanticParseJson.getAggregateType()); - semanticParseInfo.setDomainId(domain); semanticParseInfo.setQueryMode(semanticParseJson.getQueryMode()); semanticParseInfo.setMetrics(metricList); semanticParseInfo.setDimensions(dimensionList); @@ -72,9 +72,9 @@ public class SemanticParseObjectHelper { return null; } - private static Filter getChatFilter(List filters) { + private static QueryFilter getChatFilter(List filters) { if (filters.size() > 1) { - Filter chatFilter = new Filter(); + QueryFilter chatFilter = new QueryFilter(); chatFilter.setBizName(filters.get(1)); chatFilter.setOperator(FilterOperatorEnum.getSqlOperator(filters.get(2))); @@ -91,18 +91,15 @@ public class SemanticParseObjectHelper { return null; } - - private static SchemaItem getMetric(String bizName, Long domainId) { - SchemaItem metric = new SchemaItem(); + private static SchemaElement getMetric(String bizName, Long domainId) { + SchemaElement metric = new SchemaElement(); metric.setBizName(bizName); - //metric.set(domainId); return metric; } - private static SchemaItem getDimension(String bizName, Long domainId) { - SchemaItem dimension = new SchemaItem(); + private static SchemaElement getDimension(String bizName, Long domainId) { + SchemaElement dimension = new SchemaElement(); dimension.setBizName(bizName); - //dimension.setDomainId(domainId); return dimension; } diff --git a/chat/knowledge/pom.xml b/chat/knowledge/pom.xml index f6b39bbc8..5fed94b0e 100644 --- a/chat/knowledge/pom.xml +++ b/chat/knowledge/pom.xml @@ -102,6 +102,16 @@ auth-api ${project.version} + + com.tencent.supersonic + chat-api + ${project.version} + + + com.tencent.supersonic + semantic-query + ${project.version} + diff --git a/chat/knowledge/src/main/java/com/hankcs/hanlp/collection/trie/bintrie/BaseNode.java b/chat/knowledge/src/main/java/com/hankcs/hanlp/collection/trie/bintrie/BaseNode.java index ec978fe09..2f1a01f93 100644 --- a/chat/knowledge/src/main/java/com/hankcs/hanlp/collection/trie/bintrie/BaseNode.java +++ b/chat/knowledge/src/main/java/com/hankcs/hanlp/collection/trie/bintrie/BaseNode.java @@ -36,7 +36,7 @@ public abstract class BaseNode implements Comparable { */ protected V value; - public String prefix = null; + protected String prefix = null; public BaseNode transition(String path, int begin) { BaseNode cur = this; diff --git a/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/common/Term.java b/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/common/Term.java index 50332957c..fa52780f6 100644 --- a/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/common/Term.java +++ b/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/common/Term.java @@ -3,7 +3,7 @@ package com.hankcs.hanlp.seg.common; import com.hankcs.hanlp.corpus.tag.Nature; import com.hankcs.hanlp.dictionary.CoreDictionary; import com.hankcs.hanlp.dictionary.CustomDictionary; -import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; +import com.tencent.supersonic.knowledge.utils.HanlpHelper; import lombok.Data; import lombok.ToString; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/ApplicationStartedInit.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/ApplicationStartedInit.java new file mode 100644 index 000000000..5deb2dda1 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/ApplicationStartedInit.java @@ -0,0 +1,69 @@ +package com.tencent.supersonic.knowledge; + +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.service.SchemaService; +import com.tencent.supersonic.knowledge.service.KnowledgeService; +import com.tencent.supersonic.knowledge.service.WordService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +public class ApplicationStartedInit implements ApplicationListener { + + @Autowired + private KnowledgeService knowledgeService; + @Autowired + private WordService wordService; + @Autowired + private SchemaService schemaService; + + @Override + public void onApplicationEvent(ApplicationStartedEvent event) { + try { + log.debug("ApplicationStartedInit start"); + + List dictWords = wordService.getAllDictWords(); + wordService.setPreDictWords(dictWords); + knowledgeService.reloadAllData(dictWords); + + log.debug("ApplicationStartedInit end"); + } catch (Exception e) { + log.error("ApplicationStartedInit error", e); + } + } + + /*** + * reload knowledge task + */ + @Scheduled(cron = "${reload.knowledge.corn:0 0/1 * * * ?}") + public void reloadKnowledge() { + log.debug("reloadKnowledge start"); + + try { + List dictWords = wordService.getAllDictWords(); + List preDictWords = wordService.getPreDictWords(); + + if (CollectionUtils.isEqualCollection(dictWords, preDictWords)) { + log.debug("dictWords has not changed, reloadKnowledge end"); + return; + } + log.info("dictWords has changed"); + wordService.setPreDictWords(dictWords); + knowledgeService.updateOnlineKnowledge(wordService.getAllDictWords()); + schemaService.getCache().refresh(SchemaService.ALL_CACHE); + + } catch (Exception e) { + log.error("reloadKnowledge error", e); + } + + log.debug("reloadKnowledge end"); + } +} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/BaseWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/BaseWordNature.java deleted file mode 100644 index fe5de093c..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/BaseWordNature.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import java.util.ArrayList; -import java.util.List; -import lombok.extern.slf4j.Slf4j; - -/** - * base word nature - */ -@Slf4j -public abstract class BaseWordNature { - - /** - * 获取所有wordNature - * - * @param itemDOS - * @return - */ - public List getWordNatureList(List itemDOS) { - List wordNatures = new ArrayList<>(); - try { - wordNatures = getWordNaturesWithException(itemDOS); - } catch (Exception e) { - log.error("getWordNatureList error,", e); - } - return wordNatures; - } - - public List getWordNaturesWithException(List itemDOS) { - - List wordNatures = new ArrayList<>(); - - for (ItemDO itemDO : itemDOS) { - wordNatures.addAll(getWordNature(itemDO.getName(), itemDO)); - } - return wordNatures; - } - - public abstract List getWordNature(String word, ItemDO itemDO); - - public Integer getElementID(String nature) { - String[] split = nature.split(NatureType.NATURE_SPILT); - if (split.length >= 3) { - return Integer.valueOf(split[2]); - } - return 0; - } - -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DimensionWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DimensionWordNature.java deleted file mode 100644 index 7c5bae307..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DimensionWordNature.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - -import com.google.common.collect.Lists; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import java.util.List; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -/** - * dimension word nature - */ -@Service -public class DimensionWordNature extends BaseWordNature { - - @Value("${nlp.dimension.use.suffix:true}") - private boolean nlpDimensionUseSuffix = true; - - - @Override - public List getWordNature(String word, ItemDO itemDO) { - List result = Lists.newArrayList(); - result.add(getOnwWordNature(word, itemDO, false)); - if (nlpDimensionUseSuffix) { - String reverseWord = StringUtils.reverse(word); - if (StringUtils.isNotEmpty(word) && !word.equalsIgnoreCase(reverseWord)) { - result.add(getOnwWordNature(reverseWord, itemDO, true)); - } - } - return result; - } - - private WordNature getOnwWordNature(String word, ItemDO itemDO, boolean isSuffix) { - WordNature wordNature = new WordNature(); - wordNature.setWord(word); - Integer domainId = itemDO.getDomain(); - String nature = NatureType.NATURE_SPILT + domainId + NatureType.NATURE_SPILT + itemDO.getItemId() - + NatureType.DIMENSION.getType(); - if (isSuffix) { - nature = NatureType.NATURE_SPILT + domainId + NatureType.NATURE_SPILT + itemDO.getItemId() - + NatureType.SUFFIX.getType() + NatureType.DIMENSION.getType(); - } - wordNature.setNatureWithFrequency(String.format("%s 100000", nature)); - return wordNature; - } - -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DomainWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DomainWordNature.java deleted file mode 100644 index d76234985..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DomainWordNature.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - -import com.google.common.collect.Lists; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -/** - * domain word nature - */ -@Service -@Slf4j -public class DomainWordNature extends BaseWordNature { - - @Override - public List getWordNature(String word, ItemDO itemDO) { - List result = Lists.newArrayList(); - WordNature wordNature = new WordNature(); - wordNature.setWord(word); - Integer domainId = itemDO.getDomain(); - String nature = NatureType.NATURE_SPILT + domainId; - wordNature.setNatureWithFrequency(String.format("%s 100000", nature)); - result.add(wordNature); - return result; - } - -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/EntityWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/EntityWordNature.java deleted file mode 100644 index 5682b67cc..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/EntityWordNature.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - -import com.google.common.collect.Lists; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -/** - * dimension value wordNature - */ -@Service -@Slf4j -public class EntityWordNature extends BaseWordNature { - - @Override - public List getWordNature(String word, ItemDO itemDO) { - List result = Lists.newArrayList(); - WordNature wordNature = new WordNature(); - wordNature.setWord(word); - Integer domain = itemDO.getDomain(); - String nature = NatureType.NATURE_SPILT + domain + NatureType.NATURE_SPILT + itemDO.getItemId() - + NatureType.ENTITY.getType(); - wordNature.setNatureWithFrequency(String.format("%s 200000", nature)); - result.add(wordNature); - return result; - } - -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/MetricWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/MetricWordNature.java deleted file mode 100644 index 34bae35b9..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/MetricWordNature.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - -import com.google.common.collect.Lists; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import java.util.List; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -/** - * Metric WordNature - */ -@Service -public class MetricWordNature extends BaseWordNature { - - @Value("${nlp.metric.use.suffix:true}") - private boolean nlpMetricUseSuffix = true; - - @Override - public List getWordNature(String word, ItemDO itemDO) { - List result = Lists.newArrayList(); - result.add(getOnwWordNature(word, itemDO, false)); - if (nlpMetricUseSuffix) { - String reverseWord = StringUtils.reverse(word); - if (!word.equalsIgnoreCase(reverseWord)) { - result.add(getOnwWordNature(reverseWord, itemDO, true)); - } - } - return result; - } - - private WordNature getOnwWordNature(String word, ItemDO itemDO, boolean isSuffix) { - WordNature wordNature = new WordNature(); - wordNature.setWord(word); - Integer domainId = itemDO.getDomain(); - String nature = NatureType.NATURE_SPILT + domainId + NatureType.NATURE_SPILT + itemDO.getItemId() - + NatureType.METRIC.getType(); - if (isSuffix) { - nature = NatureType.NATURE_SPILT + domainId + NatureType.NATURE_SPILT + itemDO.getItemId() - + NatureType.SUFFIX.getType() + NatureType.METRIC.getType(); - } - wordNature.setNatureWithFrequency(String.format("%s 100000", nature)); - return wordNature; - } - -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/OnlineKnowledgeServiceImpl.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/OnlineKnowledgeServiceImpl.java deleted file mode 100644 index b9e624948..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/OnlineKnowledgeServiceImpl.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import com.tencent.supersonic.knowledge.domain.service.OnlineKnowledgeService; -import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; -import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester; -import java.util.List; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -/** - * online knowledge service impl - */ -@Service -public class OnlineKnowledgeServiceImpl implements OnlineKnowledgeService { - - private final Logger logger = LoggerFactory.getLogger(OnlineKnowledgeServiceImpl.class); - - public void updateSemanticKnowledge(List natures) { - - List prefixes = natures.stream() - .filter(entry -> !entry.getNatureWithFrequency().contains(NatureType.SUFFIX.getType())) - .collect(Collectors.toList()); - - for (WordNature nature : prefixes) { - HanlpHelper.addToCustomDictionary(nature); - } - - List suffixes = natures.stream() - .filter(entry -> entry.getNatureWithFrequency().contains(NatureType.SUFFIX.getType())) - .collect(Collectors.toList()); - - Suggester.loadSuffix(suffixes); - } - - - public void reloadAllData(List natures) { - // 1. reload custom knowledge - try { - HanlpHelper.reloadCustomDictionary(); - } catch (Exception e) { - logger.error("reloadCustomDictionary error", e); - } - - // 2. update online knowledge - updateOnlineKnowledge(natures); - } - - public void updateOnlineKnowledge(List natures) { - try { - updateSemanticKnowledge(natures); - } catch (Exception e) { - logger.error("updateSemanticKnowledge error", e); - } - } - -} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/ValueWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/ValueWordNature.java deleted file mode 100644 index 7f4d58c04..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/ValueWordNature.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - -import com.google.common.collect.Lists; -import com.tencent.supersonic.common.nlp.ItemDO; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -/** - * dimension value wordNature - */ -@Service -@Slf4j -public class ValueWordNature extends BaseWordNature { - - @Override - public List getWordNature(String word, ItemDO itemDO) { - List result = Lists.newArrayList(); - WordNature wordNature = new WordNature(); - wordNature.setWord(word); - Integer domain = itemDO.getDomain(); - String nature = NatureType.NATURE_SPILT + domain + NatureType.NATURE_SPILT + itemDO.getItemId(); - wordNature.setNatureWithFrequency(String.format("%s 100000", nature)); - result.add(wordNature); - return result; - } - -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/WordNatureStrategyFactory.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/WordNatureStrategyFactory.java deleted file mode 100644 index e69f063e6..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/WordNatureStrategyFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.tencent.supersonic.knowledge.application.online; - - -import com.tencent.supersonic.common.nlp.NatureType; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * WordNature Strategy Factory - */ -public class WordNatureStrategyFactory { - - private static Map strategyFactory = new ConcurrentHashMap<>(); - - static { - strategyFactory.put(NatureType.DIMENSION, new DimensionWordNature()); - strategyFactory.put(NatureType.METRIC, new MetricWordNature()); - strategyFactory.put(NatureType.DOMAIN, new DomainWordNature()); - strategyFactory.put(NatureType.ENTITY, new EntityWordNature()); - strategyFactory.put(NatureType.VALUE, new ValueWordNature()); - - - } - - public static BaseWordNature get(NatureType strategyType) { - return strategyFactory.get(strategyType); - } -} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictConfig.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictConfig.java similarity index 74% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictConfig.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictConfig.java index 5c9d4ace2..a3a17e080 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictConfig.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictConfig.java @@ -1,6 +1,7 @@ -package com.tencent.supersonic.knowledge.domain.pojo; +package com.tencent.supersonic.knowledge.dictionary; import java.util.List; + import lombok.Data; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictTaskFilter.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictTaskFilter.java similarity index 76% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictTaskFilter.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictTaskFilter.java index 0ab2a7a14..c5758e8cc 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictTaskFilter.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictTaskFilter.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.domain.pojo; +package com.tencent.supersonic.knowledge.dictionary; public class DictTaskFilter { diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictUpdateMode.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictUpdateMode.java similarity index 92% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictUpdateMode.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictUpdateMode.java index 4b3d6415d..df5cd9173 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DictUpdateMode.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictUpdateMode.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.domain.pojo; +package com.tencent.supersonic.knowledge.dictionary; public enum DictUpdateMode { diff --git a/common/src/main/java/com/tencent/supersonic/common/nlp/WordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictWord.java similarity index 84% rename from common/src/main/java/com/tencent/supersonic/common/nlp/WordNature.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictWord.java index 75e9950b9..955864006 100644 --- a/common/src/main/java/com/tencent/supersonic/common/nlp/WordNature.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictWord.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.nlp; +package com.tencent.supersonic.knowledge.dictionary; import java.util.Objects; import lombok.Data; @@ -9,14 +9,12 @@ import lombok.ToString; */ @Data @ToString -public class WordNature { +public class DictWord { private String word; - private String nature; private String natureWithFrequency; - @Override public boolean equals(Object o) { if (this == o) { @@ -25,7 +23,7 @@ public class WordNature { if (o == null || getClass() != o.getClass()) { return false; } - WordNature that = (WordNature) o; + DictWord that = (DictWord) o; return Objects.equals(word, that.word) && Objects.equals(natureWithFrequency, that.natureWithFrequency); } diff --git a/common/src/main/java/com/tencent/supersonic/common/nlp/NatureType.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictWordType.java similarity index 63% rename from common/src/main/java/com/tencent/supersonic/common/nlp/NatureType.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictWordType.java index 302dbc633..bcb391bf4 100644 --- a/common/src/main/java/com/tencent/supersonic/common/nlp/NatureType.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictWordType.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.nlp; +package com.tencent.supersonic.knowledge.dictionary; import org.apache.commons.lang3.StringUtils; @@ -6,7 +6,7 @@ import org.apache.commons.lang3.StringUtils; * nature type * such as : metric、dimension etc. */ -public enum NatureType { +public enum DictWordType { METRIC("metric"), DIMENSION("dimension"), VALUE("value"), @@ -17,13 +17,12 @@ public enum NatureType { NUMBER("m"), SUFFIX("suffix"); + + public static final String NATURE_SPILT = "_"; + public static final String SPACE = " "; private String type; - public static String NATURE_SPILT = "_"; - - public static String SPACE = " "; - - NatureType(String type) { + DictWordType(String type) { this.type = type; } @@ -31,17 +30,19 @@ public enum NatureType { return NATURE_SPILT + type; } - public static NatureType getNatureType(String nature) { + + + public static DictWordType getNatureType(String nature) { if (StringUtils.isEmpty(nature) || !nature.startsWith(NATURE_SPILT)) { return null; } - for (NatureType natureType : values()) { - if (nature.endsWith(natureType.getType())) { - return natureType; + for (DictWordType dictWordType : values()) { + if (nature.endsWith(dictWordType.getType())) { + return dictWordType; } } //domain - String[] natures = nature.split(NatureType.NATURE_SPILT); + String[] natures = nature.split(DictWordType.NATURE_SPILT); if (natures.length == 2 && StringUtils.isNumeric(natures[1])) { return DOMAIN; } diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/DictionaryAttributeUtil.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictionaryAttributeUtil.java similarity index 96% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/DictionaryAttributeUtil.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictionaryAttributeUtil.java index c86cf68dc..6743a2cd0 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/DictionaryAttributeUtil.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DictionaryAttributeUtil.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.infrastructure.nlp; +package com.tencent.supersonic.knowledge.dictionary; import com.hankcs.hanlp.corpus.tag.Nature; import com.hankcs.hanlp.dictionary.CoreDictionary; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValue2DictCommand.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValue2DictCommand.java similarity index 70% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValue2DictCommand.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValue2DictCommand.java index 793e319ae..9a2821bdf 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValue2DictCommand.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValue2DictCommand.java @@ -1,9 +1,11 @@ -package com.tencent.supersonic.knowledge.domain.pojo; +package com.tencent.supersonic.knowledge.dictionary; import java.util.HashMap; import java.util.List; import java.util.Map; + +import com.tencent.supersonic.knowledge.dictionary.DictUpdateMode; import lombok.Data; @Data diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValueDictInfo.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValueDictInfo.java similarity index 73% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValueDictInfo.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValueDictInfo.java index b066d9a48..153e6afdd 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValueDictInfo.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValueDictInfo.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.knowledge.domain.pojo; +package com.tencent.supersonic.knowledge.dictionary; -import com.tencent.supersonic.common.enums.TaskStatusEnum; +import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; import java.util.Date; import lombok.Data; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValueInfo.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValueInfo.java similarity index 81% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValueInfo.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValueInfo.java index e60362be7..0a4f35c65 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/pojo/DimValueInfo.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/DimValueInfo.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.knowledge.domain.pojo; +package com.tencent.supersonic.knowledge.dictionary; -import com.tencent.supersonic.common.enums.TypeEnums; +import com.tencent.supersonic.common.pojo.enums.TypeEnums; import java.util.List; import javax.validation.constraints.NotNull; @@ -23,4 +23,4 @@ public class DimValueInfo { private List whiteList; private List ruleList; private Boolean isDictInfo; -} \ No newline at end of file +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/FileHandler.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/FileHandler.java similarity index 80% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/FileHandler.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/FileHandler.java index cc603cd1c..b4cee26b1 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/FileHandler.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/FileHandler.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.domain; +package com.tencent.supersonic.knowledge.dictionary; import java.util.List; @@ -12,15 +12,6 @@ public interface FileHandler { */ void backupFile(String fileName); - /** - * move files to a specific directory - * not backup - * - * @param fileName - * @param targetDirectory - */ - void moveFile(String fileName, String targetDirectory); - /** * create a directory * diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HadoopFileIOAdapter.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/HadoopFileIOAdapter.java similarity index 73% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HadoopFileIOAdapter.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/HadoopFileIOAdapter.java index 1721cfddb..f948c2817 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HadoopFileIOAdapter.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/HadoopFileIOAdapter.java @@ -1,23 +1,22 @@ -package com.tencent.supersonic.knowledge.infrastructure.nlp; +package com.tencent.supersonic.knowledge.dictionary; import com.hankcs.hanlp.corpus.io.IIOAdapter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; + +import lombok.extern.slf4j.Slf4j; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +@Slf4j public class HadoopFileIOAdapter implements IIOAdapter { - private static final Logger LOGGER = LoggerFactory.getLogger(HadoopFileIOAdapter.class); - @Override public InputStream open(String path) throws IOException { - LOGGER.info("open:{}", path); + log.info("open:{}", path); Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(URI.create(path), conf); return fs.open(new Path(path)); @@ -25,7 +24,7 @@ public class HadoopFileIOAdapter implements IIOAdapter { @Override public OutputStream create(String path) throws IOException { - LOGGER.info("create:{}", path); + log.info("create:{}", path); Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(URI.create(path), conf); return fs.create(new Path(path)); diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/LocalFileConfig.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/LocalFileConfig.java similarity index 88% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/LocalFileConfig.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/LocalFileConfig.java index 4179f1a61..80aec2a1c 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/LocalFileConfig.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/LocalFileConfig.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.knowledge.domain; +package com.tencent.supersonic.knowledge.dictionary; -import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; +import com.tencent.supersonic.knowledge.utils.HanlpHelper; import java.io.FileNotFoundException; import lombok.Data; import lombok.extern.slf4j.Slf4j; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/LocalFileHandler.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/LocalFileHandler.java similarity index 88% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/LocalFileHandler.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/LocalFileHandler.java index d651b1bee..2752b0cca 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/LocalFileHandler.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/LocalFileHandler.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.domain; +package com.tencent.supersonic.knowledge.dictionary; import java.io.BufferedWriter; @@ -44,18 +44,6 @@ public class LocalFileHandler implements FileHandler { } - @Override - public void moveFile(String filePath, String targetDirectoryPath) { - Path sourcePath = Paths.get(filePath); - Path targetPath = Paths.get(targetDirectoryPath, sourcePath.getFileName().toString()); - try { - Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); - log.info("File moved successfully!"); - } catch (IOException e) { - log.info("Failed to move file: " + e.getMessage()); - } - } - @Override public void createDir(String directoryPath) { Path path = Paths.get(directoryPath); @@ -136,4 +124,4 @@ public class LocalFileHandler implements FileHandler { } return Files.newBufferedWriter(Paths.get(filePath), StandardCharsets.UTF_8); } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/tencent/supersonic/common/nlp/MapResult.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/MapResult.java similarity index 95% rename from common/src/main/java/com/tencent/supersonic/common/nlp/MapResult.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/MapResult.java index c4d61caac..aa2a7e9ab 100644 --- a/common/src/main/java/com/tencent/supersonic/common/nlp/MapResult.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/MapResult.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.nlp; +package com.tencent.supersonic.knowledge.dictionary; import java.io.Serializable; import java.util.List; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/MultiCustomDictionary.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/MultiCustomDictionary.java similarity index 97% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/MultiCustomDictionary.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/MultiCustomDictionary.java index 2a678cf98..d2b732ca8 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/MultiCustomDictionary.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/MultiCustomDictionary.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.infrastructure.nlp; +package com.tencent.supersonic.knowledge.dictionary; import static com.hankcs.hanlp.utility.Predefine.logger; @@ -14,6 +14,8 @@ import com.hankcs.hanlp.dictionary.other.CharTable; import com.hankcs.hanlp.utility.LexiconUtility; import com.hankcs.hanlp.utility.Predefine; import com.hankcs.hanlp.utility.TextUtility; +import com.tencent.supersonic.knowledge.service.SearchService; +import com.tencent.supersonic.knowledge.utils.HanlpHelper; import java.io.BufferedOutputStream; import java.io.BufferedReader; @@ -109,13 +111,13 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { attribute = DictionaryAttributeUtil.getAttribute(map.get(word), attribute); map.put(word, attribute); if (addToSuggeterTrie) { - Suggester.put(word, attribute); + SearchService.put(word, attribute); } } else { map.put(word, attribute); if (addToSuggeterTrie) { - Suggester.put(word, attribute); + SearchService.put(word, attribute); } } } @@ -125,6 +127,20 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { } } + public boolean load(String... path) { + this.path = path; + long start = System.currentTimeMillis(); + if (!this.loadMainDictionary(path[0])) { + Predefine.logger.warning("自定义词典" + Arrays.toString(path) + "加载失败"); + return false; + } else { + Predefine.logger.info( + "自定义词典加载成功:" + this.dat.size() + "个词条,耗时" + (System.currentTimeMillis() - start) + "ms"); + this.path = path; + return true; + } + } + /*** * load main dictionary * @param mainPath @@ -176,7 +192,7 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { logger.info("正在构建DoubleArrayTrie……"); dat.build(map); if (addToSuggestTrie) { - // Suggester.save(); + // SearchService.save(); } if (isCache) { // 缓存成dat文件,下次加载会快很多 @@ -219,6 +235,10 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { } } + public boolean loadMainDictionary(String mainPath) { + return loadMainDictionary(mainPath, this.path, this.dat, true, addToSuggesterTrie); + } + public static boolean loadDat(String path, DoubleArrayTrie dat) { return loadDat(path, HanLP.Config.CustomDictionaryPath, dat); } @@ -303,24 +323,6 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { return word; } - public boolean load(String... path) { - this.path = path; - long start = System.currentTimeMillis(); - if (!this.loadMainDictionary(path[0])) { - Predefine.logger.warning("自定义词典" + Arrays.toString(path) + "加载失败"); - return false; - } else { - Predefine.logger.info( - "自定义词典加载成功:" + this.dat.size() + "个词条,耗时" + (System.currentTimeMillis() - start) + "ms"); - this.path = path; - return true; - } - } - - public boolean loadMainDictionary(String mainPath) { - return loadMainDictionary(mainPath, this.path, this.dat, true, addToSuggesterTrie); - } - public boolean reload() { if (this.path != null && this.path.length != 0) { IOUtil.deleteFile(this.path[0] + ".bin"); @@ -368,7 +370,7 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { // return true; } if (addToSuggesterTrie) { - Suggester.put(word, att); + SearchService.put(word, att); } return true; } diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/BaseWordBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/BaseWordBuilder.java new file mode 100644 index 000000000..a600b972c --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/BaseWordBuilder.java @@ -0,0 +1,49 @@ +package com.tencent.supersonic.knowledge.dictionary.builder; + +import java.util.ArrayList; +import java.util.List; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import lombok.extern.slf4j.Slf4j; + +/** + * base word nature + */ +@Slf4j +public abstract class BaseWordBuilder { + + public static final Long DEFAULT_FREQUENCY = 100000L; + + public List getDictWords(List schemaElements) { + List dictWords = new ArrayList<>(); + try { + dictWords = getDictWordsWithException(schemaElements); + } catch (Exception e) { + log.error("getWordNatureList error,", e); + } + return dictWords; + } + + protected List getDictWordsWithException(List schemaElements) { + + List dictWords = new ArrayList<>(); + + for (SchemaElement schemaElement : schemaElements) { + dictWords.addAll(doGet(schemaElement.getName(), schemaElement)); + } + return dictWords; + } + + protected abstract List doGet(String word, SchemaElement schemaElement); + + public Long getElementID(String nature) { + String[] split = nature.split(DictWordType.NATURE_SPILT); + if (split.length >= 3) { + return Long.valueOf(split[2]); + } + return 0L; + } + +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/DimensionWordBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/DimensionWordBuilder.java new file mode 100644 index 000000000..9bf4718b9 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/DimensionWordBuilder.java @@ -0,0 +1,51 @@ +package com.tencent.supersonic.knowledge.dictionary.builder; + +import com.google.common.collect.Lists; + +import java.util.List; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * dimension word nature + */ +@Service +public class DimensionWordBuilder extends BaseWordBuilder { + + @Value("${nlp.dimension.use.suffix:true}") + private boolean nlpDimensionUseSuffix = true; + + + @Override + public List doGet(String word, SchemaElement schemaElement) { + List result = Lists.newArrayList(); + result.add(getOnwWordNature(word, schemaElement, false)); + if (nlpDimensionUseSuffix) { + String reverseWord = StringUtils.reverse(word); + if (StringUtils.isNotEmpty(word) && !word.equalsIgnoreCase(reverseWord)) { + result.add(getOnwWordNature(reverseWord, schemaElement, true)); + } + } + return result; + } + + private DictWord getOnwWordNature(String word, SchemaElement schemaElement, boolean isSuffix) { + DictWord dictWord = new DictWord(); + dictWord.setWord(word); + Long domainId = schemaElement.getDomain(); + String nature = DictWordType.NATURE_SPILT + domainId + DictWordType.NATURE_SPILT + schemaElement.getId() + + DictWordType.DIMENSION.getType(); + if (isSuffix) { + nature = DictWordType.NATURE_SPILT + domainId + DictWordType.NATURE_SPILT + schemaElement.getId() + + DictWordType.SUFFIX.getType() + DictWordType.DIMENSION.getType(); + } + dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature)); + return dictWord; + } + +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/DomainWordBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/DomainWordBuilder.java new file mode 100644 index 000000000..f4c037bfa --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/DomainWordBuilder.java @@ -0,0 +1,32 @@ +package com.tencent.supersonic.knowledge.dictionary.builder; + +import com.google.common.collect.Lists; + +import java.util.List; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * domain word nature + */ +@Service +@Slf4j +public class DomainWordBuilder extends BaseWordBuilder { + + @Override + public List doGet(String word, SchemaElement schemaElement) { + List result = Lists.newArrayList(); + DictWord dictWord = new DictWord(); + dictWord.setWord(word); + Long domainId = schemaElement.getDomain(); + String nature = DictWordType.NATURE_SPILT + domainId; + dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature)); + result.add(dictWord); + return result; + } + +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/EntityWordBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/EntityWordBuilder.java new file mode 100644 index 000000000..98a2ae368 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/EntityWordBuilder.java @@ -0,0 +1,33 @@ +package com.tencent.supersonic.knowledge.dictionary.builder; + +import com.google.common.collect.Lists; + +import java.util.List; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * dimension value wordNature + */ +@Service +@Slf4j +public class EntityWordBuilder extends BaseWordBuilder { + + @Override + public List doGet(String word, SchemaElement schemaElement) { + List result = Lists.newArrayList(); + DictWord dictWord = new DictWord(); + dictWord.setWord(word); + Long domain = schemaElement.getDomain(); + String nature = DictWordType.NATURE_SPILT + domain + DictWordType.NATURE_SPILT + schemaElement.getId() + + DictWordType.ENTITY.getType(); + dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY * 2, nature)); + result.add(dictWord); + return result; + } + +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/MetricWordBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/MetricWordBuilder.java new file mode 100644 index 000000000..9802d4243 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/MetricWordBuilder.java @@ -0,0 +1,50 @@ +package com.tencent.supersonic.knowledge.dictionary.builder; + +import com.google.common.collect.Lists; + +import java.util.List; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * Metric DictWord + */ +@Service +public class MetricWordBuilder extends BaseWordBuilder { + + @Value("${nlp.metric.use.suffix:true}") + private boolean nlpMetricUseSuffix = true; + + @Override + public List doGet(String word, SchemaElement schemaElement) { + List result = Lists.newArrayList(); + result.add(getOnwWordNature(word, schemaElement, false)); + if (nlpMetricUseSuffix) { + String reverseWord = StringUtils.reverse(word); + if (!word.equalsIgnoreCase(reverseWord)) { + result.add(getOnwWordNature(reverseWord, schemaElement, true)); + } + } + return result; + } + + private DictWord getOnwWordNature(String word, SchemaElement schemaElement, boolean isSuffix) { + DictWord dictWord = new DictWord(); + dictWord.setWord(word); + Long domainId = schemaElement.getDomain(); + String nature = DictWordType.NATURE_SPILT + domainId + DictWordType.NATURE_SPILT + schemaElement.getId() + + DictWordType.METRIC.getType(); + if (isSuffix) { + nature = DictWordType.NATURE_SPILT + domainId + DictWordType.NATURE_SPILT + schemaElement.getId() + + DictWordType.SUFFIX.getType() + DictWordType.METRIC.getType(); + } + dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature)); + return dictWord; + } + +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/ValueWordBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/ValueWordBuilder.java new file mode 100644 index 000000000..d08c1f6be --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/ValueWordBuilder.java @@ -0,0 +1,41 @@ +package com.tencent.supersonic.knowledge.dictionary.builder; + +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.Objects; + +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +/** + * dimension value wordNature + */ +@Service +@Slf4j +public class ValueWordBuilder extends BaseWordBuilder { + + @Override + public List doGet(String word, SchemaElement schemaElement) { + + List result = Lists.newArrayList(); + if (Objects.nonNull(schemaElement) && !CollectionUtils.isEmpty(schemaElement.getAlias())) { + + schemaElement.getAlias().stream().forEach(value -> { + DictWord dictWord = new DictWord(); + Long domainId = schemaElement.getDomain(); + String nature = DictWordType.NATURE_SPILT + domainId + DictWordType.NATURE_SPILT + schemaElement.getId(); + dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature)); + dictWord.setWord(value); + result.add(dictWord); + }); + } + log.debug("ValueWordBuilder, result:{}", result); + return result; + } + +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/WordBuilderFactory.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/WordBuilderFactory.java new file mode 100644 index 000000000..29e72182c --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/builder/WordBuilderFactory.java @@ -0,0 +1,28 @@ +package com.tencent.supersonic.knowledge.dictionary.builder; + + +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.dictionary.builder.*; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * DictWord Strategy Factory + */ +public class WordBuilderFactory { + + private static Map wordNatures = new ConcurrentHashMap<>(); + + static { + wordNatures.put(DictWordType.DIMENSION, new DimensionWordBuilder()); + wordNatures.put(DictWordType.METRIC, new MetricWordBuilder()); + wordNatures.put(DictWordType.DOMAIN, new DomainWordBuilder()); + wordNatures.put(DictWordType.ENTITY, new EntityWordBuilder()); + wordNatures.put(DictWordType.VALUE, new ValueWordBuilder()); + } + + public static BaseWordBuilder get(DictWordType strategyType) { + return wordNatures.get(strategyType); + } +} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/converter/DictTaskConverter.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/converter/DictTaskConverter.java deleted file mode 100644 index caba1e634..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/converter/DictTaskConverter.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.tencent.supersonic.knowledge.domain.converter; - -import com.google.common.base.Strings; -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.common.enums.TaskStatusEnum; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.knowledge.domain.dataobject.DictConfPO; -import com.tencent.supersonic.knowledge.domain.dataobject.DimValueDictTaskPO; -import com.tencent.supersonic.knowledge.domain.pojo.DictConfig; -import com.tencent.supersonic.knowledge.domain.pojo.DimValue2DictCommand; -import com.tencent.supersonic.knowledge.domain.pojo.DimValueInfo; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.Date; -import java.util.List; - -public class DictTaskConverter { - - private static String dateTimeFormatter = "yyyyMMddHHmmss"; - - public static DimValueDictTaskPO generateDimValueDictTaskPO(DimValue2DictCommand dimValue2DictCommend, User user) { - DimValueDictTaskPO taskPO = new DimValueDictTaskPO(); - Date createAt = new Date(); - String date = DateTimeFormatter.ofPattern(dateTimeFormatter) - .format(createAt.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); - String creator = Strings.isNullOrEmpty(user.getName()) ? "" : user.getName(); - String updateMode = dimValue2DictCommend.getUpdateMode().getValue(); - String name = String.format("DimValue_dic_%s_%s_%s", updateMode, creator, date); - taskPO.setName(name); - - taskPO.setCreatedAt(createAt); - taskPO.setCommand(JsonUtil.toString(dimValue2DictCommend)); - taskPO.setStatus(TaskStatusEnum.RUNNING.getCode()); - taskPO.setCreatedBy(creator); - - return taskPO; - } - - public static DictConfPO generateDictConfPO(DictConfig dictConfig, User user) { - DictConfPO dictConfPO = new DictConfPO(); - dictConfPO.setDimValueInfos(JsonUtil.toString(dictConfig.getDimValueInfoList())); - dictConfPO.setDomainId(dictConfig.getDomainId()); - - dictConfPO.setCreatedBy(user.getName()); - dictConfPO.setUpdatedBy(user.getName()); - dictConfPO.setCreatedAt(new Date()); - dictConfPO.setUpdatedAt(new Date()); - - return dictConfPO; - } - - public static DictConfig dictConfPO2Config(DictConfPO dictConfPO) { - DictConfig dictConfig = new DictConfig(); - dictConfig.setDomainId(dictConfPO.getDomainId()); - List dimValueInfos = JsonUtil.toList(dictConfPO.getDimValueInfos(), DimValueInfo.class); - dictConfig.setDimValueInfoList(dimValueInfos); - return dictConfig; - } -} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/repository/DictRepository.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/repository/DictRepository.java deleted file mode 100644 index d8980fd3d..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/repository/DictRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.tencent.supersonic.knowledge.domain.repository; - -import com.tencent.supersonic.knowledge.domain.dataobject.DictConfPO; -import com.tencent.supersonic.knowledge.domain.dataobject.DimValueDictTaskPO; -import com.tencent.supersonic.knowledge.domain.pojo.DictConfig; -import com.tencent.supersonic.knowledge.domain.pojo.DictTaskFilter; -import com.tencent.supersonic.knowledge.domain.pojo.DimValueDictInfo; -import java.util.List; - -public interface DictRepository { - - Long createDimValueDictTask(DimValueDictTaskPO dimValueDictTaskPO); - - Boolean updateDictTaskStatus(Integer status, DimValueDictTaskPO dimValueDictTaskPO); - - List searchDictTaskList(DictTaskFilter filter); - - Boolean createDictConf(DictConfPO dictConfPO); - - Boolean editDictConf(DictConfPO dictConfPO); - - Boolean upsertDictInfo(DictConfPO dictConfPO); - - DictConfig getDictInfoByDomainId(Long domainId); -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/service/OnlineKnowledgeService.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/service/OnlineKnowledgeService.java deleted file mode 100644 index 58baab16a..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/service/OnlineKnowledgeService.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.tencent.supersonic.knowledge.domain.service; - -import com.tencent.supersonic.common.nlp.WordNature; -import java.util.List; - -/** - * online knowledge service interface - */ -public interface OnlineKnowledgeService { - - void updateSemanticKnowledge(List natures); - - void reloadAllData(List natures); - - void updateOnlineKnowledge(List natures); - -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/custom/DictConfMapper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/custom/DictConfMapper.java deleted file mode 100644 index 57b2867a3..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/custom/DictConfMapper.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.tencent.supersonic.knowledge.infrastructure.custom; - - -import com.tencent.supersonic.knowledge.domain.dataobject.DictConfPO; -import org.apache.ibatis.annotations.Mapper; - -@Mapper -public interface DictConfMapper { - - Boolean createDictConf(DictConfPO dictConfPO); - - Boolean editDictConf(DictConfPO dictConfPO); - - Boolean upsertDictInfo(DictConfPO dictConfPO); - - DictConfPO getDictInfoByDomainId(Long domainId); -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/custom/DictTaskMapper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/custom/DictTaskMapper.java deleted file mode 100644 index f5fa2bb9f..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/custom/DictTaskMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.tencent.supersonic.knowledge.infrastructure.custom; - -import com.tencent.supersonic.knowledge.domain.dataobject.DimValueDictTaskPO; -import com.tencent.supersonic.knowledge.domain.pojo.DictTaskFilter; -import java.util.List; -import org.apache.ibatis.annotations.Mapper; - -@Mapper -public interface DictTaskMapper { - - Long createDimValueTask(DimValueDictTaskPO dimValueDictTaskPO); - - Boolean updateTaskStatus(DimValueDictTaskPO dimValueDictTaskPO); - - List searchDictTaskList(DictTaskFilter filter); -} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/repository/DictRepositoryImpl.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/repository/DictRepositoryImpl.java deleted file mode 100644 index cf68f41b8..000000000 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/repository/DictRepositoryImpl.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.tencent.supersonic.knowledge.infrastructure.repository; - -import com.tencent.supersonic.common.enums.TaskStatusEnum; -import com.tencent.supersonic.knowledge.domain.converter.DictTaskConverter; -import com.tencent.supersonic.knowledge.domain.dataobject.DictConfPO; -import com.tencent.supersonic.knowledge.domain.dataobject.DimValueDictTaskPO; -import com.tencent.supersonic.knowledge.domain.pojo.DictConfig; -import com.tencent.supersonic.knowledge.domain.pojo.DictTaskFilter; -import com.tencent.supersonic.knowledge.domain.pojo.DimValueDictInfo; -import com.tencent.supersonic.knowledge.domain.repository.DictRepository; -import com.tencent.supersonic.knowledge.infrastructure.custom.DictConfMapper; -import com.tencent.supersonic.knowledge.infrastructure.custom.DictTaskMapper; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import org.springframework.beans.BeanUtils; -import org.springframework.stereotype.Repository; -import org.springframework.util.CollectionUtils; - - -@Repository -public class DictRepositoryImpl implements DictRepository { - - private final DictTaskMapper dictTaskMapper; - private final DictConfMapper dictConfMapper; - - public DictRepositoryImpl(DictTaskMapper dictTaskMapper, - DictConfMapper dictConfMapper) { - this.dictTaskMapper = dictTaskMapper; - this.dictConfMapper = dictConfMapper; - } - - @Override - public Long createDimValueDictTask(DimValueDictTaskPO dimValueDictTaskPO) { - dictTaskMapper.createDimValueTask(dimValueDictTaskPO); - return dimValueDictTaskPO.getId(); - } - - - @Override - public Boolean updateDictTaskStatus(Integer status, DimValueDictTaskPO dimValueDictTaskPO) { - dimValueDictTaskPO.setStatus(status); - Date createdAt = dimValueDictTaskPO.getCreatedAt(); - long elapsedMs = System.currentTimeMillis() - createdAt.getTime(); - dimValueDictTaskPO.setElapsedMs(elapsedMs); - CompletableFuture.supplyAsync(() -> { - dictTaskMapper.updateTaskStatus(dimValueDictTaskPO); - return null; - }); - return true; - } - - @Override - public List searchDictTaskList(DictTaskFilter filter) { - List dimValueDictDescList = new ArrayList<>(); - List dimValueDictTaskPOList = dictTaskMapper.searchDictTaskList(filter); - if (!CollectionUtils.isEmpty(dimValueDictTaskPOList)) { - dimValueDictTaskPOList.stream().forEach(dictTaskPO -> { - DimValueDictInfo dimValueDictDesc = new DimValueDictInfo(); - BeanUtils.copyProperties(dictTaskPO, dimValueDictDesc); - dimValueDictDesc.setStatus(TaskStatusEnum.of(dictTaskPO.getStatus())); - dimValueDictDescList.add(dimValueDictDesc); - }); - } - return dimValueDictDescList; - } - - @Override - public Boolean createDictConf(DictConfPO dictConfPO) { - return dictConfMapper.createDictConf(dictConfPO); - } - - @Override - public Boolean editDictConf(DictConfPO dictConfPO) { - return dictConfMapper.editDictConf(dictConfPO); - } - - @Override - public Boolean upsertDictInfo(DictConfPO dictConfPO) { - return dictConfMapper.upsertDictInfo(dictConfPO); - } - - @Override - public DictConfig getDictInfoByDomainId(Long domainId) { - DictConfPO dictConfPO = dictConfMapper.getDictInfoByDomainId(domainId); - if (Objects.isNull(dictConfPO)) { - return null; - } - return DictTaskConverter.dictConfPO2Config(dictConfPO); - } -} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/dataobject/DictConfPO.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/dataobject/DictConfDO.java similarity index 73% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/dataobject/DictConfPO.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/dataobject/DictConfDO.java index 4645c6049..c95c9f7fe 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/dataobject/DictConfPO.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/dataobject/DictConfDO.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.knowledge.domain.dataobject; +package com.tencent.supersonic.knowledge.persistence.dataobject; import java.util.Date; import lombok.Data; @Data -public class DictConfPO { +public class DictConfDO { private Long id; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/dataobject/DimValueDictTaskPO.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/dataobject/DictTaskDO.java similarity index 84% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/dataobject/DimValueDictTaskPO.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/dataobject/DictTaskDO.java index 2bdeb4ce4..12ff115bc 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/domain/dataobject/DimValueDictTaskPO.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/dataobject/DictTaskDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.domain.dataobject; +package com.tencent.supersonic.knowledge.persistence.dataobject; import java.util.Date; import lombok.Data; @@ -7,7 +7,7 @@ import org.apache.commons.codec.digest.DigestUtils; @Data @ToString -public class DimValueDictTaskPO { +public class DictTaskDO { private Long id; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/mapper/DictConfMapper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/mapper/DictConfMapper.java new file mode 100644 index 000000000..f8215d211 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/mapper/DictConfMapper.java @@ -0,0 +1,17 @@ +package com.tencent.supersonic.knowledge.persistence.mapper; + + +import com.tencent.supersonic.knowledge.persistence.dataobject.DictConfDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DictConfMapper { + + Boolean createDictConf(DictConfDO dictConfDO); + + Boolean editDictConf(DictConfDO dictConfDO); + + Boolean upsertDictInfo(DictConfDO dictConfDO); + + DictConfDO getDictInfoByDomainId(Long domainId); +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/mapper/DictTaskMapper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/mapper/DictTaskMapper.java new file mode 100644 index 000000000..a63926643 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/mapper/DictTaskMapper.java @@ -0,0 +1,16 @@ +package com.tencent.supersonic.knowledge.persistence.mapper; + +import com.tencent.supersonic.knowledge.persistence.dataobject.DictTaskDO; +import com.tencent.supersonic.knowledge.dictionary.DictTaskFilter; +import java.util.List; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DictTaskMapper { + + Long createDimValueTask(DictTaskDO dictTaskDO); + + Boolean updateTaskStatus(DictTaskDO dictTaskDO); + + List searchDictTaskList(DictTaskFilter filter); +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/repository/DictRepository.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/repository/DictRepository.java new file mode 100644 index 000000000..f7e00928c --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/repository/DictRepository.java @@ -0,0 +1,19 @@ +package com.tencent.supersonic.knowledge.persistence.repository; + + +import com.tencent.supersonic.knowledge.persistence.dataobject.DictTaskDO; +import com.tencent.supersonic.knowledge.dictionary.DictConfig; +import com.tencent.supersonic.knowledge.dictionary.DictTaskFilter; +import com.tencent.supersonic.knowledge.dictionary.DimValueDictInfo; +import java.util.List; + +public interface DictRepository { + + Long createDimValueDictTask(DictTaskDO dictTaskDO); + + Boolean updateDictTaskStatus(Integer status, DictTaskDO dictTaskDO); + + List searchDictTaskList(DictTaskFilter filter); + + DictConfig getDictInfoByDomainId(Long domainId); +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/repository/DictRepositoryImpl.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/repository/DictRepositoryImpl.java new file mode 100644 index 000000000..308f6b1d5 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/persistence/repository/DictRepositoryImpl.java @@ -0,0 +1,77 @@ +package com.tencent.supersonic.knowledge.persistence.repository; + +import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; +import com.tencent.supersonic.knowledge.persistence.dataobject.DictTaskDO; +import com.tencent.supersonic.knowledge.utils.DictTaskConverter; +import com.tencent.supersonic.knowledge.persistence.dataobject.DictConfDO; +import com.tencent.supersonic.knowledge.dictionary.DictConfig; +import com.tencent.supersonic.knowledge.dictionary.DictTaskFilter; +import com.tencent.supersonic.knowledge.dictionary.DimValueDictInfo; +import com.tencent.supersonic.knowledge.persistence.mapper.DictConfMapper; +import com.tencent.supersonic.knowledge.persistence.mapper.DictTaskMapper; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; + + +@Repository +public class DictRepositoryImpl implements DictRepository { + + private final DictTaskMapper dictTaskMapper; + private final DictConfMapper dictConfMapper; + + public DictRepositoryImpl(DictTaskMapper dictTaskMapper, + DictConfMapper dictConfMapper) { + this.dictTaskMapper = dictTaskMapper; + this.dictConfMapper = dictConfMapper; + } + + @Override + public Long createDimValueDictTask(DictTaskDO dictTaskDO) { + dictTaskMapper.createDimValueTask(dictTaskDO); + return dictTaskDO.getId(); + } + + + @Override + public Boolean updateDictTaskStatus(Integer status, DictTaskDO dictTaskDO) { + dictTaskDO.setStatus(status); + Date createdAt = dictTaskDO.getCreatedAt(); + long elapsedMs = System.currentTimeMillis() - createdAt.getTime(); + dictTaskDO.setElapsedMs(elapsedMs); + CompletableFuture.supplyAsync(() -> { + dictTaskMapper.updateTaskStatus(dictTaskDO); + return null; + }); + return true; + } + + @Override + public List searchDictTaskList(DictTaskFilter filter) { + List dimValueDictDescList = new ArrayList<>(); + List dictTaskDOList = dictTaskMapper.searchDictTaskList(filter); + if (!CollectionUtils.isEmpty(dictTaskDOList)) { + dictTaskDOList.stream().forEach(dictTaskPO -> { + DimValueDictInfo dimValueDictDesc = new DimValueDictInfo(); + BeanUtils.copyProperties(dictTaskPO, dimValueDictDesc); + dimValueDictDesc.setStatus(TaskStatusEnum.of(dictTaskPO.getStatus())); + dimValueDictDescList.add(dimValueDictDesc); + }); + } + return dimValueDictDescList; + } + + @Override + public DictConfig getDictInfoByDomainId(Long domainId) { + DictConfDO dictConfDO = dictConfMapper.getDictInfoByDomainId(domainId); + if (Objects.isNull(dictConfDO)) { + return null; + } + return DictTaskConverter.dictConfPO2Config(dictConfDO); + } +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/BaseSemanticLayer.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/BaseSemanticLayer.java new file mode 100644 index 000000000..56ad0ecbe --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/BaseSemanticLayer.java @@ -0,0 +1,106 @@ +package com.tencent.supersonic.knowledge.semantic; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.common.pojo.Aggregator; +import com.tencent.supersonic.common.pojo.Order; +import com.tencent.supersonic.common.pojo.ResultData; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.util.CollectionUtils; + +@Slf4j +public abstract class BaseSemanticLayer implements SemanticLayer { + + protected final Cache> domainSchemaCache = + CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); + + protected ParameterizedTypeReference> structTypeRef = + new ParameterizedTypeReference>() { + }; + + @SneakyThrows + public List fetchDomainSchema(List ids, Boolean cacheEnable) { + if (cacheEnable) { + return domainSchemaCache.get(String.valueOf(ids), () -> { + List data = doFetchDomainSchema(ids); + return data; + }); + } + List data = doFetchDomainSchema(ids); + return data; + } + + @Override + public DomainSchema getDomainSchema(Long domain, Boolean cacheEnable) { + List ids = new ArrayList<>(); + ids.add(domain); + List domainSchemaResps = fetchDomainSchema(ids, cacheEnable); + if (!CollectionUtils.isEmpty(domainSchemaResps)) { + Optional domainSchemaResp = domainSchemaResps.stream() + .filter(d -> d.getId().equals(domain)).findFirst(); + if (domainSchemaResp.isPresent()) { + DomainSchemaResp domainSchema = domainSchemaResp.get(); + return DomainSchemaBuilder.build(domainSchema); + } + } + return null; + } + + @Override + public List getDomainSchema() { + return getDomainSchema(new ArrayList<>()); + } + + @Override + public List getDomainSchema(List ids) { + List domainSchemaList = new ArrayList<>(); + + for(DomainSchemaResp resp : fetchDomainSchema(ids, true)) { + domainSchemaList.add(DomainSchemaBuilder.build(resp)); + } + + return domainSchemaList; + } + + protected void deletionDuplicated(QueryStructReq queryStructReq) { + if (!CollectionUtils.isEmpty(queryStructReq.getGroups()) && queryStructReq.getGroups().size() > 1) { + Set groups = new HashSet<>(); + groups.addAll(queryStructReq.getGroups()); + queryStructReq.getGroups().clear(); + queryStructReq.getGroups().addAll(groups); + } + } + + protected void onlyQueryFirstMetric(QueryStructReq queryStructReq) { + if (!CollectionUtils.isEmpty(queryStructReq.getAggregators()) && queryStructReq.getAggregators().size() > 1) { + log.info("multi metric in aggregators:{} , only query first one", queryStructReq.getAggregators()); + List aggregators = queryStructReq.getAggregators().subList(0, 1); + List excludeAggregators = queryStructReq.getAggregators().stream().map(a -> a.getColumn()) + .filter(a -> !a.equals(aggregators.get(0).getColumn())).collect( + Collectors.toList()); + queryStructReq.setAggregators(aggregators); + List orders = queryStructReq.getOrders().stream() + .filter(o -> !excludeAggregators.contains(o.getColumn())).collect( + Collectors.toList()); + log.info("multi metric in orders:{} ", queryStructReq.getOrders()); + queryStructReq.setOrders(orders); + + } + } + + protected abstract List doFetchDomainSchema(List ids); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticConfig.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/DefaultSemanticConfig.java similarity index 83% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticConfig.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/DefaultSemanticConfig.java index aa0715e05..6f55fb74f 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticConfig.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/DefaultSemanticConfig.java @@ -1,6 +1,5 @@ -package com.tencent.supersonic.chat.infrastructure.semantic; +package com.tencent.supersonic.knowledge.semantic; -import com.tencent.supersonic.chat.application.ConfigServiceImpl; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -17,6 +16,9 @@ public class DefaultSemanticConfig { @Value("${searchByStruct.path:/api/semantic/query/struct}") private String searchByStructPath; + @Value("${searchByStruct.path:/api/semantic/query/multiStruct}") + private String searchByMultiStructPath; + @Value("${searchByStruct.path:/api/semantic/query/sql}") private String searchBySqlPath; @@ -35,9 +37,4 @@ public class DefaultSemanticConfig { @Value("${fetchDomainList.path:/api/semantic/schema/domain/view/list}") private String fetchDomainViewListPath; - @Autowired - private RestTemplate restTemplate; - - @Autowired - private ConfigServiceImpl configService; } diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/DomainSchemaBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/DomainSchemaBuilder.java new file mode 100644 index 000000000..f6a4c2e16 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/DomainSchemaBuilder.java @@ -0,0 +1,119 @@ +package com.tencent.supersonic.knowledge.semantic; + +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; +import com.tencent.supersonic.semantic.api.model.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; +import org.springframework.beans.BeanUtils; +import org.springframework.util.CollectionUtils; + +import java.util.*; + +public class DomainSchemaBuilder { + + public static DomainSchema build(DomainSchemaResp resp) { + DomainSchema domainSchema = new DomainSchema(); + + SchemaElement domain = SchemaElement.builder() + .domain(resp.getId()) + .id(resp.getId()) + .name(resp.getName()) + .bizName(resp.getBizName()) + .type(SchemaElementType.DOMAIN) + .build(); + domainSchema.setDomain(domain); + + Set metrics = new HashSet<>(); + for (MetricSchemaResp metric : resp.getMetrics()) { + SchemaElement metricToAdd = SchemaElement.builder() + .domain(resp.getId()) + .id(metric.getId()) + .name(metric.getName()) + .bizName(metric.getBizName()) + .type(SchemaElementType.METRIC) + .useCnt(metric.getUseCnt()) + .build(); + metrics.add(metricToAdd); + + String alias = metric.getAlias(); + if (StringUtils.isNotEmpty(alias)) { + SchemaElement alisMetricToAdd = new SchemaElement(); + BeanUtils.copyProperties(metricToAdd, alisMetricToAdd); + alisMetricToAdd.setName(alias); + metrics.add(alisMetricToAdd); + } + } + domainSchema.getMetrics().addAll(metrics); + + Set dimensions = new HashSet<>(); + Set dimensionValues = new HashSet<>(); + for (DimSchemaResp dim : resp.getDimensions()) { + + Set dimValueAlias = new HashSet<>(); + if (!CollectionUtils.isEmpty(dim.getDimValueMaps())) { + List dimValueMaps = dim.getDimValueMaps(); + for (DimValueMap dimValueMap : dimValueMaps) { + if (Strings.isNotEmpty(dimValueMap.getBizName())) { + dimValueAlias.add(dimValueMap.getBizName()); + } + if (!CollectionUtils.isEmpty(dimValueMap.getAlias())) { + dimValueAlias.addAll(dimValueMap.getAlias()); + } + } + } + + SchemaElement dimToAdd = SchemaElement.builder() + .domain(resp.getId()) + .id(dim.getId()) + .name(dim.getName()) + .bizName(dim.getBizName()) + .type(SchemaElementType.DIMENSION) + .useCnt(dim.getUseCnt()) + .build(); + dimensions.add(dimToAdd); + + String alias = dim.getAlias(); + if (StringUtils.isNotEmpty(alias)) { + SchemaElement alisDimToAdd = new SchemaElement(); + BeanUtils.copyProperties(dimToAdd, alisDimToAdd); + alisDimToAdd.setName(alias); + dimensions.add(alisDimToAdd); + } + + + SchemaElement dimValueToAdd = SchemaElement.builder() + .domain(resp.getId()) + .id(dim.getId()) + .name(dim.getName()) + .bizName(dim.getBizName()) + .type(SchemaElementType.VALUE) + .useCnt(dim.getUseCnt()) + .alias(new ArrayList<>(Arrays.asList(dimValueAlias.toArray(new String[0])))) + .build(); + dimensionValues.add(dimValueToAdd); + } + domainSchema.getDimensions().addAll(dimensions); + domainSchema.getDimensionValues().addAll(dimensionValues); + + if (!CollectionUtils.isEmpty(resp.getEntityNames())) { + Set entities = new HashSet<>(); + for (String entity : resp.getEntityNames()) { + entities.add(SchemaElement.builder() + .domain(resp.getId()) + .id(resp.getId()) + .name(entity) + .bizName(entity) + .type(SchemaElementType.ENTITY) + .build()); + } + domainSchema.getEntities().addAll(entities); + } + + return domainSchema; + } +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/LocalSemanticLayer.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/LocalSemanticLayer.java new file mode 100644 index 000000000..9cc896198 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/LocalSemanticLayer.java @@ -0,0 +1,116 @@ +package com.tencent.supersonic.knowledge.semantic; + +import com.github.pagehelper.PageInfo; +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.common.util.S2ThreadContext; +import com.tencent.supersonic.common.util.ThreadContext; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.request.QueryDslReq; +import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.query.service.QueryService; +import com.tencent.supersonic.semantic.query.service.SchemaService; +import java.util.List; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class LocalSemanticLayer extends BaseSemanticLayer { + + private SchemaService schemaService; + private S2ThreadContext s2ThreadContext; + private DomainService domainService; + private DimensionService dimensionService; + private MetricService metricService; + + @Override + public QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user) { + deletionDuplicated(queryStructReq); + onlyQueryFirstMetric(queryStructReq); + try { + QueryService queryService = ContextUtils.getBean(QueryService.class); + QueryResultWithSchemaResp queryResultWithSchemaResp = queryService.queryByStruct(queryStructReq, user); + return queryResultWithSchemaResp; + } catch (Exception e) { + log.info("queryByStruct has an exception:{}", e.toString()); + } + return null; + } + + @Override + public QueryResultWithSchemaResp queryByMultiStruct(QueryMultiStructReq queryMultiStructReq, User user) { + for (QueryStructReq queryStructReq : queryMultiStructReq.getQueryStructReqs()) { + deletionDuplicated(queryStructReq); + onlyQueryFirstMetric(queryStructReq); + } + try { + QueryService queryService = ContextUtils.getBean(QueryService.class); + return queryService.queryByMultiStruct(queryMultiStructReq, user); + } catch (Exception e) { + log.info("queryByMultiStruct has an exception:{}", e); + } + return null; + } + + @Override + public QueryResultWithSchemaResp queryByDsl(QueryDslReq queryDslReq, User user) { + try { + QueryService queryService = ContextUtils.getBean(QueryService.class); + Object object = queryService.queryBySql(queryDslReq, user); + QueryResultWithSchemaResp queryResultWithSchemaResp = JsonUtil.toObject(JsonUtil.toString(object), + QueryResultWithSchemaResp.class); + return queryResultWithSchemaResp; + } catch (Exception e) { + log.info("queryByDsl has an exception:{}", e); + } + return null; + } + + @Override + public List doFetchDomainSchema(List ids) { + DomainSchemaFilterReq filter = new DomainSchemaFilterReq(); + filter.setDomainIds(ids); + User user = new User(1L, "admin", "admin", "admin@email"); + schemaService = ContextUtils.getBean(SchemaService.class); + return schemaService.fetchDomainSchema(filter, user); + } + @Override + public List getDomainListForViewer() { + s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class); + ThreadContext threadContext = s2ThreadContext.get(); + domainService = ContextUtils.getBean(DomainService.class); + return domainService.getDomainListForViewer(threadContext.getUserName()); + } + + @Override + public List getDomainListForAdmin() { + domainService = ContextUtils.getBean(DomainService.class); + s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class); + ThreadContext threadContext = s2ThreadContext.get(); + return domainService.getDomainListForAdmin(threadContext.getUserName()); + } + + @Override + public PageInfo getDimensionPage(PageDimensionReq pageDimensionCmd) { + dimensionService = ContextUtils.getBean(DimensionService.class); + return dimensionService.queryDimension(pageDimensionCmd); + } + + @Override + public PageInfo getMetricPage(PageMetricReq pageMetricCmd) { + metricService = ContextUtils.getBean(MetricService.class); + return metricService.queryMetric(pageMetricCmd); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/RemoteSemanticLayerImpl.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/RemoteSemanticLayer.java similarity index 54% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/RemoteSemanticLayerImpl.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/RemoteSemanticLayer.java index 084138e76..7a229b1ba 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/RemoteSemanticLayerImpl.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/RemoteSemanticLayer.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.infrastructure.semantic; +package com.tencent.supersonic.knowledge.semantic; import com.alibaba.fastjson.JSON; import com.github.pagehelper.PageInfo; @@ -8,29 +8,25 @@ import com.google.gson.Gson; import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; import com.tencent.supersonic.auth.api.authentication.constant.UserConstants; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.component.SemanticLayer; -import com.tencent.supersonic.chat.application.ConfigServiceImpl; -import com.tencent.supersonic.chat.domain.pojo.config.*; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.common.util.context.S2ThreadContext; -import com.tencent.supersonic.common.util.context.ThreadContext; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.*; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.common.util.S2ThreadContext; +import com.tencent.supersonic.common.util.ThreadContext; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.*; +import com.tencent.supersonic.semantic.api.query.request.QueryDslReq; +import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.common.exception.CommonException; -import com.tencent.supersonic.common.result.ResultData; -import com.tencent.supersonic.common.result.ReturnCode; +import com.tencent.supersonic.common.pojo.exception.CommonException; +import com.tencent.supersonic.common.pojo.ResultData; +import com.tencent.supersonic.common.pojo.ReturnCode; import java.net.URI; import java.util.*; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; @@ -41,25 +37,16 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; -import static com.tencent.supersonic.common.constant.Constants.*; -import static com.tencent.supersonic.common.constant.Constants.PAGESIZE_LOWER; +import static com.tencent.supersonic.common.pojo.Constants.*; +import static com.tencent.supersonic.common.pojo.Constants.PAGESIZE_LOWER; @Slf4j -public class RemoteSemanticLayerImpl implements SemanticLayer { - - - private RestTemplate restTemplate; - - @Autowired - private ConfigServiceImpl configService; - +public class RemoteSemanticLayer extends BaseSemanticLayer { @Autowired private S2ThreadContext s2ThreadContext; - @Autowired private AuthenticationConfig authenticationConfig; @@ -80,10 +67,22 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { } @Override - public QueryResultWithSchemaResp queryBySql(QuerySqlReq querySqlReq, User user) { + public QueryResultWithSchemaResp queryByMultiStruct(QueryMultiStructReq queryMultiStructReq, User user) { + for (QueryStructReq queryStructReq : queryMultiStructReq.getQueryStructReqs()) { + deletionDuplicated(queryStructReq); + onlyQueryFirstMetric(queryStructReq); + } + DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); + return searchByRestTemplate( + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getSearchByMultiStructPath(), + new Gson().toJson(queryMultiStructReq)); + } + + @Override + public QueryResultWithSchemaResp queryByDsl(QueryDslReq queryDslReq, User user) { DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); return searchByRestTemplate(defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getSearchBySqlPath(), - new Gson().toJson(querySqlReq)); + new Gson().toJson(queryDslReq)); } public QueryResultWithSchemaResp searchByRestTemplate(String url, String jsonReq) { @@ -95,10 +94,10 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { log.info("url:{},searchByRestTemplate:{}", url, entity.getBody()); ResultData responseBody; try { - DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); - ResponseEntity> responseEntity = defaultSemanticConfig.getRestTemplate() - .exchange(requestUrl, - HttpMethod.POST, entity, structTypeRef); + RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); + + ResponseEntity> responseEntity = restTemplate.exchange( + requestUrl, HttpMethod.POST, entity, structTypeRef); responseBody = responseEntity.getBody(); log.info("ApiResponse responseBody:{}", responseBody); QueryResultWithSchemaResp semanticQuery = new QueryResultWithSchemaResp(); @@ -116,7 +115,7 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { throw new CommonException(responseBody.getCode(), responseBody.getMsg()); } - public List fetchDomainSchemaAll(List ids) { + public List doFetchDomainSchema(List ids) { HttpHeaders headers = new HttpHeaders(); headers.set(UserConstants.INTERNAL, TRUE_LOWER); headers.setContentType(MediaType.APPLICATION_JSON); @@ -124,7 +123,7 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); URI requestUrl = UriComponentsBuilder.fromHttpUrl( - defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDomainSchemaPath()).build() + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDomainSchemaPath()).build() .encode().toUri(); DomainSchemaFilterReq filter = new DomainSchemaFilterReq(); filter.setDomainIds(ids); @@ -135,9 +134,9 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { HttpEntity entity = new HttpEntity<>(JSON.toJSONString(filter), headers); try { - ResponseEntity>> responseEntity = defaultSemanticConfig.getRestTemplate() - .exchange(requestUrl, - HttpMethod.POST, entity, responseTypeRef); + RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); + ResponseEntity>> responseEntity = restTemplate.exchange( + requestUrl, HttpMethod.POST, entity, responseTypeRef); ResultData> responseBody = responseEntity.getBody(); log.debug("ApiResponse responseBody:{}", responseBody); if (ReturnCode.SUCCESS.getCode() == responseBody.getCode()) { @@ -150,141 +149,6 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { throw new RuntimeException("fetchDomainSchema interface error"); } - - @SneakyThrows - public List fetchDomainSchema(List ids, Boolean cacheEnable) { - if (cacheEnable) { - return domainSchemaCache.get(String.valueOf(ids), () -> { - List data = fetchDomainSchemaAll(ids); - fillEntityNameAndFilterBlackElement(data); - return data; - }); - } - List data = fetchDomainSchemaAll(ids); - fillEntityNameAndFilterBlackElement(data); - return data; - } - - @Override - public DomainSchemaResp getDomainSchemaInfo(Long domain, Boolean cacheEnable) { - List ids = new ArrayList<>(); - ids.add(domain); - List domainSchemaResps = fetchDomainSchema(ids, cacheEnable); - if (!CollectionUtils.isEmpty(domainSchemaResps)) { - Optional domainSchemaResp = domainSchemaResps.stream() - .filter(d -> d.getId().equals(domain)).findFirst(); - if (domainSchemaResp.isPresent()) { - DomainSchemaResp domainSchema = domainSchemaResp.get(); - return domainSchema; - } - } - return null; - } - - @Override - public List getDomainSchemaInfo(List ids) { - return fetchDomainSchema(ids, true); - } - - public DomainSchemaResp fillEntityNameAndFilterBlackElement(DomainSchemaResp domainSchemaResp) { - if (Objects.isNull(domainSchemaResp) || Objects.isNull(domainSchemaResp.getId())) { - return domainSchemaResp; - } - ChatConfigResp chaConfigInfo = getConfigBaseInfo(domainSchemaResp.getId()); - // fill entity names - fillEntityNamesInfo(domainSchemaResp, chaConfigInfo); - - // filter black element - filterBlackDim(domainSchemaResp, chaConfigInfo); - filterBlackMetric(domainSchemaResp, chaConfigInfo); - - return domainSchemaResp; - } - - public void fillEntityNameAndFilterBlackElement(List domainSchemaRespList) { - if (!CollectionUtils.isEmpty(domainSchemaRespList)) { - domainSchemaRespList.stream() - .forEach(domainSchemaResp -> fillEntityNameAndFilterBlackElement(domainSchemaResp)); - } - } - - private void filterBlackMetric(DomainSchemaResp domainSchemaResp, ChatConfigResp chaConfigInfo) { - - ItemVisibility visibility = generateFinalVisibility(chaConfigInfo); - if (Objects.nonNull(chaConfigInfo) && Objects.nonNull(visibility) - && !CollectionUtils.isEmpty(visibility.getBlackMetricIdList()) - && !CollectionUtils.isEmpty(domainSchemaResp.getMetrics())) { - List metric4Chat = domainSchemaResp.getMetrics().stream() - .filter(metric -> !visibility.getBlackMetricIdList().contains(metric.getId())) - .collect(Collectors.toList()); - domainSchemaResp.setMetrics(metric4Chat); - } - } - - private ItemVisibility generateFinalVisibility(ChatConfigResp chatConfigInfo) { - ItemVisibility visibility = new ItemVisibility(); - - ChatAggConfig chatAggConfig = chatConfigInfo.getChatAggConfig(); - ChatDetailConfig chatDetailConfig = chatConfigInfo.getChatDetailConfig(); - - // both black is exist - if (Objects.nonNull(chatAggConfig) && Objects.nonNull(chatAggConfig.getVisibility()) - && Objects.nonNull(chatDetailConfig) && Objects.nonNull(chatDetailConfig.getVisibility())) { - List blackDimIdList = new ArrayList<>(); - blackDimIdList.addAll(chatAggConfig.getVisibility().getBlackDimIdList()); - blackDimIdList.retainAll(chatDetailConfig.getVisibility().getBlackDimIdList()); - List blackMetricIdList = new ArrayList<>(); - - blackMetricIdList.addAll(chatAggConfig.getVisibility().getBlackMetricIdList()); - blackMetricIdList.retainAll(chatDetailConfig.getVisibility().getBlackMetricIdList()); - - visibility.setBlackDimIdList(blackDimIdList); - visibility.setBlackMetricIdList(blackMetricIdList); - } - return visibility; - } - - private void filterBlackDim(DomainSchemaResp domainSchemaResp, ChatConfigResp chatConfigInfo) { - ItemVisibility visibility = generateFinalVisibility(chatConfigInfo); - if (Objects.nonNull(chatConfigInfo) && Objects.nonNull(visibility) - && !CollectionUtils.isEmpty(visibility.getBlackDimIdList()) - && !CollectionUtils.isEmpty(domainSchemaResp.getDimensions())) { - List dim4Chat = domainSchemaResp.getDimensions().stream() - .filter(dim -> !visibility.getBlackDimIdList().contains(dim.getId())) - .collect(Collectors.toList()); - domainSchemaResp.setDimensions(dim4Chat); - } - } - - private void fillEntityNamesInfo(DomainSchemaResp domainSchemaResp, ChatConfigResp chatConfigInfo) { - if (Objects.nonNull(chatConfigInfo) && Objects.nonNull(chatConfigInfo.getChatDetailConfig()) - && Objects.nonNull(chatConfigInfo.getChatDetailConfig().getEntity()) - && !CollectionUtils.isEmpty(chatConfigInfo.getChatDetailConfig().getEntity().getNames())) { - domainSchemaResp.setEntityNames(chatConfigInfo.getChatDetailConfig().getEntity().getNames()); - } - } - - private void deletionDuplicated(QueryStructReq queryStructReq) { - if (!CollectionUtils.isEmpty(queryStructReq.getGroups()) && queryStructReq.getGroups().size() > 1) { - Set groups = new HashSet<>(); - groups.addAll(queryStructReq.getGroups()); - queryStructReq.getGroups().clear(); - queryStructReq.getGroups().addAll(groups); - } - } - - private void onlyQueryFirstMetric(QueryStructReq queryStructReq) { - if (!CollectionUtils.isEmpty(queryStructReq.getAggregators()) && queryStructReq.getAggregators().size() > 1) { - log.info("multi metric in aggregators:{} , only query first one", queryStructReq.getAggregators()); - queryStructReq.setAggregators(queryStructReq.getAggregators().subList(0, 1)); - } - } - - public ChatConfigResp getConfigBaseInfo(Long domain) { - DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); - return defaultSemanticConfig.getConfigService().fetchConfigByDomainId(domain); - } - @Override public List getDomainListForViewer() { DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); @@ -311,7 +175,7 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { }; HttpEntity entity = new HttpEntity<>(JsonUtil.toString(bodyJson), headers); try { - restTemplate = ContextUtils.getBean(RestTemplate.class); + RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); ResponseEntity> responseEntity = restTemplate.exchange(requestUrl, httpMethod, entity, responseTypeRef); ResultData responseBody = responseEntity.getBody(); @@ -341,7 +205,7 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { } @Override - public PageInfo queryMetricPage(PageMetricReq pageMetricCmd) { + public PageInfo getMetricPage(PageMetricReq pageMetricCmd) { String body = JsonUtil.toString(pageMetricCmd); DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); log.info("url:{}", defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchMetricPagePath()); @@ -355,7 +219,7 @@ public class RemoteSemanticLayerImpl implements SemanticLayer { } @Override - public PageInfo queryDimensionPage(PageDimensionReq pageDimensionCmd) { + public PageInfo getDimensionPage(PageDimensionReq pageDimensionCmd) { String body = JsonUtil.toString(pageDimensionCmd); DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); Object dimensionListObject = fetchHttpResult(defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDimensionPagePath(), body, HttpMethod.POST); diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/KnowledgeService.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/KnowledgeService.java new file mode 100644 index 000000000..ff26cad82 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/KnowledgeService.java @@ -0,0 +1,15 @@ +package com.tencent.supersonic.knowledge.service; + +import com.tencent.supersonic.knowledge.dictionary.DictWord; + +import java.util.List; + +public interface KnowledgeService { + + void updateSemanticKnowledge(List natures); + + void reloadAllData(List natures); + + void updateOnlineKnowledge(List natures); + +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/KnowledgeServiceImpl.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/KnowledgeServiceImpl.java new file mode 100644 index 000000000..1f089a5d4 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/KnowledgeServiceImpl.java @@ -0,0 +1,55 @@ +package com.tencent.supersonic.knowledge.service; + +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.utils.HanlpHelper; + +import java.util.List; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class KnowledgeServiceImpl implements KnowledgeService { + + public void updateSemanticKnowledge(List natures) { + + List prefixes = natures.stream() + .filter(entry -> !entry.getNatureWithFrequency().contains(DictWordType.SUFFIX.getType())) + .collect(Collectors.toList()); + + for (DictWord nature : prefixes) { + HanlpHelper.addToCustomDictionary(nature); + } + + List suffixes = natures.stream() + .filter(entry -> entry.getNatureWithFrequency().contains(DictWordType.SUFFIX.getType())) + .collect(Collectors.toList()); + + SearchService.loadSuffix(suffixes); + } + + + public void reloadAllData(List natures) { + // 1. reload custom knowledge + try { + HanlpHelper.reloadCustomDictionary(); + } catch (Exception e) { + log.error("reloadCustomDictionary error", e); + } + + // 2. update online knowledge + updateOnlineKnowledge(natures); + } + + public void updateOnlineKnowledge(List natures) { + try { + updateSemanticKnowledge(natures); + } catch (Exception e) { + log.error("updateSemanticKnowledge error", e); + } + } + +} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SchemaService.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SchemaService.java new file mode 100644 index 000000000..05a4602be --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SchemaService.java @@ -0,0 +1,47 @@ +package com.tencent.supersonic.knowledge.service; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.pojo.DomainSchema; +import com.tencent.supersonic.chat.api.pojo.SemanticSchema; +import com.tencent.supersonic.knowledge.utils.ComponentFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +@Service +@Slf4j +public class SchemaService { + + private static final Integer META_CACHE_TIME = 5; + public static final String ALL_CACHE = "all"; + + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + + private LoadingCache cache = CacheBuilder.newBuilder() + .expireAfterWrite(META_CACHE_TIME, TimeUnit.MINUTES) + .build( + new CacheLoader() { + @Override + public SemanticSchema load(String key) { + log.info("load getDomainSchemaInfo cache [{}]", key); + return new SemanticSchema(semanticLayer.getDomainSchema()); + } + } + ); + + public DomainSchema getDomainSchema(Long id) { + return semanticLayer.getDomainSchema(id, true); + } + + public SemanticSchema getSemanticSchema() { + return cache.getUnchecked(ALL_CACHE); + } + + public LoadingCache getCache() { + return cache; + } +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/Suggester.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SearchService.java similarity index 89% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/Suggester.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SearchService.java index 36b700ed0..de5139dae 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/Suggester.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SearchService.java @@ -1,12 +1,13 @@ -package com.tencent.supersonic.knowledge.infrastructure.nlp; +package com.tencent.supersonic.knowledge.service; import com.hankcs.hanlp.collection.trie.bintrie.BaseNode; import com.hankcs.hanlp.collection.trie.bintrie.BinTrie; import com.hankcs.hanlp.corpus.tag.Nature; import com.hankcs.hanlp.dictionary.CoreDictionary; -import com.tencent.supersonic.common.nlp.MapResult; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.MapResult; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; + import java.util.Arrays; import java.util.List; import java.util.Map; @@ -14,17 +15,18 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.stream.Collectors; + +import com.tencent.supersonic.knowledge.dictionary.DictionaryAttributeUtil; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @Service -public class Suggester { +@Slf4j +public class SearchService { public static final int SEARCH_SIZE = 200; - private static final Logger LOGGER = LoggerFactory.getLogger(Suggester.class); private static BinTrie> trie; private static BinTrie> suffixTrie; private static String localFileCache = ""; @@ -75,7 +77,7 @@ public class Suggester { entry -> { String name = entry.getKey().replace("#", " "); List natures = entry.getValue().stream() - .map(nature -> nature.replaceAll(NatureType.SUFFIX.getType(), "")) + .map(nature -> nature.replaceAll(DictWordType.SUFFIX.getType(), "")) .collect(Collectors.toList()); name = StringUtils.reverse(name); return new MapResult(name, natures, key); @@ -107,7 +109,7 @@ public class Suggester { } public static void clear() { - LOGGER.info("clear all trie"); + log.info("clear all trie"); trie = new BinTrie<>(); suffixTrie = new BinTrie<>(); } @@ -117,12 +119,12 @@ public class Suggester { } - public static void loadSuffix(List suffixes) { + public static void loadSuffix(List suffixes) { if (CollectionUtils.isEmpty(suffixes)) { return; } TreeMap map = new TreeMap(); - for (WordNature suffix : suffixes) { + for (DictWord suffix : suffixes) { CoreDictionary.Attribute attributeNew = suffix.getNatureWithFrequency() == null ? new CoreDictionary.Attribute(Nature.nz, 1) : CoreDictionary.Attribute.create(suffix.getNatureWithFrequency()); diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/WordService.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/WordService.java new file mode 100644 index 000000000..0ff33d425 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/WordService.java @@ -0,0 +1,52 @@ +package com.tencent.supersonic.knowledge.service; + +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SemanticSchema; +import com.tencent.supersonic.knowledge.dictionary.DictWord; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.dictionary.builder.WordBuilderFactory; + +import java.util.ArrayList; +import java.util.List; + +import com.tencent.supersonic.knowledge.utils.ComponentFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + + +@Service +@Slf4j +public class WordService { + + private List preDictWords = new ArrayList<>(); + + public List getAllDictWords() { + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + SemanticSchema semanticSchema = new SemanticSchema(semanticLayer.getDomainSchema()); + + List words = new ArrayList<>(); + + addWordsByType(DictWordType.DIMENSION, semanticSchema.getDimensions(), words); + addWordsByType(DictWordType.METRIC, semanticSchema.getMetrics(), words); + addWordsByType(DictWordType.DOMAIN, semanticSchema.getDomains(), words); + addWordsByType(DictWordType.ENTITY, semanticSchema.getEntities(), words); + addWordsByType(DictWordType.VALUE, semanticSchema.getDimensionValues(), words); + + return words; + } + + private void addWordsByType(DictWordType value, List metas, List natures) { + List natureList = WordBuilderFactory.get(value).getDictWords(metas); + log.debug("nature type:{} , nature size:{}", value.name(), natureList.size()); + natures.addAll(natureList); + } + + public List getPreDictWords() { + return preDictWords; + } + + public void setPreDictWords(List preDictWords) { + this.preDictWords = preDictWords; + } +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/ComponentFactory.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/ComponentFactory.java new file mode 100644 index 000000000..532f58203 --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/ComponentFactory.java @@ -0,0 +1,34 @@ +package com.tencent.supersonic.knowledge.utils; + +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import org.springframework.core.io.support.SpringFactoriesLoader; + +import java.util.List; +import java.util.Objects; + +public class ComponentFactory { + + private static SemanticLayer semanticLayer; + + public static SemanticLayer getSemanticLayer() { + if (Objects.isNull(semanticLayer)) { + semanticLayer = init(SemanticLayer.class); + } + return semanticLayer; + } + + public static void setSemanticLayer(SemanticLayer layer) { + semanticLayer = layer; + } + + private static List init(Class factoryType, List list) { + list.addAll(SpringFactoriesLoader.loadFactories(factoryType, + Thread.currentThread().getContextClassLoader())); + return list; + } + + private static T init(Class factoryType) { + return SpringFactoriesLoader.loadFactories(factoryType, + Thread.currentThread().getContextClassLoader()).get(0); + } +} \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/DictTaskConverter.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/DictTaskConverter.java new file mode 100644 index 000000000..0e4b8f1de --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/DictTaskConverter.java @@ -0,0 +1,47 @@ +package com.tencent.supersonic.knowledge.utils; + +import com.google.common.base.Strings; +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.knowledge.dictionary.DictConfig; +import com.tencent.supersonic.knowledge.dictionary.DimValue2DictCommand; +import com.tencent.supersonic.knowledge.dictionary.DimValueInfo; +import com.tencent.supersonic.knowledge.persistence.dataobject.DictConfDO; +import com.tencent.supersonic.knowledge.persistence.dataobject.DictTaskDO; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; + +public class DictTaskConverter { + + private static String dateTimeFormatter = "yyyyMMddHHmmss"; + + public static DictTaskDO generateDimValueDictTaskPO(DimValue2DictCommand dimValue2DictCommend, User user) { + DictTaskDO taskPO = new DictTaskDO(); + Date createAt = new Date(); + String date = DateTimeFormatter.ofPattern(dateTimeFormatter) + .format(createAt.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); + String creator = Strings.isNullOrEmpty(user.getName()) ? "" : user.getName(); + String updateMode = dimValue2DictCommend.getUpdateMode().getValue(); + String name = String.format("DimValue_dic_%s_%s_%s", updateMode, creator, date); + taskPO.setName(name); + + taskPO.setCreatedAt(createAt); + taskPO.setCommand(JsonUtil.toString(dimValue2DictCommend)); + taskPO.setStatus(TaskStatusEnum.RUNNING.getCode()); + taskPO.setCreatedBy(creator); + + return taskPO; + } + + public static DictConfig dictConfPO2Config(DictConfDO dictConfDO) { + DictConfig dictConfig = new DictConfig(); + dictConfig.setDomainId(dictConfDO.getDomainId()); + List dimValueInfos = JsonUtil.toList(dictConfDO.getDimValueInfos(), DimValueInfo.class); + dictConfig.setDimValueInfoList(dimValueInfos); + return dictConfig; + } +} diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/FileHelper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/FileHelper.java similarity index 81% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/FileHelper.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/FileHelper.java index cff816c98..3ad816b90 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/FileHelper.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/FileHelper.java @@ -1,19 +1,19 @@ -package com.tencent.supersonic.knowledge.infrastructure.nlp; +package com.tencent.supersonic.knowledge.utils; import static com.hankcs.hanlp.HanLP.Config.CustomDictionaryPath; -import static com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper.FILE_SPILT; import com.hankcs.hanlp.dictionary.DynamicCustomDictionary; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class FileHelper { - private static final Logger LOGGER = LoggerFactory.getLogger(FileHelper.class); + public static final String FILE_SPILT = "/"; public static void deleteCacheFile(String[] path) throws IOException { @@ -25,9 +25,9 @@ public class FileHelper { for (File file : customSubFiles) { try { file.delete(); - LOGGER.info("customPath:{},delete cache file:{}", customPath, file); + log.info("customPath:{},delete cache file:{}", customPath, file); } catch (Exception e) { - LOGGER.error("delete " + file, e); + log.error("delete " + file, e); } } } @@ -70,7 +70,7 @@ public class FileHelper { } } - LOGGER.info("CustomDictionaryPath:{}", fileList); + log.info("CustomDictionaryPath:{}", fileList); CustomDictionaryPath = fileList.toArray(new String[0]); customDictionary.path = (CustomDictionaryPath == null || CustomDictionaryPath.length == 0) ? path : CustomDictionaryPath; diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HanlpHelper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/HanlpHelper.java similarity index 86% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HanlpHelper.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/HanlpHelper.java index 156c6977e..89987b103 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HanlpHelper.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/HanlpHelper.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.knowledge.infrastructure.nlp; +package com.tencent.supersonic.knowledge.utils; import static com.hankcs.hanlp.HanLP.Config.CustomDictionaryPath; @@ -7,30 +7,33 @@ import com.hankcs.hanlp.dictionary.CoreDictionary; import com.hankcs.hanlp.dictionary.DynamicCustomDictionary; import com.hankcs.hanlp.seg.Segment; import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.common.nlp.MapResult; -import com.tencent.supersonic.common.nlp.NatureType; -import com.tencent.supersonic.common.nlp.WordNature; +import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.dictionary.DictWord; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import com.tencent.supersonic.knowledge.dictionary.MapResult; +import com.tencent.supersonic.knowledge.dictionary.HadoopFileIOAdapter; +import com.tencent.supersonic.knowledge.service.SearchService; +import com.tencent.supersonic.knowledge.dictionary.MultiCustomDictionary; +import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; import org.springframework.util.ResourceUtils; /** * HanLP helper */ +@Slf4j public class HanlpHelper { public static final String FILE_SPILT = "/"; public static final String SPACE_SPILT = "#"; public static final String DICT_MAIN_FILE_NAME = "CustomDictionary.txt"; public static final String DICT_CLASS = "classes"; - private static final Logger LOGGER = LoggerFactory.getLogger(HanlpHelper.class); - public static volatile DynamicCustomDictionary CustomDictionary; + private static volatile DynamicCustomDictionary CustomDictionary; private static volatile Segment segment; static { @@ -38,7 +41,7 @@ public class HanlpHelper { try { resetHanlpConfig(); } catch (FileNotFoundException e) { - LOGGER.error("resetHanlpConfig error", e); + log.error("resetHanlpConfig error", e); } } @@ -76,7 +79,7 @@ public class HanlpHelper { */ public static boolean reloadCustomDictionary() throws IOException { - LOGGER.info("reloadCustomDictionary start"); + log.info("reloadCustomDictionary start"); final long startTime = System.currentTimeMillis(); @@ -93,10 +96,10 @@ public class HanlpHelper { FileHelper.resetCustomPath(getDynamicCustomDictionary()); } // 3.clear trie - Suggester.clear(); + SearchService.clear(); boolean reload = getDynamicCustomDictionary().reload(); - LOGGER.info("reloadCustomDictionary end ,cost:{},reload:{}", System.currentTimeMillis() - startTime, reload); + log.info("reloadCustomDictionary end ,cost:{},reload:{}", System.currentTimeMillis() - startTime, reload); return reload; } @@ -108,7 +111,7 @@ public class HanlpHelper { CustomDictionaryPath = Arrays.stream(CustomDictionaryPath).map(path -> hanlpPropertiesPath + FILE_SPILT + path) .toArray(String[]::new); - LOGGER.info("hanlpPropertiesPath:{},CustomDictionaryPath:{}", hanlpPropertiesPath, CustomDictionaryPath); + log.info("hanlpPropertiesPath:{},CustomDictionaryPath:{}", hanlpPropertiesPath, CustomDictionaryPath); HanLP.Config.CoreDictionaryPath = hanlpPropertiesPath + FILE_SPILT + HanLP.Config.BiGramDictionaryPath; HanLP.Config.CoreDictionaryTransformMatrixDictionaryPath = hanlpPropertiesPath + FILE_SPILT @@ -155,9 +158,9 @@ public class HanlpHelper { return ResourceUtils.getFile("classpath:hanlp.properties").getParent(); } - public static boolean addToCustomDictionary(WordNature wordNature) { - LOGGER.info("wordNature:{}", wordNature); - return getDynamicCustomDictionary().insert(wordNature.getWord(), wordNature.getNatureWithFrequency()); + public static boolean addToCustomDictionary(DictWord dictWord) { + log.info("dictWord:{}", dictWord); + return getDynamicCustomDictionary().insert(dictWord.getWord(), dictWord.getNatureWithFrequency()); } public static void transLetterOriginal(List mapResults) { @@ -178,7 +181,7 @@ public class HanlpHelper { public static List getTerms(String text) { return getSegment().seg(text.toLowerCase()).stream() - .filter(term -> term.getNature().startsWith(NatureType.NATURE_SPILT)) + .filter(term -> term.getNature().startsWith(DictWordType.NATURE_SPILT)) .collect(Collectors.toList()); } diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HdfsFileHelper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/HdfsFileHelper.java similarity index 74% rename from chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HdfsFileHelper.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/HdfsFileHelper.java index 48863fbf5..2d4943954 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HdfsFileHelper.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/HdfsFileHelper.java @@ -1,7 +1,6 @@ -package com.tencent.supersonic.knowledge.infrastructure.nlp; +package com.tencent.supersonic.knowledge.utils; import static com.hankcs.hanlp.HanLP.Config.CustomDictionaryPath; -import static com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper.FILE_SPILT; import com.hankcs.hanlp.dictionary.DynamicCustomDictionary; import com.hankcs.hanlp.utility.Predefine; @@ -9,20 +8,19 @@ import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; + +import lombok.extern.slf4j.Slf4j; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Hdfs File Helper */ +@Slf4j public class HdfsFileHelper { - private static final Logger LOGGER = LoggerFactory.getLogger(HdfsFileHelper.class); - /*** * delete cache file * @param path @@ -31,24 +29,24 @@ public class HdfsFileHelper { public static void deleteCacheFile(String[] path) throws IOException { FileSystem fs = FileSystem.get(URI.create(path[0]), new Configuration()); String cacheFilePath = path[0] + Predefine.BIN_EXT; - LOGGER.info("delete cache file:{}", cacheFilePath); + log.info("delete cache file:{}", cacheFilePath); try { fs.delete(new Path(cacheFilePath), false); } catch (Exception e) { - LOGGER.error("delete:" + cacheFilePath, e); + log.error("delete:" + cacheFilePath, e); } - int customBase = cacheFilePath.lastIndexOf(FILE_SPILT); - String customPath = cacheFilePath.substring(0, customBase) + FILE_SPILT + "*.bin"; + int customBase = cacheFilePath.lastIndexOf(FileHelper.FILE_SPILT); + String customPath = cacheFilePath.substring(0, customBase) + FileHelper.FILE_SPILT + "*.bin"; List fileList = getFileList(fs, new Path(customPath)); for (String file : fileList) { try { fs.delete(new Path(file), false); - LOGGER.info("delete cache file:{}", file); + log.info("delete cache file:{}", file); } catch (Exception e) { - LOGGER.error("delete " + file, e); + log.error("delete " + file, e); } } - LOGGER.info("fileList:{}", fileList); + log.info("fileList:{}", fileList); } /** @@ -61,11 +59,11 @@ public class HdfsFileHelper { String[] path = CustomDictionaryPath; FileSystem fs = FileSystem.get(URI.create(path[0]), new Configuration()); String cacheFilePath = path[0] + Predefine.BIN_EXT; - int customBase = cacheFilePath.lastIndexOf(FILE_SPILT); - String customPath = cacheFilePath.substring(0, customBase) + FILE_SPILT + "*.txt"; - LOGGER.info("customPath:{}", customPath); + int customBase = cacheFilePath.lastIndexOf(FileHelper.FILE_SPILT); + String customPath = cacheFilePath.substring(0, customBase) + FileHelper.FILE_SPILT + "*.txt"; + log.info("customPath:{}", customPath); List fileList = getFileList(fs, new Path(customPath)); - LOGGER.info("CustomDictionaryPath:{}", fileList); + log.info("CustomDictionaryPath:{}", fileList); CustomDictionaryPath = fileList.toArray(new String[0]); customDictionary.path = (CustomDictionaryPath == null || CustomDictionaryPath.length == 0) ? path : CustomDictionaryPath; diff --git a/chat/knowledge/src/main/resources/META-INF/spring.factories b/chat/knowledge/src/main/resources/META-INF/spring.factories index 6d4e71c08..68e94072d 100644 --- a/chat/knowledge/src/main/resources/META-INF/spring.factories +++ b/chat/knowledge/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ -com.tencent.supersonic.knowledge.domain.FileHandler=\ - com.tencent.supersonic.knowledge.domain.LocalFileHandler \ No newline at end of file +com.tencent.supersonic.knowledge.dictionary.FileHandler=\ + com.tencent.supersonic.knowledge.dictionary.LocalFileHandler \ No newline at end of file diff --git a/chat/knowledge/src/main/resources/mapper/DictConfMapper.xml b/chat/knowledge/src/main/resources/mapper/DictConfMapper.xml index 50541ac4c..7189d70ca 100644 --- a/chat/knowledge/src/main/resources/mapper/DictConfMapper.xml +++ b/chat/knowledge/src/main/resources/mapper/DictConfMapper.xml @@ -2,10 +2,10 @@ - + + type="com.tencent.supersonic.knowledge.persistence.dataobject.DictConfDO"> diff --git a/chat/knowledge/src/main/resources/mapper/DictTaskMapper.xml b/chat/knowledge/src/main/resources/mapper/DictTaskMapper.xml index e9b3b6918..2f26482a4 100644 --- a/chat/knowledge/src/main/resources/mapper/DictTaskMapper.xml +++ b/chat/knowledge/src/main/resources/mapper/DictTaskMapper.xml @@ -2,10 +2,10 @@ - + + type="com.tencent.supersonic.knowledge.persistence.dataobject.DictTaskDO"> diff --git a/checkstyle/checkstyle.xml b/checkstyle/checkstyle.xml new file mode 100644 index 000000000..47cd1044e --- /dev/null +++ b/checkstyle/checkstyle.xml @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/pom.xml b/common/pom.xml index 70397847c..f7440e463 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -129,6 +129,10 @@ calcite-core ${calcite.version} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + diff --git a/common/src/main/java/com/tencent/supersonic/common/nlp/ItemDO.java b/common/src/main/java/com/tencent/supersonic/common/nlp/ItemDO.java deleted file mode 100644 index df47bb072..000000000 --- a/common/src/main/java/com/tencent/supersonic/common/nlp/ItemDO.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.tencent.supersonic.common.nlp; - -import com.google.common.base.Objects; -import java.io.Serializable; -import lombok.Data; -import lombok.Getter; -import lombok.Setter; - -@Data -@Setter -@Getter -public class ItemDO implements Serializable { - - private Integer domain; - private Integer itemId; - private String name; - private String bizName; - private Long useCnt = 0L; - - public ItemDO() { - } - - public ItemDO(Integer domain, Integer itemId, String name, String bizName) { - this.domain = domain; - this.itemId = itemId; - this.name = name; - this.bizName = bizName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ItemDO itemDO = (ItemDO) o; - return Objects.equal(domain, itemDO.domain) && Objects.equal(itemId, - itemDO.itemId) && Objects.equal(name, itemDO.name) - && Objects.equal(bizName, itemDO.bizName) && Objects.equal( - useCnt, itemDO.useCnt); - } - - @Override - public int hashCode() { - return Objects.hashCode(domain, itemId, name, bizName, useCnt); - } -} diff --git a/common/src/main/java/com/tencent/supersonic/common/pojo/Aggregator.java b/common/src/main/java/com/tencent/supersonic/common/pojo/Aggregator.java index 7492543ca..e535de293 100644 --- a/common/src/main/java/com/tencent/supersonic/common/pojo/Aggregator.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/Aggregator.java @@ -1,6 +1,6 @@ package com.tencent.supersonic.common.pojo; -import com.tencent.supersonic.common.enums.AggOperatorEnum; +import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum; import java.util.List; import javax.validation.constraints.NotBlank; diff --git a/common/src/main/java/com/tencent/supersonic/common/constant/Constants.java b/common/src/main/java/com/tencent/supersonic/common/pojo/Constants.java similarity index 82% rename from common/src/main/java/com/tencent/supersonic/common/constant/Constants.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/Constants.java index 5d06e987b..3dc422c3e 100644 --- a/common/src/main/java/com/tencent/supersonic/common/constant/Constants.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/Constants.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.constant; +package com.tencent.supersonic.common.pojo; import java.util.regex.Pattern; @@ -41,7 +41,10 @@ public class Constants { public static final String DAY = "DAY"; public static final String DAY_FORMAT = "yyyy-MM-dd"; public static final String MONTH_FORMAT = "yyyy-MM"; + public static final String TIMES_FORMAT = "yyyy-MM-dd HH:mm:ss.S"; + public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String DAY_FORMAT_INT = "YYYYMMDD"; + public static final String MONTH_FORMAT_INT = "YYYYMM"; public static final String MONTH = "MONTH"; public static final String WEEK = "WEEK"; public static final String YEAR = "YEAR"; @@ -53,4 +56,10 @@ public class Constants { public static final String PAGESIZE_LOWER = "pageSize"; public static final String TRUE_LOWER = "true"; + public static final String NULL = "null"; + public static final Double MAX_SIMILARITY = 1.0d; + public static final String CONTEXT = "CONTEXT"; + public static final String BRACKETS_START = "["; + public static final String BRACKETS_END = "]"; + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DataFormat.java b/common/src/main/java/com/tencent/supersonic/common/pojo/DataFormat.java similarity index 70% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DataFormat.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/DataFormat.java index f2749f5d4..b4e23ce71 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DataFormat.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/DataFormat.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.common.pojo; import lombok.Data; diff --git a/common/src/main/java/com/tencent/supersonic/common/pojo/DateConf.java b/common/src/main/java/com/tencent/supersonic/common/pojo/DateConf.java index 9ebae3e5f..a3f0d292c 100644 --- a/common/src/main/java/com/tencent/supersonic/common/pojo/DateConf.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/DateConf.java @@ -2,8 +2,6 @@ package com.tencent.supersonic.common.pojo; import static java.time.LocalDate.now; -import com.tencent.supersonic.common.constant.Constants; - import java.util.ArrayList; import java.util.List; @@ -47,10 +45,10 @@ public class DateConf { public enum DateMode { /** * date mode - * 1 - between, continuous value, - * 2 - list discrete value, - * 3 - recent time units, - * 4 - advance time until data is available + * 1 - BETWEEN_CONTINUOUS, continuous static value, [startDate, endDate] + * 2 - LIST_DISCRETE, discrete static value, [dateList] + * 3 - RECENT_UNITS, dynamic time related to the actual available time of the element, [unit, period] + * 4 - AVAILABLE_TIME, dynamic time which guaranteed to query some data, [startDate, endDate] */ BETWEEN_CONTINUOUS, LIST_DISCRETE, RECENT_UNITS, AVAILABLE_TIME } @@ -75,4 +73,4 @@ public class DateConf { sb.append('}'); return sb.toString(); } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java b/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java index 4f05f1b30..9e8b70b36 100644 --- a/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java @@ -1,6 +1,6 @@ package com.tencent.supersonic.common.pojo; -import static com.tencent.supersonic.common.constant.Constants.ASC_UPPER; +import static com.tencent.supersonic.common.pojo.Constants.ASC_UPPER; import com.google.common.base.Objects; import javax.validation.constraints.NotBlank; diff --git a/common/src/main/java/com/tencent/supersonic/common/request/PageBaseReq.java b/common/src/main/java/com/tencent/supersonic/common/pojo/PageBaseReq.java similarity index 89% rename from common/src/main/java/com/tencent/supersonic/common/request/PageBaseReq.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/PageBaseReq.java index c8db4524c..0d20903ba 100644 --- a/common/src/main/java/com/tencent/supersonic/common/request/PageBaseReq.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/PageBaseReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.request; +package com.tencent.supersonic.common.pojo; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryAuthorization.java b/common/src/main/java/com/tencent/supersonic/common/pojo/QueryAuthorization.java similarity index 87% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryAuthorization.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/QueryAuthorization.java index 66eae2b85..b06b26768 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryAuthorization.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/QueryAuthorization.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.common.pojo; import java.util.List; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryColumn.java b/common/src/main/java/com/tencent/supersonic/common/pojo/QueryColumn.java similarity index 91% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryColumn.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/QueryColumn.java index 748f3f362..942ab3310 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryColumn.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/QueryColumn.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.common.pojo; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/RecordInfo.java b/common/src/main/java/com/tencent/supersonic/common/pojo/RecordInfo.java similarity index 96% rename from common/src/main/java/com/tencent/supersonic/common/util/RecordInfo.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/RecordInfo.java index 47160c564..a463977f3 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/RecordInfo.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/RecordInfo.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util; +package com.tencent.supersonic.common.pojo; import com.google.common.base.Objects; import java.util.Date; diff --git a/common/src/main/java/com/tencent/supersonic/common/result/ResultData.java b/common/src/main/java/com/tencent/supersonic/common/pojo/ResultData.java similarity index 94% rename from common/src/main/java/com/tencent/supersonic/common/result/ResultData.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/ResultData.java index 9191bb410..0314ec35c 100644 --- a/common/src/main/java/com/tencent/supersonic/common/result/ResultData.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/ResultData.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.result; +package com.tencent.supersonic.common.pojo; import lombok.Data; diff --git a/common/src/main/java/com/tencent/supersonic/common/result/ReturnCode.java b/common/src/main/java/com/tencent/supersonic/common/pojo/ReturnCode.java similarity index 91% rename from common/src/main/java/com/tencent/supersonic/common/result/ReturnCode.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/ReturnCode.java index e964fe11a..fa579a227 100644 --- a/common/src/main/java/com/tencent/supersonic/common/result/ReturnCode.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/ReturnCode.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.result; +package com.tencent.supersonic.common.pojo; public enum ReturnCode { SUCCESS(200, "success"), diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/AggOperatorEnum.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/AggOperatorEnum.java similarity index 86% rename from common/src/main/java/com/tencent/supersonic/common/enums/AggOperatorEnum.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/AggOperatorEnum.java index c4c3abd84..2852be869 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/AggOperatorEnum.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/AggOperatorEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum AggOperatorEnum { @@ -16,15 +16,17 @@ public enum AggOperatorEnum { PERCENTILE("PERCENTILE"), + RATIO_ROLL("RATIO_ROLL"), + RATIO_OVER("RATIO_OVER"), + UNKNOWN("UNKNOWN"); + private String operator; AggOperatorEnum(String operator) { this.operator = operator; } - private String operator; - public String getOperator() { return operator; } diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/AggregateTypeEnum.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/AggregateTypeEnum.java similarity index 88% rename from common/src/main/java/com/tencent/supersonic/common/enums/AggregateTypeEnum.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/AggregateTypeEnum.java index 5694a37c5..ad1907133 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/AggregateTypeEnum.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/AggregateTypeEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum AggregateTypeEnum { SUM, diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/ConfigMode.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/ConfigMode.java similarity index 91% rename from common/src/main/java/com/tencent/supersonic/common/enums/ConfigMode.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/ConfigMode.java index f1ccf7d4f..2549469e3 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/ConfigMode.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/ConfigMode.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum ConfigMode { diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/ErrorCode.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/ErrorCode.java similarity index 83% rename from common/src/main/java/com/tencent/supersonic/common/enums/ErrorCode.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/ErrorCode.java index 243117117..1a19b31be 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/ErrorCode.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/ErrorCode.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum ErrorCode { diff --git a/common/src/main/java/com/tencent/supersonic/common/pojo/enums/RatioOverType.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/RatioOverType.java new file mode 100644 index 000000000..2b58b7062 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/RatioOverType.java @@ -0,0 +1,21 @@ +package com.tencent.supersonic.common.pojo.enums; + +public enum RatioOverType { + DAY_ON_DAY("日环比"), + WEEK_ON_DAY("周同比"), + WEEK_ON_WEEK("周环比"), + MONTH_ON_WEEK("月同比"), + MONTH_ON_MONTH("月环比"), + YEAR_ON_MONTH("年同比"), + YEAR_ON_YEAR("年环比"); + + private String showName; + + RatioOverType(String showName) { + this.showName = showName; + } + + public String getShowName() { + return showName; + } +} diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/SensitiveLevelEnum.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/SensitiveLevelEnum.java similarity index 82% rename from common/src/main/java/com/tencent/supersonic/common/enums/SensitiveLevelEnum.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/SensitiveLevelEnum.java index 8a2146514..901f6ba90 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/SensitiveLevelEnum.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/SensitiveLevelEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum SensitiveLevelEnum { diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/SinkDbEnum.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/SinkDbEnum.java similarity index 91% rename from common/src/main/java/com/tencent/supersonic/common/enums/SinkDbEnum.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/SinkDbEnum.java index 9695b6143..072aec700 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/SinkDbEnum.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/SinkDbEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum SinkDbEnum { diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/StatusEnum.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/StatusEnum.java similarity index 95% rename from common/src/main/java/com/tencent/supersonic/common/enums/StatusEnum.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/StatusEnum.java index 0d68a6a02..478001c84 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/StatusEnum.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/StatusEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum StatusEnum { diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/TaskStatusEnum.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/TaskStatusEnum.java similarity index 95% rename from common/src/main/java/com/tencent/supersonic/common/enums/TaskStatusEnum.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/TaskStatusEnum.java index da1e72712..21e8861ca 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/TaskStatusEnum.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/TaskStatusEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum TaskStatusEnum { diff --git a/common/src/main/java/com/tencent/supersonic/common/enums/TypeEnums.java b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/TypeEnums.java similarity index 92% rename from common/src/main/java/com/tencent/supersonic/common/enums/TypeEnums.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/enums/TypeEnums.java index 99c851364..7f83e4fc1 100644 --- a/common/src/main/java/com/tencent/supersonic/common/enums/TypeEnums.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/enums/TypeEnums.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.enums; +package com.tencent.supersonic.common.pojo.enums; public enum TypeEnums { diff --git a/common/src/main/java/com/tencent/supersonic/common/exception/AccessException.java b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/AccessException.java similarity index 75% rename from common/src/main/java/com/tencent/supersonic/common/exception/AccessException.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/exception/AccessException.java index 96d69fc39..606984bf9 100644 --- a/common/src/main/java/com/tencent/supersonic/common/exception/AccessException.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/AccessException.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.exception; +package com.tencent.supersonic.common.pojo.exception; public class AccessException extends RuntimeException { diff --git a/common/src/main/java/com/tencent/supersonic/common/exception/CommonException.java b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/CommonException.java similarity index 78% rename from common/src/main/java/com/tencent/supersonic/common/exception/CommonException.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/exception/CommonException.java index 25ede0b8d..4a79d8ef4 100644 --- a/common/src/main/java/com/tencent/supersonic/common/exception/CommonException.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/CommonException.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.exception; +package com.tencent.supersonic.common.pojo.exception; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/common/src/main/java/com/tencent/supersonic/common/exception/InvalidArgumentException.java b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/InvalidArgumentException.java similarity index 77% rename from common/src/main/java/com/tencent/supersonic/common/exception/InvalidArgumentException.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/exception/InvalidArgumentException.java index 9bb3b0027..bc55e9bb1 100644 --- a/common/src/main/java/com/tencent/supersonic/common/exception/InvalidArgumentException.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/InvalidArgumentException.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.exception; +package com.tencent.supersonic.common.pojo.exception; public class InvalidArgumentException extends RuntimeException { diff --git a/common/src/main/java/com/tencent/supersonic/common/exception/InvalidPermissionException.java b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/InvalidPermissionException.java similarity index 77% rename from common/src/main/java/com/tencent/supersonic/common/exception/InvalidPermissionException.java rename to common/src/main/java/com/tencent/supersonic/common/pojo/exception/InvalidPermissionException.java index f094506a4..5ee97a4b4 100644 --- a/common/src/main/java/com/tencent/supersonic/common/exception/InvalidPermissionException.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/exception/InvalidPermissionException.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.exception; +package com.tencent.supersonic.common.pojo.exception; public class InvalidPermissionException extends RuntimeException { diff --git a/common/src/main/java/com/tencent/supersonic/common/util/mapper/BeanMapper.java b/common/src/main/java/com/tencent/supersonic/common/util/BeanMapper.java similarity index 95% rename from common/src/main/java/com/tencent/supersonic/common/util/mapper/BeanMapper.java rename to common/src/main/java/com/tencent/supersonic/common/util/BeanMapper.java index 95b162f21..2ee4c189c 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/mapper/BeanMapper.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/BeanMapper.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.mapper; +package com.tencent.supersonic.common.util; import java.beans.PropertyDescriptor; import java.util.HashSet; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/context/ContextUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/ContextUtils.java similarity index 97% rename from common/src/main/java/com/tencent/supersonic/common/util/context/ContextUtils.java rename to common/src/main/java/com/tencent/supersonic/common/util/ContextUtils.java index 81b1418e9..6fc04b817 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/context/ContextUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/ContextUtils.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.context; +package com.tencent.supersonic.common.util; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeansException; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/DateUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/DateUtils.java new file mode 100644 index 000000000..76efdad78 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/DateUtils.java @@ -0,0 +1,43 @@ +package com.tencent.supersonic.common.util; + +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +public class DateUtils { + + public static Integer currentYear(){ + Date date = new Date(); + SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd"); + String time=dateFormat.format(date).replaceAll("-",""); + int year = Integer.parseInt(time.substring(0,4)); + return year; + } + + public static DateTimeFormatter getDateFormatter(String date, String[] formats) { + for (int i = 0; i < formats.length; i++) { + String format = formats[i]; + SimpleDateFormat dateFormat = new SimpleDateFormat(format); + try { + dateFormat.parse(date); + return DateTimeFormatter.ofPattern(format); + } catch (Exception e) { + } + } + return DateTimeFormatter.ofPattern(formats[0]); + } + + public static DateTimeFormatter getTimeFormatter(String date, String[] formats) { + for (int i = 0; i < formats.length; i++) { + String format = formats[i]; + try { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); + LocalDateTime.parse(date,dateTimeFormatter); + return dateTimeFormatter; + } catch (Exception e) { + } + } + return DateTimeFormatter.ofPattern(formats[0]); + } +} diff --git a/common/src/main/java/com/tencent/supersonic/common/util/http/HttpClientResult.java b/common/src/main/java/com/tencent/supersonic/common/util/HttpClientResult.java similarity index 95% rename from common/src/main/java/com/tencent/supersonic/common/util/http/HttpClientResult.java rename to common/src/main/java/com/tencent/supersonic/common/util/HttpClientResult.java index f05e72972..694a81995 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/http/HttpClientResult.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/HttpClientResult.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.http; +package com.tencent.supersonic.common.util; import java.io.Serializable; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/http/HttpClientUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/HttpClientUtils.java similarity index 99% rename from common/src/main/java/com/tencent/supersonic/common/util/http/HttpClientUtils.java rename to common/src/main/java/com/tencent/supersonic/common/util/HttpClientUtils.java index b39f31e93..a9cc50825 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/http/HttpClientUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/HttpClientUtils.java @@ -1,7 +1,6 @@ -package com.tencent.supersonic.common.util.http; +package com.tencent.supersonic.common.util; -import com.tencent.supersonic.common.util.retry.RetryUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -231,7 +230,7 @@ public class HttpClientUtils { public static HttpClientResult doPost(String url, Map header, Map params) { return doPost(url, null, null, header, params); } - + /** * Send a get request; Without request header and request parameters * @@ -537,7 +536,6 @@ public class HttpClientUtils { HttpPost httpPost = null; try { -// File uploadFile = ResourceUtils.getFile("classpath:" + fullFilePath); File uploadFile = new File(fullFilePath); inputStream = new FileInputStream(uploadFile); @@ -641,9 +639,8 @@ public class HttpClientUtils { public static final String METHOD_NAME = "DELETE"; - @Override - public String getMethod() { - return METHOD_NAME; + public HttpDeleteWithBody() { + super(); } public HttpDeleteWithBody(final String uri) { @@ -656,8 +653,9 @@ public class HttpClientUtils { setURI(uri); } - public HttpDeleteWithBody() { - super(); + @Override + public String getMethod() { + return METHOD_NAME; } } diff --git a/common/src/main/java/com/tencent/supersonic/common/util/json/JsonUtil.java b/common/src/main/java/com/tencent/supersonic/common/util/JsonUtil.java similarity index 99% rename from common/src/main/java/com/tencent/supersonic/common/util/json/JsonUtil.java rename to common/src/main/java/com/tencent/supersonic/common/util/JsonUtil.java index a5a0b7d9a..eb1cdf24e 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/json/JsonUtil.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/JsonUtil.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.json; +package com.tencent.supersonic.common.util; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonParser; @@ -19,6 +19,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; + +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -49,6 +51,8 @@ public class JsonUtil { objectMapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true); // Java8日期时间类支持 objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); + + objectMapper.registerModule(new JavaTimeModule()); } /** diff --git a/common/src/main/java/com/tencent/supersonic/common/util/coder/MD5Util.java b/common/src/main/java/com/tencent/supersonic/common/util/MD5Util.java similarity index 97% rename from common/src/main/java/com/tencent/supersonic/common/util/coder/MD5Util.java rename to common/src/main/java/com/tencent/supersonic/common/util/MD5Util.java index 70d33b656..63c56ab1e 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/coder/MD5Util.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/MD5Util.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.coder; +package com.tencent.supersonic.common.util; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/mybatis/PageUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/PageUtils.java similarity index 88% rename from common/src/main/java/com/tencent/supersonic/common/util/mybatis/PageUtils.java rename to common/src/main/java/com/tencent/supersonic/common/util/PageUtils.java index fb8a49c28..5d86a382c 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/mybatis/PageUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/PageUtils.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.mybatis; +package com.tencent.supersonic.common.util; import com.github.pagehelper.Page; import com.github.pagehelper.PageInfo; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/retry/RetryUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/RetryUtils.java similarity index 95% rename from common/src/main/java/com/tencent/supersonic/common/util/retry/RetryUtils.java rename to common/src/main/java/com/tencent/supersonic/common/util/RetryUtils.java index 381a748b0..03dc0392e 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/retry/RetryUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/RetryUtils.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.retry; +package com.tencent.supersonic.common.util; import java.util.function.Supplier; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/context/S2ThreadContext.java b/common/src/main/java/com/tencent/supersonic/common/util/S2ThreadContext.java similarity index 88% rename from common/src/main/java/com/tencent/supersonic/common/util/context/S2ThreadContext.java rename to common/src/main/java/com/tencent/supersonic/common/util/S2ThreadContext.java index bbfc71158..b3ba60dda 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/context/S2ThreadContext.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/S2ThreadContext.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.context; +package com.tencent.supersonic.common.util; import com.alibaba.ttl.TransmittableThreadLocal; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContext.java b/common/src/main/java/com/tencent/supersonic/common/util/ThreadContext.java similarity index 78% rename from common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContext.java rename to common/src/main/java/com/tencent/supersonic/common/util/ThreadContext.java index 74b152401..7399e787a 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContext.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/ThreadContext.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.context; +package com.tencent.supersonic.common.util; import lombok.Builder; @@ -6,8 +6,6 @@ import lombok.Data; import lombok.ToString; import java.util.Map; -import java.util.Map; - @Builder @ToString @Data diff --git a/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContextConfig.java b/common/src/main/java/com/tencent/supersonic/common/util/ThreadContextConfig.java similarity index 83% rename from common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContextConfig.java rename to common/src/main/java/com/tencent/supersonic/common/util/ThreadContextConfig.java index a7a24c99a..5b47dfc2b 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContextConfig.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/ThreadContextConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.context; +package com.tencent.supersonic.common.util; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/yaml/YamlUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/YamlUtils.java similarity index 98% rename from common/src/main/java/com/tencent/supersonic/common/util/yaml/YamlUtils.java rename to common/src/main/java/com/tencent/supersonic/common/util/YamlUtils.java index bec6c2c59..f32eba300 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/yaml/YamlUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/YamlUtils.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.common.util.yaml; +package com.tencent.supersonic.common.util; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; diff --git a/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParseUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParseUtils.java index 46393e517..383ce3584 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParseUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParseUtils.java @@ -19,6 +19,7 @@ import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.util.SqlString; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; /** * sql parse utils @@ -66,6 +67,8 @@ public class SqlParseUtils { case ORDER_BY: handlerOrderBy(sqlNode, sqlParserInfo); break; + default: + break; } } @@ -91,31 +94,50 @@ public class SqlParseUtils { * @param sqlParserInfo */ private static void handlerSelect(SqlNode select, SqlParserInfo sqlParserInfo) { + List allFields = sqlParserInfo.getAllFields(); SqlSelect sqlSelect = (SqlSelect) select; SqlNodeList selectList = sqlSelect.getSelectList(); - List allFields = sqlParserInfo.getAllFields(); - selectList.getList().forEach(list -> { Set selectFields = handlerField(list); sqlParserInfo.getSelectFields().addAll(selectFields); - allFields.addAll(selectFields); }); String tableName = handlerFrom(sqlSelect.getFrom()); sqlParserInfo.setTableName(tableName); + Set selectFields = handlerSelectField(sqlSelect); + allFields.addAll(selectFields); + } + + private static Set handlerSelectField(SqlSelect sqlSelect) { + Set results = new HashSet<>(); + if (sqlSelect.getFrom() instanceof SqlBasicCall) { + Set formFields = handlerField(sqlSelect.getFrom()); + results.addAll(formFields); + } + + sqlSelect.getSelectList().getList().forEach(list -> { + Set selectFields = handlerField(list); + results.addAll(selectFields); + }); + if (sqlSelect.hasWhere()) { - allFields.addAll(handlerField(sqlSelect.getWhere())); + Set whereFields = handlerField(sqlSelect.getWhere()); + results.addAll(whereFields); } if (sqlSelect.hasOrderBy()) { - allFields.addAll(handlerField(sqlSelect.getOrderList())); + Set orderByFields = handlerField(sqlSelect.getOrderList()); + results.addAll(orderByFields); } SqlNodeList group = sqlSelect.getGroup(); if (group != null) { group.forEach(groupField -> { - allFields.addAll(handlerField(groupField)); + Set groupByFields = handlerField(groupField); + results.addAll(groupByFields); + }); } + return results; } /** @@ -135,6 +157,8 @@ public class SqlParseUtils { SqlNode sqlNode = sqlBasicCall.getOperandList().get(0); SqlSelect sqlSelect = (SqlSelect) sqlNode; return handlerFrom(sqlSelect.getFrom()); + default: + break; } return ""; } @@ -155,7 +179,14 @@ public class SqlParseUtils { break; case IDENTIFIER: SqlIdentifier sqlIdentifier = (SqlIdentifier) field; - fields.add(sqlIdentifier.getSimple()); + String simpleName = sqlIdentifier.getSimple(); + if (StringUtils.isNotEmpty(simpleName)) { + fields.add(simpleName); + } + break; + case SELECT: + SqlSelect sqlSelect = (SqlSelect) field; + fields.addAll(handlerSelectField(sqlSelect)); break; default: if (field instanceof SqlBasicCall) { @@ -254,6 +285,8 @@ public class SqlParseUtils { SqlOrderBy sqlOrderBy = (SqlOrderBy) sqlNode; SqlSelect query = (SqlSelect) sqlOrderBy.query; return query.getSelectList(); + default: + break; } return null; } diff --git a/common/src/test/java/com/tencent/supersonic/common/util/calcite/SqlParseUtilsTest.java b/common/src/test/java/com/tencent/supersonic/common/util/calcite/SqlParseUtilsTest.java index 21bbd8bb9..ed65a10ce 100644 --- a/common/src/test/java/com/tencent/supersonic/common/util/calcite/SqlParseUtilsTest.java +++ b/common/src/test/java/com/tencent/supersonic/common/util/calcite/SqlParseUtilsTest.java @@ -18,28 +18,35 @@ class SqlParseUtilsTest { void addAliasToSql() throws SqlParseException { String addAliasToSql = SqlParseUtils.addAliasToSql( - "select sum(pv) from ( select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1"); + "select sum(pv) from ( select * from t_1 " + + "where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1"); - Assert.assertTrue(addAliasToSql.toLowerCase().contains("as `pv`")); + Assert.assertTrue(addAliasToSql.toLowerCase().contains("as pv")); } @Test void addFieldToSql() throws SqlParseException { String addFieldToSql = SqlParseUtils.addFieldsToSql( - "select pv from ( select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1", + "select pv from ( select * from t_1 " + + "where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1", Collections.singletonList("uv")); Assert.assertTrue(addFieldToSql.toLowerCase().contains("uv")); - addFieldToSql = SqlParseUtils.addFieldsToSql( - "select uv from ( select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1 order by play_count desc limit 10", + "select uv from ( select * from t_1 " + + "where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1 " + + "order by play_count desc limit 10", Collections.singletonList("pv")); Assert.assertTrue(addFieldToSql.toLowerCase().contains("pv")); addFieldToSql = SqlParseUtils.addFieldsToSql( - "select uv from ( select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1 where user_id = '张三' order by play_count desc limit 10", + "select uv from " + + "( select * from t_1 where sys_imp_date >= '2023-07-07' " + + " and sys_imp_date <= '2023-07-07' " + + ") as t_sub_1 " + + "where user_id = '张三' order by play_count desc limit 10", Collections.singletonList("pv")); Assert.assertTrue(addFieldToSql.toLowerCase().contains("pv")); } @@ -49,7 +56,9 @@ class SqlParseUtilsTest { void getSqlParseInfo() { SqlParserInfo sqlParserInfo = SqlParseUtils.getSqlParseInfo( - "select pv from ( select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1 "); + "select pv from " + + "( select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' )" + + " as t_sub_1 "); Assert.assertTrue(sqlParserInfo.getTableName().equalsIgnoreCase("t_1")); @@ -59,13 +68,11 @@ class SqlParseUtilsTest { Assert.assertTrue(collect.contains("pv")); Assert.assertTrue(!collect.contains("uv")); - List selectFields = sqlParserInfo.getSelectFields().stream().map(field -> field.toLowerCase()) .collect(Collectors.toList()); Assert.assertTrue(selectFields.contains("pv")); Assert.assertTrue(!selectFields.contains("uv")); - sqlParserInfo = SqlParseUtils.getSqlParseInfo( "select uv from t_1 order by play_count desc limit 10"); @@ -82,10 +89,13 @@ class SqlParseUtilsTest { Assert.assertTrue(!selectFields.contains("pv")); Assert.assertTrue(!selectFields.contains("play_count")); - - sqlParserInfo = SqlParseUtils.getSqlParseInfo( - "select uv from ( select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' ) as t_sub_1 where user_id = '1' order by play_count desc limit 10"); + "select uv from " + + "( " + + " select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' " + + ") as t_sub_1 " + + "where user_id = '1' order by play_count desc limit 10" + ); Assert.assertTrue(sqlParserInfo.getTableName().equalsIgnoreCase("t_1")); collect = sqlParserInfo.getAllFields().stream().map(field -> field.toLowerCase()) @@ -103,4 +113,18 @@ class SqlParseUtilsTest { Assert.assertTrue(!selectFields.contains("play_count")); } + + @Test + void getWhereFieldTest() { + SqlParserInfo sqlParserInfo = SqlParseUtils.getSqlParseInfo( + "select uv from " + + " ( " + + " select * from t_1 where sys_imp_date >= '2023-07-07' and sys_imp_date <= '2023-07-07' and user_id = 22 " + + " ) as t_sub_1 " + + " where user_name_元 = 'zhangsan' order by play_count desc limit 10" + ); + List collect = sqlParserInfo.getAllFields().stream().map(field -> field.toLowerCase()) + .collect(Collectors.toList()); + Assert.assertTrue(collect.contains("user_id")); + } } \ No newline at end of file diff --git a/docs/images/chat_config.png b/docs/images/chat_config.png new file mode 100644 index 000000000..73107b1d1 Binary files /dev/null and b/docs/images/chat_config.png differ diff --git a/docs/images/database.png b/docs/images/database.png new file mode 100644 index 000000000..f32dd2384 Binary files /dev/null and b/docs/images/database.png differ diff --git a/docs/images/datasource_base_info.png b/docs/images/datasource_base_info.png new file mode 100644 index 000000000..7b8797e41 Binary files /dev/null and b/docs/images/datasource_base_info.png differ diff --git a/docs/images/datasource_create.png b/docs/images/datasource_create.png new file mode 100644 index 000000000..b8da1b650 Binary files /dev/null and b/docs/images/datasource_create.png differ diff --git a/docs/images/datasource_extend_info.png b/docs/images/datasource_extend_info.png new file mode 100644 index 000000000..dfe83b293 Binary files /dev/null and b/docs/images/datasource_extend_info.png differ diff --git a/docs/images/datasource_list.png b/docs/images/datasource_list.png new file mode 100644 index 000000000..fc9c6b860 Binary files /dev/null and b/docs/images/datasource_list.png differ diff --git a/docs/images/datasource_sql.png b/docs/images/datasource_sql.png new file mode 100644 index 000000000..aea8be911 Binary files /dev/null and b/docs/images/datasource_sql.png differ diff --git a/docs/images/detail_default.png b/docs/images/detail_default.png new file mode 100644 index 000000000..30e337194 Binary files /dev/null and b/docs/images/detail_default.png differ diff --git a/docs/images/detail_entity.png b/docs/images/detail_entity.png new file mode 100644 index 000000000..edf9127eb Binary files /dev/null and b/docs/images/detail_entity.png differ diff --git a/docs/images/dimension_create.png b/docs/images/dimension_create.png new file mode 100644 index 000000000..46f3ad6d6 Binary files /dev/null and b/docs/images/dimension_create.png differ diff --git a/docs/images/dimension_list.png b/docs/images/dimension_list.png new file mode 100644 index 000000000..6a86726a3 Binary files /dev/null and b/docs/images/dimension_list.png differ diff --git a/docs/images/domain.png b/docs/images/domain.png new file mode 100644 index 000000000..cfc4cc0cd Binary files /dev/null and b/docs/images/domain.png differ diff --git a/docs/images/metric_base_info.png b/docs/images/metric_base_info.png new file mode 100644 index 000000000..33968b331 Binary files /dev/null and b/docs/images/metric_base_info.png differ diff --git a/docs/images/metric_default.png b/docs/images/metric_default.png new file mode 100644 index 000000000..a3a031af6 Binary files /dev/null and b/docs/images/metric_default.png differ diff --git a/docs/images/metric_list.png b/docs/images/metric_list.png new file mode 100644 index 000000000..2998dcc9e Binary files /dev/null and b/docs/images/metric_list.png differ diff --git a/docs/images/metric_sql_info.png b/docs/images/metric_sql_info.png new file mode 100644 index 000000000..350ff8df0 Binary files /dev/null and b/docs/images/metric_sql_info.png differ diff --git a/docs/images/visibility_dim_value.png b/docs/images/visibility_dim_value.png new file mode 100644 index 000000000..34a18792b Binary files /dev/null and b/docs/images/visibility_dim_value.png differ diff --git a/docs/images/visibility_dim_value_show.png b/docs/images/visibility_dim_value_show.png new file mode 100644 index 000000000..84d69a56a Binary files /dev/null and b/docs/images/visibility_dim_value_show.png differ diff --git a/docs/images/visibility_item.png b/docs/images/visibility_item.png new file mode 100644 index 000000000..7e9d8acf5 Binary files /dev/null and b/docs/images/visibility_item.png differ diff --git a/docs/userguides/chat_config_cn.md b/docs/userguides/chat_config_cn.md new file mode 100644 index 000000000..9b5e4c1fe --- /dev/null +++ b/docs/userguides/chat_config_cn.md @@ -0,0 +1,67 @@ +English | [中文](chat_config_cn.md) +# 问答设置 + +问答设置旨在进一步降低用户通过自然语言方式获取数据的门槛。在超音数平台首页, 单击顶部菜单栏的**问答设置**, 然后选择特定的**主题域**, 便可对特定主题域进行问答设置, 当前支持对指标场景和明细场景分别进行设置。 + + + +## 1. 指标场景 + +指标场景指基于特定的维度, 进行指标的分析, 这会涉及到 group by 的聚合计算, 比如"按活跃区域查询播放量", 会基于维度**活跃区域**, 查看指标**播放量**在不同活跃区域的聚合数据。 + +### 1.1 问答可见 + +* 如果希望在指标场景中设置特定维度/指标的可见性, 通过以下3步即可实现: + +1. 在左侧列表中选择需要可见的维度和指标; +2. 点击中间的 **>** 标志, 可将其状态由不可见转变为可见; +3. 点击底部**完成**按钮。 + + + +* 如果还希望实现**维度值的联想**, 通过以下步骤即可实现: + +1. 对特定的维度, 勾选**维度值可见**选项; +2. 如果有高级设置的需要, 可点击**可见维度值设置**[可选的], 高级设置可对该维度的维度值设置黑名单、白名单、sql规则等 ; +3. 点击底部**完成**按钮。 + + + +设置后, 系统会启动后台任务, 计算对应维度的维度值, 并写入到问答知识库中, 当用户输入不完整的歌手名时, 系统会根据知识库中的数据进行维度值联想。 + + + +### 1.2 默认设置 + +指标场景的默认设置分为指标和时间范围两个选项: + + + +- **指标:** 在指标场景时, 如果用户查询中没有指定指标, 系统会用此处设置的指标进行查询; +- **时间范围:** 在指标场景时, 如果用户查询中没有指定时间范围, 如"查询流行歌手的播放量", 系统会用此处设置的时间选项进行查询, 最终查询为"查询流行歌手的最近7天的播放量"。 + +## 2. 明细场景 + +指标场景指仅仅查询原始明细数据, 不会涉及到聚合计算, 比如"周杰伦的代表作"。 + +### 2.1 实体 + +实体是指数据表中的唯一标识, 类似于主键。 一般而言,一个主题域中只有一个实体。如维度歌手名可以作为艺人库实体的唯一标识。 + +实体只在明细场景中存在,指标场景不存在实体。当系统识别出当前查询是针对实体展开的,那么就可确定当前是一个明细查询的场景。实体设置主要分为实体别名和唯一标识两部分: + +- **实体别名:** 可用别名来简化实体查询, 使查询更简单; +- **唯一标识:** 一个实体的唯一标识, 一般是维度。 + + + +### 2.2 问答可见 + +具体配置含义可参考 *1.1 指标场景问答可见* + +### 2.3 默认设置 + +- **维度/指标:** 在明细场景时, 如果用户查询中没有指定维度/指标, 系统会用此处设置的维度/指标进行查询, 如输入"周杰伦", 系统会将周杰伦作为维度歌手名的筛选条件, 然后查询出设置的维度/指标数据; +- **时间范围:** 用户可根据数据特定的时效性, 设置时间点, 如果用户明细查询中不涉及时间信息, 则会用此处配置的时间进行查询。 + + diff --git a/docs/userguides/semantic_user_guide_cn.md b/docs/userguides/semantic_user_guide_cn.md new file mode 100644 index 000000000..f9e335956 --- /dev/null +++ b/docs/userguides/semantic_user_guide_cn.md @@ -0,0 +1,108 @@ +# 语义建模 + +### **简介** + +语义建模是使用超音数的第一步。在这个模块中,它可以连接上你的数据库引擎,并通过简单方便的方式来帮助你将物理数据建模为数据源、维度和指标等逻辑概念。建模完成后,你就可以在问答中通过自然语言的方式来和你的物理数据交互啦~ + +### **问题示例** +为了帮助你更好地理解建模的过程,我们通过一个问题示例来进行介绍: 超音数本身作为一个产品,那么如何用语义建模来统计它的埋点访问数据呢?比如超音数在一段时间内的访问用户数是多少?这些用户的访问次数和停留时长是怎样的?这些用户来自哪些部门?这些用户看了哪些页面?分别看了多少次?等我们建模完成,这些问题的答案也就浮出水面了。 + + +### **1. 创建一个主题域** + +在超音数中,主题域是一个非常重要的概念,它存在并作用于系统的每一个地方。简单来说,超音数引导用户把数据划分为一个个主题域,用户在创建主题域之后,可以在这个主题域中进行数据源,维度,指标等建模。如图1-1所示,为了统计超音数的埋点访问情况,我们创建了一个叫"超音数"的主题域作为示例: + +
+ +

图1-1 主题域示例

+
+ +### **2. 创建一个数据库连接** + +创建一个数据库连接主要分为三个步骤, +1. 填写连接信息 +2. 点击测试连接,若连接测试通过,则可点击保存。否则,返回步骤1 +3. 点击保存。 + +如图2-1所示,由于超音数的埋点访问数据被存放在H2数据库中,因此我们创建了一个H2数据库实例作为例子。除了H2数据库以外,我们还支持MySQL,ClickHouse等多种常见数据库。 + +
+ +

图2-1 数据库连接示例

+
+ +### **3. 创建数据源** +连接上数据库之后,我们首先需要把物理数据抽象为一个个数据源。在超音数中,数据源是对数据库中数据的一种逻辑层面上的抽象,它既可以直接指代一张物理表,也可以由一段SQL逻辑表示而成。数据源中涉及的字段可被指定为维度或者度量,而这些维度和度量又可以衍生出更复杂的维度和指标。如图3-1,超音数提供了两种创建数据源方式。 +
+ +

图3-1 数据源创建方式

+
+ +其中,**快速创建** 可以直接指定一张物理表来把它创建为数据源,而**SQL脚本** 则提供了更为灵活的数据源创建方式,我们可以通过写一条逻辑SQL来把它指定为数据源 + +如图3-2为通过**SQL脚本**的方式创建数据源,首先我们写一条SQL来表达我们的数据源逻辑,然后点击运行,就可以看到这条SQL查询出来的数据,校验数据无误之后,我们可以点击生成数据源 +
+ +

图3-2 SQL脚本

+
+ +如图3-3所示,点击生成数据源之后,需要我们填写一些基本信息,如数据源名称和描述,填写完成之后,点击下一步 +
+ +

图3-3 数据源基本信息

+
+ +如图3-4所示,填写完基本信息之后,需要填写一些字段信息,把数据源的字段指定为维度或者度量,其中日期和主键/外键为特殊的维度。 +**维度**主要用于筛选和分组 +**度量**主要标识数值类型字段,用来进行聚合计算 +**日期字段**主要用于标识,方便问答进行数据查询。 +**主键/外键**则用于不同数据源之间的连接字段,若多个不同数据源存在相同的主键外键,则可以进行多数据源连接 + +
+ +

图3-4 数据源字段信息

+
+ +把字段指定为维度/度量之后,还可选择是否勾选**快速创建**单选框。若**勾选**,则会直接把选中的维度/度量批量创建到维度/指标列表。若**不勾选**,但字段已被选定为维度/度量,该字段虽然不会直接被创建到维度/指标列表,但是后续在创建衍生维度/指标的时候也可作为表达式中的字段被用上。如图3-5所示,为我们创建的3个数据源示例,分别为超音数用户停留时长统计,访问次数和访问人数统计,用户部门统计。 + +
+ +

图3-5 数据源列表

+
+ + +### **4. 创建维度** +如图4-1,为刚刚创建数据源时,通过勾选**快速创建**按钮创建出来的维度。分别为用户名,用户所在的部门,用户浏览过的超音数页面。 +
+ +

图4-1 维度列表

+
+ +若我们需要更复杂的维度,如我们需要根据页面来划分模块,那我们可以点击创建按钮来创建一个更复杂的维度。如图4-2所示 +
+ +

图4-2 维度创建

+
+ +### **5. 创建指标** +和维度类似,如图5-1为通过**快速创建**按钮创建出来的指标,分别为访问超音数的次数,人数和停留时长。这几个指标都可以在用户、部门 、页面等分组粒度上进行计算。 +
+ +

图5-1 指标列表

+
+ +若我们需要统计口径更复杂的指标,如用户的平均停留时长,可以通过点击**创建指标**按钮来进行创建,如图5-2和5-3所示: + +
+ +

图5-2 指标基本信息

+
+ +如图5-3, 展示了人均停留时长这个指标依赖的度量信息,分别依赖了访问人数和停留时长这两个度量(分别来自于停留时长统计和PVUV统计两个数据源,均在度量名称前加上数据源名称作为前缀加以区分),并通过在表达中将它们相除,计算出人均停留时长。 +
+ +

图5-3 指标表达式信息

+
+ +### **总结** +到此为止,我们就成功把超音数的访问统计数据建模成了相关的数据源、维度和指标。通过在问答中直接对这些维度和指标进行提问,就可以回答我们在介绍开头提到的那些问题啦! diff --git a/launchers/chat/src/main/resources/META-INF/spring.factories b/launchers/chat/src/main/resources/META-INF/spring.factories index c32fc28ea..b61047efd 100644 --- a/launchers/chat/src/main/resources/META-INF/spring.factories +++ b/launchers/chat/src/main/resources/META-INF/spring.factories @@ -1,23 +1,24 @@ com.tencent.supersonic.chat.api.component.SchemaMapper=\ - com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper, \ - com.tencent.supersonic.chat.application.mapper.DatabaseSchemaMapper, \ - com.tencent.supersonic.chat.application.mapper.QueryFilterMapper + com.tencent.supersonic.chat.mapper.HanlpDictMapper, \ + com.tencent.supersonic.chat.mapper.FuzzyNameMapper, \ + com.tencent.supersonic.chat.mapper.QueryFilterMapper com.tencent.supersonic.chat.api.component.SemanticParser=\ - com.tencent.supersonic.chat.application.parser.DomainSemanticParser, \ - com.tencent.supersonic.chat.application.parser.TimeSemanticParser, \ - com.tencent.supersonic.chat.application.parser.AggregateSemanticParser, \ - com.tencent.supersonic.chat.application.parser.LLMSemanticParser + com.tencent.supersonic.chat.parser.rule.QueryModeParser, \ + com.tencent.supersonic.chat.parser.rule.ContextInheritParser, \ + com.tencent.supersonic.chat.parser.rule.TimeRangeParser, \ + com.tencent.supersonic.chat.parser.rule.AggregateTypeParser, \ + com.tencent.supersonic.chat.parser.function.FunctionBasedParser com.tencent.supersonic.chat.api.component.SemanticLayer=\ - com.tencent.supersonic.chat.infrastructure.semantic.RemoteSemanticLayerImpl + com.tencent.supersonic.knowledge.semantic.RemoteSemanticLayer -com.tencent.supersonic.chat.application.query.QuerySelector=\ - com.tencent.supersonic.chat.application.query.HeuristicQuerySelector +com.tencent.supersonic.chat.query.QuerySelector=\ + com.tencent.supersonic.chat.query.HeuristicQuerySelector -com.tencent.supersonic.chat.application.parser.DomainResolver=\ - com.tencent.supersonic.chat.application.parser.HeuristicDomainResolver +com.tencent.supersonic.chat.parser.function.DomainResolver=\ + com.tencent.supersonic.chat.parser.function.HeuristicDomainResolver com.tencent.supersonic.auth.authentication.domain.interceptor.AuthenticationInterceptor=\ com.tencent.supersonic.auth.authentication.domain.interceptor.DefaultAuthenticationInterceptor diff --git a/launchers/chat/src/main/resources/db/chat-data-h2.sql b/launchers/chat/src/main/resources/db/chat-data-h2.sql index f997a6e74..65155e3e4 100644 --- a/launchers/chat/src/main/resources/db/chat-data-h2.sql +++ b/launchers/chat/src/main/resources/db/chat-data-h2.sql @@ -5,9 +5,11 @@ insert into s2_user (id, `name`, password, display_name, email) values (4, 'lucy -- insert into s2_chat_config (`id` ,`domain_id` ,`default_metrics`,`visibility`,`entity_info` ,`dictionary_info`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (1,1,'[{"metricId":1,"unit":7,"period":"DAY"}]','{"blackDimIdList":[],"blackMetricIdList":[]}','{"entityIds":[2],"names":["用户","用户姓名"],"detailData":{"dimensionIds":[1,2],"metricIds":[2]}}','[{"itemId":1,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":2,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":3,"type":"DIMENSION","blackList":[],"isDictInfo":true}]','2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); insert into s2_chat_config (`id` ,`domain_id` ,`chat_detail_config`,`chat_agg_config`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) -values (1,1,'{"visibility":{"blackDimIdList":[1],"blackMetricIdList":[2]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":1,"period":"DAY"},"entity":null}', -'{"visibility":{"blackDimIdList":[3],"blackMetricIdList":[3]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":1,"period":"DAY"}}', -'2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); +values (1,1, + '{"visibility":{"blackDimIdList":[1],"blackMetricIdList":[2]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":7,"period":"DAY"},"entity":null}', + '{"visibility":{"blackDimIdList":[3],"blackMetricIdList":[3]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":7,"period":"DAY"}}', + '[{"question":"超音数访问次数"},{"question":"超音数访问人数"},{"question":"超音数按部门访问次数"}]', + '2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); insert into s2_chat_config (`id` ,`domain_id` ,`chat_detail_config`,`chat_agg_config`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (2,2,'{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":7,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[4,5,6,7],"metricIds":[4],"unit":7,"period":"DAY"},"entity":{"entityId":1,"names":["歌手","艺人"]}}', '{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":7,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[4,5,6,7],"metricIds":[4],"unit":7,"period":"DAY"}}', @@ -25,3 +27,6 @@ insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`, insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(4, '2023-06-10 10:41:18.589','alice 访问次数','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `pv` FROM ( SELECT `sys_imp_date` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` FROM ( SELECT `user_name` , `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_b825` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","pv":2},{"sys_imp_date":"2023-06-04","pv":2},{"sys_imp_date":"2023-06-06","pv":2},{"sys_imp_date":"2023-06-07","pv":2},{"sys_imp_date":"2023-06-08","pv":5},{"sys_imp_date":"2023-06-09","pv":2}]}',0,''); insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(5, '2023-06-10 10:41:48.211','停留时长','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(6, '2023-06-10 10:42:02.184','访问','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); + +insert into s2_plugin (id, type, domain, pattern, parse_mode, name, created_at, created_by, updated_at, updated_by, config) VALUES (1, 'WEB_PAGE', 1, '访问情况', 'EMBEDDING_RECALL', '访问情况', '2023-06-11 19:36:47', 'admin', '2023-06-21 15:26:46', 'admin', '{"params":{"487C128A":"2"}, "url":"www.test.com"}'); +insert into s2_plugin (id, type, domain, pattern, parse_mode, name, created_at, created_by, updated_at, updated_by, config) VALUES (2, 'DSL', null, '', 'FUNCTION_CALL', '访问情况', '2023-06-11 19:36:47', 'admin', '2023-06-21 15:26:46', 'admin', ''); diff --git a/launchers/chat/src/main/resources/db/chat-schema-h2.sql b/launchers/chat/src/main/resources/db/chat-schema-h2.sql index f603eb4aa..2842efa02 100644 --- a/launchers/chat/src/main/resources/db/chat-schema-h2.sql +++ b/launchers/chat/src/main/resources/db/chat-schema-h2.sql @@ -42,6 +42,7 @@ CREATE TABLE IF NOT EXISTS `s2_chat_config` ( `domain_id` INT DEFAULT NULL , `chat_detail_config` varchar(655) , `chat_agg_config` varchar(655) , + `recommended_questions` varchar(1500) , `created_at` TIMESTAMP NOT NULL , `updated_at` TIMESTAMP NOT NULL , `created_by` varchar(100) NOT NULL , @@ -113,5 +114,19 @@ create table s2_user ); COMMENT ON TABLE s2_user IS 'user information table'; - +CREATE TABLE IF NOT EXISTS `s2_plugin` +( + `id` INT AUTO_INCREMENT, + `type` varchar(50) NULL, + `domain` varchar(100) NULL, + `pattern` varchar(500) NULL, + `parse_mode` varchar(100) NULL, + `name` varchar(100) NULL, + `created_at` TIMESTAMP NULL, + `created_by` varchar(100) null, + `updated_at` TIMESTAMP NULL, + `updated_by` varchar(100) NULL, + `config` LONGVARCHAR NULL, + PRIMARY KEY (`id`) +); COMMENT ON TABLE s2_plugin IS 'plugin information table'; diff --git a/launchers/common/src/main/java/com/tencent/supersonic/advice/ResponseAdvice.java b/launchers/common/src/main/java/com/tencent/supersonic/advice/ResponseAdvice.java index 793c2a440..f33237c57 100644 --- a/launchers/common/src/main/java/com/tencent/supersonic/advice/ResponseAdvice.java +++ b/launchers/common/src/main/java/com/tencent/supersonic/advice/ResponseAdvice.java @@ -1,7 +1,7 @@ package com.tencent.supersonic.advice; import com.fasterxml.jackson.databind.ObjectMapper; -import com.tencent.supersonic.common.result.ResultData; +import com.tencent.supersonic.common.pojo.ResultData; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; diff --git a/launchers/common/src/main/java/com/tencent/supersonic/advice/RestExceptionHandler.java b/launchers/common/src/main/java/com/tencent/supersonic/advice/RestExceptionHandler.java index f919346bb..5b62f20ee 100644 --- a/launchers/common/src/main/java/com/tencent/supersonic/advice/RestExceptionHandler.java +++ b/launchers/common/src/main/java/com/tencent/supersonic/advice/RestExceptionHandler.java @@ -1,10 +1,10 @@ package com.tencent.supersonic.advice; -import com.tencent.supersonic.common.exception.AccessException; -import com.tencent.supersonic.common.exception.CommonException; -import com.tencent.supersonic.common.exception.InvalidPermissionException; -import com.tencent.supersonic.common.result.ResultData; -import com.tencent.supersonic.common.result.ReturnCode; +import com.tencent.supersonic.common.pojo.exception.AccessException; +import com.tencent.supersonic.common.pojo.exception.CommonException; +import com.tencent.supersonic.common.pojo.exception.InvalidPermissionException; +import com.tencent.supersonic.common.pojo.ResultData; +import com.tencent.supersonic.common.pojo.ReturnCode; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; diff --git a/launchers/semantic/pom.xml b/launchers/semantic/pom.xml index 206fc7505..9d7f850af 100644 --- a/launchers/semantic/pom.xml +++ b/launchers/semantic/pom.xml @@ -33,7 +33,7 @@ com.tencent.supersonic - semantic-core + semantic-model ${project.version} diff --git a/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql b/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql index bc98b4f9e..8d2e0d290 100644 --- a/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql +++ b/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql @@ -14,6 +14,7 @@ CREATE TABLE IF NOT EXISTS `s2_domain` ( `is_open` TINYINT DEFAULT NULL , -- whether the domain is public `viewer` varchar(3000) DEFAULT NULL , -- domain available users `view_org` varchar(3000) DEFAULT NULL , -- domain available organization + `entity` varchar(500) DEFAULT NULL , -- domain entity info PRIMARY KEY (`id`) ); COMMENT ON TABLE s2_domain IS 'domain basic information'; @@ -24,6 +25,7 @@ CREATE TABLE `s2_database` ( `domain_id` INT NOT NULL , `name` varchar(255) NOT NULL , `description` varchar(500) DEFAULT NULL , + `version` varchar(64) DEFAULT NULL , `type` varchar(20) NOT NULL , -- type: mysql,clickhouse,tdw `config` varchar(655) NOT NULL , `created_at` TIMESTAMP NOT NULL , @@ -109,6 +111,7 @@ CREATE TABLE IF NOT EXISTS `s2_dimension` ( `semantic_type` varchar(20) NOT NULL, -- semantic type: DATE, ID, CATEGORY `alias` varchar(500) DEFAULT NULL, `default_values` varchar(500) DEFAULT NULL, + `dim_value_maps` varchar(500) DEFAULT NULL, PRIMARY KEY (`id`) ); COMMENT ON TABLE s2_dimension IS 'dimension information table'; diff --git a/launchers/standalone/pom.xml b/launchers/standalone/pom.xml index 665faab73..0a82f3708 100644 --- a/launchers/standalone/pom.xml +++ b/launchers/standalone/pom.xml @@ -55,7 +55,7 @@ com.tencent.supersonic - semantic-core + semantic-model ${project.version} diff --git a/launchers/standalone/src/main/java/com/tencent/supersonic/ConfigureDemo.java b/launchers/standalone/src/main/java/com/tencent/supersonic/ConfigureDemo.java new file mode 100644 index 000000000..43ad1e99a --- /dev/null +++ b/launchers/standalone/src/main/java/com/tencent/supersonic/ConfigureDemo.java @@ -0,0 +1,63 @@ +package com.tencent.supersonic; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.service.ChatService; +import com.tencent.supersonic.chat.service.QueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ConfigureDemo implements ApplicationListener { + @Autowired + private QueryService queryService; + @Autowired + private ChatService chatService; + private User user = User.getFakeUser(); + + public void addSampleChats()throws Exception { + chatService.addChat(user, "样例对话1"); + + QueryRequest queryRequest = new QueryRequest(); + queryRequest.setQueryText("超音数 访问次数"); + queryRequest.setChatId(1); + queryRequest.setUser(User.getFakeUser()); + queryService.executeQuery(queryRequest); + + queryRequest.setQueryText("按部门统计"); + queryService.executeQuery(queryRequest); + + queryRequest.setQueryText("查询近30天"); + queryService.executeQuery(queryRequest); + } + + public void addSampleChats2() throws Exception { + chatService.addChat(user, "样例对话2"); + + QueryRequest queryRequest = new QueryRequest(); + queryRequest.setChatId(2); + queryRequest.setUser(User.getFakeUser()); + queryRequest.setQueryText("alice 停留时长"); + queryService.executeQuery(queryRequest); + + queryRequest.setQueryText("对比alice和lucy的访问次数"); + queryService.executeQuery(queryRequest); + + queryRequest.setQueryText("访问次数最高的部门"); + queryService.executeQuery(queryRequest); + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { + try { + addSampleChats(); + addSampleChats2(); + } catch (Exception e) { + log.error("Failed to add sample chats"); + } + } +} diff --git a/launchers/standalone/src/main/java/com/tencent/supersonic/StandaloneLauncher.java b/launchers/standalone/src/main/java/com/tencent/supersonic/StandaloneLauncher.java index 0356d5a94..cb3c96d6e 100644 --- a/launchers/standalone/src/main/java/com/tencent/supersonic/StandaloneLauncher.java +++ b/launchers/standalone/src/main/java/com/tencent/supersonic/StandaloneLauncher.java @@ -6,9 +6,6 @@ import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfigurat import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.scheduling.annotation.EnableScheduling; -/** - * StandaloneLauncher - **/ @SpringBootApplication(scanBasePackages = {"com.tencent.supersonic"}, exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) @EnableScheduling diff --git a/launchers/standalone/src/main/resources/META-INF/spring.factories b/launchers/standalone/src/main/resources/META-INF/spring.factories index 1219927d9..4130a3f2c 100644 --- a/launchers/standalone/src/main/resources/META-INF/spring.factories +++ b/launchers/standalone/src/main/resources/META-INF/spring.factories @@ -1,23 +1,25 @@ com.tencent.supersonic.chat.api.component.SchemaMapper=\ - com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper, \ - com.tencent.supersonic.chat.application.mapper.DatabaseSchemaMapper, \ - com.tencent.supersonic.chat.application.mapper.QueryFilterMapper + com.tencent.supersonic.chat.mapper.HanlpDictMapper, \ + com.tencent.supersonic.chat.mapper.FuzzyNameMapper, \ + com.tencent.supersonic.chat.mapper.QueryFilterMapper com.tencent.supersonic.chat.api.component.SemanticParser=\ - com.tencent.supersonic.chat.application.parser.DomainSemanticParser, \ - com.tencent.supersonic.chat.application.parser.TimeSemanticParser, \ - com.tencent.supersonic.chat.application.parser.AggregateSemanticParser, \ - com.tencent.supersonic.chat.application.parser.LLMSemanticParser + com.tencent.supersonic.chat.parser.rule.QueryModeParser, \ + com.tencent.supersonic.chat.parser.rule.ContextInheritParser, \ + com.tencent.supersonic.chat.parser.rule.TimeRangeParser, \ + com.tencent.supersonic.chat.parser.rule.AggregateTypeParser, \ + com.tencent.supersonic.chat.parser.embedding.EmbeddingBasedParser, \ + com.tencent.supersonic.chat.parser.function.FunctionBasedParser com.tencent.supersonic.chat.api.component.SemanticLayer=\ - com.tencent.supersonic.chat.infrastructure.semantic.LocalSemanticLayerImpl + com.tencent.supersonic.knowledge.semantic.LocalSemanticLayer -com.tencent.supersonic.chat.application.query.QuerySelector=\ - com.tencent.supersonic.chat.application.query.HeuristicQuerySelector +com.tencent.supersonic.chat.query.QuerySelector=\ + com.tencent.supersonic.chat.query.HeuristicQuerySelector -com.tencent.supersonic.chat.application.parser.DomainResolver=\ - com.tencent.supersonic.chat.application.parser.HeuristicDomainResolver +com.tencent.supersonic.chat.parser.function.DomainResolver=\ + com.tencent.supersonic.chat.parser.function.HeuristicDomainResolver com.tencent.supersonic.auth.authentication.domain.interceptor.AuthenticationInterceptor=\ com.tencent.supersonic.auth.authentication.domain.interceptor.DefaultAuthenticationInterceptor diff --git a/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_2_7.txt b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_2_7.txt new file mode 100644 index 000000000..6699a0fc8 --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_2_7.txt @@ -0,0 +1,9 @@ +周杰伦 _2_7 9000 +周深 _2_7 8000 +周传雄 _2_7 7000 +周华建 _2_7 6000 +陈奕迅 _2_7 8000 +林俊杰 _2_7 7000 +张碧晨 _2_7 7000 +程响 _2_7 7000 +Taylor#Swift _2_7 7000 \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/db/data-h2.sql b/launchers/standalone/src/main/resources/db/data-h2.sql index 138f1f438..b09845661 100644 --- a/launchers/standalone/src/main/resources/db/data-h2.sql +++ b/launchers/standalone/src/main/resources/db/data-h2.sql @@ -1,34 +1,25 @@ --- chat data +-- sample user insert into s2_user (id, `name`, password, display_name, email) values (1, 'admin','admin','admin','admin@xx.com'); insert into s2_user (id, `name`, password, display_name, email) values (2, 'jack','123456','jack','jack@xx.com'); insert into s2_user (id, `name`, password, display_name, email) values (3, 'tom','123456','tom','tom@xx.com'); insert into s2_user (id, `name`, password, display_name, email) values (4, 'lucy','123456','lucy','lucy@xx.com'); --insert into s2_chat_config (`id` ,`domain_id` ,`default_metrics`,`visibility`,`entity_info` ,`dictionary_info`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (1,1,'[{"metricId":1,"unit":7,"period":"DAY"}]','{"blackDimIdList":[],"blackMetricIdList":[]}','{"entityIds":[2],"names":["用户","用户姓名"],"detailData":{"dimensionIds":[1,2],"metricIds":[2]}}','[{"itemId":1,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":2,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":3,"type":"DIMENSION","blackList":[],"isDictInfo":true}]','2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); +insert into s2_chat_config (`id` ,`domain_id` ,`chat_detail_config`,`chat_agg_config`, `recommended_questions`, `created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) +values (1,1, + '{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":7,"period":"DAY"},"entity":null}', + '{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":7,"period":"DAY"}}', + '[{"question":"超音数访问次数"},{"question":"超音数访问人数"},{"question":"超音数按部门访问次数"}]', + '2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); insert into s2_chat_config (`id` ,`domain_id` ,`chat_detail_config`,`chat_agg_config`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) -values (1,1,'{"visibility":{"blackDimIdList":[1],"blackMetricIdList":[2]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":1,"period":"DAY"},"entity":null}', -'{"visibility":{"blackDimIdList":[3],"blackMetricIdList":[3]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":1,"period":"DAY"}}', -'2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); -insert into s2_chat_config (`id` ,`domain_id` ,`chat_detail_config`,`chat_agg_config`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) -values (2,2,'{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":7,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[4,5,6,7],"metricIds":[4],"unit":7,"period":"DAY"},"entity":{"entityId":1,"names":["歌手","艺人"]}}', - '{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":7,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[4,5,6,7],"metricIds":[4],"unit":7,"period":"DAY"}}', - '2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); +values (2,2, + '{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":7,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[4,5,6,7],"metricIds":[4],"unit":7,"period":"DAY"},"entity":{"entityId":7,"names":["歌手","艺人"]}}', + '{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":7,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[4,5,6,7],"metricIds":[4],"unit":7,"period":"DAY"}}', + '2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); -insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (1, '超音数访问统计','2023-06-10 10:00:52.495','2023-06-10 10:00:52','admin','您好,欢迎使用内容智能小Q','0','0'); -insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (2, '用户访问统计','2023-06-10 10:01:04.528','2023-06-10 10:01:04','admin','您好,欢迎使用内容智能小Q','0','0'); +insert into s2_plugin (id, `type`, `domain`, pattern, parse_mode, `name`, created_at, created_by, updated_at, updated_by, config) VALUES (1, 'WEB_PAGE', 1, '访问情况', 'EMBEDDING_RECALL', '访问情况', '2023-06-11 19:36:47', 'admin', '2023-06-21 15:26:46', 'admin', '{"params":{"487C128A":"2"}, "url":"www.test.com"}'); -insert into s2_chat_context (chat_id, modified_at , `user`, `query_text`, `semantic_parse` ,ext_data) VALUES(1, '2023-06-10 10:40:49.877', 'admin', '访问', '{"queryMode":"METRIC_ORDERBY","aggType":"NONE","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"nativeQuery":false}', 'admin'); -insert into s2_chat_context (chat_id, modified_at , `user`, `query_text`, `semantic_parse` ,ext_data) VALUES(2, '2023-06-10 10:42:02.184', 'null', '访问', '{"queryMode":"METRIC_ORDERBY","aggType":"NONE","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"nativeQuery":false}', 'null'); - -insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(1, '2023-06-10 10:39:55.178', '超音数 访问次数', 'admin',0,1,'{"queryMode":"METRIC_DOMAIN","querySql":"SELECT `sys_imp_date` , `pv` FROM ( SELECT `sys_imp_date` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` FROM ( SELECT `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_f370` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_DOMAIN","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","pv":11},{"sys_imp_date":"2023-06-04","pv":14},{"sys_imp_date":"2023-06-05","pv":1},{"sys_imp_date":"2023-06-06","pv":19},{"sys_imp_date":"2023-06-07","pv":18},{"sys_imp_date":"2023-06-08","pv":24},{"sys_imp_date":"2023-06-09","pv":23}]}',0,''); -insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(2, '2023-06-10 10:40:12.259', '按页面', 'admin',0,1,'{"queryMode":"METRIC_ORDERBY","querySql":"SELECT `sys_imp_date` , `page` , `pv` FROM ( SELECT `sys_imp_date` , `page` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` , `page` FROM ( SELECT `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` , `page` AS `page` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_ecf5` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` , `page` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"页面","type":"VARCHAR","nameEn":"page","showType":"CATEGORY","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_ORDERBY","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","page":"p1","pv":2},{"sys_imp_date":"2023-06-03","page":"p2","pv":3},{"sys_imp_date":"2023-06-03","page":"p3","pv":2},{"sys_imp_date":"2023-06-03","page":"p4","pv":1},{"sys_imp_date":"2023-06-03","page":"p5","pv":3},{"sys_imp_date":"2023-06-04","page":"p1","pv":3},{"sys_imp_date":"2023-06-04","page":"p2","pv":1},{"sys_imp_date":"2023-06-04","page":"p3","pv":2},{"sys_imp_date":"2023-06-04","page":"p4","pv":4},{"sys_imp_date":"2023-06-04","page":"p5","pv":4}]}',0,''); -insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(3, '2023-06-10 10:40:49.877', '访问', 'admin',0,1,'{"queryMode":"METRIC_ORDERBY","querySql":"SELECT `sys_imp_date` , `page` , `uv` , `pv` FROM ( SELECT `sys_imp_date` , `page` , `s2_pv_uv_statis_uv` AS `uv` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT COUNT ( DISTINCT `s2_pv_uv_statis_uv` ) AS `s2_pv_uv_statis_uv` , SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` , `page` FROM ( SELECT `uv` AS `s2_pv_uv_statis_uv` , `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` , `page` AS `page` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_022c` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` , `page` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"页面","type":"VARCHAR","nameEn":"page","showType":"CATEGORY","authorized":true},{"name":"访问人数","type":"BIGINT","nameEn":"uv","showType":"NUMBER","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_ORDERBY","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","page":"p1","uv":2,"pv":2},{"sys_imp_date":"2023-06-03","page":"p2","uv":3,"pv":3},{"sys_imp_date":"2023-06-03","page":"p3","uv":2,"pv":2},{"sys_imp_date":"2023-06-03","page":"p4","uv":1,"pv":1},{"sys_imp_date":"2023-06-03","page":"p5","uv":3,"pv":3},{"sys_imp_date":"2023-06-04","page":"p1","uv":2,"pv":3},{"sys_imp_date":"2023-06-04","page":"p2","uv":1,"pv":1},{"sys_imp_date":"2023-06-04","page":"p3","uv":2,"pv":2},{"sys_imp_date":"2023-06-04","page":"p4","uv":3,"pv":4},{"sys_imp_date":"2023-06-04","page":"p5","uv":3,"pv":4}]}',0,''); -insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(4, '2023-06-10 10:41:18.589','alice 访问次数','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `pv` FROM ( SELECT `sys_imp_date` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` FROM ( SELECT `user_name` , `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_b825` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","pv":2},{"sys_imp_date":"2023-06-04","pv":2},{"sys_imp_date":"2023-06-06","pv":2},{"sys_imp_date":"2023-06-07","pv":2},{"sys_imp_date":"2023-06-08","pv":5},{"sys_imp_date":"2023-06-09","pv":2}]}',0,''); -insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(5, '2023-06-10 10:41:48.211','停留时长','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); -insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(6, '2023-06-10 10:42:02.184','访问','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); - - --- semantic data +-- sample models insert into s2_database (id, domain_id , `name`, description, `type` ,config ,created_at ,created_by ,updated_at ,updated_by) VALUES(1, 1, 'H2数据实例', '', 'h2', '{"password":"semantic","url":"jdbc:h2:mem:semantic;DATABASE_TO_UPPER=false","userName":"root"}', '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin'); insert into s2_database (id, domain_id , `name`, description, `type` ,config ,created_at ,created_by ,updated_at ,updated_by) VALUES(2, 2, 'H2数据实例', '', 'h2', '{"password":"semantic","url":"jdbc:h2:mem:semantic;DATABASE_TO_UPPER=false","userName":"root"}', '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin'); insert into s2_datasource (id , domain_id, `name`, biz_name, description, database_id ,datasource_detail, created_at, created_by, updated_at, updated_by ) VALUES(1, 1, '停留时长统计', 's2_stay_time_statis', '停留时长统计', 1, '{"dimensions":[{"bizName":"imp_date","dateFormat":"yyyy-MM-dd","expr":"imp_date","isCreateDimension":0,"type":"time","typeParams":{"isPrimary":"true","timeGranularity":"day"}},{"bizName":"page","dateFormat":"yyyy-MM-dd","expr":"page","isCreateDimension":0,"type":"categorical"}],"identifiers":[{"bizName":"user_name","name":"用户名","type":"primary"}],"measures":[{"agg":"sum","bizName":"s2_stay_time_statis_stay_hours","expr":"stay_hours","isCreateMetric":1,"name":"停留时长"}],"queryType":"sql_query","sqlQuery":"SELECT imp_date, page,user_name,stay_hours FROM s2_stay_time_statis"}', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); @@ -38,7 +29,7 @@ insert into s2_datasource (id , domain_id, `name`, biz_name, description, da insert into s2_datasource_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(1, 1, 1, 2, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); insert into s2_datasource_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(2, 1, 1, 3, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); insert into s2_datasource_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(3, 1, 2, 3, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); -insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(1, 1, 3, '部门', 'department', '部门', 1, 0, 'categorical', NULL, 'department', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type, dim_value_maps) VALUES(1, 1, 3, '部门', 'department', '部门', 1, 0, 'categorical', NULL, 'department', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY', '[{"alias":["人力资源","人力"],"bizName":"人力资源","techName":"HR"},{"alias":["营销","销售"],"bizName":"营销部门","techName":"sales"}]'); insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(2, 1, 1, '用户名', 'user_name', '用户名', 1, 0, 'primary', NULL, 'user_name', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(3, 1, 2, '页面', 'page', '页面', 1, 2, 'categorical', NULL, 'page', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(4, 2, 4, '活跃区域', 'act_area', '活跃区域', 1, 2, 'categorical', NULL, 'act_area', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); @@ -47,12 +38,12 @@ insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, descr insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(7, 2, 4, '歌手名', 'singer_name', '歌手名', 1, 2, 'categorical', NULL, 'singer_name', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); insert into s2_domain (id, `name`, biz_name, parent_id, status, created_at, created_by, updated_at, updated_by, `admin`, admin_org, is_open, viewer, view_org) VALUES(1, '超音数', 'supersonic', 0, 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', 'admin', '', 0, 'admin,tom,jack', 'admin' ); insert into s2_domain (id, `name`, biz_name, parent_id, status, created_at, created_by, updated_at, updated_by, `admin`, admin_org, is_open, viewer, view_org) VALUES(2, '艺人库', 'singer', 0, 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', 'admin', '', 0, 'admin,tom,jack', 'admin' ); -insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(1, 1, '停留时长', 'stay_hours', '停留时长', 1, 2, 'expr', '{"expr":"s2_stay_time_statis_stay_hours","measures":[{"agg":"sum","expr":"stay_hours","isCreateMetric":1,"datasourceId":1,"bizName":"s2_stay_time_statis_stay_hours","name":"s2_stay_time_statis_stay_hours"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); -insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(2, 1, '访问次数', 'pv', '访问次数', 1, 0, 'expr', ' {"expr":"s2_pv_uv_statis_pv","measures":[{"agg":"sum","bizName":"s2_pv_uv_statis_pv","datasourceId":2,"expr":"pv","isCreateMetric":1,"name":"s2_pv_uv_statis_pv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); -insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(3, 1, '访问人数', 'uv', '访问人数', 1, 0, 'expr', ' {"expr":"s2_pv_uv_statis_uv","measures":[{"agg":"count_distinct","bizName":"s2_pv_uv_statis_uv","datasourceId":2,"expr":"uv","isCreateMetric":1,"name":"s2_pv_uv_statis_uv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); -insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(4, 2, '播放量', 'js_play_cnt', '播放量', 1, 2, 'expr', '{"expr":"music_js_play_cnt","measures":[{"agg":"sum","expr":"js_play_cnt","isCreateMetric":1,"datasourceId":4,"bizName":"music_js_play_cnt","name":"music_js_play_cnt"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); -insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(5, 2, '下载量', 'down_cnt', '下载量', 1, 0, 'expr', ' {"expr":"music_down_cnt","measures":[{"agg":"sum","bizName":"music_down_cnt","datasourceId":4,"expr":"down_cnt","isCreateMetric":1,"name":"music_down_cnt"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); -insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(6, 2, '收藏量', 'favor_cnt', '收藏量', 1, 0, 'expr', ' {"expr":"music_favor_cnt","measures":[{"agg":"sum","bizName":"music_favor_cnt","datasourceId":4,"expr":"favor_cnt","isCreateMetric":1,"name":"music_favor_cnt"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(1, 1, '停留时长', 'stay_hours', '停留时长', 1, 2, 'ATOMIC', '{"expr":"s2_stay_time_statis_stay_hours","measures":[{"agg":"sum","expr":"stay_hours","isCreateMetric":1,"datasourceId":1,"bizName":"s2_stay_time_statis_stay_hours","name":"s2_stay_time_statis_stay_hours"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(2, 1, '访问次数', 'pv', '访问次数', 1, 0, 'ATOMIC', ' {"expr":"s2_pv_uv_statis_pv","measures":[{"agg":"sum","bizName":"s2_pv_uv_statis_pv","datasourceId":2,"expr":"pv","isCreateMetric":1,"name":"s2_pv_uv_statis_pv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(3, 1, '访问人数', 'uv', '访问人数', 1, 0, 'ATOMIC', ' {"expr":"s2_pv_uv_statis_uv","measures":[{"agg":"count_distinct","bizName":"s2_pv_uv_statis_uv","datasourceId":2,"expr":"uv","isCreateMetric":1,"name":"s2_pv_uv_statis_uv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(4, 2, '播放量', 'js_play_cnt', '播放量', 1, 2, 'ATOMIC', '{"expr":"music_js_play_cnt","measures":[{"agg":"sum","expr":"js_play_cnt","isCreateMetric":1,"datasourceId":4,"bizName":"music_js_play_cnt","name":"music_js_play_cnt"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(5, 2, '下载量', 'down_cnt', '下载量', 1, 0, 'ATOMIC', ' {"expr":"music_down_cnt","measures":[{"agg":"sum","bizName":"music_down_cnt","datasourceId":4,"expr":"down_cnt","isCreateMetric":1,"name":"music_down_cnt"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(6, 2, '收藏量', 'favor_cnt', '收藏量', 1, 0, 'ATOMIC', ' {"expr":"music_favor_cnt","measures":[{"agg":"sum","bizName":"music_favor_cnt","datasourceId":4,"expr":"favor_cnt","isCreateMetric":1,"name":"music_favor_cnt"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); insert into s2_available_date_info(`item_id` ,`type` ,`date_format` ,`start_date` ,`end_date` ,`unavailable_date` ,`created_at` ,`created_by` ,`updated_at` ,`updated_by` ) values (1, 'dimension', 'yyyy-MM-dd', DATEADD('DAY', -28, CURRENT_DATE()), DATEADD('DAY', -1, CURRENT_DATE()), '[]', '2023-06-01', 'admin', '2023-06-01', 'admin'); @@ -66,6 +57,7 @@ values (1, '{"domainId":"1","name":"admin-permission","groupId":1,"authRules":[{ insert into s2_auth_groups (group_id, config) values (2, '{"domainId":"1","name":"tom_sales_permission","groupId":2,"authRules":[{"metrics":["stay_hours"],"dimensions":["page"]}],"dimensionFilters":["department in (''sales'')"],"dimensionFilterDescription":"开通 tom sales部门权限", "authorizedUsers":["tom"],"authorizedDepartmentIds":[]}'); +-- sample data INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), '周杰伦', '中国','青花瓷','流行',1000000,1000000,1000000); INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -5, CURRENT_DATE()), '周杰伦', '中国','青花瓷','流行',1000000,1000000,1000000); INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), '周杰伦', '中国','青花瓷','流行',1000000,1000000,1000000); diff --git a/launchers/standalone/src/main/resources/db/schema-h2.sql b/launchers/standalone/src/main/resources/db/schema-h2.sql index 5bc3bac12..a5ffde8e6 100644 --- a/launchers/standalone/src/main/resources/db/schema-h2.sql +++ b/launchers/standalone/src/main/resources/db/schema-h2.sql @@ -44,6 +44,7 @@ CREATE TABLE IF NOT EXISTS `s2_chat_config` ( `domain_id` INT DEFAULT NULL , `chat_detail_config` varchar(655) , `chat_agg_config` varchar(655) , + `recommended_questions` varchar(1500) , `created_at` TIMESTAMP NOT NULL , `updated_at` TIMESTAMP NOT NULL , `created_by` varchar(100) NOT NULL , @@ -117,6 +118,7 @@ CREATE TABLE IF NOT EXISTS `s2_domain` ( `is_open` TINYINT DEFAULT NULL , -- whether the domain is public `viewer` varchar(3000) DEFAULT NULL , -- domain available users `view_org` varchar(3000) DEFAULT NULL , -- domain available organization + `entity` varchar(500) DEFAULT NULL , -- domain entity info PRIMARY KEY (`id`) ); COMMENT ON TABLE s2_domain IS 'domain basic information'; @@ -127,6 +129,7 @@ CREATE TABLE `s2_database` ( `domain_id` INT NOT NULL , `name` varchar(255) NOT NULL , `description` varchar(500) DEFAULT NULL , + `version` varchar(64) DEFAULT NULL , `type` varchar(20) NOT NULL , -- type: mysql,clickhouse,tdw `config` varchar(655) NOT NULL , `created_at` TIMESTAMP NOT NULL , @@ -201,6 +204,7 @@ CREATE TABLE IF NOT EXISTS `s2_dimension` ( `semantic_type` varchar(20) NOT NULL, -- semantic type: DATE, ID, CATEGORY `alias` varchar(500) DEFAULT NULL, `default_values` varchar(500) DEFAULT NULL, + `dim_value_maps` varchar(500) DEFAULT NULL, PRIMARY KEY (`id`) ); COMMENT ON TABLE s2_dimension IS 'dimension information table'; @@ -310,6 +314,23 @@ CREATE TABLE IF NOT EXISTS `s2_available_date_info` ( COMMENT ON TABLE s2_dimension IS 'dimension information table'; +CREATE TABLE IF NOT EXISTS `s2_plugin` +( + `id` INT AUTO_INCREMENT, + `type` varchar(50) NULL, + `domain` varchar(100) NULL, + `pattern` varchar(500) NULL, + `parse_mode` varchar(100) NULL, + `name` varchar(100) NULL, + `created_at` TIMESTAMP NULL, + `created_by` varchar(100) null, + `updated_at` TIMESTAMP NULL, + `updated_by` varchar(100) NULL, + `config` LONGVARCHAR NULL, + PRIMARY KEY (`id`) +); COMMENT ON TABLE s2_plugin IS 'plugin information table'; + + -------demo for semantic and chat CREATE TABLE IF NOT EXISTS `s2_user_department` ( `user_name` varchar(200) NOT NULL, diff --git a/launchers/standalone/src/main/resources/db/schema-mysql.sql b/launchers/standalone/src/main/resources/db/schema-mysql.sql new file mode 100644 index 000000000..b89ae203f --- /dev/null +++ b/launchers/standalone/src/main/resources/db/schema-mysql.sql @@ -0,0 +1,301 @@ +create table supersonic_sit.s2_auth_groups +( + group_id int not null + primary key, + config varchar(2048) null +) + collate = utf8mb4_unicode_ci; + +create table supersonic_sit.s2_available_date_info +( + id int auto_increment + primary key, + item_id int not null, + type varchar(255) not null, + date_format varchar(64) not null, + start_date varchar(64) null, + end_date varchar(64) null, + unavailable_date text null, + created_at timestamp default CURRENT_TIMESTAMP not null, + created_by varchar(100) not null, + updated_at timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP, + updated_by varchar(100) not null, + status int default 0 null +) + collate = utf8mb4_unicode_ci; + +create table supersonic_sit.s2_chat +( + chat_id bigint(8) auto_increment + primary key, + chat_name varchar(100) null, + create_time datetime null, + last_time datetime null, + creator varchar(30) null, + last_question varchar(200) null, + is_delete int(2) default 0 null comment 'is deleted', + is_top int(2) default 0 null comment 'is top' +) + charset = utf8; + +create table supersonic_sit.s2_chat_config +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `domain_id` bigint(20) DEFAULT NULL COMMENT '主题域id', + `chat_detail_config` mediumtext COMMENT '明细模式配置信息', + `chat_agg_config` mediumtext COMMENT '指标模式配置信息', + `recommended_questions` mediumtext COMMENT '推荐问题配置', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间', + `created_by` varchar(100) NOT NULL COMMENT '创建人', + `updated_by` varchar(100) NOT NULL COMMENT '更新人', + `status` int(10) NOT NULL COMMENT '主题域扩展信息状态, 0-删除,1-生效', + PRIMARY KEY (`id`) +) + comment '主题域扩展信息表' charset = utf8; + +create table supersonic_sit.s2_chat_context +( + chat_id bigint not null comment 'context chat id' + primary key, + modified_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'row modify time', + user varchar(64) null comment 'row modify user', + query_text text null comment 'query text', + semantic_parse text null comment 'parse data', + ext_data text null comment 'extend data' +) + charset = utf8; + +create table supersonic_sit.s2_chat_query +( + question_id bigint auto_increment + primary key, + create_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP, + query_text mediumtext null, + user_name varchar(150) null, + query_state int(1) null, + chat_id bigint not null, + query_response mediumtext not null, + score int default 0 null, + feedback varchar(1024) default '' null +) + charset = utf8; + +create table supersonic_sit.s2_database +( + id bigint auto_increment + primary key, + domain_id bigint not null comment '主题域ID', + name varchar(255) not null comment '名称', + description varchar(500) null comment '描述', + version varchar(64) null comment '版本', + type varchar(20) not null comment '类型 mysql,clickhouse,tdw', + config text not null comment '配置信息', + created_at datetime not null comment '创建时间', + created_by varchar(100) not null comment '创建人', + updated_at datetime not null comment '更新时间', + updated_by varchar(100) not null comment '更新人' +) + comment '数据库实例表' charset = utf8; + +create table supersonic_sit.s2_datasource +( + id bigint auto_increment + primary key, + domain_id bigint not null comment '主题域ID', + name varchar(255) not null comment '数据源名称', + biz_name varchar(255) not null comment '内部名称', + description varchar(500) null comment '数据源描述', + database_id bigint not null comment '数据库实例ID', + datasource_detail mediumtext not null comment '数据源配置', + created_at datetime not null comment '创建时间', + created_by varchar(100) not null comment '创建人', + updated_at datetime not null comment '更新时间', + updated_by varchar(100) not null comment '更新人' +) + charset = utf8; + +create table supersonic_sit.s2_datasource_rela +( + id bigint auto_increment + primary key, + domain_id bigint null, + datasource_from bigint null, + datasource_to bigint null, + join_key varchar(100) null, + created_at datetime null, + created_by varchar(100) null, + updated_at datetime null, + updated_by varchar(100) null +) + charset = utf8; + + +create table supersonic_sit.s2_dimension +( + id bigint auto_increment comment '维度ID' + primary key, + domain_id bigint not null comment '主题域id', + datasource_id bigint not null comment '所属数据源id', + name varchar(255) not null comment '维度名称', + biz_name varchar(255) not null comment '字段名称', + description varchar(500) not null comment '描述', + status int(10) not null comment '维度状态,0正常,1下架,2删除', + sensitive_level int(10) null comment '敏感级别', + type varchar(50) not null comment '维度类型 categorical,time', + type_params text null comment '类型参数', + expr text not null comment '表达式', + created_at datetime not null comment '创建时间', + created_by varchar(100) not null comment '创建人', + updated_at datetime not null comment '更新时间', + updated_by varchar(100) not null comment '更新人', + semantic_type varchar(20) not null comment '语义类型DATE, ID, CATEGORY', + alias varchar(500) collate utf8_unicode_ci null, + default_values varchar(500) DEFAULT NULL, + dim_value_maps varchar(500) DEFAULT NULL +) + comment '维度表' charset = utf8; + +create table supersonic_sit.s2_domain +( + id bigint auto_increment comment '自增ID' + primary key, + name varchar(255) null comment '主题域名称', + biz_name varchar(255) null comment '内部名称', + parent_id bigint default 0 null comment '父主题域ID', + status int(10) not null comment '主题域状态', + created_at datetime null comment '创建时间', + created_by varchar(100) null comment '创建人', + updated_at datetime null comment '更新时间', + updated_by varchar(100) null comment '更新人', + admin varchar(3000) null comment '主题域管理员', + admin_org varchar(3000) null comment '主题域管理员组织', + is_open int null comment '主题域是否公开', + viewer varchar(3000) null comment '主题域可用用户', + view_org varchar(3000) null comment '主题域可用组织', + entity varchar(500) DEFAULT NULL COMMENT '主题域实体信息' +) + comment '主题域基础信息表' charset = utf8; + + +create table supersonic_sit.s2_domain_extend +( + id bigint unsigned auto_increment + primary key, + domain_id bigint null comment '主题域id', + default_metrics varchar(655) null comment '默认指标', + visibility mediumtext null comment '不可见的维度/指标信息', + entity_info mediumtext null comment '实体信息', + dictionary_info mediumtext null comment '字典相关的维度设置信息', + created_at datetime not null comment '创建时间', + updated_at datetime not null comment '更新时间', + created_by varchar(100) not null comment '创建人', + updated_by varchar(100) not null comment '更新人', + status int(10) not null comment '主题域扩展信息状态, 0-删除,1-生效' +) + comment '主题域扩展信息表' collate = utf8mb4_unicode_ci; + + +create table supersonic_sit.s2_metric +( + id bigint auto_increment + primary key, + domain_id bigint not null comment '主体域ID', + name varchar(255) not null comment '指标名称', + biz_name varchar(255) not null comment '字段名称', + description varchar(500) null comment '描述', + status int(10) not null comment '指标状态,0正常,1下架,2删除', + sensitive_level int(10) not null comment '敏感级别', + type varchar(50) not null comment '指标类型 proxy,expr', + type_params text not null comment '类型参数', + created_at datetime not null comment '创建时间', + created_by varchar(100) not null comment '创建人', + updated_at datetime not null comment '更新时间', + updated_by varchar(100) not null comment '更新人', + data_format_type varchar(50) null comment '数值类型', + data_format varchar(500) null comment '数值类型参数', + alias varchar(500) collate utf8_unicode_ci null +) + comment '指标表' charset = utf8; + +create table supersonic_sit.s2_query_stat_info +( + id bigint unsigned auto_increment + primary key, + trace_id varchar(200) null comment '查询标识', + domain_id bigint null comment '主题域ID', + user varchar(200) null comment '执行sql的用户', + created_at datetime default CURRENT_TIMESTAMP null comment '创建时间', + query_type varchar(200) null comment '查询对应的场景', + query_type_back int(10) default 0 null comment '查询类型, 0-正常查询, 1-预刷类型', + query_sql_cmd mediumtext null comment '对应查询的struct', + sql_cmd_md5 varchar(200) null comment 'sql md5值', + query_struct_cmd mediumtext null comment '对应查询的struct', + struct_cmd_md5 varchar(200) null comment 'sql md5值', + `sql` mediumtext null comment '对应查询的sql', + sql_md5 varchar(200) null comment 'sql md5值', + query_engine varchar(20) null comment '查询引擎', + elapsed_ms bigint(10) null comment '查询耗时', + query_state varchar(20) null comment '查询最终状态', + native_query int(10) null comment '1-明细查询,0-聚合查询', + start_date varchar(50) null comment 'sql开始日期', + end_date varchar(50) null comment 'sql结束日期', + dimensions mediumtext null comment 'sql 涉及的维度', + metrics mediumtext null comment 'sql 涉及的指标', + select_cols mediumtext null comment 'sql select部分涉及的标签', + agg_cols mediumtext null comment 'sql agg部分涉及的标签', + filter_cols mediumtext null comment 'sql where部分涉及的标签', + group_by_cols mediumtext null comment 'sql grouy by部分涉及的标签', + order_by_cols mediumtext null comment 'sql order by部分涉及的标签', + use_result_cache tinyint(1) default -1 null comment '是否命中sql缓存', + use_sql_cache tinyint(1) default -1 null comment '是否命中sql缓存', + sql_cache_key mediumtext null comment '缓存的key', + result_cache_key mediumtext null comment '缓存的key' +) + comment '查询统计信息表' collate = utf8mb4_unicode_ci; + +create index domain_index + on supersonic_sit.s2_query_stat_info (domain_id); + +create table supersonic_sit.s2_semantic_pasre_info +( + id bigint unsigned auto_increment + primary key, + trace_id varchar(200) not null comment '查询标识', + domain_id bigint not null comment '主体域ID', + dimensions mediumtext null comment '查询相关的维度信息', + metrics mediumtext null comment '查询相关的指标信息', + orders mediumtext null comment '查询相关的排序信息', + filters mediumtext null comment '查询相关的过滤信息', + date_info mediumtext null comment '查询相关的日期信息', + `limit` bigint not null comment '查询相关的limit信息', + native_query tinyint(1) default 0 not null comment '1-明细查询,0-聚合查询', + `sql` mediumtext null comment '解析后的sql', + created_at datetime not null comment '创建时间', + created_by varchar(100) not null comment '创建人', + status int(10) not null comment '运行状态', + elapsed_ms bigint(10) null comment 'sql解析耗时' +) comment '语义层sql解析信息表' charset = utf8; + +create table supersonic_sit.s2_view_info +( + id bigint auto_increment + primary key, + domain_id bigint null, + type varchar(20) null comment 'datasource、dimension、metric', + config text null comment 'config detail', + created_at datetime null, + created_by varchar(100) null, + updated_at datetime null, + updated_by varchar(100) not null +) charset = utf8; + + +CREATE TABLE `s2_user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `display_name` varchar(100) DEFAULT NULL, + `password` varchar(100) DEFAULT NULL, + `email` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/db/sql-update.sql b/launchers/standalone/src/main/resources/db/sql-update.sql new file mode 100644 index 000000000..0b358de19 --- /dev/null +++ b/launchers/standalone/src/main/resources/db/sql-update.sql @@ -0,0 +1 @@ +alter table s2_domain add column `entity`varchar(500) DEFAULT NULL COMMENT '主题域实体信息'; \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/docker/Dockerfile b/launchers/standalone/src/main/resources/docker/Dockerfile new file mode 100644 index 000000000..efed17138 --- /dev/null +++ b/launchers/standalone/src/main/resources/docker/Dockerfile @@ -0,0 +1,8 @@ +FROM docker-images.music.woa.com/di_base_img/tme_di_base_centos:8_7 +MAINTAINER admin +ADD ../../../../target/launchers-standalone-*.gz /app/ +RUN ls -l /app/launchers-standalone-*/bin/ +ENV TZ=Asia/Shanghai +ENV LANG C.UTF-8 +EXPOSE 9082 +ENTRYPOINT ["sh","-c","/app/launchers-standalone-0.6-SNAPSHOT/bin/run.sh && tail -f /dev/null"] \ No newline at end of file diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/BaseQueryTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/BaseQueryTest.java new file mode 100644 index 000000000..0d03808da --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/BaseQueryTest.java @@ -0,0 +1,112 @@ +package com.tencent.supersonic.integration; + +import com.tencent.supersonic.StandaloneLauncher; +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.service.ChatService; +import com.tencent.supersonic.chat.service.ConfigService; +import com.tencent.supersonic.chat.service.QueryService; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.util.DataUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import java.time.LocalDate; +import java.util.Comparator; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = StandaloneLauncher.class) +@ActiveProfiles("local") +public class BaseQueryTest { + + protected final int unit = 7; + protected final String startDay = LocalDate.now().plusDays(-unit).toString(); + protected final String endDay = LocalDate.now().plusDays(-1).toString(); + + @Autowired + @Qualifier("chatQueryService") + protected QueryService queryService; + @Autowired + protected ChatService chatService; + @Autowired + protected ConfigService configService; + + protected Integer getNewChat(String chatName) { + chatService.addChat(User.getFakeUser(), chatName); + Optional chatId = chatService.getAll(User.getFakeUser().getName()).stream().map(c -> c.getChatId()).sorted(Comparator.reverseOrder()).findFirst(); + if (chatId.isPresent()) { + return chatId.get().intValue(); + } + return 1; + } + + protected QueryResult submitMultiTurnChat(String queryText) throws Exception { + QueryRequest queryContextReq = DataUtils.getQueryContextReq(20, queryText); + return queryService.executeQuery(queryContextReq); + } + + protected QueryResult submitNewChat(String queryText) throws Exception { + chatService.addChat(User.getFakeUser(), RandomStringUtils.random(5)); + + ChatContext chatContext = chatService.getOrCreateContext(10); + chatContext.setParseInfo(new SemanticParseInfo()); + chatService.updateContext(chatContext); + + QueryRequest queryContextReq = DataUtils.getQueryContextReq(10, queryText); + return queryService.executeQuery(queryContextReq); + } + + protected void assertSchemaElements(Set expected, Set actual) { + Set expectedNames = expected.stream().map(s -> s.getName()) + .filter(s -> s != null).collect(Collectors.toSet()); + Set actualNames = actual.stream().map(s -> s.getName()) + .filter(s -> s != null).collect(Collectors.toSet()); + + assertEquals(expectedNames, actualNames); + } + + protected void assertDateConf(DateConf expected, DateConf actual) { + Boolean timeFilterExist = expected.getStartDate().equals(actual.getStartDate()) + && expected.getEndDate().equals(actual.getEndDate()) + && expected.getDateMode().equals(actual.getDateMode()) + || expected.getUnit().equals(actual.getUnit()) && + expected.getDateMode().equals(actual.getDateMode()) && + expected.getPeriod().equals(actual.getPeriod()); + + assertTrue(timeFilterExist); + } + + protected void assertQueryResult(QueryResult expected, QueryResult actual) { + SemanticParseInfo expectedParseInfo = expected.getChatContext(); + SemanticParseInfo actualParseInfo = actual.getChatContext(); + + assertEquals(QueryState.SUCCESS, actual.getQueryState()); + assertEquals(expected.getQueryMode(), actual.getQueryMode()); + assertEquals(expectedParseInfo.getAggType(), actualParseInfo.getAggType()); + + assertSchemaElements(expectedParseInfo.getMetrics(), actualParseInfo.getMetrics()); + assertSchemaElements(expectedParseInfo.getDimensions(), actualParseInfo.getDimensions()); + + assertEquals(expectedParseInfo.getDimensionFilters(), actualParseInfo.getDimensionFilters()); + assertEquals(expectedParseInfo.getMetricFilters(), actualParseInfo.getMetricFilters()); + + assertDateConf(expectedParseInfo.getDateInfo(), actualParseInfo.getDateInfo()); + } + +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/EntityQueryTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/EntityQueryTest.java new file mode 100644 index 000000000..8d0737a32 --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/EntityQueryTest.java @@ -0,0 +1,42 @@ +package com.tencent.supersonic.integration; + +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.query.rule.entity.EntityFilterQuery; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import com.tencent.supersonic.util.DataUtils; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.NONE; + +public class EntityQueryTest extends BaseQueryTest { + + @Test + public void queryTest_ENTITY_LIST_FILTER()throws Exception { + QueryResult actualResult = submitNewChat("爱情、流行类型的艺人"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(EntityFilterQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + List list = new ArrayList<>(); + list.add("爱情"); + list.add("流行"); + QueryFilter dimensionFilter = DataUtils.getFilter("genre", FilterOperatorEnum.IN, list, "风格", 6L); + expectedParseInfo.getDimensionFilters().add(dimensionFilter); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(1, DateConf.DateMode.RECENT_UNITS, "DAY")); + expectedParseInfo.setNativeQuery(true); + + assertQueryResult(expectedResult, actualResult); + } + +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricQueryTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricQueryTest.java new file mode 100644 index 000000000..611e035fc --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricQueryTest.java @@ -0,0 +1,220 @@ +package com.tencent.supersonic.integration; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.config.ChatConfigEditReqReq; +import com.tencent.supersonic.chat.config.ChatConfigResp; +import com.tencent.supersonic.chat.config.ItemVisibility; +import com.tencent.supersonic.chat.query.rule.metric.MetricDomainQuery; +import com.tencent.supersonic.chat.query.rule.metric.MetricFilterQuery; +import com.tencent.supersonic.chat.query.rule.metric.MetricGroupByQuery; +import com.tencent.supersonic.chat.query.rule.metric.MetricTopNQuery; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import com.tencent.supersonic.util.DataUtils; +import org.junit.Test; +import org.springframework.beans.BeanUtils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.*; + + +public class MetricQueryTest extends BaseQueryTest { + + @Test + public void queryTest_METRIC_FILTER() throws Exception { + QueryResult actualResult = submitNewChat("alice的访问次数"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricFilterQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + + expectedParseInfo.getDimensionFilters().add(DataUtils.getFilter("user_name", + FilterOperatorEnum.EQUALS, "alice", "用户名", 2L)); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + public void queryTest_METRIC_DOMAIN() throws Exception { + QueryResult actualResult = submitNewChat("超音数的访问次数"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricDomainQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + public void queryTest_METRIC_GROUPBY() throws Exception { + QueryResult actualResult = submitNewChat("超音数各部门的访问次数"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricGroupByQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + expectedParseInfo.getDimensions().add(DataUtils.getSchemaElement("部门")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + public void queryTest_METRIC_FILTER_COMPARE() throws Exception { + QueryResult actualResult = submitNewChat("对比alice和lucy的访问次数"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricFilterQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + + List list = new ArrayList<>(); + list.add("alice"); + list.add("lucy"); + QueryFilter dimensionFilter = DataUtils.getFilter("user_name", FilterOperatorEnum.IN, list, "用户名", 2L); + expectedParseInfo.getDimensionFilters().add(dimensionFilter); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + public void queryTest_METRIC_TOPN() throws Exception { + QueryResult actualResult = submitNewChat("近3天访问次数最多的用户"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricTopNQuery.QUERY_MODE); + expectedParseInfo.setAggType(SUM); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + expectedParseInfo.getDimensions().add(DataUtils.getSchemaElement("用户名")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(3, DateConf.DateMode.RECENT_UNITS, "DAY")); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + public void queryTest_METRIC_GROUPBY_SUM() throws Exception { + QueryResult actualResult = submitNewChat("超音数各部门的访问次数总和"); + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricGroupByQuery.QUERY_MODE); + expectedParseInfo.setAggType(SUM); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + expectedParseInfo.getDimensions().add(DataUtils.getSchemaElement("部门")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + public void queryTest_METRIC_FILTER_TIME() throws Exception { + DateFormat format = new SimpleDateFormat("yyyy-mm-dd"); + DateFormat textFormat = new SimpleDateFormat("yyyy年mm月dd日"); + String dateStr = textFormat.format(format.parse(startDay)); + + QueryResult actualResult = submitNewChat(String.format("想知道{}alice的访问次数", dateStr)); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricFilterQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + + expectedParseInfo.getDimensionFilters().add(DataUtils.getFilter("user_name", + FilterOperatorEnum.EQUALS, "alice", "用户名", 2L)); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, startDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + public void queryTest_CONFIG_VISIBILITY() throws Exception { + // 1. round_1 use blacklist + ChatConfigResp chatConfig = configService.fetchConfigByDomainId(1L); + ChatConfigEditReqReq extendEditCmd = new ChatConfigEditReqReq(); + BeanUtils.copyProperties(chatConfig, extendEditCmd); + // add blacklist + List blackMetrics = Arrays.asList(3L); + extendEditCmd.getChatAggConfig().getVisibility().setBlackMetricIdList(blackMetrics); + configService.editConfig(extendEditCmd, User.getFakeUser()); + + QueryResult actualResult = submitNewChat("超音数访问人数、访问次数"); + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricDomainQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + + // 2. round_2 no blacklist + // remove blacklist + extendEditCmd.getChatAggConfig().setVisibility(new ItemVisibility()); + configService.editConfig(extendEditCmd, User.getFakeUser()); + + actualResult = submitNewChat("超音数访问人数、访问次数"); + expectedParseInfo.getMetrics().clear(); + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问人数")); + + assertQueryResult(expectedResult, actualResult); + + } + +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MultiTurnQueryTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MultiTurnQueryTest.java deleted file mode 100644 index f926defa9..000000000 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MultiTurnQueryTest.java +++ /dev/null @@ -1,444 +0,0 @@ -package com.tencent.supersonic.integration; - -import com.tencent.supersonic.StandaloneLauncher; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.application.query.MetricCompare; -import com.tencent.supersonic.chat.application.query.MetricDomain; -import com.tencent.supersonic.chat.application.query.MetricFilter; -import com.tencent.supersonic.chat.application.query.MetricGroupBy; -import com.tencent.supersonic.chat.domain.service.QueryService; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import com.tencent.supersonic.util.DataUtils; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = StandaloneLauncher.class) -@ActiveProfiles("local") -public class MultiTurnQueryTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(MultiTurnQueryTest.class); - - @Autowired - @Qualifier("chatQueryService") - private QueryService queryService; - - //case:alice的访问次数->停留时长呢?->想知道lucy的,queryMode:METRIC_FILTER - @Test - public void queryTest1() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(1,"alice的访问次数"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter = DataUtils.getFilter("user_name", FilterOperatorEnum.EQUALS, "alice", "用户名", 2L); - Boolean dimensionFilterExist = DataUtils.compareDimensionFilter(dimensionFilters, dimensionFilter); - assertThat(dimensionFilterExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - - queryContextReq = DataUtils.getQueryContextReq(1,"停留时长呢?"); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics1 = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric1 = DataUtils.getSchemaItem(1L, "停留时长", "stay_hours"); - Boolean metricExist1 = DataUtils.compareSchemaItem(metrics1, schemaItemMetric1); - assertThat(metricExist1).isEqualTo(true); - - //assert 维度 - Set dimensions1 = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist1 = DataUtils.compareDateDimension(dimensions1); - assertThat(dimensionExist1).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters1 = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter1 = DataUtils.getFilter("user_name", FilterOperatorEnum.EQUALS, "alice", "用户名", 2L); - Boolean dimensionFilterExist1 = DataUtils.compareDimensionFilter(dimensionFilters1, dimensionFilter1); - assertThat(dimensionFilterExist1).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo1 = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist1 = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo1); - assertThat(timeFilterExist1).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - - queryContextReq = DataUtils.getQueryContextReq(1,"想知道lucy的"); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics2 = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric2 = DataUtils.getSchemaItem(1L, "停留时长", "stay_hours"); - Boolean metricExist2 = DataUtils.compareSchemaItem(metrics2, schemaItemMetric2); - assertThat(metricExist2).isEqualTo(true); - - //assert 维度 - Set dimensions2 = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist2 = DataUtils.compareDateDimension(dimensions2); - assertThat(dimensionExist2).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters2 = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter2 = DataUtils.getFilter("user_name", FilterOperatorEnum.EQUALS, "lucy", "用户名", 2L); - Boolean dimensionFilterExist2 = DataUtils.compareDimensionFilter(dimensionFilters2, dimensionFilter2); - ; - assertThat(dimensionFilterExist2).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo2 = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist2 = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo2); - assertThat(timeFilterExist2).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - - //case:超音数的访问次数->按部门的呢->p2的呢 - @Test - public void queryTest2() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(2,"超音数的访问次数"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricDomain.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - - queryContextReq = DataUtils.getQueryContextReq(2,"按部门的呢"); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricGroupBy.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics1 = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric1 = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist1 = DataUtils.compareSchemaItem(metrics1, schemaItemMetric1); - assertThat(metricExist1).isEqualTo(true); - - //assert 维度 - Set dimensions1 = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist1 = DataUtils.compareDateDimension(dimensions1); - assertThat(dimensionExist1).isEqualTo(true); - - SchemaItem schemaItemDimension2 = DataUtils.getSchemaItem(1L, "部门", "department"); - Boolean dimensionExist2 = DataUtils.compareSchemaItem(dimensions1, schemaItemDimension2); - assertThat(dimensionExist2).isEqualTo(true); - - - //assert 时间filter - DateConf dateInfo1 = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist1 = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo1); - assertThat(timeFilterExist1).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - - queryContextReq = DataUtils.getQueryContextReq(2,"p2的呢"); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics2 = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric2 = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist2 = DataUtils.compareSchemaItem(metrics2, schemaItemMetric2); - assertThat(metricExist2).isEqualTo(true); - - //assert 维度 - Set dimensions2 = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist3 = DataUtils.compareDateDimension(dimensions2); - assertThat(dimensionExist3).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters2 = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter2 = DataUtils.getFilter("page", FilterOperatorEnum.EQUALS, "p2", "页面", 3L); - Boolean dimensionFilterExist2 = DataUtils.compareDimensionFilter(dimensionFilters2, dimensionFilter2); - assertThat(dimensionFilterExist2).isEqualTo(true); - - - //assert 时间filter - DateConf dateInfo2 = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist2 = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo2); - assertThat(timeFilterExist2).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - //alice的访问次数->对比alice和lucy呢->他是哪个部门的呢 - @Test - public void queryTest3() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(1,"alice的访问次数"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter = DataUtils.getFilter("user_name", FilterOperatorEnum.EQUALS, "alice", "用户名", 2L); - Boolean dimensionFilterExist = DataUtils.compareDimensionFilter(dimensionFilters, dimensionFilter); - assertThat(dimensionFilterExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - - queryContextReq = DataUtils.getQueryContextReq(1,"对比alice和lucy呢"); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricCompare.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics1 = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric1 = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist1 = DataUtils.compareSchemaItem(metrics1, schemaItemMetric1); - assertThat(metricExist1).isEqualTo(true); - - //assert 维度 - Set dimensions1 = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist1 = DataUtils.compareDateDimension(dimensions1); - assertThat(dimensionExist1).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters1 = queryResultResp.getChatContext().getDimensionFilters(); - List list = new ArrayList<>(); - list.add("alice"); - list.add("lucy"); - Filter dimensionFilter1 = DataUtils.getFilter("user_name", FilterOperatorEnum.IN, list, "用户名", 2L); - Boolean dimensionFilterExist1 = DataUtils.compareDimensionFilter(dimensionFilters1, dimensionFilter1); - assertThat(dimensionFilterExist1).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo1 = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist1 = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo1); - assertThat(timeFilterExist1).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - - queryContextReq = DataUtils.getQueryContextReq(1,"他是哪个部门的呢"); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics2 = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric2 = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist2 = DataUtils.compareSchemaItem(metrics2, schemaItemMetric2); - assertThat(metricExist2).isEqualTo(true); - - //assert 维度 - Set dimensions2 = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist2 = DataUtils.compareDateDimension(dimensions2); - assertThat(dimensionExist2).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters2 = queryResultResp.getChatContext().getDimensionFilters(); - List list1 = new ArrayList<>(); - list1.add("alice"); - list1.add("lucy"); - Filter dimensionFilter2 = DataUtils.getFilter("user_name", FilterOperatorEnum.IN, list1, "用户名", 2L); - Boolean dimensionFilterExist2 = DataUtils.compareDimensionFilter(dimensionFilters2, dimensionFilter2); - assertThat(dimensionFilterExist2).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo2 = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist2 = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo2); - assertThat(timeFilterExist2).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - - } - - -} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MultiTurnsTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MultiTurnsTest.java new file mode 100644 index 000000000..7902a015d --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MultiTurnsTest.java @@ -0,0 +1,154 @@ +package com.tencent.supersonic.integration; + +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.query.rule.metric.MetricFilterQuery; +import com.tencent.supersonic.chat.query.rule.metric.MetricGroupByQuery; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import com.tencent.supersonic.util.DataUtils; +import org.junit.Test; +import org.junit.jupiter.api.Order; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.NONE; + +public class MultiTurnsTest extends BaseQueryTest { + + @Test + @Order(1) + public void queryTest_01() throws Exception { + QueryResult actualResult = submitMultiTurnChat("alice的访问次数"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricFilterQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("访问次数")); + + expectedParseInfo.getDimensionFilters().add(DataUtils.getFilter("user_name", + FilterOperatorEnum.EQUALS, "alice", "用户名", 2L)); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + @Order(2) + public void queryTest_02() throws Exception { + QueryResult actualResult = submitMultiTurnChat("停留时长呢"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricFilterQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("停留时长")); + + expectedParseInfo.getDimensionFilters().add(DataUtils.getFilter("user_name", + FilterOperatorEnum.EQUALS, "alice", "用户名", 2L)); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + @Order(3) + public void queryTest_03() throws Exception { + QueryResult actualResult = submitMultiTurnChat("lucy的如何"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricFilterQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("停留时长")); + + expectedParseInfo.getDimensionFilters().add(DataUtils.getFilter("user_name", + FilterOperatorEnum.EQUALS, "lucy", "用户名", 2L)); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + @Order(4) + public void queryTest_04() throws Exception { + QueryResult actualResult = submitMultiTurnChat("按部门统计"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricGroupByQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("停留时长")); + expectedParseInfo.getDimensions().add(DataUtils.getSchemaElement("部门")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + @Order(5) + public void queryTest_05() throws Exception { + DateFormat format = new SimpleDateFormat("yyyy-mm-dd"); + DateFormat textFormat = new SimpleDateFormat("yyyy年mm月dd日"); + QueryResult actualResult = submitMultiTurnChat(textFormat.format(format.parse(startDay))); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricGroupByQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("停留时长")); + expectedParseInfo.getDimensions().add(DataUtils.getSchemaElement("部门")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.BETWEEN_CONTINUOUS, startDay, startDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + + @Test + @Order(6) + public void queryTest_06() throws Exception { + QueryResult actualResult = submitMultiTurnChat("近30天"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricGroupByQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + expectedParseInfo.getMetrics().add(DataUtils.getSchemaElement("停留时长")); + expectedParseInfo.getDimensions().add(DataUtils.getSchemaElement("部门")); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(30, DateConf.DateMode.RECENT_UNITS, "DAY")); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/QueryTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/QueryTest.java deleted file mode 100644 index 5ffa68bd5..000000000 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/QueryTest.java +++ /dev/null @@ -1,567 +0,0 @@ -package com.tencent.supersonic.integration; - -import com.tencent.supersonic.StandaloneLauncher; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.application.query.*; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import com.tencent.supersonic.util.DataUtils; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import com.tencent.supersonic.chat.domain.service.QueryService; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = StandaloneLauncher.class) -@ActiveProfiles("local") -public class QueryTest { - private static final Logger LOGGER = LoggerFactory.getLogger(QueryTest.class); - - @Autowired - @Qualifier("chatQueryService") - private QueryService queryService; - - //case:alice的访问次数,queryMode:METRIC_FILTER, - @Test - public void queryTest_01() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(1, "alice的访问次数"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter = DataUtils.getFilter("user_name", FilterOperatorEnum.EQUALS, "alice", "用户名", 2L); - Boolean dimensionFilterExist = DataUtils.compareDimensionFilter(dimensionFilters, dimensionFilter); - assertThat(dimensionFilterExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - //case:超音数的访问次数,queryMode:METRIC_DOMAIN - @Test - public void queryTest_02() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(2, "超音数的访问次数"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricDomain.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - - //case:超音数各部门的访问次数,queryMode:METRIC_GROUPBY - @Test - public void queryTest_03() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(1, "超音数各部门的访问次数"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricGroupBy.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - SchemaItem schemaItemDimension1 = DataUtils.getSchemaItem(1L, "部门", "department"); - Boolean dimensionExist1 = DataUtils.compareSchemaItem(dimensions, schemaItemDimension1); - assertThat(dimensionExist1).isEqualTo(true); - - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - - //case:对比alice和lucy的访问次数,queryMode:METRIC_COMPARE - @Test - public void queryTest_04() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(1, "对比alice和lucy的访问次数"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricCompare.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); - List list = new ArrayList<>(); - list.add("alice"); - list.add("lucy"); - Filter dimensionFilter = DataUtils.getFilter("user_name", FilterOperatorEnum.IN, list, "用户名", 2L); - Boolean dimensionFilterExist = DataUtils.compareDimensionFilter(dimensionFilters, dimensionFilter); - assertThat(dimensionFilterExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - //case:近3天访问次数最多的用户,queryMode:ENTITY_detail - @Test - public void queryTest_05() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(2, "艺人周杰伦的代表作"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", queryResultResp); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), EntityDetail.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(2L); - - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - SchemaItem schemaItemDimension = DataUtils.getSchemaItem(5L, "代表作", "song_name"); - Boolean dimensionExist = DataUtils.compareSchemaItem(dimensions, schemaItemDimension); - assertThat(dimensionExist).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter = DataUtils.getFilter("singer_name", FilterOperatorEnum.EQUALS, "周杰伦", "歌手名", 7L); - Boolean dimensionFilterExist = DataUtils.compareDimensionFilter(dimensionFilters, dimensionFilter); - assertThat(dimensionFilterExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(1, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(true); - - } - - //case:近3天访问次数最多的用户名,queryMode:METRIC_ORDERBY - @Test - public void queryTest_06() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(2, "近3天访问次数最多的用户名"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricOrderBy.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), AggregateTypeEnum.MAX); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - SchemaItem schemaItemDimension = DataUtils.getSchemaItem(2L, "用户名", "user_name"); - Boolean dimensionExist = DataUtils.compareSchemaItem(dimensions, schemaItemDimension); - assertThat(dimensionExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(3, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - - //case:播放量最多的艺人,queryMode:ENTITY_LIST_TOPN - @Test - public void queryTest_07() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(2, "播放量最多的艺人"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", queryResultResp); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), EntityListTopN.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), AggregateTypeEnum.MAX); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(2L); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - SchemaItem schemaItemDimension = DataUtils.getSchemaItem(7L, "歌手名", "singer_name"); - Boolean dimensionExist = DataUtils.compareSchemaItem(dimensions, schemaItemDimension); - assertThat(dimensionExist).isEqualTo(true); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(4L, "播放量", "js_play_cnt"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(1, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(true); - - } - - //case:超音数各部门的访问次数总和,queryMode:METRIC_GROUPBY,aggType:sum - @Test - public void queryTest_09() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(1, "超音数各部门的访问次数总和"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), MetricGroupBy.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), AggregateTypeEnum.SUM); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); - assertThat(dimensionExist).isEqualTo(true); - - SchemaItem schemaItemDimension1 = DataUtils.getSchemaItem(1L, "部门", "department"); - Boolean dimensionExist1 = DataUtils.compareSchemaItem(dimensions, schemaItemDimension1); - assertThat(dimensionExist1).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - ; - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); - - } - - @Test - public void queryTest_10() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(2, "爱情、流行类型的艺人"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), EntityListFilter.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(2L); - - //assert 指标 - Set metrics = queryResultResp.getChatContext().getMetrics(); - SchemaItem schemaItemMetric = DataUtils.getSchemaItem(4L, "播放量", "js_play_cnt"); - Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); - assertThat(metricExist).isEqualTo(true); - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - SchemaItem schemaItemDimension = DataUtils.getSchemaItem(7L, "歌手名", "singer_name"); - Boolean dimensionExist = DataUtils.compareSchemaItem(dimensions, schemaItemDimension); - assertThat(dimensionExist).isEqualTo(true); - - SchemaItem schemaItemDimension1 = DataUtils.getSchemaItem(6L, "风格", "genre"); - Boolean dimensionExist1 = DataUtils.compareSchemaItem(dimensions, schemaItemDimension1); - assertThat(dimensionExist1).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); - List list = new ArrayList<>(); - list.add("爱情"); - list.add("流行"); - Filter dimensionFilter = DataUtils.getFilter("genre", FilterOperatorEnum.IN, list, "风格", 6L); - Boolean dimensionFilterExist = DataUtils.compareDimensionFilter(dimensionFilters, dimensionFilter); - assertThat(dimensionFilterExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(1, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(true); - - } - - //case:近3天访问次数最多的用户,queryMode:ENTITY_detail - @Test - public void queryTest_11() { - QueryContextReq queryContextReq = DataUtils.getQueryContextReq(1, "艺人周杰伦的代表作、风格、活跃区域"); - QueryResultResp queryResultResp = new QueryResultResp(); - try { - queryResultResp = queryService.executeQuery(queryContextReq); - } catch (Exception e) { - - } - LOGGER.info("QueryResultResp queryResultResp:{}", queryResultResp); - //assert queryState - Assert.assertEquals(queryResultResp.getQueryState(), 0); - //assert queryMode - Assert.assertEquals(queryResultResp.getQueryMode(), EntityDetail.QUERY_MODE); - //assert aggType - Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); - //assert 主题域Id - assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(2L); - - - //assert 维度 - Set dimensions = queryResultResp.getChatContext().getDimensions(); - SchemaItem schemaItemDimension = DataUtils.getSchemaItem(5L, "代表作", "song_name"); - Boolean dimensionExist = DataUtils.compareSchemaItem(dimensions, schemaItemDimension); - assertThat(dimensionExist).isEqualTo(true); - - SchemaItem schemaItemDimension1 = DataUtils.getSchemaItem(4L, "活跃区域", "act_area"); - Boolean dimensionExist1 = DataUtils.compareSchemaItem(dimensions, schemaItemDimension1); - assertThat(dimensionExist1).isEqualTo(true); - - SchemaItem schemaItemDimension2 = DataUtils.getSchemaItem(6L, "风格", "genre"); - Boolean dimensionExist2 = DataUtils.compareSchemaItem(dimensions, schemaItemDimension2); - assertThat(dimensionExist2).isEqualTo(true); - - //assert 维度filter - Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); - Filter dimensionFilter = DataUtils.getFilter("singer_name", FilterOperatorEnum.EQUALS, "周杰伦", "歌手名", 7L); - Boolean dimensionFilterExist = DataUtils.compareDimensionFilter(dimensionFilters, dimensionFilter); - assertThat(dimensionFilterExist).isEqualTo(true); - - //assert 时间filter - DateConf dateInfo = DataUtils.getDateConf(1, DateConf.DateMode.RECENT_UNITS, "DAY"); - Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); - assertThat(timeFilterExist).isEqualTo(true); - - //assert nativeQuery - assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(true); - - } - - // @Test -// public void queryTest_11() { -// QueryContextReq queryContextReq = DataUtils.getQueryContextReq("最近4天HR部门的访问人数"); -// try { -// QueryResultResp queryResultResp = queryService.executeQuery(queryContextReq); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -//case:各部门对各页面的访问次数,queryMode:METRIC_GROUPBY -// @Test -// public void queryTest_08() { -// QueryContextReq queryContextReq = DataUtils.getQueryContextReq(3, "各部门对各页面的访问次数"); -// QueryResultResp queryResultResp = new QueryResultResp(); -// try { -// queryResultResp = queryService.executeQuery(queryContextReq); -// } catch (Exception e) { -// -// } -// LOGGER.info("QueryResultResp queryResultResp:{}", JsonUtil.toString(queryResultResp)); -// //assert queryState -// Assert.assertEquals(queryResultResp.getQueryState(), 0); -// //assert queryMode -// Assert.assertEquals(queryResultResp.getQueryMode(), MetricGroupBy.QUERY_MODE); -// //assert aggType -// Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); -// //assert 主题域Id -// assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); -// -// //assert 指标 -// Set metrics = queryResultResp.getChatContext().getMetrics(); -// SchemaItem schemaItemMetric = DataUtils.getSchemaItem(2L, "访问次数", "pv"); -// Boolean metricExist = DataUtils.compareSchemaItem(metrics, schemaItemMetric); -// assertThat(metricExist).isEqualTo(true); -// -// //assert 维度 -// Set dimensions = queryResultResp.getChatContext().getDimensions(); -// Boolean dimensionExist = DataUtils.compareDateDimension(dimensions); -// assertThat(dimensionExist).isEqualTo(true); -// -// SchemaItem schemaItemDimension1 = DataUtils.getSchemaItem(1L, "部门", "department"); -// Boolean dimensionExist1 = DataUtils.compareSchemaItem(dimensions, schemaItemDimension1); -// assertThat(dimensionExist1).isEqualTo(true); -// -// SchemaItem schemaItemDimension2 = DataUtils.getSchemaItem(3L, "页面", "page"); -// Boolean dimensionExist2 = DataUtils.compareSchemaItem(dimensions, schemaItemDimension2); -// assertThat(dimensionExist2).isEqualTo(true); -// -// -// //assert 时间filter -// DateConf dateInfo = DataUtils.getDateConf(7, DateConf.DateMode.RECENT_UNITS, "DAY"); -// Boolean timeFilterExist = DataUtils.compareDate(queryResultResp.getChatContext().getDateInfo(), dateInfo); -// assertThat(timeFilterExist).isEqualTo(true); -// -// //assert nativeQuery -// assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); -// -// } - -} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/BasePluginTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/BasePluginTest.java new file mode 100644 index 000000000..bb0e00d19 --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/BasePluginTest.java @@ -0,0 +1,34 @@ +package com.tencent.supersonic.integration.plugin; + +import com.tencent.supersonic.StandaloneLauncher; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.query.plugin.WebBase; +import com.tencent.supersonic.chat.query.plugin.webpage.WebPageQuery; +import com.tencent.supersonic.chat.query.plugin.webpage.WebPageResponse; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Map; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = StandaloneLauncher.class) +@ActiveProfiles("local") +@Slf4j +public class BasePluginTest { + + protected void assertPluginRecognizeResult(QueryResult queryResult) { + Assert.assertEquals(queryResult.getQueryState(), QueryState.SUCCESS); + Assert.assertEquals(queryResult.getQueryMode(), WebPageQuery.QUERY_MODE); + WebPageResponse webPageResponse = (WebPageResponse) queryResult.getResponse(); + WebBase webPage = webPageResponse.getWebPage(); + Assert.assertEquals(webPage.getUrl(), "www.test.com"); + Map valueParams = webPage.getValueParams(); + Assert.assertEquals(valueParams.get("name"), "alice"); + } + +} \ No newline at end of file diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/PluginMockConfiguration.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/PluginMockConfiguration.java new file mode 100644 index 000000000..73bc16a11 --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/PluginMockConfiguration.java @@ -0,0 +1,32 @@ +package com.tencent.supersonic.integration.plugin; + + +import com.google.common.collect.Lists; +import com.tencent.supersonic.chat.parser.embedding.EmbeddingConfig; +import com.tencent.supersonic.chat.parser.embedding.EmbeddingResp; +import com.tencent.supersonic.chat.parser.embedding.RecallRetrieval; +import com.tencent.supersonic.chat.plugin.PluginManager; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import static org.mockito.Mockito.when; + +@Configuration +@Slf4j +public class PluginMockConfiguration { + + public static void mockEmbeddingRecognize(PluginManager pluginManager, String text, String id) { + EmbeddingResp embeddingResp = new EmbeddingResp(); + RecallRetrieval embeddingRetrieval = new RecallRetrieval(); + embeddingRetrieval.setId(id); + embeddingRetrieval.setPresetId(id); + embeddingRetrieval.setDistance("0.15"); + embeddingResp.setQuery(text); + embeddingResp.setRetrieval(Lists.newArrayList(embeddingRetrieval)); + when(pluginManager.recognize(text)).thenReturn(embeddingResp); + } + + public static void mockEmbeddingUrl(EmbeddingConfig embeddingConfig) { + when(embeddingConfig.getUrl()).thenReturn("test"); + } + +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/PluginRecognizeTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/PluginRecognizeTest.java new file mode 100644 index 000000000..bb6b8394c --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/plugin/PluginRecognizeTest.java @@ -0,0 +1,52 @@ +package com.tencent.supersonic.integration.plugin; + +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.parser.embedding.EmbeddingConfig; +import com.tencent.supersonic.chat.plugin.PluginManager; +import com.tencent.supersonic.chat.service.QueryService; +import com.tencent.supersonic.util.DataUtils; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.mock.mockito.MockBean; + +public class PluginRecognizeTest extends BasePluginTest{ + + @MockBean + private EmbeddingConfig embeddingConfig; + + @MockBean + protected PluginManager pluginManager; + + @Autowired + @Qualifier("chatQueryService") + private QueryService queryService; + + @Test + public void webPageRecognize() throws Exception { + PluginMockConfiguration.mockEmbeddingRecognize(pluginManager, "最近的访问情况怎么样","1"); + PluginMockConfiguration.mockEmbeddingUrl(embeddingConfig); + QueryRequest queryContextReq = DataUtils.getQueryContextReq(1000, "alice最近的访问情况怎么样"); + QueryResult queryResult = queryService.executeQuery(queryContextReq); + assertPluginRecognizeResult(queryResult); + } + + @Test + public void webPageRecognizeWithQueryFilter() throws Exception { + PluginMockConfiguration.mockEmbeddingRecognize(pluginManager, "在超音数最近的情况怎么样","1"); + PluginMockConfiguration.mockEmbeddingUrl(embeddingConfig); + QueryRequest queryRequest = DataUtils.getQueryContextReq(1000, "在超音数最近的情况怎么样"); + QueryFilters queryFilters = new QueryFilters(); + QueryFilter queryFilter = new QueryFilter(); + queryFilter.setElementID(2L); + queryFilter.setValue("alice"); + queryFilters.getFilters().add(queryFilter); + queryRequest.setQueryFilters(queryFilters); + QueryResult queryResult = queryService.executeQuery(queryRequest); + assertPluginRecognizeResult(queryResult); + } + +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/util/DataUtils.java b/launchers/standalone/src/test/java/com/tencent/supersonic/util/DataUtils.java index 3901badf3..7269133f0 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/util/DataUtils.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/util/DataUtils.java @@ -1,35 +1,56 @@ package com.tencent.supersonic.util; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.request.QueryRequest; import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import java.util.Set; public class DataUtils { - public static QueryContextReq getQueryContextReq(Integer id,String query) { - QueryContextReq queryContextReq = new QueryContextReq(); + public static QueryRequest getQueryContextReq(Integer id, String query) { + QueryRequest queryContextReq = new QueryRequest(); queryContextReq.setQueryText(query);//"alice的访问次数" queryContextReq.setChatId(id); queryContextReq.setUser(new User(1L, "admin", "admin", "admin@email")); return queryContextReq; } - public static SchemaItem getSchemaItem(Long id, String name, String bizName) { - SchemaItem schemaItem = new SchemaItem(); - schemaItem.setId(id); - schemaItem.setName(name); - schemaItem.setBizName(bizName); - return schemaItem; + public static SchemaElement getSchemaElement(String name) { + return SchemaElement.builder() + .name(name) + .build(); } - public static Filter getFilter(String bizName, FilterOperatorEnum filterOperatorEnum, Object value, String name, - Long elementId) { - Filter filter = new Filter(); + public static SchemaElement getMetric(Long domainId, Long id, String name, String bizName) { + return SchemaElement.builder() + .domain(domainId) + .id(id) + .name(name) + .bizName(bizName) + .useCnt(0L) + .type(SchemaElementType.METRIC) + .build(); + } + + public static SchemaElement getDimension(Long domainId, Long id, String name, String bizName) { + return SchemaElement.builder() + .domain(domainId) + .id(id) + .name(name) + .bizName(bizName) + .useCnt(null) + .type(SchemaElementType.DIMENSION) + .build(); + } + + public static QueryFilter getFilter(String bizName, FilterOperatorEnum filterOperatorEnum, Object value, String name, + Long elementId) { + QueryFilter filter = new QueryFilter(); filter.setBizName(bizName); filter.setOperator(filterOperatorEnum); filter.setValue(value); @@ -46,6 +67,13 @@ public class DataUtils { return dateInfo; } + public static DateConf getDateConf(DateConf.DateMode dateMode, String startDate, String endDate) { + DateConf dateInfo = new DateConf(); + dateInfo.setDateMode(dateMode); + dateInfo.setStartDate(startDate); + dateInfo.setEndDate(endDate); + return dateInfo; + } public static Boolean compareDate(DateConf dateInfo1, DateConf dateInfo2) { Boolean timeFilterExist = dateInfo1.getUnit().equals(dateInfo2.getUnit()) && @@ -54,23 +82,11 @@ public class DataUtils { return timeFilterExist; } - public static Boolean compareSchemaItem(Set metrics, SchemaItem schemaItemMetric) { - Boolean metricExist = false; - for (SchemaItem schemaItem : metrics) { - if(schemaItem.getBizName().equals(schemaItemMetric.getBizName())) - if (schemaItem.getId()!=null&&schemaItem.getId().equals(schemaItemMetric.getId()) && - schemaItem.getName()!=null&&schemaItem.getName().equals(schemaItemMetric.getName()) ) { - metricExist = true; - } - } - return metricExist; - } - - public static Boolean compareDateDimension(Set dimensions) { - SchemaItem schemaItemDimension = new SchemaItem(); + public static Boolean compareDateDimension(Set dimensions) { + SchemaElement schemaItemDimension = new SchemaElement(); schemaItemDimension.setBizName("sys_imp_date"); Boolean dimensionExist = false; - for (SchemaItem schemaItem : dimensions) { + for (SchemaElement schemaItem : dimensions) { if (schemaItem.getBizName().equals(schemaItemDimension.getBizName())) { dimensionExist = true; } @@ -78,9 +94,9 @@ public class DataUtils { return dimensionExist; } - public static Boolean compareDimensionFilter(Set dimensionFilters, Filter dimensionFilter) { + public static Boolean compareDimensionFilter(Set dimensionFilters, QueryFilter dimensionFilter) { Boolean dimensionFilterExist = false; - for (Filter filter : dimensionFilters) { + for (QueryFilter filter : dimensionFilters) { if (filter.getBizName().equals(dimensionFilter.getBizName()) && filter.getOperator().equals(dimensionFilter.getOperator()) && filter.getValue().toString().equals(dimensionFilter.getValue().toString()) && diff --git a/launchers/standalone/src/test/resources/META-INF/spring.factories b/launchers/standalone/src/test/resources/META-INF/spring.factories index bc01631d4..c9a823edb 100644 --- a/launchers/standalone/src/test/resources/META-INF/spring.factories +++ b/launchers/standalone/src/test/resources/META-INF/spring.factories @@ -1,20 +1,21 @@ com.tencent.supersonic.chat.api.component.SchemaMapper=\ - com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper + com.tencent.supersonic.chat.mapper.HanlpDictMapper com.tencent.supersonic.chat.api.component.SemanticParser=\ - com.tencent.supersonic.chat.application.parser.DomainSemanticParser, \ - com.tencent.supersonic.chat.application.parser.TimeSemanticParser, \ - com.tencent.supersonic.chat.application.parser.AggregateSemanticParser -# com.tencent.supersonic.chat.application.parser.LLMSemanticParser + com.tencent.supersonic.chat.parser.rule.QueryModeParser, \ + com.tencent.supersonic.chat.parser.rule.ContextInheritParser, \ + com.tencent.supersonic.chat.parser.rule.TimeRangeParser, \ + com.tencent.supersonic.chat.parser.rule.AggregateTypeParser +# com.tencent.supersonic.chat.parser.llm.DSLQueryFunction com.tencent.supersonic.chat.api.component.QueryProcessor=\ com.tencent.supersonic.chat.application.processor.SemanticQueryProcessor com.tencent.supersonic.chat.api.component.SemanticLayer=\ - com.tencent.supersonic.chat.infrastructure.semantic.LocalSemanticLayerImpl + com.tencent.supersonic.knowledge.semantic.LocalSemanticLayer -com.tencent.supersonic.chat.application.query.QuerySelector=\ - com.tencent.supersonic.chat.application.query.HeuristicQuerySelector +com.tencent.supersonic.chat.query.QuerySelector=\ + com.tencent.supersonic.chat.query.HeuristicQuerySelector com.tencent.supersonic.chat.application.query.DomainResolver=\ com.tencent.supersonic.chat.application.query.HeuristicDomainResolver diff --git a/launchers/standalone/src/test/resources/db/data-h2.sql b/launchers/standalone/src/test/resources/db/data-h2.sql index 6188a1aa6..2c9f9b80f 100644 --- a/launchers/standalone/src/test/resources/db/data-h2.sql +++ b/launchers/standalone/src/test/resources/db/data-h2.sql @@ -6,8 +6,8 @@ insert into s2_user (id, `name`, password, display_name, email) values (4, 'lucy --insert into s2_chat_config (`id` ,`domain_id` ,`default_metrics`,`visibility`,`entity_info` ,`dictionary_info`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (1,1,'[{"metricId":1,"unit":7,"period":"DAY"}]','{"blackDimIdList":[],"blackMetricIdList":[]}','{"entityIds":[2],"names":["用户","用户姓名"],"detailData":{"dimensionIds":[1,2],"metricIds":[2]}}','[{"itemId":1,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":2,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":3,"type":"DIMENSION","blackList":[],"isDictInfo":true}]','2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); insert into s2_chat_config (`id` ,`domain_id` ,`chat_detail_config`,`chat_agg_config`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) -values (1,1,'{"visibility":{"blackDimIdList":[1],"blackMetricIdList":[2]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":1,"period":"DAY"},"entity":null}', - '{"visibility":{"blackDimIdList":[3],"blackMetricIdList":[3]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":1,"period":"DAY"}}', +values (1,1,'{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"unit":7,"period":"DAY"},"entity":null}', + '{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":2,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[1,2],"metricIds":[1],"ratioMetricIds":[2],"unit":7,"period":"DAY"}}', '2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); insert into s2_chat_config (`id` ,`domain_id` ,`chat_detail_config`,`chat_agg_config`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (2,2,'{"visibility":{"blackDimIdList":[],"blackMetricIdList":[]},"knowledgeInfos":[{"itemId":7,"type":"DIMENSION","searchEnable":true}],"chatDefaultConfig":{"dimensionIds":[4,5,6,7],"metricIds":[4],"unit":7,"period":"DAY"},"entity":{"entityId":1,"names":["歌手","艺人"]}}', @@ -27,6 +27,8 @@ insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`, insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(5, '2023-06-10 10:41:48.211','停留时长','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(6, '2023-06-10 10:42:02.184','访问','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); +insert into s2_plugin (id, `type`, `domain`, pattern, parse_mode, `name`, created_at, created_by, updated_at, updated_by, config) VALUES (1, 'WEB_PAGE', 1, '访问情况', 'EMBEDDING_RECALL', '访问情况', '2023-06-11 19:36:47', 'admin', '2023-06-21 15:26:46', 'admin', '{"params":{"name":"2"}, "url":"www.test.com"}'); +insert into s2_plugin (id, `type`, `domain`, pattern, parse_mode, `name`, created_at, created_by, updated_at, updated_by, config) VALUES (2, 'WEB_PAGE', 2, '播放表现', 'EMBEDDING_RECALL', '播放表现', '2023-06-11 19:36:47', 'admin', '2023-06-21 15:26:46', 'admin', '{"params":{"name":"7"}, "url":"www.test.com"}'); -- semantic data insert into s2_database (id, domain_id , `name`, description, `type` ,config ,created_at ,created_by ,updated_at ,updated_by) VALUES(1, 1, 'H2数据实例', '', 'h2', '{"password":"semantic","url":"jdbc:h2:mem:semantic;DATABASE_TO_UPPER=false","userName":"root"}', '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin'); diff --git a/launchers/standalone/src/test/resources/db/schema-h2.sql b/launchers/standalone/src/test/resources/db/schema-h2.sql index 6d41f684a..ba2b35a7b 100644 --- a/launchers/standalone/src/test/resources/db/schema-h2.sql +++ b/launchers/standalone/src/test/resources/db/schema-h2.sql @@ -44,6 +44,7 @@ CREATE TABLE IF NOT EXISTS `s2_chat_config` ( `domain_id` INT DEFAULT NULL , `chat_detail_config` varchar(655) , `chat_agg_config` varchar(655) , + `recommended_questions` varchar(1500) , `created_at` TIMESTAMP NOT NULL , `updated_at` TIMESTAMP NOT NULL , `created_by` varchar(100) NOT NULL , @@ -117,6 +118,7 @@ CREATE TABLE IF NOT EXISTS `s2_domain` ( `is_open` TINYINT DEFAULT NULL , -- whether the domain is public `viewer` varchar(3000) DEFAULT NULL , -- domain available users `view_org` varchar(3000) DEFAULT NULL , -- domain available organization + `entity` varchar(500) DEFAULT NULL , -- domain entity info PRIMARY KEY (`id`) ); COMMENT ON TABLE s2_domain IS 'domain basic information'; @@ -127,6 +129,7 @@ CREATE TABLE `s2_database` ( `domain_id` INT NOT NULL , `name` varchar(255) NOT NULL , `description` varchar(500) DEFAULT NULL , + `version` varchar(64) DEFAULT NULL , `type` varchar(20) NOT NULL , -- type: mysql,clickhouse,tdw `config` varchar(655) NOT NULL , `created_at` TIMESTAMP NOT NULL , @@ -201,6 +204,7 @@ CREATE TABLE IF NOT EXISTS `s2_dimension` ( `semantic_type` varchar(20) NOT NULL, -- semantic type: DATE, ID, CATEGORY `alias` varchar(500) DEFAULT NULL, `default_values` varchar(500) DEFAULT NULL, + `dim_value_maps` varchar(500) DEFAULT NULL, PRIMARY KEY (`id`) ); COMMENT ON TABLE s2_dimension IS 'dimension information table'; @@ -309,6 +313,22 @@ CREATE TABLE IF NOT EXISTS `s2_available_date_info` ( ); COMMENT ON TABLE s2_dimension IS 'dimension information table'; +CREATE TABLE IF NOT EXISTS `s2_plugin` +( + `id` INT AUTO_INCREMENT, + `type` varchar(50) NULL, + `domain` varchar(100) NULL, + `pattern` varchar(500) NULL, + `parse_mode` varchar(100) NULL, + `name` varchar(100) NULL, + `created_at` TIMESTAMP NULL, + `created_by` varchar(100) null, + `updated_at` TIMESTAMP NULL, + `updated_by` varchar(100) NULL, + `config` LONGVARCHAR NULL, + PRIMARY KEY (`id`) +); COMMENT ON TABLE s2_plugin IS 'plugin information table'; + -------demo for semantic and chat CREATE TABLE IF NOT EXISTS `s2_user_department` ( diff --git a/pom.xml b/pom.xml index 7e6c4be5a..4a67beb53 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ 5.1.46 2.3.1 1.3.2 - 0.3.2 + 0.4.6 1.4.200 2.0.24 6.5.0 @@ -61,6 +61,7 @@ 2.5.1 1.34.0 1.23.0 + 3.2.4 0.6-SNAPSHOT @@ -140,6 +141,10 @@ maven-resources-plugin 3.1.0 + + + + @@ -148,6 +153,35 @@ sonar-maven-plugin 3.6.0.1398 + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.2 + + + com.puppycrawl.tools + checkstyle + 9.3 + + + + checkstyle/checkstyle.xml + UTF-8 + true + true + false + true + + + + validate + validate + + check + + + + diff --git a/semantic/api/pom.xml b/semantic/api/pom.xml index 73c749879..7c6b480e6 100644 --- a/semantic/api/pom.xml +++ b/semantic/api/pom.xml @@ -12,10 +12,17 @@ semantic-api + + + + + - ru.yandex.clickhouse + com.clickhouse clickhouse-jdbc ${clickhouse.jdbc.version} + + all org.projectlombok diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/RecordInfo.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/RecordInfo.java deleted file mode 100644 index 8842939cd..000000000 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/RecordInfo.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.tencent.supersonic.semantic.api.core.pojo; - -import java.util.Date; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.ToString; - - -@Data -@ToString -@AllArgsConstructor -public class RecordInfo { - - - private String createdBy; - - private String updatedBy; - - private Date createdAt; - - private Date updatedAt; - -} diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricBaseReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricBaseReq.java deleted file mode 100644 index fcea10637..000000000 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricBaseReq.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tencent.supersonic.semantic.api.core.request; - - -import com.tencent.supersonic.common.pojo.SchemaItem; -import lombok.Data; - - -@Data -public class MetricBaseReq extends SchemaItem { - - private Long domainId; - - private String alias; - -} diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatasourceResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatasourceResp.java deleted file mode 100644 index e022ed200..000000000 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatasourceResp.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.tencent.supersonic.semantic.api.core.response; - -import com.tencent.supersonic.semantic.api.core.pojo.DatasourceDetail; -import com.tencent.supersonic.common.pojo.SchemaItem; -import lombok.Data; - -@Data -public class DatasourceResp extends SchemaItem { - - private Long domainId; - - private Long databaseId; - - private DatasourceDetail datasourceDetail; - - -} diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/DataTypeEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/DataTypeEnum.java similarity index 96% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/DataTypeEnum.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/DataTypeEnum.java index 2f2c0928c..a9174fc47 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/DataTypeEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/DataTypeEnum.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.api.core.enums; +package com.tencent.supersonic.semantic.api.model.enums; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import java.util.HashSet; import java.util.Set; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/DimensionTypeEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/DimensionTypeEnum.java similarity index 53% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/DimensionTypeEnum.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/DimensionTypeEnum.java index 47d4cafe9..ce299d856 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/DimensionTypeEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/DimensionTypeEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.enums; +package com.tencent.supersonic.semantic.api.model.enums; public enum DimensionTypeEnum { diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/MetricTypeEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/MetricTypeEnum.java similarity index 50% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/MetricTypeEnum.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/MetricTypeEnum.java index 09674c884..112426b14 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/MetricTypeEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/MetricTypeEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.enums; +package com.tencent.supersonic.semantic.api.model.enums; public enum MetricTypeEnum { diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/OperatorEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/OperatorEnum.java similarity index 86% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/OperatorEnum.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/OperatorEnum.java index 3a37f9a31..707f5db91 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/OperatorEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/OperatorEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.enums; +package com.tencent.supersonic.semantic.api.model.enums; public enum OperatorEnum { diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeBackEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/QueryTypeBackEnum.java similarity index 92% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeBackEnum.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/QueryTypeBackEnum.java index 942f02ee3..038b72fac 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeBackEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/QueryTypeBackEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.enums; +package com.tencent.supersonic.semantic.api.model.enums; public enum QueryTypeBackEnum { diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/QueryTypeEnum.java similarity index 89% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeEnum.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/QueryTypeEnum.java index 0cfa26322..db23db28f 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/QueryTypeEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.enums; +package com.tencent.supersonic.semantic.api.model.enums; public enum QueryTypeEnum { diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/TimeDimensionEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/TimeDimensionEnum.java similarity index 90% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/TimeDimensionEnum.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/TimeDimensionEnum.java index 0ad46bca3..5f39acc70 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/TimeDimensionEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/enums/TimeDimensionEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.enums; +package com.tencent.supersonic.semantic.api.model.enums; import java.util.Arrays; import java.util.List; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DatasourceDetail.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DatasourceDetail.java similarity index 84% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DatasourceDetail.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DatasourceDetail.java index a46c8e5d7..a0a53e93c 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DatasourceDetail.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DatasourceDetail.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import java.util.List; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DatasourceType.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DatasourceType.java similarity index 77% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DatasourceType.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DatasourceType.java index 4c2eff730..729c88be2 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DatasourceType.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DatasourceType.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import java.util.List; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Dim.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Dim.java similarity index 85% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Dim.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Dim.java index 9c7d57fe2..618b7da33 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Dim.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Dim.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DimValueMap.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DimValueMap.java new file mode 100644 index 000000000..24aeefbfa --- /dev/null +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DimValueMap.java @@ -0,0 +1,30 @@ +package com.tencent.supersonic.semantic.api.model.pojo; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author: kanedai + * @date: 2023/7/24 + */ + +@Data +public class DimValueMap { + + /** + * dimension value in db + */ + private String techName; + + /** + * dimension value for result show + */ + private String bizName; + + /** + * dimension value for user query + */ + private List alias = new ArrayList<>(); +} \ No newline at end of file diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DimensionTimeTypeParams.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DimensionTimeTypeParams.java similarity index 81% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DimensionTimeTypeParams.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DimensionTimeTypeParams.java index a303bfcd0..db3a265bd 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/DimensionTimeTypeParams.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/DimensionTimeTypeParams.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Entity.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Entity.java new file mode 100644 index 000000000..a547a98fb --- /dev/null +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Entity.java @@ -0,0 +1,26 @@ +package com.tencent.supersonic.semantic.api.model.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.util.List; + +@Data +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class Entity { + + + /** + * uniquely identifies an entity + */ + private Long entityId; + + /** + * entity name list + */ + private List names; +} \ No newline at end of file diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Identify.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Identify.java similarity index 83% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Identify.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Identify.java index c81db11c7..e3bddbf0f 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Identify.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Identify.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/ItemDateFilter.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/ItemDateFilter.java similarity index 82% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/ItemDateFilter.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/ItemDateFilter.java index a51821dae..19cb7d60a 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/ItemDateFilter.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/ItemDateFilter.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import java.util.List; import lombok.AllArgsConstructor; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Measure.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Measure.java similarity index 88% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Measure.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Measure.java index a9fb2e721..17efa7938 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/Measure.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/Measure.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/MetricTypeParams.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/MetricTypeParams.java similarity index 79% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/MetricTypeParams.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/MetricTypeParams.java index b97bf56f8..78d403b23 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/MetricTypeParams.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/MetricTypeParams.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import java.util.List; import com.google.common.collect.Lists; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryResult.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/QueryResult.java similarity index 86% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryResult.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/QueryResult.java index 8a856f3bc..5c7a94967 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryResult.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/QueryResult.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import java.io.Serializable; import java.util.ArrayList; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryStat.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/QueryStat.java similarity index 98% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryStat.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/QueryStat.java index bb6037e3b..e2a429a13 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryStat.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/QueryStat.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; diff --git a/common/src/main/java/com/tencent/supersonic/common/pojo/SchemaItem.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/SchemaItem.java similarity index 77% rename from common/src/main/java/com/tencent/supersonic/common/pojo/SchemaItem.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/SchemaItem.java index 7394bf03b..ab1ab75fa 100644 --- a/common/src/main/java/com/tencent/supersonic/common/pojo/SchemaItem.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/pojo/SchemaItem.java @@ -1,13 +1,15 @@ -package com.tencent.supersonic.common.pojo; +package com.tencent.supersonic.semantic.api.model.pojo; import com.google.common.base.Objects; -import com.tencent.supersonic.common.enums.SensitiveLevelEnum; -import com.tencent.supersonic.common.enums.StatusEnum; -import com.tencent.supersonic.common.enums.TypeEnums; -import com.tencent.supersonic.common.util.RecordInfo; +import com.tencent.supersonic.common.pojo.RecordInfo; +import com.tencent.supersonic.common.pojo.enums.SensitiveLevelEnum; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; +import com.tencent.supersonic.common.pojo.enums.TypeEnums; import lombok.Data; +import lombok.ToString; @Data +@ToString(callSuper = true) public class SchemaItem extends RecordInfo { private Long id; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatabaseReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatabaseReq.java similarity index 83% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatabaseReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatabaseReq.java index 1924d91ed..8d7ee8d16 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatabaseReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatabaseReq.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; -import com.tencent.supersonic.semantic.api.core.enums.DataTypeEnum; +import com.tencent.supersonic.semantic.api.model.enums.DataTypeEnum; import lombok.Data; import org.apache.commons.lang3.StringUtils; @@ -26,6 +26,8 @@ public class DatabaseReq { private String database; + private String version; + private String description; private String url; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceRelaReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatasourceRelaReq.java similarity index 88% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceRelaReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatasourceRelaReq.java index 6cdebd54e..7afeb0a1d 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceRelaReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatasourceRelaReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import javax.validation.constraints.NotNull; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatasourceReq.java similarity index 54% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatasourceReq.java index bcfeb3363..acf3e0fec 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DatasourceReq.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; -import com.tencent.supersonic.semantic.api.core.pojo.Dim; -import com.tencent.supersonic.semantic.api.core.pojo.Identify; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.model.pojo.Dim; +import com.tencent.supersonic.semantic.api.model.pojo.Identify; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; import java.util.List; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DateInfoReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DateInfoReq.java similarity index 95% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DateInfoReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DateInfoReq.java index cf2f0e15a..ca830162e 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DateInfoReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DateInfoReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import java.util.ArrayList; import java.util.List; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DimensionReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DimensionReq.java similarity index 65% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DimensionReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DimensionReq.java index 31a101129..37bc1db50 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DimensionReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DimensionReq.java @@ -1,8 +1,12 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; + +import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; -import com.tencent.supersonic.common.pojo.SchemaItem; import javax.validation.constraints.NotNull; + import lombok.Data; + import java.util.List; @Data @@ -25,5 +29,5 @@ public class DimensionReq extends SchemaItem { private List defaultValues; - + private List dimValueMaps; } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainReq.java similarity index 65% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainReq.java index 1ef18fa69..03945e854 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainReq.java @@ -1,9 +1,12 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; -import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.model.pojo.Entity; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; + import java.util.ArrayList; import java.util.List; + import lombok.Data; @@ -21,4 +24,6 @@ public class DomainReq extends SchemaItem { private List admins = new ArrayList<>(); private List adminOrgs = new ArrayList<>(); + + private Entity entity; } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainSchemaFilterReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainSchemaFilterReq.java similarity index 76% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainSchemaFilterReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainSchemaFilterReq.java index d9dce1750..db0d04c99 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainSchemaFilterReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainSchemaFilterReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import java.util.List; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainUpdateReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainUpdateReq.java similarity index 63% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainUpdateReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainUpdateReq.java index 0cc9862b5..ef8ab9fcc 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DomainUpdateReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainUpdateReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/MetricBaseReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/MetricBaseReq.java new file mode 100644 index 000000000..13549bcdf --- /dev/null +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/MetricBaseReq.java @@ -0,0 +1,20 @@ +package com.tencent.supersonic.semantic.api.model.request; + + +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; +import com.tencent.supersonic.common.pojo.DataFormat; +import lombok.Data; + + +@Data +public class MetricBaseReq extends SchemaItem { + + private Long domainId; + + private String alias; + + private String dataFormatType; + + private DataFormat dataFormat; + +} diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/MetricReq.java similarity index 72% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/MetricReq.java index 0eef7bc0b..092a8c537 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/MetricReq.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; -import com.tencent.supersonic.semantic.api.core.enums.MetricTypeEnum; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.semantic.api.core.pojo.MetricTypeParams; +import com.tencent.supersonic.semantic.api.model.enums.MetricTypeEnum; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.pojo.MetricTypeParams; import lombok.Data; import java.util.List; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageDimensionReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageDimensionReq.java similarity index 60% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageDimensionReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageDimensionReq.java index 418e3ddc4..0178fdeb3 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageDimensionReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageDimensionReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageMetricReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageMetricReq.java similarity index 65% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageMetricReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageMetricReq.java index f283becd2..40edea0c2 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageMetricReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageMetricReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageSchemaItemReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageSchemaItemReq.java similarity index 70% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageSchemaItemReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageSchemaItemReq.java index 9644ba893..de2ace366 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/PageSchemaItemReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/PageSchemaItemReq.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; -import com.tencent.supersonic.common.request.PageBaseReq; +import com.tencent.supersonic.common.pojo.PageBaseReq; import lombok.Data; @Data diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/SqlExecuteReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/SqlExecuteReq.java similarity index 63% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/SqlExecuteReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/SqlExecuteReq.java index f3c74506b..9a162460a 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/SqlExecuteReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/SqlExecuteReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import javax.validation.constraints.NotBlank; @@ -7,7 +7,7 @@ import lombok.Data; @Data public class SqlExecuteReq { - + public static final String LIMIT_WRAPPER = " select * from ( %s ) a limit 1000 "; @NotNull(message = "domainId can not be null") private Long domainId; @@ -16,7 +16,7 @@ public class SqlExecuteReq { private String sql; public String getSql() { - return String.format(" select * from ( %s ) a limit 1000 ", sql); + return String.format(LIMIT_WRAPPER, sql); } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/ViewInfoReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/ViewInfoReq.java similarity index 83% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/ViewInfoReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/ViewInfoReq.java index a3c47d26b..ba253f349 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/ViewInfoReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/ViewInfoReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.request; +package com.tencent.supersonic.semantic.api.model.request; import java.util.Date; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatabaseResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatabaseResp.java similarity index 91% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatabaseResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatabaseResp.java index 76b4f2444..5e4a00eee 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatabaseResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatabaseResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -28,6 +28,8 @@ public class DatabaseResp { private String database; + private String version; + public String getHost() { Pattern p = Pattern.compile("jdbc:(?\\w+):.*((//)|@)(?.+):(?\\d+).*"); Matcher m = p.matcher(url); diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatasourceRelaResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatasourceRelaResp.java similarity index 85% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatasourceRelaResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatasourceRelaResp.java index 7207c9609..3cb409523 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DatasourceRelaResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatasourceRelaResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import java.util.Date; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatasourceResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatasourceResp.java new file mode 100644 index 000000000..20b34f97f --- /dev/null +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DatasourceResp.java @@ -0,0 +1,17 @@ +package com.tencent.supersonic.semantic.api.model.response; + +import com.tencent.supersonic.semantic.api.model.pojo.DatasourceDetail; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; +import lombok.Data; + +@Data +public class DatasourceResp extends SchemaItem { + + private Long domainId; + + private Long databaseId; + + private DatasourceDetail datasourceDetail; + + +} diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimSchemaResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DimSchemaResp.java similarity index 50% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimSchemaResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DimSchemaResp.java index 58e993abb..e4118d52a 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimSchemaResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DimSchemaResp.java @@ -1,8 +1,10 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import lombok.Data; +import lombok.ToString; @Data +@ToString(callSuper = true) public class DimSchemaResp extends DimensionResp { private Long useCnt = 0L; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimensionResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DimensionResp.java similarity index 60% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimensionResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DimensionResp.java index 38a0ce7a1..3d98d935d 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimensionResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DimensionResp.java @@ -1,12 +1,17 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; -import com.tencent.supersonic.common.pojo.SchemaItem; -import lombok.Data; +import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; + import java.util.List; +import lombok.Data; +import lombok.ToString; + @Data +@ToString(callSuper = true) public class DimensionResp extends SchemaItem { private Long domainId; @@ -29,5 +34,6 @@ public class DimensionResp extends SchemaItem { private List defaultValues; + private List dimValueMaps; } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainResp.java similarity index 66% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainResp.java index e0b8689e4..13c66160c 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainResp.java @@ -1,7 +1,10 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; + +import com.tencent.supersonic.semantic.api.model.pojo.Entity; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; -import com.tencent.supersonic.common.pojo.SchemaItem; import java.util.List; + import lombok.Data; import lombok.ToString; @@ -27,5 +30,6 @@ public class DomainResp extends SchemaItem { private Integer metricCnt; + private Entity entity; } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainSchemaRelaResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainSchemaRelaResp.java similarity index 80% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainSchemaRelaResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainSchemaRelaResp.java index 54f15b41e..33d3c11be 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainSchemaRelaResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainSchemaRelaResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import java.util.List; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainSchemaResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainSchemaResp.java similarity index 84% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainSchemaResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainSchemaResp.java index 5d4b4b39e..00ee2dcca 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainSchemaResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/DomainSchemaResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import java.util.List; import lombok.AllArgsConstructor; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/ItemDateResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/ItemDateResp.java similarity index 87% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/ItemDateResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/ItemDateResp.java index 0a62e1b6a..7914a5d77 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/ItemDateResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/ItemDateResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import java.util.ArrayList; import java.util.List; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MeasureResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MeasureResp.java similarity index 85% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MeasureResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MeasureResp.java index 52bfd63ee..d7947bc3b 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MeasureResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MeasureResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MetricResp.java similarity index 54% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MetricResp.java index c3dfb0295..682d970d3 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MetricResp.java @@ -1,13 +1,15 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; -import com.tencent.supersonic.semantic.api.core.pojo.DataFormat; -import com.tencent.supersonic.semantic.api.core.pojo.MetricTypeParams; -import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.common.pojo.DataFormat; +import com.tencent.supersonic.semantic.api.model.pojo.MetricTypeParams; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; import lombok.Data; +import lombok.ToString; @Data +@ToString(callSuper = true) public class MetricResp extends SchemaItem { private Long domainId; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricSchemaResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MetricSchemaResp.java similarity index 50% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricSchemaResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MetricSchemaResp.java index 25b71c370..4c90188b6 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricSchemaResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/MetricSchemaResp.java @@ -1,8 +1,10 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import lombok.Data; +import lombok.ToString; @Data +@ToString(callSuper = true) public class MetricSchemaResp extends MetricResp { private Long useCnt = 0L; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/QueryResultWithSchemaResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/QueryResultWithSchemaResp.java similarity index 51% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/QueryResultWithSchemaResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/QueryResultWithSchemaResp.java index 7107dc6f2..72ddcd66c 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/QueryResultWithSchemaResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/QueryResultWithSchemaResp.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; -import com.tencent.supersonic.semantic.api.core.pojo.QueryAuthorization; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.pojo.QueryResult; +import com.tencent.supersonic.common.pojo.QueryAuthorization; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.model.pojo.QueryResult; import java.util.List; import java.util.Map; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/SqlParserResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/SqlParserResp.java similarity index 89% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/SqlParserResp.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/SqlParserResp.java index 4c329754c..b8b37a688 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/SqlParserResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/response/SqlParserResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.response; +package com.tencent.supersonic.semantic.api.model.response; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DatasourceYamlTpl.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DatasourceYamlTpl.java similarity index 85% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DatasourceYamlTpl.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DatasourceYamlTpl.java index 41360317d..ee02f712a 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DatasourceYamlTpl.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DatasourceYamlTpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo.yaml; +package com.tencent.supersonic.semantic.api.model.yaml; import java.util.List; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DimensionTimeTypeParamsTpl.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DimensionTimeTypeParamsTpl.java similarity index 70% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DimensionTimeTypeParamsTpl.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DimensionTimeTypeParamsTpl.java index 19f2b4616..83943e388 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DimensionTimeTypeParamsTpl.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DimensionTimeTypeParamsTpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo.yaml; +package com.tencent.supersonic.semantic.api.model.yaml; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DimensionYamlTpl.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DimensionYamlTpl.java similarity index 78% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DimensionYamlTpl.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DimensionYamlTpl.java index ebdc50aad..b08bf252f 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/DimensionYamlTpl.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/DimensionYamlTpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo.yaml; +package com.tencent.supersonic.semantic.api.model.yaml; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/IdentifyYamlTpl.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/IdentifyYamlTpl.java similarity index 82% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/IdentifyYamlTpl.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/IdentifyYamlTpl.java index cff864527..8de633418 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/IdentifyYamlTpl.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/IdentifyYamlTpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo.yaml; +package com.tencent.supersonic.semantic.api.model.yaml; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MeasureYamlTpl.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MeasureYamlTpl.java similarity index 84% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MeasureYamlTpl.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MeasureYamlTpl.java index 95738edef..681041062 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MeasureYamlTpl.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MeasureYamlTpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo.yaml; +package com.tencent.supersonic.semantic.api.model.yaml; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MetricTypeParamsYamlTpl.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MetricTypeParamsYamlTpl.java similarity index 73% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MetricTypeParamsYamlTpl.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MetricTypeParamsYamlTpl.java index 6127012f8..20986bfba 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MetricTypeParamsYamlTpl.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MetricTypeParamsYamlTpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo.yaml; +package com.tencent.supersonic.semantic.api.model.yaml; import java.util.List; import lombok.Data; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MetricYamlTpl.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MetricYamlTpl.java similarity index 78% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MetricYamlTpl.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MetricYamlTpl.java index 44e8c61c0..e4c5cea59 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/yaml/MetricYamlTpl.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/yaml/MetricYamlTpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.api.core.pojo.yaml; +package com.tencent.supersonic.semantic.api.model.yaml; import java.util.List; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/ParseSqlReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/ParseSqlReq.java index 9d8722d13..6c1281d59 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/ParseSqlReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/ParseSqlReq.java @@ -13,6 +13,7 @@ public class ParseSqlReq { private Map variables; private String sql = ""; private List tables; + private boolean supportWith = true; public Map getVariables() { if (variables == null) { diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QuerySqlReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QueryDslReq.java similarity index 90% rename from semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QuerySqlReq.java rename to semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QueryDslReq.java index c4e2ede09..f5f916ad3 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QuerySqlReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QueryDslReq.java @@ -6,7 +6,7 @@ import lombok.ToString; @Data @ToString -public class QuerySqlReq { +public class QueryDslReq { private Long domainId; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QueryMultiStructReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QueryMultiStructReq.java index fec8d6d07..c154aaacb 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QueryMultiStructReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/request/QueryMultiStructReq.java @@ -11,11 +11,11 @@ import org.apache.commons.codec.digest.DigestUtils; public class QueryMultiStructReq { - List queryStructCmds; + List queryStructReqs; public String toCustomizedString() { - return JSONObject.toJSONString(queryStructCmds); + return JSONObject.toJSONString(queryStructReqs); } public String generateCommandMd5() { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/Catalog.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/Catalog.java deleted file mode 100644 index 36ddf8bc0..000000000 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/Catalog.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.tencent.supersonic.semantic.core.domain; - -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DatasourceYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public interface Catalog { - - DatabaseResp getDatabase(Long id); - - List getDatasourceList(Long domainId); - - String getDomainFullPath(Long domainId); - - Map getDomainFullPath(); - - DimensionResp getDimension(String bizName, Long domainId); - - List getDimensions(Long domainId); - - List getMetrics(Long domainId); - - void getModelYamlTplByDomainIds(Set domainIds, Map> dimensionYamlMap, - List datasourceYamlTplList, List metricYamlTplList); - - - ItemDateResp getDateDate(ItemDateFilter dimension, ItemDateFilter metric); - -} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Datasource.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Datasource.java deleted file mode 100644 index 24c5f9ee8..000000000 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Datasource.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; - - -import com.tencent.supersonic.semantic.api.core.pojo.DatasourceDetail; -import com.tencent.supersonic.common.pojo.SchemaItem; -import lombok.Data; - - -@Data -public class Datasource extends SchemaItem { - - private Long domainId; - - private Long databaseId; - - private DatasourceDetail datasourceDetail; - - -} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DateInfoRepository.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DateInfoRepository.java deleted file mode 100644 index 73f09c02f..000000000 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DateInfoRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.tencent.supersonic.semantic.core.domain.repository; - - -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.core.request.DateInfoReq; -import com.tencent.supersonic.semantic.core.domain.dataobject.DateInfoDO; - -import java.util.List; - -public interface DateInfoRepository { - - Integer upsertDateInfo(List dateInfoReqs); - - List getDateInfos(ItemDateFilter itemDateFilter); - -} diff --git a/semantic/core/pom.xml b/semantic/model/pom.xml similarity index 93% rename from semantic/core/pom.xml rename to semantic/model/pom.xml index c7a9465c4..264bfe3ae 100644 --- a/semantic/core/pom.xml +++ b/semantic/model/pom.xml @@ -9,7 +9,7 @@ 4.0.0 - semantic-core + semantic-model 8 @@ -34,7 +34,10 @@ ${project.version} compile - + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + org.springframework.boot spring-boot-starter-jdbc diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/CatalogImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/CatalogImpl.java similarity index 58% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/CatalogImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/CatalogImpl.java index 615e950c7..223463a80 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/CatalogImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/CatalogImpl.java @@ -1,24 +1,25 @@ -package com.tencent.supersonic.semantic.core.application; +package com.tencent.supersonic.semantic.model.application; -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DatasourceYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.core.domain.DatasourceService; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDO; -import com.tencent.supersonic.semantic.core.domain.repository.DatabaseRepository; -import com.tencent.supersonic.semantic.core.domain.utils.DatabaseConverter; +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.api.model.yaml.DatasourceYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricYamlTpl; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.ItemDateResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO; +import com.tencent.supersonic.semantic.model.domain.repository.DatabaseRepository; +import com.tencent.supersonic.semantic.model.domain.utils.DatabaseConverter; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -49,6 +50,12 @@ public class CatalogImpl implements Catalog { return DatabaseConverter.convert(databaseDO); } + public DatabaseResp getDatabaseByDomainId(Long domainId) { + List databaseDOS = databaseRepository.getDatabaseByDomainId(domainId); + Optional databaseDO = databaseDOS.stream().findFirst(); + return databaseDO.map(DatabaseConverter::convert).orElse(null); + } + @Override public String getDomainFullPath(Long domainId) { return domainService.getDomainFullPath(domainId); @@ -87,7 +94,7 @@ public class CatalogImpl implements Catalog { } @Override - public ItemDateResp getDateDate(ItemDateFilter dimension, ItemDateFilter metric) { - return datasourceService.getDateDate(dimension, metric); + public ItemDateResp getItemDate(ItemDateFilter dimension, ItemDateFilter metric) { + return datasourceService.getItemDate(dimension, metric); } } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatabaseServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatabaseServiceImpl.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatabaseServiceImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatabaseServiceImpl.java index c61bdf965..fb7e150e8 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatabaseServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatabaseServiceImpl.java @@ -1,19 +1,19 @@ -package com.tencent.supersonic.semantic.core.application; +package com.tencent.supersonic.semantic.model.application; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DatabaseReq; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; -import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptor; -import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptorFactory; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDO; -import com.tencent.supersonic.semantic.core.domain.repository.DatabaseRepository; -import com.tencent.supersonic.semantic.core.domain.utils.DatabaseConverter; -import com.tencent.supersonic.semantic.core.domain.utils.JdbcDataSourceUtils; -import com.tencent.supersonic.semantic.core.domain.utils.SqlUtils; -import com.tencent.supersonic.semantic.core.domain.DatabaseService; -import com.tencent.supersonic.semantic.core.domain.pojo.Database; +import com.tencent.supersonic.semantic.api.model.request.DatabaseReq; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.SqlParserResp; +import com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter.EngineAdaptor; +import com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter.EngineAdaptorFactory; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO; +import com.tencent.supersonic.semantic.model.domain.repository.DatabaseRepository; +import com.tencent.supersonic.semantic.model.domain.utils.DatabaseConverter; +import com.tencent.supersonic.semantic.model.domain.utils.JdbcDataSourceUtils; +import com.tencent.supersonic.semantic.model.domain.utils.SqlUtils; +import com.tencent.supersonic.semantic.model.domain.DatabaseService; +import com.tencent.supersonic.semantic.model.domain.pojo.Database; import java.util.List; import java.util.Optional; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatasourceServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatasourceServiceImpl.java similarity index 84% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatasourceServiceImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatasourceServiceImpl.java index cb87e595d..03ae3fc12 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatasourceServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatasourceServiceImpl.java @@ -1,44 +1,44 @@ -package com.tencent.supersonic.semantic.core.application; +package com.tencent.supersonic.semantic.model.application; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.common.util.json.JsonUtil; -import com.tencent.supersonic.semantic.api.core.pojo.DatasourceDetail; -import com.tencent.supersonic.semantic.api.core.pojo.Dim; -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DatasourceYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.semantic.api.core.request.DatasourceRelaReq; -import com.tencent.supersonic.semantic.api.core.request.DatasourceReq; -import com.tencent.supersonic.semantic.api.core.request.DateInfoReq; -import com.tencent.supersonic.semantic.api.core.request.DimensionReq; -import com.tencent.supersonic.semantic.api.core.request.MetricReq; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.DatasourceRelaResp; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; -import com.tencent.supersonic.semantic.api.core.response.MeasureResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.core.domain.DatabaseService; -import com.tencent.supersonic.semantic.core.domain.DatasourceService; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.MetricService; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceRelaDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DateInfoDO; -import com.tencent.supersonic.semantic.core.domain.manager.DatasourceYamlManager; -import com.tencent.supersonic.semantic.core.domain.manager.DimensionYamlManager; -import com.tencent.supersonic.semantic.core.domain.manager.MetricYamlManager; -import com.tencent.supersonic.semantic.core.domain.pojo.Datasource; -import com.tencent.supersonic.semantic.core.domain.repository.DatasourceRepository; -import com.tencent.supersonic.semantic.core.domain.repository.DateInfoRepository; -import com.tencent.supersonic.semantic.core.domain.utils.DatasourceConverter; -import com.tencent.supersonic.semantic.core.domain.utils.DimensionConverter; -import com.tencent.supersonic.semantic.core.domain.utils.MetricConverter; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.semantic.api.model.pojo.DatasourceDetail; +import com.tencent.supersonic.semantic.api.model.pojo.Dim; +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.yaml.DatasourceYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricYamlTpl; +import com.tencent.supersonic.semantic.api.model.request.DatasourceRelaReq; +import com.tencent.supersonic.semantic.api.model.request.DatasourceReq; +import com.tencent.supersonic.semantic.api.model.request.DateInfoReq; +import com.tencent.supersonic.semantic.api.model.request.DimensionReq; +import com.tencent.supersonic.semantic.api.model.request.MetricReq; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceRelaResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.ItemDateResp; +import com.tencent.supersonic.semantic.api.model.response.MeasureResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.model.domain.DatabaseService; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DateInfoDO; +import com.tencent.supersonic.semantic.model.domain.manager.DatasourceYamlManager; +import com.tencent.supersonic.semantic.model.domain.manager.DimensionYamlManager; +import com.tencent.supersonic.semantic.model.domain.manager.MetricYamlManager; +import com.tencent.supersonic.semantic.model.domain.pojo.Datasource; +import com.tencent.supersonic.semantic.model.domain.repository.DatasourceRepository; +import com.tencent.supersonic.semantic.model.domain.repository.DateInfoRepository; +import com.tencent.supersonic.semantic.model.domain.utils.DatasourceConverter; +import com.tencent.supersonic.semantic.model.domain.utils.DimensionConverter; +import com.tencent.supersonic.semantic.model.domain.utils.MetricConverter; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -301,7 +301,7 @@ public class DatasourceServiceImpl implements DatasourceService { @Override - public ItemDateResp getDateDate(ItemDateFilter dimension, ItemDateFilter metric) { + public ItemDateResp getItemDate(ItemDateFilter dimension, ItemDateFilter metric) { List itemDates = new ArrayList<>(); List dimensions = dateInfoRepository.getDateInfos(dimension); List metrics = dateInfoRepository.getDateInfos(metric); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DimensionServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DimensionServiceImpl.java similarity index 90% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DimensionServiceImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DimensionServiceImpl.java index 3fcfdf0d4..5d06e641e 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DimensionServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DimensionServiceImpl.java @@ -1,23 +1,23 @@ -package com.tencent.supersonic.semantic.core.application; +package com.tencent.supersonic.semantic.model.application; import com.alibaba.fastjson.JSONObject; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.common.enums.SensitiveLevelEnum; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; -import com.tencent.supersonic.semantic.core.domain.repository.DimensionRepository; -import com.tencent.supersonic.semantic.core.domain.utils.DimensionConverter; -import com.tencent.supersonic.semantic.core.domain.DatasourceService; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.pojo.Dimension; -import com.tencent.supersonic.semantic.core.domain.pojo.DimensionFilter; +import com.tencent.supersonic.semantic.api.model.request.DimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.common.pojo.enums.SensitiveLevelEnum; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDO; +import com.tencent.supersonic.semantic.model.domain.repository.DimensionRepository; +import com.tencent.supersonic.semantic.model.domain.utils.DimensionConverter; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.pojo.Dimension; +import com.tencent.supersonic.semantic.model.domain.pojo.DimensionFilter; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DomainServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DomainServiceImpl.java similarity index 86% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DomainServiceImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DomainServiceImpl.java index 9e081b645..f8fa1d773 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DomainServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DomainServiceImpl.java @@ -1,27 +1,29 @@ -package com.tencent.supersonic.semantic.core.application; +package com.tencent.supersonic.semantic.model.application; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.common.util.mapper.BeanMapper; -import com.tencent.supersonic.semantic.api.core.request.DomainReq; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.DomainUpdateReq; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.semantic.core.domain.DatasourceService; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; -import com.tencent.supersonic.semantic.core.domain.pojo.Domain; -import com.tencent.supersonic.semantic.core.domain.repository.DomainRepository; -import com.tencent.supersonic.semantic.core.domain.utils.DomainConvert; +import com.tencent.supersonic.common.util.BeanMapper; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.semantic.api.model.request.DomainReq; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.DomainUpdateReq; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO; +import com.tencent.supersonic.semantic.model.domain.pojo.Domain; +import com.tencent.supersonic.semantic.model.domain.repository.DomainRepository; +import com.tencent.supersonic.semantic.model.domain.utils.DomainConvert; + import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -29,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.context.annotation.Lazy; @@ -47,7 +50,7 @@ public class DomainServiceImpl implements DomainService { public DomainServiceImpl(DomainRepository domainRepository, @Lazy MetricService metricService, - @Lazy DimensionService dimensionService, @Lazy DatasourceService datasourceService) { + @Lazy DimensionService dimensionService, @Lazy DatasourceService datasourceService) { this.domainRepository = domainRepository; this.metricService = metricService; this.dimensionService = dimensionService; @@ -75,6 +78,7 @@ public class DomainServiceImpl implements DomainService { domainDO.setAdminOrg(String.join(",", domainUpdateReq.getAdminOrgs())); domainDO.setViewer(String.join(",", domainUpdateReq.getViewers())); domainDO.setViewOrg(String.join(",", domainUpdateReq.getViewOrgs())); + domainDO.setEntity(JsonUtil.toString(domainUpdateReq.getEntity())); domainRepository.updateDomain(domainDO); } @@ -161,7 +165,7 @@ public class DomainServiceImpl implements DomainService { return ""; } Map map = getDomainFullPathMap(); - return map.get(domainId); + return map.containsKey(domainId) ? map.get(domainId) : ""; } @Override @@ -178,7 +182,7 @@ public class DomainServiceImpl implements DomainService { private List convertList(List domainDOS, Map> metricDomainMap, - Map> dimensionDomainMap) { + Map> dimensionDomainMap) { List domainDescs = Lists.newArrayList(); if (CollectionUtils.isEmpty(domainDOS)) { return domainDescs; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/MetricServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/MetricServiceImpl.java similarity index 87% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/MetricServiceImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/MetricServiceImpl.java index 2f9d3f8f6..3d12e030a 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/MetricServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/MetricServiceImpl.java @@ -1,24 +1,24 @@ -package com.tencent.supersonic.semantic.core.application; +package com.tencent.supersonic.semantic.model.application; import com.alibaba.fastjson.JSONObject; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.semantic.api.core.pojo.MetricTypeParams; -import com.tencent.supersonic.semantic.api.core.request.MetricReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.common.enums.SensitiveLevelEnum; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDO; -import com.tencent.supersonic.semantic.core.domain.pojo.MetricFilter; -import com.tencent.supersonic.semantic.core.domain.repository.MetricRepository; -import com.tencent.supersonic.semantic.core.domain.utils.MetricConverter; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; -import com.tencent.supersonic.semantic.core.domain.pojo.Metric; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.pojo.MetricTypeParams; +import com.tencent.supersonic.semantic.api.model.request.MetricReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.common.pojo.enums.SensitiveLevelEnum; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO; +import com.tencent.supersonic.semantic.model.domain.pojo.MetricFilter; +import com.tencent.supersonic.semantic.model.domain.repository.MetricRepository; +import com.tencent.supersonic.semantic.model.domain.utils.MetricConverter; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.model.domain.pojo.Metric; import java.util.List; import java.util.Map; @@ -99,14 +99,11 @@ public class MetricServiceImpl implements MetricService { } @Override - public PageInfo queryMetric(PageMetricReq pageMetrricReq) { - if (pageMetrricReq.getDomainId() == null) { - return PageInfo.of(Lists.newArrayList()); - } + public PageInfo queryMetric(PageMetricReq pageMetricReq) { MetricFilter metricFilter = new MetricFilter(); - BeanUtils.copyProperties(pageMetrricReq, metricFilter); - PageInfo metricDOPageInfo = PageHelper.startPage(pageMetrricReq.getCurrent(), - pageMetrricReq.getPageSize()) + BeanUtils.copyProperties(pageMetricReq, metricFilter); + PageInfo metricDOPageInfo = PageHelper.startPage(pageMetricReq.getCurrent(), + pageMetricReq.getPageSize()) .doSelectPageInfo(() -> queryMetric(metricFilter)); PageInfo pageInfo = new PageInfo<>(); BeanUtils.copyProperties(metricDOPageInfo, pageInfo); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/ViewInfoServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/ViewInfoServiceImpl.java similarity index 79% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/ViewInfoServiceImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/ViewInfoServiceImpl.java index 9b489ec28..a8ae68a86 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/ViewInfoServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/ViewInfoServiceImpl.java @@ -1,17 +1,17 @@ -package com.tencent.supersonic.semantic.core.application; +package com.tencent.supersonic.semantic.model.application; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.ViewInfoReq; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaRelaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.core.domain.dataobject.ViewInfoDO; -import com.tencent.supersonic.semantic.core.domain.repository.ViewInfoRepository; -import com.tencent.supersonic.semantic.core.domain.DatasourceService; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.MetricService; +import com.tencent.supersonic.semantic.api.model.request.ViewInfoReq; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaRelaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO; +import com.tencent.supersonic.semantic.model.domain.repository.ViewInfoRepository; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.MetricService; import java.util.Date; import java.util.List; diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/Catalog.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/Catalog.java new file mode 100644 index 000000000..f0a6203eb --- /dev/null +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/Catalog.java @@ -0,0 +1,39 @@ +package com.tencent.supersonic.semantic.model.domain; + +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.api.model.yaml.DatasourceYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricYamlTpl; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.ItemDateResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface Catalog { + + DatabaseResp getDatabase(Long id); + DatabaseResp getDatabaseByDomainId(Long domainId); + + List getDatasourceList(Long domainId); + + String getDomainFullPath(Long domainId); + + Map getDomainFullPath(); + + DimensionResp getDimension(String bizName, Long domainId); + + List getDimensions(Long domainId); + + List getMetrics(Long domainId); + + void getModelYamlTplByDomainIds(Set domainIds, Map> dimensionYamlMap, + List datasourceYamlTplList, List metricYamlTplList); + + + ItemDateResp getItemDate(ItemDateFilter dimension, ItemDateFilter metric); + +} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatabaseService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatabaseService.java similarity index 69% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatabaseService.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatabaseService.java index 85f30a730..3b7e50c9b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatabaseService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatabaseService.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.semantic.core.domain; +package com.tencent.supersonic.semantic.model.domain; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DatabaseReq; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; +import com.tencent.supersonic.semantic.api.model.request.DatabaseReq; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.SqlParserResp; public interface DatabaseService { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatasourceService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatasourceService.java similarity index 59% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatasourceService.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatasourceService.java index 4d32c4281..5832e92b1 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatasourceService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatasourceService.java @@ -1,17 +1,17 @@ -package com.tencent.supersonic.semantic.core.domain; +package com.tencent.supersonic.semantic.model.domain; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DatasourceYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.semantic.api.core.request.DatasourceRelaReq; -import com.tencent.supersonic.semantic.api.core.request.DatasourceReq; -import com.tencent.supersonic.semantic.api.core.response.DatasourceRelaResp; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; -import com.tencent.supersonic.semantic.api.core.response.MeasureResp; +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.api.model.yaml.DatasourceYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricYamlTpl; +import com.tencent.supersonic.semantic.api.model.request.DatasourceRelaReq; +import com.tencent.supersonic.semantic.api.model.request.DatasourceReq; +import com.tencent.supersonic.semantic.api.model.response.DatasourceRelaResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.ItemDateResp; +import com.tencent.supersonic.semantic.api.model.response.MeasureResp; import java.util.List; import java.util.Map; import java.util.Set; @@ -40,7 +40,7 @@ public interface DatasourceService { void deleteDatasourceRela(Long id); - ItemDateResp getDateDate(ItemDateFilter dimension, ItemDateFilter metric); + ItemDateResp getItemDate(ItemDateFilter dimension, ItemDateFilter metric); List getMeasureListOfDomain(Long domainId); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DimensionService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DimensionService.java similarity index 78% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DimensionService.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DimensionService.java index 8dbe47ddb..ff3928afa 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DimensionService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DimensionService.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.semantic.core.domain; +package com.tencent.supersonic.semantic.model.domain; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.request.DimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; import java.util.List; public interface DimensionService { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DomainService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DomainService.java similarity index 66% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DomainService.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DomainService.java index c87b5ac11..e466d0ff8 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DomainService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DomainService.java @@ -1,11 +1,11 @@ -package com.tencent.supersonic.semantic.core.domain; +package com.tencent.supersonic.semantic.model.domain; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DomainReq; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.DomainUpdateReq; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.request.DomainReq; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.DomainUpdateReq; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; import java.util.List; import java.util.Map; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/MetricService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/MetricService.java similarity index 77% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/MetricService.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/MetricService.java index a4c764470..f00f7d26e 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/MetricService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/MetricService.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.semantic.core.domain; +package com.tencent.supersonic.semantic.model.domain; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.MetricReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.request.MetricReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; import java.util.List; public interface MetricService { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/ClickHouseAdaptor.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/ClickHouseAdaptor.java similarity index 89% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/ClickHouseAdaptor.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/ClickHouseAdaptor.java index b03758ceb..4a3d48e7a 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/ClickHouseAdaptor.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/ClickHouseAdaptor.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter; +package com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; +import com.tencent.supersonic.common.pojo.Constants; public class ClickHouseAdaptor extends EngineAdaptor { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptor.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/EngineAdaptor.java similarity index 79% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptor.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/EngineAdaptor.java index be5635330..63af21df2 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptor.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/EngineAdaptor.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter; +package com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter; public abstract class EngineAdaptor { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptorFactory.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/EngineAdaptorFactory.java similarity index 69% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptorFactory.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/EngineAdaptorFactory.java index e283d7eb2..1ad3f7f51 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptorFactory.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/EngineAdaptorFactory.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter; +package com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter; -import com.tencent.supersonic.semantic.core.domain.pojo.EngineTypeEnum; +import com.tencent.supersonic.semantic.model.domain.pojo.EngineTypeEnum; import java.util.HashMap; import java.util.Map; @@ -14,7 +14,7 @@ public class EngineAdaptorFactory { engineAdaptorMap = new HashMap<>(); engineAdaptorMap.put(EngineTypeEnum.CLICKHOUSE.getName(), new ClickHouseAdaptor()); engineAdaptorMap.put(EngineTypeEnum.MYSQL.getName(), new MysqlAdaptor()); - engineAdaptorMap.put(EngineTypeEnum.H2.getName(), new MysqlAdaptor()); + engineAdaptorMap.put(EngineTypeEnum.H2.getName(), new H2Adaptor()); } diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/H2Adaptor.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/H2Adaptor.java new file mode 100644 index 000000000..52a29b7c7 --- /dev/null +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/H2Adaptor.java @@ -0,0 +1,45 @@ +package com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter; + +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; + +public class H2Adaptor extends EngineAdaptor { + + @Override + public String getDateFormat(String dateType, String dateFormat, String column) { + if (dateFormat.equalsIgnoreCase(Constants.DAY_FORMAT_INT)) { + if (TimeDimensionEnum.MONTH.name().equalsIgnoreCase(dateType)) { + return "FORMATDATETIME(PARSEDATETIME(%s, 'yyyyMMdd'),'yyyy-MM')".replace("%s", column); + } else if (TimeDimensionEnum.WEEK.name().equalsIgnoreCase(dateType)) { + return "DATE_TRUNC('week',%s)".replace("%s", column); + } else { + return "FORMATDATETIME(PARSEDATETIME(%s, 'yyyyMMdd'),'yyyy-MM-dd')".replace("%s", column); + } + } else if (dateFormat.equalsIgnoreCase(Constants.DAY_FORMAT)) { + if (TimeDimensionEnum.MONTH.name().equalsIgnoreCase(dateType)) { + return "FORMATDATETIME(PARSEDATETIME(%s, 'yyyy-MM-dd'),'yyyy-MM') ".replace("%s", column); + } else if (TimeDimensionEnum.WEEK.name().equalsIgnoreCase(dateType)) { + return "DATE_TRUNC('week',%s)".replace("%s", column); + } else { + return column; + } + } + return column; + } + + @Override + public String getColumnMetaQueryTpl() { + return "SELECT COLUMN_NAME AS name, DATA_TYPE AS dataType\n" + + "FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ='%s' AND TABLE_NAME = '%s'"; + } + + @Override + public String getDbMetaQueryTpl() { + return "SELECT DISTINCT TABLE_SCHEMA as name FROM INFORMATION_SCHEMA.TABLES WHERE STORAGE_TYPE = 'MEMORY'"; + } + + @Override + public String getTableMetaQueryTpl() { + return "SELECT TABLE_NAME as name FROM INFORMATION_SCHEMA.TABLES WHERE STORAGE_TYPE = 'MEMORY' AND TABLE_SCHEMA = '%s'"; + } +} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/MysqlAdaptor.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/MysqlAdaptor.java similarity index 78% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/MysqlAdaptor.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/MysqlAdaptor.java index 1e6fc0073..e3a68bf29 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/MysqlAdaptor.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/MysqlAdaptor.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter; +package com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; +import com.tencent.supersonic.common.pojo.Constants; public class MysqlAdaptor extends EngineAdaptor { @@ -35,12 +35,12 @@ public class MysqlAdaptor extends EngineAdaptor { @Override public String getDbMetaQueryTpl() { - return "select distinct TABLE_SCHEMA from information_schema.tables where TABLE_SCHEMA not in ('information_schema','mysql','performance_schema','sys');"; + return "select distinct TABLE_SCHEMA as name from information_schema.tables where TABLE_SCHEMA not in ('information_schema','mysql','performance_schema','sys');"; } @Override public String getTableMetaQueryTpl() { - return "select TABLE_NAME from information_schema.tables where TABLE_SCHEMA = '%s';"; + return "select TABLE_NAME as name from information_schema.tables where TABLE_SCHEMA = '%s';"; } @Override diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/config/YamlConfig.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/config/YamlConfig.java similarity index 84% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/config/YamlConfig.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/config/YamlConfig.java index 41e29f35f..218a95089 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/config/YamlConfig.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/config/YamlConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.config; +package com.tencent.supersonic.semantic.model.domain.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDO.java similarity index 92% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDO.java index 3e65a3151..48d603cdf 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; @@ -24,6 +24,11 @@ public class DatabaseDO { */ private String description; + /** + * 版本 + */ + private String version; + /** * 类型 mysql,clickhouse,tdw */ @@ -229,4 +234,16 @@ public class DatabaseDO { public void setConfig(String config) { this.config = config == null ? null : config.trim(); } + + /** + * 版本信息 + * + */ + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } } \ No newline at end of file diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDOExample.java index 916ba9322..4aba80b86 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDO.java similarity index 98% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDO.java index 7b899bc45..fb0e18766 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDOExample.java index f8b87fbd4..136d0e44a 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDO.java similarity index 97% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDO.java index a8e2fc2e4..0c6f8a2af 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDOExample.java index f4264d58d..650f61c59 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DateInfoDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DateInfoDO.java similarity index 84% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DateInfoDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DateInfoDO.java index e4d467cbb..e05be7b61 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DateInfoDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DateInfoDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import lombok.Data; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryDO.java similarity index 98% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryDO.java index 071c6558f..c35b82689 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryDOExample.java index ff9cbb1c5..b91f929bc 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryTaskDO.java similarity index 98% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryTaskDO.java index a0aa07b0d..ea1e90076 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryTaskDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; public class DictionaryTaskDO { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryTaskDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryTaskDOExample.java index d8548809c..7e721616c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DictionaryTaskDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.List; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDO.java similarity index 95% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDO.java index eec2ef285..a48888117 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; @@ -94,6 +94,11 @@ public class DimensionDO { */ private String expr; + /** + * dimension value map info + */ + private String dimValueMaps; + /** * 维度ID * @@ -413,4 +418,12 @@ public class DimensionDO { public void setExpr(String expr) { this.expr = expr == null ? null : expr.trim(); } + + public String getDimValueMaps() { + return dimValueMaps; + } + + public void setDimValueMaps(String dimValueMaps) { + this.dimValueMaps = dimValueMaps; + } } \ No newline at end of file diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOExample.java index 32ebe9944..a44cbd256 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOWithDictInfo.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOWithDictInfo.java similarity index 65% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOWithDictInfo.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOWithDictInfo.java index e71d6fb5d..468c7be2b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOWithDictInfo.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOWithDictInfo.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import lombok.Data; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDO.java similarity index 95% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDO.java index 60f1a5065..22639f934 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; @@ -74,6 +74,12 @@ public class DomainDO { */ private String viewOrg; + + /** + * 主题域实体信息 + */ + private String entity; + /** * 自增ID * @@ -325,4 +331,12 @@ public class DomainDO { public void setViewOrg(String viewOrg) { this.viewOrg = viewOrg == null ? null : viewOrg.trim(); } + + public String getEntity() { + return entity; + } + + public void setEntity(String entity) { + this.entity = entity; + } } \ No newline at end of file diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDOExample.java index 37e67289c..36f5ea790 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainExtendDO.java similarity index 98% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainExtendDO.java index e1c30e32f..f8228c628 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainExtendDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainExtendDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainExtendDOExample.java index df30d4ae2..22fa5bb78 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainExtendDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDO.java similarity index 98% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDO.java index 9e52c7009..2c7a526a6 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDOExample.java index fa9afb69e..673a42cad 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/UpdateDimValueDictBatchDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/UpdateDimValueDictBatchDO.java similarity index 82% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/UpdateDimValueDictBatchDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/UpdateDimValueDictBatchDO.java index 0883c9a3a..50aab4671 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/UpdateDimValueDictBatchDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/UpdateDimValueDictBatchDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.List; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDO.java similarity index 97% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDO.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDO.java index a2cf58626..fc72737c8 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDO.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDOExample.java similarity index 99% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDOExample.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDOExample.java index f37588017..9de28bcda 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDOExample.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.dataobject; +package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.ArrayList; import java.util.Date; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DatasourceYamlManager.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/DatasourceYamlManager.java similarity index 75% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DatasourceYamlManager.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/DatasourceYamlManager.java index 66112635b..74f78b4b1 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DatasourceYamlManager.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/DatasourceYamlManager.java @@ -1,20 +1,20 @@ -package com.tencent.supersonic.semantic.core.domain.manager; +package com.tencent.supersonic.semantic.model.domain.manager; -import com.tencent.supersonic.semantic.api.core.pojo.DatasourceDetail; -import com.tencent.supersonic.semantic.api.core.pojo.Dim; -import com.tencent.supersonic.semantic.api.core.pojo.Identify; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DatasourceYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionTimeTypeParamsTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.IdentifyYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MeasureYamlTpl; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.core.domain.utils.SysTimeDimensionBuilder; -import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptor; -import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptorFactory; -import com.tencent.supersonic.semantic.core.domain.pojo.Datasource; -import com.tencent.supersonic.semantic.core.domain.pojo.DatasourceQueryEnum; +import com.tencent.supersonic.semantic.api.model.pojo.DatasourceDetail; +import com.tencent.supersonic.semantic.api.model.pojo.Dim; +import com.tencent.supersonic.semantic.api.model.pojo.Identify; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.yaml.DatasourceYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionTimeTypeParamsTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.IdentifyYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MeasureYamlTpl; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.model.domain.utils.SysTimeDimensionBuilder; +import com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter.EngineAdaptor; +import com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter.EngineAdaptorFactory; +import com.tencent.supersonic.semantic.model.domain.pojo.Datasource; +import com.tencent.supersonic.semantic.model.domain.pojo.DatasourceQueryEnum; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DimensionYamlManager.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/DimensionYamlManager.java similarity index 63% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DimensionYamlManager.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/DimensionYamlManager.java index ffec920ee..da2e265d7 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DimensionYamlManager.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/DimensionYamlManager.java @@ -1,15 +1,11 @@ -package com.tencent.supersonic.semantic.core.domain.manager; +package com.tencent.supersonic.semantic.model.domain.manager; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.common.enums.TypeEnums; -import com.tencent.supersonic.common.util.yaml.YamlUtils; -import com.tencent.supersonic.semantic.core.domain.pojo.Dimension; -import com.tencent.supersonic.semantic.core.domain.utils.DimensionConverter; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.model.domain.pojo.Dimension; +import com.tencent.supersonic.semantic.model.domain.utils.DimensionConverter; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/MetricYamlManager.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/MetricYamlManager.java similarity index 67% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/MetricYamlManager.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/MetricYamlManager.java index 6a3b570ce..b266a386c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/MetricYamlManager.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/manager/MetricYamlManager.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.core.domain.manager; +package com.tencent.supersonic.semantic.model.domain.manager; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.semantic.core.domain.pojo.Metric; -import com.tencent.supersonic.semantic.core.domain.utils.MetricConverter; +import com.tencent.supersonic.semantic.api.model.yaml.MetricYamlTpl; +import com.tencent.supersonic.semantic.model.domain.pojo.Metric; +import com.tencent.supersonic.semantic.model.domain.utils.MetricConverter; import java.util.ArrayList; import java.util.List; import lombok.extern.slf4j.Slf4j; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/ConnectInfo.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/ConnectInfo.java similarity index 71% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/ConnectInfo.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/ConnectInfo.java index cc9ecd64d..23e7c8dcb 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/ConnectInfo.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/ConnectInfo.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; import lombok.Data; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Database.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Database.java similarity index 67% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Database.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Database.java index 34ddaa463..122d5af92 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Database.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Database.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; -import com.tencent.supersonic.common.util.RecordInfo; +import com.tencent.supersonic.common.pojo.RecordInfo; import lombok.Data; @Data @@ -16,6 +16,8 @@ public class Database extends RecordInfo { private String description; + private String version; + /** * mysql,clickhouse */ diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Datasource.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Datasource.java new file mode 100644 index 000000000..0361679b9 --- /dev/null +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Datasource.java @@ -0,0 +1,19 @@ +package com.tencent.supersonic.semantic.model.domain.pojo; + + +import com.tencent.supersonic.semantic.api.model.pojo.DatasourceDetail; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; +import lombok.Data; + + +@Data +public class Datasource extends SchemaItem { + + private Long domainId; + + private Long databaseId; + + private DatasourceDetail datasourceDetail; + + +} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/DatasourceQueryEnum.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/DatasourceQueryEnum.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/DatasourceQueryEnum.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/DatasourceQueryEnum.java index 72d5972e0..1314a890e 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/DatasourceQueryEnum.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/DatasourceQueryEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; public enum DatasourceQueryEnum { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Dimension.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Dimension.java similarity index 58% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Dimension.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Dimension.java index ba024e60a..c3c0a416b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Dimension.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Dimension.java @@ -1,7 +1,8 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; -import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; import lombok.Data; import java.util.List; @@ -23,4 +24,6 @@ public class Dimension extends SchemaItem { private List defaultValues; + private List dimValueMaps; + } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/DimensionFilter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/DimensionFilter.java similarity index 58% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/DimensionFilter.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/DimensionFilter.java index 07550062d..9cb20e45b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/DimensionFilter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/DimensionFilter.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; import lombok.Data; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Domain.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Domain.java similarity index 62% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Domain.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Domain.java index 49e198302..3470147da 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Domain.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Domain.java @@ -1,9 +1,10 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; -import com.tencent.supersonic.semantic.api.core.request.DomainReq; -import com.tencent.supersonic.common.enums.StatusEnum; -import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.model.pojo.Entity; +import com.tencent.supersonic.semantic.api.model.request.DomainReq; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; import java.util.List; import lombok.Data; import org.springframework.beans.BeanUtils; @@ -24,6 +25,8 @@ public class Domain extends SchemaItem { private List adminOrgs; + private Entity entity; + public static Domain create(DomainReq domainCmd) { Domain domain = new Domain(); BeanUtils.copyProperties(domainCmd, domain); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/EngineTypeEnum.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/EngineTypeEnum.java similarity index 88% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/EngineTypeEnum.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/EngineTypeEnum.java index 81f6acbe3..91eeac39b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/EngineTypeEnum.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/EngineTypeEnum.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; public enum EngineTypeEnum { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/JdbcDataSource.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/JdbcDataSource.java similarity index 96% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/JdbcDataSource.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/JdbcDataSource.java index 74aaaa59c..c4f24750b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/JdbcDataSource.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/JdbcDataSource.java @@ -1,14 +1,14 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; -import static com.tencent.supersonic.common.constant.Constants.STATISTIC; +import static com.tencent.supersonic.common.pojo.Constants.STATISTIC; import com.alibaba.druid.filter.Filter; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallFilter; -import com.tencent.supersonic.semantic.api.core.enums.DataTypeEnum; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.core.domain.utils.JdbcDataSourceUtils; +import com.tencent.supersonic.semantic.api.model.enums.DataTypeEnum; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.model.domain.utils.JdbcDataSourceUtils; import java.util.Arrays; import java.util.Map; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/MetaFilter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/MetaFilter.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/MetaFilter.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/MetaFilter.java index 7c281fd71..1771eb67b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/MetaFilter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/MetaFilter.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; import lombok.Data; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Metric.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Metric.java similarity index 55% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Metric.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Metric.java index fab864d76..174e17342 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Metric.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/Metric.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; -import com.tencent.supersonic.semantic.api.core.pojo.DataFormat; -import com.tencent.supersonic.semantic.api.core.pojo.MetricTypeParams; -import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.common.pojo.DataFormat; +import com.tencent.supersonic.semantic.api.model.pojo.MetricTypeParams; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; import lombok.Data; @Data diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/MetricFilter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/MetricFilter.java similarity index 63% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/MetricFilter.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/MetricFilter.java index b352a1855..334f2f453 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/MetricFilter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/pojo/MetricFilter.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.core.domain.pojo; +package com.tencent.supersonic.semantic.model.domain.pojo; import lombok.Data; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DatabaseRepository.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DatabaseRepository.java similarity index 65% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DatabaseRepository.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DatabaseRepository.java index 0f53087a4..67f3fcd68 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DatabaseRepository.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DatabaseRepository.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.core.domain.repository; +package com.tencent.supersonic.semantic.model.domain.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO; import java.util.List; public interface DatabaseRepository { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DatasourceRepository.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DatasourceRepository.java similarity index 74% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DatasourceRepository.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DatasourceRepository.java index 1286e1583..486849340 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DatasourceRepository.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DatasourceRepository.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.core.domain.repository; +package com.tencent.supersonic.semantic.model.domain.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceRelaDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO; import java.util.List; diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DateInfoRepository.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DateInfoRepository.java new file mode 100644 index 000000000..e5d313b80 --- /dev/null +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DateInfoRepository.java @@ -0,0 +1,16 @@ +package com.tencent.supersonic.semantic.model.domain.repository; + + +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.api.model.request.DateInfoReq; +import com.tencent.supersonic.semantic.model.domain.dataobject.DateInfoDO; + +import java.util.List; + +public interface DateInfoRepository { + + Integer upsertDateInfo(List dateInfoReqs); + + List getDateInfos(ItemDateFilter itemDateFilter); + +} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DimensionRepository.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DimensionRepository.java similarity index 75% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DimensionRepository.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DimensionRepository.java index 84fe70b2b..476c86961 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DimensionRepository.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DimensionRepository.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.domain.repository; +package com.tencent.supersonic.semantic.model.domain.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; -import com.tencent.supersonic.semantic.core.domain.pojo.DimensionFilter; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDO; +import com.tencent.supersonic.semantic.model.domain.pojo.DimensionFilter; import java.util.List; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DomainRepository.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DomainRepository.java similarity index 66% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DomainRepository.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DomainRepository.java index 372e0f572..5aacb9b9e 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DomainRepository.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/DomainRepository.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.domain.repository; +package com.tencent.supersonic.semantic.model.domain.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO; import java.util.List; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/MetricRepository.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/MetricRepository.java similarity index 71% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/MetricRepository.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/MetricRepository.java index 674257fa6..891233dd0 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/MetricRepository.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/MetricRepository.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.core.domain.repository; +package com.tencent.supersonic.semantic.model.domain.repository; -import com.tencent.supersonic.semantic.core.domain.pojo.MetricFilter; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDO; +import com.tencent.supersonic.semantic.model.domain.pojo.MetricFilter; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO; import java.util.List; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/ViewInfoRepository.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/ViewInfoRepository.java similarity index 67% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/ViewInfoRepository.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/ViewInfoRepository.java index 86c0f42e2..0b79932af 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/ViewInfoRepository.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/repository/ViewInfoRepository.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.core.domain.repository; +package com.tencent.supersonic.semantic.model.domain.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.ViewInfoDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO; import java.util.List; public interface ViewInfoRepository { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatabaseConverter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DatabaseConverter.java similarity index 80% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatabaseConverter.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DatabaseConverter.java index f49a7ede9..90aaf8290 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatabaseConverter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DatabaseConverter.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; import com.alibaba.fastjson.JSONObject; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DatabaseReq; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDO; -import com.tencent.supersonic.semantic.core.domain.pojo.ConnectInfo; -import com.tencent.supersonic.semantic.core.domain.pojo.Database; +import com.tencent.supersonic.semantic.api.model.request.DatabaseReq; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO; +import com.tencent.supersonic.semantic.model.domain.pojo.ConnectInfo; +import com.tencent.supersonic.semantic.model.domain.pojo.Database; import java.util.Date; import org.springframework.beans.BeanUtils; @@ -25,6 +25,7 @@ public class DatabaseConverter { database.setCreatedBy(user.getName()); database.setUpdatedAt(new Date()); database.setUpdatedBy(user.getName()); + database.setVersion(databaseReq.getVersion()); return database; } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatasourceConverter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DatasourceConverter.java similarity index 86% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatasourceConverter.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DatasourceConverter.java index 520d2c99f..71c366259 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatasourceConverter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DatasourceConverter.java @@ -1,25 +1,25 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.enums.MetricTypeEnum; -import com.tencent.supersonic.semantic.api.core.pojo.DatasourceDetail; -import com.tencent.supersonic.semantic.api.core.pojo.Dim; -import com.tencent.supersonic.semantic.api.core.pojo.Identify; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.semantic.api.core.pojo.MetricTypeParams; -import com.tencent.supersonic.semantic.api.core.request.DatasourceReq; -import com.tencent.supersonic.semantic.api.core.request.DimensionReq; -import com.tencent.supersonic.semantic.api.core.request.MetricReq; -import com.tencent.supersonic.semantic.api.core.response.DatasourceRelaResp; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.MeasureResp; -import com.tencent.supersonic.common.enums.StatusEnum; -import com.tencent.supersonic.common.util.mapper.BeanMapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceRelaDO; -import com.tencent.supersonic.semantic.core.domain.pojo.Datasource; +import com.tencent.supersonic.semantic.api.model.enums.MetricTypeEnum; +import com.tencent.supersonic.semantic.api.model.pojo.DatasourceDetail; +import com.tencent.supersonic.semantic.api.model.pojo.Dim; +import com.tencent.supersonic.semantic.api.model.pojo.Identify; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.pojo.MetricTypeParams; +import com.tencent.supersonic.semantic.api.model.request.DatasourceReq; +import com.tencent.supersonic.semantic.api.model.request.DimensionReq; +import com.tencent.supersonic.semantic.api.model.request.MetricReq; +import com.tencent.supersonic.semantic.api.model.response.DatasourceRelaResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.MeasureResp; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; +import com.tencent.supersonic.common.util.BeanMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO; +import com.tencent.supersonic.semantic.model.domain.pojo.Datasource; import java.util.Date; import java.util.List; import java.util.stream.Collectors; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DimensionConverter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DimensionConverter.java similarity index 66% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DimensionConverter.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DimensionConverter.java index 06b615e94..347096a7c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DimensionConverter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DimensionConverter.java @@ -1,17 +1,23 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; import com.alibaba.fastjson.JSONObject; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.semantic.api.core.request.DimensionReq; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.common.util.mapper.BeanMapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; -import com.tencent.supersonic.semantic.core.domain.pojo.Dimension; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.api.model.request.DimensionReq; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.common.util.BeanMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDO; +import com.tencent.supersonic.semantic.model.domain.pojo.Dimension; + import java.util.ArrayList; import java.util.List; import java.util.Map; + +import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; +import org.springframework.util.CollectionUtils; public class DimensionConverter { @@ -24,6 +30,9 @@ public class DimensionConverter { public static DimensionDO convert(DimensionDO dimensionDO, Dimension dimension) { BeanMapper.mapper(dimension, dimensionDO); dimensionDO.setDefaultValues(JSONObject.toJSONString(dimension.getDefaultValues())); + if (!CollectionUtils.isEmpty(dimension.getDimValueMaps())) { + dimensionDO.setDimValueMaps(JSONObject.toJSONString(dimension.getDimValueMaps())); + } return dimensionDO; } @@ -31,13 +40,14 @@ public class DimensionConverter { DimensionDO dimensionDO = new DimensionDO(); BeanUtils.copyProperties(dimension, dimensionDO); dimensionDO.setDefaultValues(JSONObject.toJSONString(dimension.getDefaultValues())); + dimensionDO.setDimValueMaps(JSONObject.toJSONString(dimension.getDimValueMaps())); return dimensionDO; } public static DimensionResp convert2DimensionResp(DimensionDO dimensionDO, - Map fullPathMap, - Map datasourceRespMap) { + Map fullPathMap, + Map datasourceRespMap) { DimensionResp dimensionResp = new DimensionResp(); BeanUtils.copyProperties(dimensionDO, dimensionResp); dimensionResp.setFullPath(fullPathMap.get(dimensionDO.getDomainId()) + dimensionDO.getBizName()); @@ -50,6 +60,9 @@ public class DimensionConverter { if (dimensionDO.getDefaultValues() != null) { dimensionResp.setDefaultValues(JSONObject.parseObject(dimensionDO.getDefaultValues(), List.class)); } + if (Strings.isNotEmpty(dimensionDO.getDimValueMaps())) { + dimensionResp.setDimValueMaps(JsonUtil.toList(dimensionDO.getDimValueMaps(), DimValueMap.class)); + } return dimensionResp; } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DomainConvert.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DomainConvert.java similarity index 73% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DomainConvert.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DomainConvert.java index 4951d96d8..1443f0710 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DomainConvert.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DomainConvert.java @@ -1,19 +1,23 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DomainReq; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.common.enums.StatusEnum; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; -import com.tencent.supersonic.semantic.core.domain.pojo.Domain; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.semantic.api.model.pojo.Entity; +import com.tencent.supersonic.semantic.api.model.request.DomainReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO; +import com.tencent.supersonic.semantic.model.domain.pojo.Domain; + import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; + import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; @@ -37,6 +41,7 @@ public class DomainConvert { domainDO.setAdminOrg(String.join(",", domain.getAdminOrgs())); domainDO.setViewer(String.join(",", domain.getViewers())); domainDO.setViewOrg(String.join(",", domain.getViewOrgs())); + domainDO.setEntity(JsonUtil.toString(domain.getEntity())); return domainDO; } @@ -52,11 +57,12 @@ public class DomainConvert { ? Lists.newArrayList() : Arrays.asList(domainDO.getViewer().split(","))); domainResp.setViewOrgs(StringUtils.isBlank(domainDO.getViewOrg()) ? Lists.newArrayList() : Arrays.asList(domainDO.getViewOrg().split(","))); + domainResp.setEntity(JsonUtil.toObject(domainDO.getEntity(), Entity.class)); return domainResp; } public static DomainResp convert(DomainDO domainDO, Map domainFullPathMap, - Map> dimensionMap, Map> metricMap) { + Map> dimensionMap, Map> metricMap) { DomainResp domainResp = convert(domainDO, domainFullPathMap); domainResp.setDimensionCnt(dimensionMap.getOrDefault(domainResp.getId(), Lists.newArrayList()).size()); domainResp.setMetricCnt(metricMap.getOrDefault(domainResp.getId(), Lists.newArrayList()).size()); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/JdbcDataSourceUtils.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/JdbcDataSourceUtils.java similarity index 85% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/JdbcDataSourceUtils.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/JdbcDataSourceUtils.java index 10099610e..7b6750dfc 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/JdbcDataSourceUtils.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/JdbcDataSourceUtils.java @@ -1,20 +1,20 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; -import static com.tencent.supersonic.common.constant.Constants.AT_SYMBOL; -import static com.tencent.supersonic.common.constant.Constants.COLON; -import static com.tencent.supersonic.common.constant.Constants.DOUBLE_SLASH; -import static com.tencent.supersonic.common.constant.Constants.EMPTY; -import static com.tencent.supersonic.common.constant.Constants.JDBC_PREFIX_FORMATTER; -import static com.tencent.supersonic.common.constant.Constants.NEW_LINE_CHAR; -import static com.tencent.supersonic.common.constant.Constants.PATTERN_JDBC_TYPE; -import static com.tencent.supersonic.common.constant.Constants.SPACE; +import static com.tencent.supersonic.common.pojo.Constants.AT_SYMBOL; +import static com.tencent.supersonic.common.pojo.Constants.COLON; +import static com.tencent.supersonic.common.pojo.Constants.DOUBLE_SLASH; +import static com.tencent.supersonic.common.pojo.Constants.EMPTY; +import static com.tencent.supersonic.common.pojo.Constants.JDBC_PREFIX_FORMATTER; +import static com.tencent.supersonic.common.pojo.Constants.NEW_LINE_CHAR; +import static com.tencent.supersonic.common.pojo.Constants.PATTERN_JDBC_TYPE; +import static com.tencent.supersonic.common.pojo.Constants.SPACE; import com.alibaba.druid.util.StringUtils; -import com.tencent.supersonic.semantic.api.core.enums.DataTypeEnum; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.common.util.coder.MD5Util; -import com.tencent.supersonic.semantic.core.domain.pojo.Database; -import com.tencent.supersonic.semantic.core.domain.pojo.JdbcDataSource; +import com.tencent.supersonic.semantic.api.model.enums.DataTypeEnum; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.common.util.MD5Util; +import com.tencent.supersonic.semantic.model.domain.pojo.Database; +import com.tencent.supersonic.semantic.model.domain.pojo.JdbcDataSource; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/MetricConverter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/MetricConverter.java similarity index 79% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/MetricConverter.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/MetricConverter.java index e251ef844..bbb84a32f 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/MetricConverter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/MetricConverter.java @@ -1,20 +1,19 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; -import com.tencent.supersonic.semantic.api.core.enums.MetricTypeEnum; -import com.tencent.supersonic.semantic.api.core.pojo.DataFormat; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.semantic.api.core.pojo.MetricTypeParams; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MeasureYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricTypeParamsYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.semantic.api.core.request.MetricReq; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.common.util.mapper.BeanMapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDO; -import com.tencent.supersonic.semantic.core.domain.pojo.Metric; +import com.tencent.supersonic.common.pojo.DataFormat; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.pojo.MetricTypeParams; +import com.tencent.supersonic.semantic.api.model.yaml.MeasureYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricTypeParamsYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricYamlTpl; +import com.tencent.supersonic.semantic.api.model.request.MetricReq; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.common.util.BeanMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO; +import com.tencent.supersonic.semantic.model.domain.pojo.Metric; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SqlUtils.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/SqlUtils.java similarity index 93% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SqlUtils.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/SqlUtils.java index 98d12bd3c..ea2f71963 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SqlUtils.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/SqlUtils.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; -import static com.tencent.supersonic.common.constant.Constants.AT_SYMBOL; +import static com.tencent.supersonic.common.pojo.Constants.AT_SYMBOL; -import com.tencent.supersonic.semantic.api.core.enums.DataTypeEnum; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.core.domain.pojo.JdbcDataSource; +import com.tencent.supersonic.semantic.api.model.enums.DataTypeEnum; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.model.domain.pojo.JdbcDataSource; import java.rmi.ServerException; import java.sql.Connection; import java.sql.ResultSet; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SysTimeDimensionBuilder.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/SysTimeDimensionBuilder.java similarity index 86% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SysTimeDimensionBuilder.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/SysTimeDimensionBuilder.java index 673358695..1a2c0f163 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SysTimeDimensionBuilder.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/SysTimeDimensionBuilder.java @@ -1,13 +1,12 @@ -package com.tencent.supersonic.semantic.core.domain.utils; +package com.tencent.supersonic.semantic.model.domain.utils; -import com.tencent.supersonic.semantic.api.core.enums.DimensionTypeEnum; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; -import com.tencent.supersonic.semantic.api.core.pojo.Dim; -import com.tencent.supersonic.semantic.api.core.pojo.DimensionTimeTypeParams; -import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptor; +import com.tencent.supersonic.semantic.api.model.enums.DimensionTypeEnum; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; +import com.tencent.supersonic.semantic.api.model.pojo.Dim; +import com.tencent.supersonic.semantic.api.model.pojo.DimensionTimeTypeParams; +import com.tencent.supersonic.semantic.model.domain.adaptor.engineadapter.EngineAdaptor; import java.util.List; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; @Slf4j public class SysTimeDimensionBuilder { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatabaseDOMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatabaseDOMapper.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatabaseDOMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatabaseDOMapper.java index 4d97b0ddb..538accb00 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatabaseDOMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatabaseDOMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDOExample; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatasourceDOMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatasourceDOMapper.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatasourceDOMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatasourceDOMapper.java index e820f158a..49ee9a404 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatasourceDOMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatasourceDOMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDOExample; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatasourceRelaDOMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatasourceRelaDOMapper.java similarity index 78% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatasourceRelaDOMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatasourceRelaDOMapper.java index d4a1902ba..65777f0a9 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DatasourceRelaDOMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DatasourceRelaDOMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceRelaDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceRelaDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDOExample; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DateInfoMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DateInfoMapper.java similarity index 52% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DateInfoMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DateInfoMapper.java index 95566bd46..57617967f 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DateInfoMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DateInfoMapper.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.core.domain.dataobject.DateInfoDO; +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.model.domain.dataobject.DateInfoDO; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOCustomMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DimensionDOCustomMapper.java similarity index 61% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOCustomMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DimensionDOCustomMapper.java index f4f6f7dc4..f9bb9a746 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOCustomMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DimensionDOCustomMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDO; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DimensionDOMapper.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DimensionDOMapper.java index 5f586c637..597754a84 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DimensionDOMapper.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDOExample; import org.apache.ibatis.annotations.Mapper; import java.util.List; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DomainDOMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DomainDOMapper.java similarity index 78% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DomainDOMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DomainDOMapper.java index 177bc0559..95a9ed246 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DomainDOMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/DomainDOMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DomainDOExample; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/MetricDOCustomMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/MetricDOCustomMapper.java similarity index 60% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/MetricDOCustomMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/MetricDOCustomMapper.java index 67f9c2969..62845f58d 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/MetricDOCustomMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/MetricDOCustomMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/MetricDOMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/MetricDOMapper.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/MetricDOMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/MetricDOMapper.java index 6795a3cf1..4de46bdd8 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/MetricDOMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/MetricDOMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDOExample; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/ViewInfoDOMapper.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/ViewInfoDOMapper.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/ViewInfoDOMapper.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/ViewInfoDOMapper.java index 0f044b003..097d143d7 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/ViewInfoDOMapper.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/mapper/ViewInfoDOMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.core.infrastructure.mapper; +package com.tencent.supersonic.semantic.model.infrastructure.mapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.ViewInfoDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.ViewInfoDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDOExample; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatabaseRepositoryImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DatabaseRepositoryImpl.java similarity index 72% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatabaseRepositoryImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DatabaseRepositoryImpl.java index cdd9e0325..a0214c790 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatabaseRepositoryImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DatabaseRepositoryImpl.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.core.infrastructure.repository; +package com.tencent.supersonic.semantic.model.infrastructure.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDOExample; -import com.tencent.supersonic.semantic.core.domain.repository.DatabaseRepository; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.DatabaseDOMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDOExample; +import com.tencent.supersonic.semantic.model.domain.repository.DatabaseRepository; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.DatabaseDOMapper; import java.util.List; import org.springframework.stereotype.Component; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatasourceRepositoryImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DatasourceRepositoryImpl.java similarity index 79% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatasourceRepositoryImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DatasourceRepositoryImpl.java index e521c9e3c..d53e9ef3c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatasourceRepositoryImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DatasourceRepositoryImpl.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.semantic.core.infrastructure.repository; +package com.tencent.supersonic.semantic.model.infrastructure.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceDOExample; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceRelaDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DatasourceRelaDOExample; -import com.tencent.supersonic.semantic.core.domain.repository.DatasourceRepository; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.DatasourceDOMapper; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.DatasourceRelaDOMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDOExample; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDOExample; +import com.tencent.supersonic.semantic.model.domain.repository.DatasourceRepository; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.DatasourceDOMapper; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.DatasourceRelaDOMapper; import java.util.List; import org.springframework.stereotype.Component; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DateInfoRepositoryImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DateInfoRepositoryImpl.java similarity index 81% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DateInfoRepositoryImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DateInfoRepositoryImpl.java index bd4fb6733..6ac386c14 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DateInfoRepositoryImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DateInfoRepositoryImpl.java @@ -1,14 +1,14 @@ -package com.tencent.supersonic.semantic.core.infrastructure.repository; +package com.tencent.supersonic.semantic.model.infrastructure.repository; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Stopwatch; -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.core.request.DateInfoReq; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.semantic.core.domain.dataobject.DateInfoDO; -import com.tencent.supersonic.semantic.core.domain.repository.DateInfoRepository; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.DateInfoMapper; +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.api.model.request.DateInfoReq; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.semantic.model.domain.dataobject.DateInfoDO; +import com.tencent.supersonic.semantic.model.domain.repository.DateInfoRepository; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.DateInfoMapper; import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DimensionRepositoryImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DimensionRepositoryImpl.java similarity index 87% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DimensionRepositoryImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DimensionRepositoryImpl.java index eeef1f45a..1d92f0299 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DimensionRepositoryImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DimensionRepositoryImpl.java @@ -1,11 +1,11 @@ -package com.tencent.supersonic.semantic.core.infrastructure.repository; +package com.tencent.supersonic.semantic.model.infrastructure.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDOExample; -import com.tencent.supersonic.semantic.core.domain.repository.DimensionRepository; -import com.tencent.supersonic.semantic.core.domain.pojo.DimensionFilter; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.DimensionDOCustomMapper; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.DimensionDOMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDOExample; +import com.tencent.supersonic.semantic.model.domain.repository.DimensionRepository; +import com.tencent.supersonic.semantic.model.domain.pojo.DimensionFilter; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.DimensionDOCustomMapper; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.DimensionDOMapper; import java.util.List; import org.springframework.stereotype.Service; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DomainRepositoryImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DomainRepositoryImpl.java similarity index 72% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DomainRepositoryImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DomainRepositoryImpl.java index dcea2c7a7..8b6a475f0 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DomainRepositoryImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/DomainRepositoryImpl.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.core.infrastructure.repository; +package com.tencent.supersonic.semantic.model.infrastructure.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDOExample; -import com.tencent.supersonic.semantic.core.domain.repository.DomainRepository; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.DomainDOMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.DomainDOExample; +import com.tencent.supersonic.semantic.model.domain.repository.DomainRepository; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.DomainDOMapper; import java.util.List; import lombok.extern.slf4j.Slf4j; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/MetricRepositoryImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/MetricRepositoryImpl.java similarity index 86% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/MetricRepositoryImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/MetricRepositoryImpl.java index 356114b5a..0f0b80733 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/MetricRepositoryImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/MetricRepositoryImpl.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.semantic.core.infrastructure.repository; +package com.tencent.supersonic.semantic.model.infrastructure.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDOExample; -import com.tencent.supersonic.semantic.core.domain.pojo.MetricFilter; -import com.tencent.supersonic.semantic.core.domain.repository.MetricRepository; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.MetricDOCustomMapper; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.MetricDOMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.MetricDOExample; +import com.tencent.supersonic.semantic.model.domain.pojo.MetricFilter; +import com.tencent.supersonic.semantic.model.domain.repository.MetricRepository; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.MetricDOCustomMapper; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.MetricDOMapper; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/ViewInfoRepositoryImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/ViewInfoRepositoryImpl.java similarity index 74% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/ViewInfoRepositoryImpl.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/ViewInfoRepositoryImpl.java index c28976f23..5c8c15f8f 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/ViewInfoRepositoryImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/infrastructure/repository/ViewInfoRepositoryImpl.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.core.infrastructure.repository; +package com.tencent.supersonic.semantic.model.infrastructure.repository; -import com.tencent.supersonic.semantic.core.domain.dataobject.ViewInfoDO; -import com.tencent.supersonic.semantic.core.domain.dataobject.ViewInfoDOExample; -import com.tencent.supersonic.semantic.core.domain.repository.ViewInfoRepository; -import com.tencent.supersonic.semantic.core.infrastructure.mapper.ViewInfoDOMapper; +import com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO; +import com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDOExample; +import com.tencent.supersonic.semantic.model.domain.repository.ViewInfoRepository; +import com.tencent.supersonic.semantic.model.infrastructure.mapper.ViewInfoDOMapper; import java.util.List; import org.springframework.stereotype.Component; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatabaseController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DatabaseController.java similarity index 86% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatabaseController.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DatabaseController.java index 527684374..c5f20f1c0 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatabaseController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DatabaseController.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.semantic.core.rest; +package com.tencent.supersonic.semantic.model.rest; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.request.DatabaseReq; -import com.tencent.supersonic.semantic.api.core.request.SqlExecuteReq; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.core.domain.DatabaseService; +import com.tencent.supersonic.semantic.api.model.request.DatabaseReq; +import com.tencent.supersonic.semantic.api.model.request.SqlExecuteReq; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.model.domain.DatabaseService; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.GetMapping; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatasourceController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DatasourceController.java similarity index 86% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatasourceController.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DatasourceController.java index 94e54d2ac..7708d7706 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatasourceController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DatasourceController.java @@ -1,13 +1,13 @@ -package com.tencent.supersonic.semantic.core.rest; +package com.tencent.supersonic.semantic.model.rest; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.request.DatasourceRelaReq; -import com.tencent.supersonic.semantic.api.core.request.DatasourceReq; -import com.tencent.supersonic.semantic.api.core.response.DatasourceRelaResp; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.MeasureResp; -import com.tencent.supersonic.semantic.core.domain.DatasourceService; +import com.tencent.supersonic.semantic.api.model.request.DatasourceRelaReq; +import com.tencent.supersonic.semantic.api.model.request.DatasourceReq; +import com.tencent.supersonic.semantic.api.model.response.DatasourceRelaResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.MeasureResp; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DimensionController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DimensionController.java similarity index 89% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DimensionController.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DimensionController.java index be15f4cad..3d3b53ecd 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DimensionController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DimensionController.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.semantic.core.rest; +package com.tencent.supersonic.semantic.model.rest; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.request.DimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.core.domain.DimensionService; +import com.tencent.supersonic.semantic.api.model.request.DimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.model.domain.DimensionService; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DomainController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DomainController.java similarity index 86% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DomainController.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DomainController.java index 5687c956a..f22512aaf 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DomainController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DomainController.java @@ -1,13 +1,13 @@ -package com.tencent.supersonic.semantic.core.rest; +package com.tencent.supersonic.semantic.model.rest; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.request.DomainReq; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.DomainUpdateReq; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.core.domain.DomainService; +import com.tencent.supersonic.semantic.api.model.request.DomainReq; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.DomainUpdateReq; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.model.domain.DomainService; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/MetricController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/MetricController.java similarity index 88% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/MetricController.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/MetricController.java index 441dbcb63..5fcc16acd 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/MetricController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/MetricController.java @@ -1,13 +1,13 @@ -package com.tencent.supersonic.semantic.core.rest; +package com.tencent.supersonic.semantic.model.rest; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.request.MetricReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.core.domain.MetricService; +import com.tencent.supersonic.semantic.api.model.request.MetricReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.model.domain.MetricService; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/ViewInfoController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/ViewInfoController.java similarity index 84% rename from semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/ViewInfoController.java rename to semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/ViewInfoController.java index d6e1d16d8..a88f028d9 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/ViewInfoController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/ViewInfoController.java @@ -1,12 +1,12 @@ -package com.tencent.supersonic.semantic.core.rest; +package com.tencent.supersonic.semantic.model.rest; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.request.ViewInfoReq; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaRelaResp; -import com.tencent.supersonic.semantic.core.domain.dataobject.ViewInfoDO; -import com.tencent.supersonic.semantic.core.application.ViewInfoServiceImpl; +import com.tencent.supersonic.semantic.api.model.request.ViewInfoReq; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaRelaResp; +import com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO; +import com.tencent.supersonic.semantic.model.application.ViewInfoServiceImpl; import java.util.List; import javax.servlet.http.HttpServletRequest; diff --git a/semantic/core/src/main/resources/mapper/DatabaseDOMapper.xml b/semantic/model/src/main/resources/mapper/DatabaseDOMapper.xml similarity index 84% rename from semantic/core/src/main/resources/mapper/DatabaseDOMapper.xml rename to semantic/model/src/main/resources/mapper/DatabaseDOMapper.xml index d911cf01c..7ebe89615 100644 --- a/semantic/core/src/main/resources/mapper/DatabaseDOMapper.xml +++ b/semantic/model/src/main/resources/mapper/DatabaseDOMapper.xml @@ -1,13 +1,14 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO"> + @@ -15,7 +16,7 @@ + type="com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO"> @@ -51,13 +52,13 @@ id - , domain_id, name, description, type, created_at, created_by, updated_at, updated_by + , domain_id, name, description, version, type, created_at, created_by, updated_at, updated_by config select count(*) from s2_database @@ -196,7 +203,7 @@ + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO"> update s2_database @@ -208,6 +215,9 @@ description = #{description,jdbcType=VARCHAR}, + + version = #{version,jdbcType=VARCHAR}, + type = #{type,jdbcType=VARCHAR}, @@ -230,11 +240,12 @@ where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO"> update s2_database set domain_id = #{domainId,jdbcType=BIGINT}, name = #{name,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR}, + version = #{version,jdbcType=VARCHAR}, type = #{type,jdbcType=VARCHAR}, created_at = #{createdAt,jdbcType=TIMESTAMP}, created_by = #{createdBy,jdbcType=VARCHAR}, @@ -244,11 +255,12 @@ where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatabaseDO"> update s2_database set domain_id = #{domainId,jdbcType=BIGINT}, name = #{name,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR}, + version = #{version,jdbcType=VARCHAR}, type = #{type,jdbcType=VARCHAR}, created_at = #{createdAt,jdbcType=TIMESTAMP}, created_by = #{createdBy,jdbcType=VARCHAR}, diff --git a/semantic/core/src/main/resources/mapper/DatasourceDOMapper.xml b/semantic/model/src/main/resources/mapper/DatasourceDOMapper.xml similarity index 90% rename from semantic/core/src/main/resources/mapper/DatasourceDOMapper.xml rename to semantic/model/src/main/resources/mapper/DatasourceDOMapper.xml index 388ab00fd..86f9dd6e3 100644 --- a/semantic/core/src/main/resources/mapper/DatasourceDOMapper.xml +++ b/semantic/model/src/main/resources/mapper/DatasourceDOMapper.xml @@ -1,9 +1,9 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO"> @@ -16,7 +16,7 @@ + type="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO"> @@ -59,7 +59,7 @@ datasource_detail select count(*) from s2_datasource @@ -204,7 +204,7 @@ + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO"> update s2_datasource @@ -241,7 +241,7 @@ where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO"> update s2_datasource set domain_id = #{domainId,jdbcType=BIGINT}, name = #{name,jdbcType=VARCHAR}, @@ -256,7 +256,7 @@ where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceDO"> update s2_datasource set domain_id = #{domainId,jdbcType=BIGINT}, name = #{name,jdbcType=VARCHAR}, diff --git a/semantic/core/src/main/resources/mapper/DatasourceRelaDOMapper.xml b/semantic/model/src/main/resources/mapper/DatasourceRelaDOMapper.xml similarity index 90% rename from semantic/core/src/main/resources/mapper/DatasourceRelaDOMapper.xml rename to semantic/model/src/main/resources/mapper/DatasourceRelaDOMapper.xml index 1862ac4e4..6c2fe6359 100644 --- a/semantic/core/src/main/resources/mapper/DatasourceRelaDOMapper.xml +++ b/semantic/model/src/main/resources/mapper/DatasourceRelaDOMapper.xml @@ -1,9 +1,9 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO"> @@ -51,7 +51,7 @@ updated_at, updated_by select count(*) from s2_datasource_rela @@ -163,7 +163,7 @@ + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO"> update s2_datasource_rela @@ -194,7 +194,7 @@ where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DatasourceRelaDO"> update s2_datasource_rela set domain_id = #{domainId,jdbcType=BIGINT}, datasource_from = #{datasourceFrom,jdbcType=BIGINT}, diff --git a/semantic/core/src/main/resources/mapper/DimensionDOMapper.xml b/semantic/model/src/main/resources/mapper/DimensionDOMapper.xml similarity index 89% rename from semantic/core/src/main/resources/mapper/DimensionDOMapper.xml rename to semantic/model/src/main/resources/mapper/DimensionDOMapper.xml index fa5d52624..97f1d5e76 100644 --- a/semantic/core/src/main/resources/mapper/DimensionDOMapper.xml +++ b/semantic/model/src/main/resources/mapper/DimensionDOMapper.xml @@ -1,7 +1,7 @@ - - + + @@ -18,8 +18,9 @@ + - + @@ -54,12 +55,12 @@ id, domain_id, datasource_id, name, biz_name, description, status, sensitive_level, - type, created_at, created_by, updated_at, updated_by, semantic_type, alias, default_values + type, created_at, created_by, updated_at, updated_by, semantic_type, alias, default_values, dim_value_maps type_params, expr - select distinct @@ -75,7 +76,7 @@ order by ${orderByClause} - select distinct @@ -104,23 +105,25 @@ delete from s2_dimension where id = #{id,jdbcType=BIGINT} - + insert into s2_dimension (id, domain_id, datasource_id, name, biz_name, description, status, sensitive_level, type, created_at, created_by, updated_at, updated_by, semantic_type, alias, - default_values, type_params, expr + default_values, type_params, expr, + dim_value_maps ) values (#{id,jdbcType=BIGINT}, #{domainId,jdbcType=BIGINT}, #{datasourceId,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{bizName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=INTEGER}, #{sensitiveLevel,jdbcType=INTEGER}, #{type,jdbcType=VARCHAR}, #{createdAt,jdbcType=TIMESTAMP}, #{createdBy,jdbcType=VARCHAR}, #{updatedAt,jdbcType=TIMESTAMP}, #{updatedBy,jdbcType=VARCHAR}, #{semanticType,jdbcType=VARCHAR}, #{alias,jdbcType=VARCHAR}, - #{defaultValues,jdbcType=VARCHAR}, #{typeParams,jdbcType=LONGVARCHAR}, #{expr,jdbcType=LONGVARCHAR} + #{defaultValues,jdbcType=VARCHAR}, #{typeParams,jdbcType=LONGVARCHAR}, #{expr,jdbcType=LONGVARCHAR}, + #{dimValueMaps,jdbcType=VARCHAR} ) - + insert into s2_dimension @@ -171,6 +174,9 @@ default_values, + + dim_value_maps, + type_params, @@ -227,6 +233,9 @@ #{defaultValues,jdbcType=VARCHAR}, + + #{dimValueMaps,jdbcType=VARCHAR}, + #{typeParams,jdbcType=LONGVARCHAR}, @@ -235,13 +244,13 @@ - select count(*) from s2_dimension - + update s2_dimension @@ -289,6 +298,9 @@ default_values = #{defaultValues,jdbcType=VARCHAR}, + + dim_value_maps = #{dimValueMaps,jdbcType=VARCHAR}, + type_params = #{typeParams,jdbcType=LONGVARCHAR}, @@ -298,7 +310,7 @@ where id = #{id,jdbcType=BIGINT} - + update s2_dimension set domain_id = #{domainId,jdbcType=BIGINT}, datasource_id = #{datasourceId,jdbcType=BIGINT}, @@ -315,11 +327,12 @@ semantic_type = #{semanticType,jdbcType=VARCHAR}, alias = #{alias,jdbcType=VARCHAR}, default_values = #{defaultValues,jdbcType=VARCHAR}, + dim_value_maps = #{dimValueMaps,jdbcType=VARCHAR}, type_params = #{typeParams,jdbcType=LONGVARCHAR}, expr = #{expr,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=BIGINT} - + update s2_dimension set domain_id = #{domainId,jdbcType=BIGINT}, datasource_id = #{datasourceId,jdbcType=BIGINT}, @@ -335,7 +348,8 @@ updated_by = #{updatedBy,jdbcType=VARCHAR}, semantic_type = #{semanticType,jdbcType=VARCHAR}, alias = #{alias,jdbcType=VARCHAR}, - default_values = #{defaultValues,jdbcType=VARCHAR} + default_values = #{defaultValues,jdbcType=VARCHAR}, + dim_value_maps = #{dimValueMaps,jdbcType=VARCHAR} where id = #{id,jdbcType=BIGINT} \ No newline at end of file diff --git a/semantic/core/src/main/resources/mapper/DomainDOMapper.xml b/semantic/model/src/main/resources/mapper/DomainDOMapper.xml similarity index 88% rename from semantic/core/src/main/resources/mapper/DomainDOMapper.xml rename to semantic/model/src/main/resources/mapper/DomainDOMapper.xml index c30846ed3..3d27b8f19 100644 --- a/semantic/core/src/main/resources/mapper/DomainDOMapper.xml +++ b/semantic/model/src/main/resources/mapper/DomainDOMapper.xml @@ -1,9 +1,9 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO"> @@ -18,6 +18,7 @@ + @@ -53,10 +54,10 @@ id , name, biz_name, parent_id, status, created_at, created_by, updated_at, updated_by, - admin, admin_org, is_open, viewer, view_org + admin, admin_org, is_open, viewer, view_org, entity select count(*) from s2_domain @@ -201,7 +208,7 @@ + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO"> update s2_domain @@ -243,11 +250,14 @@ view_org = #{viewOrg,jdbcType=VARCHAR}, + + entity = #{entity,jdbcType=VARCHAR}, + where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.DomainDO"> update s2_domain set name = #{name,jdbcType=VARCHAR}, biz_name = #{bizName,jdbcType=VARCHAR}, @@ -261,7 +271,8 @@ admin_org = #{adminOrg,jdbcType=VARCHAR}, is_open = #{isOpen,jdbcType=INTEGER}, viewer = #{viewer,jdbcType=VARCHAR}, - view_org = #{viewOrg,jdbcType=VARCHAR} + view_org = #{viewOrg,jdbcType=VARCHAR}, + entity = #{entity,jdbcType=VARCHAR} where id = #{id,jdbcType=BIGINT} \ No newline at end of file diff --git a/semantic/core/src/main/resources/mapper/MetricDOMapper.xml b/semantic/model/src/main/resources/mapper/MetricDOMapper.xml similarity index 93% rename from semantic/core/src/main/resources/mapper/MetricDOMapper.xml rename to semantic/model/src/main/resources/mapper/MetricDOMapper.xml index cb173cc0a..bd3175540 100644 --- a/semantic/core/src/main/resources/mapper/MetricDOMapper.xml +++ b/semantic/model/src/main/resources/mapper/MetricDOMapper.xml @@ -1,7 +1,7 @@ - - + + @@ -18,7 +18,7 @@ - + @@ -57,7 +57,7 @@ type_params - select distinct @@ -73,7 +73,7 @@ order by ${orderByClause} - select distinct @@ -102,7 +102,7 @@ delete from s2_metric where id = #{id,jdbcType=BIGINT} - + insert into s2_metric (id, domain_id, name, biz_name, description, status, sensitive_level, type, created_at, @@ -116,7 +116,7 @@ #{dataFormatType,jdbcType=VARCHAR}, #{dataFormat,jdbcType=VARCHAR}, #{alias,jdbcType=VARCHAR}, #{typeParams,jdbcType=LONGVARCHAR}) - + insert into s2_metric @@ -219,13 +219,13 @@ - select count(*) from s2_metric - + update s2_metric @@ -276,7 +276,7 @@ where id = #{id,jdbcType=BIGINT} - + update s2_metric set domain_id = #{domainId,jdbcType=BIGINT}, name = #{name,jdbcType=VARCHAR}, @@ -295,7 +295,7 @@ type_params = #{typeParams,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=BIGINT} - + update s2_metric set domain_id = #{domainId,jdbcType=BIGINT}, name = #{name,jdbcType=VARCHAR}, diff --git a/semantic/core/src/main/resources/mapper/ViewInfoDOMapper.xml b/semantic/model/src/main/resources/mapper/ViewInfoDOMapper.xml similarity index 89% rename from semantic/core/src/main/resources/mapper/ViewInfoDOMapper.xml rename to semantic/model/src/main/resources/mapper/ViewInfoDOMapper.xml index c8959c20a..06be22d1a 100644 --- a/semantic/core/src/main/resources/mapper/ViewInfoDOMapper.xml +++ b/semantic/model/src/main/resources/mapper/ViewInfoDOMapper.xml @@ -1,9 +1,9 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO"> @@ -13,7 +13,7 @@ + type="com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO"> @@ -55,7 +55,7 @@ config select count(*) from s2_view_info @@ -179,7 +179,7 @@ + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO"> update s2_view_info @@ -207,7 +207,7 @@ where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO"> update s2_view_info set domain_id = #{domainId,jdbcType=BIGINT}, type = #{type,jdbcType=VARCHAR}, @@ -219,7 +219,7 @@ where id = #{id,jdbcType=BIGINT} + parameterType="com.tencent.supersonic.semantic.model.domain.dataobject.ViewInfoDO"> update s2_view_info set domain_id = #{domainId,jdbcType=BIGINT}, type = #{type,jdbcType=VARCHAR}, diff --git a/semantic/core/src/main/resources/mapper/custom/DateInfoMapper.xml b/semantic/model/src/main/resources/mapper/custom/DateInfoMapper.xml similarity index 92% rename from semantic/core/src/main/resources/mapper/custom/DateInfoMapper.xml rename to semantic/model/src/main/resources/mapper/custom/DateInfoMapper.xml index 1e9823b71..6ff811b16 100644 --- a/semantic/core/src/main/resources/mapper/custom/DateInfoMapper.xml +++ b/semantic/model/src/main/resources/mapper/custom/DateInfoMapper.xml @@ -1,10 +1,10 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.DateInfoDO"> diff --git a/semantic/core/src/main/resources/mapper/custom/DimensionDOCustomMapper.xml b/semantic/model/src/main/resources/mapper/custom/DimensionDOCustomMapper.xml similarity index 96% rename from semantic/core/src/main/resources/mapper/custom/DimensionDOCustomMapper.xml rename to semantic/model/src/main/resources/mapper/custom/DimensionDOCustomMapper.xml index 6fcc4da18..ee4fb0362 100644 --- a/semantic/core/src/main/resources/mapper/custom/DimensionDOCustomMapper.xml +++ b/semantic/model/src/main/resources/mapper/custom/DimensionDOCustomMapper.xml @@ -1,9 +1,9 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.DimensionDO"> diff --git a/semantic/core/src/main/resources/mapper/custom/MetricDOCustomMapper.xml b/semantic/model/src/main/resources/mapper/custom/MetricDOCustomMapper.xml similarity index 94% rename from semantic/core/src/main/resources/mapper/custom/MetricDOCustomMapper.xml rename to semantic/model/src/main/resources/mapper/custom/MetricDOCustomMapper.xml index 2e8f4acd1..8054bdcc3 100644 --- a/semantic/core/src/main/resources/mapper/custom/MetricDOCustomMapper.xml +++ b/semantic/model/src/main/resources/mapper/custom/MetricDOCustomMapper.xml @@ -1,9 +1,9 @@ - + + type="com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO"> @@ -16,7 +16,7 @@ + type="com.tencent.supersonic.semantic.model.domain.dataobject.MetricDO"> diff --git a/semantic/core/src/main/resources/sql.ddl/s2_database.sql b/semantic/model/src/main/resources/sql.ddl/s2_database.sql similarity index 92% rename from semantic/core/src/main/resources/sql.ddl/s2_database.sql rename to semantic/model/src/main/resources/sql.ddl/s2_database.sql index e2cf67f11..c429234f8 100644 --- a/semantic/core/src/main/resources/sql.ddl/s2_database.sql +++ b/semantic/model/src/main/resources/sql.ddl/s2_database.sql @@ -4,6 +4,7 @@ CREATE TABLE `s2_database` `domain_id` bigint(20) NOT NULL COMMENT '主题域ID', `name` varchar(255) NOT NULL COMMENT '名称', `description` varchar(500) DEFAULT NULL COMMENT '描述', + `version` varchar(64) DEFAULT NULL COMMENT '版本', `type` varchar(20) NOT NULL COMMENT '类型 mysql,clickhouse,tdw', `config` text NOT NULL COMMENT '配置信息', `created_at` datetime NOT NULL COMMENT '创建时间', diff --git a/semantic/core/src/main/resources/sql.ddl/s2_datasource.sql b/semantic/model/src/main/resources/sql.ddl/s2_datasource.sql similarity index 100% rename from semantic/core/src/main/resources/sql.ddl/s2_datasource.sql rename to semantic/model/src/main/resources/sql.ddl/s2_datasource.sql diff --git a/semantic/core/src/main/resources/sql.ddl/s2_dimension.sql b/semantic/model/src/main/resources/sql.ddl/s2_dimension.sql similarity index 100% rename from semantic/core/src/main/resources/sql.ddl/s2_dimension.sql rename to semantic/model/src/main/resources/sql.ddl/s2_dimension.sql diff --git a/semantic/core/src/main/resources/sql.ddl/s2_domain.sql b/semantic/model/src/main/resources/sql.ddl/s2_domain.sql similarity index 100% rename from semantic/core/src/main/resources/sql.ddl/s2_domain.sql rename to semantic/model/src/main/resources/sql.ddl/s2_domain.sql diff --git a/semantic/core/src/main/resources/sql.ddl/s2_domain_extend.sql b/semantic/model/src/main/resources/sql.ddl/s2_domain_extend.sql similarity index 100% rename from semantic/core/src/main/resources/sql.ddl/s2_domain_extend.sql rename to semantic/model/src/main/resources/sql.ddl/s2_domain_extend.sql diff --git a/semantic/core/src/main/resources/sql.ddl/s2_metric.sql b/semantic/model/src/main/resources/sql.ddl/s2_metric.sql similarity index 100% rename from semantic/core/src/main/resources/sql.ddl/s2_metric.sql rename to semantic/model/src/main/resources/sql.ddl/s2_metric.sql diff --git a/semantic/core/src/test/java/com/tencent/supersonic/semantic/model/application/DatabaseApplicationServiceTest.java b/semantic/model/src/test/java/com/tencent/supersonic/semantic/model/application/DatabaseApplicationServiceTest.java similarity index 100% rename from semantic/core/src/test/java/com/tencent/supersonic/semantic/model/application/DatabaseApplicationServiceTest.java rename to semantic/model/src/test/java/com/tencent/supersonic/semantic/model/application/DatabaseApplicationServiceTest.java diff --git a/semantic/core/src/test/java/com/tencent/supersonic/semantic/model/application/DatasourceApplicationServiceTest.java b/semantic/model/src/test/java/com/tencent/supersonic/semantic/model/application/DatasourceApplicationServiceTest.java similarity index 100% rename from semantic/core/src/test/java/com/tencent/supersonic/semantic/model/application/DatasourceApplicationServiceTest.java rename to semantic/model/src/test/java/com/tencent/supersonic/semantic/model/application/DatasourceApplicationServiceTest.java diff --git a/semantic/core/src/test/java/com/tencent/supersonic/semantic/model/application/DomainApplicationServiceTest.java b/semantic/model/src/test/java/com/tencent/supersonic/semantic/model/application/DomainApplicationServiceTest.java similarity index 100% rename from semantic/core/src/test/java/com/tencent/supersonic/semantic/model/application/DomainApplicationServiceTest.java rename to semantic/model/src/test/java/com/tencent/supersonic/semantic/model/application/DomainApplicationServiceTest.java diff --git a/semantic/pom.xml b/semantic/pom.xml index 16c91c885..af3fa6a42 100644 --- a/semantic/pom.xml +++ b/semantic/pom.xml @@ -14,7 +14,7 @@ pom api - core + model query diff --git a/semantic/query/pom.xml b/semantic/query/pom.xml index df1a00f0d..82f96e737 100644 --- a/semantic/query/pom.xml +++ b/semantic/query/pom.xml @@ -66,7 +66,7 @@ com.tencent.supersonic - semantic-core + semantic-model ${project.version} compile diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/executor/QueryExecutor.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/executor/QueryExecutor.java deleted file mode 100644 index d66287b40..000000000 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/executor/QueryExecutor.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.tencent.supersonic.semantic.query.application.executor; - -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; - -public interface QueryExecutor { - - boolean accept(QueryStatement queryStatement); - - QueryResultWithSchemaResp execute(Catalog catalog,QueryStatement queryStatement); -} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/optimizer/QueryOptimizer.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/optimizer/QueryOptimizer.java deleted file mode 100644 index 79514c2fb..000000000 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/optimizer/QueryOptimizer.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tencent.supersonic.semantic.query.application.optimizer; - -import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; -import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; - -public interface QueryOptimizer { - void rewrite(QueryStructReq queryStructCmd, QueryStatement queryStatement); -} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticItem.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticItem.java deleted file mode 100644 index fd0cdaf83..000000000 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticItem.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.schema; - -public interface SemanticItem { - - public String getName(); -} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/Optimization.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/Optimization.java deleted file mode 100644 index cb3624c9d..000000000 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/Optimization.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql; - - -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.SemanticNode; - -public interface Optimization { - - public void visit(SemanticNode semanticNode); -} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/CalculateConverterAgg.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/CalculateConverterAgg.java deleted file mode 100644 index c76f1fdba..000000000 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/CalculateConverterAgg.java +++ /dev/null @@ -1,344 +0,0 @@ -package com.tencent.supersonic.semantic.query.application.parser.convert; - - -import com.tencent.supersonic.common.enums.AggOperatorEnum; -import com.tencent.supersonic.common.pojo.Aggregator; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import com.tencent.supersonic.semantic.api.query.pojo.Filter; -import com.tencent.supersonic.semantic.api.query.pojo.MetricTable; -import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; -import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.application.parser.SemanticConverter; -import com.tencent.supersonic.semantic.query.domain.SemanticQueryEngine; -import com.tencent.supersonic.semantic.query.domain.utils.QueryStructUtils; -import com.tencent.supersonic.semantic.query.domain.utils.SqlGenerateUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -@Component("CalculateConverterAgg") -@Slf4j -public class CalculateConverterAgg implements SemanticConverter { - - - private final SemanticQueryEngine parserService; - private final QueryStructUtils queryStructUtils; - private final SqlGenerateUtils sqlGenerateUtils; - private final Catalog catalog; - - @Value("${metricParser.agg.default:sum}") - private String metricAggDefault; - - @Value("${metricParser.agg.ratio_roll.name:ratio_roll}") - private String metricAggRatioRollName; - - @Value("${metricParser.agg.ratio_over.week:ratio_over_week}") // week over - private String metricAggRatioOverWeek; - @Value("${metricParser.agg.ratio_over.month:ratio_over_month}") - private String metricAggRatioOverMonth; - @Value("${metricParser.agg.ratio_over.quarter:ratio_over_quarter}") - private String metricAggRatioOverQuarter; - @Value("${metricParser.agg.ratio_over.year:ratio_over_year}") - private String metricAggRatioOverYear; - private List dateGrain = new ArrayList<>(Arrays.asList("day", "week", "month", "year", "quarter")); - private Set aggFunctionsOver = new HashSet<>( - Arrays.asList(metricAggRatioOverWeek, metricAggRatioOverMonth, metricAggRatioOverQuarter, - metricAggRatioOverYear)); - - - public CalculateConverterAgg( - SemanticQueryEngine parserService, - @Lazy QueryStructUtils queryStructUtils, - SqlGenerateUtils sqlGenerateUtils, Catalog catalog) { - this.parserService = parserService; - this.queryStructUtils = queryStructUtils; - this.sqlGenerateUtils = sqlGenerateUtils; - this.catalog = catalog; - } - - public ParseSqlReq generateSqlCommend(QueryStructReq queryStructCmd) throws Exception { - // 同环比 - if (isRatioAccept(queryStructCmd)) { - return generateRatioSqlCommand(queryStructCmd); - } - ParseSqlReq sqlCommand = new ParseSqlReq(); - sqlCommand.setRootPath(catalog.getDomainFullPath(queryStructCmd.getDomainId())); - String metricTableName = "metric_tb"; - MetricTable metricTable = new MetricTable(); - metricTable.setAlias(metricTableName); - metricTable.setMetrics(queryStructCmd.getMetrics()); - metricTable.setDimensions(queryStructCmd.getGroups()); - String where = queryStructUtils.generateWhere(queryStructCmd); - log.info("in generateSqlCommand, complete where:{}", where); - metricTable.setWhere(where); - metricTable.setAgg(true); - sqlCommand.setTables(new ArrayList<>(Collections.singletonList(metricTable))); - String sql = String.format("select %s from %s %s %s %s", sqlGenerateUtils.getSelect(queryStructCmd), - metricTableName, - sqlGenerateUtils.getGroupBy(queryStructCmd), sqlGenerateUtils.getOrderBy(queryStructCmd), - sqlGenerateUtils.getLimit(queryStructCmd)); - sqlCommand.setSql(sql); - return sqlCommand; - } - - - @Override - public boolean accept(QueryStructReq queryStructCmd) { - if (queryStructCmd.getNativeQuery()) { - return false; - } - if (CollectionUtils.isEmpty(queryStructCmd.getAggregators())) { - return false; - } - //todo ck类型暂不拼with语句 - if (queryStructCmd.getDomainId().equals(34L)) { - return false; - } - int nonSumFunction = 0; - for (Aggregator agg : queryStructCmd.getAggregators()) { - if (agg.getFunc() == null || "".equals(agg.getFunc())) { - return false; - } - if (agg.getFunc().equals(AggOperatorEnum.UNKNOWN)) { - return false; - } - if (agg.getFunc() != null - // && !agg.getFunc().equalsIgnoreCase(MetricAggDefault) - ) { - nonSumFunction++; - } - } - return nonSumFunction > 0; - } - - @Override - public void converter(Catalog catalog, QueryStructReq queryStructCmd, ParseSqlReq sqlCommend, - MetricReq metricCommand) throws Exception { - ParseSqlReq parseSqlReq = generateSqlCommend(queryStructCmd); - sqlCommend.setSql(parseSqlReq.getSql()); - sqlCommend.setTables(parseSqlReq.getTables()); - sqlCommend.setRootPath(parseSqlReq.getRootPath()); - sqlCommend.setVariables(parseSqlReq.getVariables()); - } - - - - /** - * Ratio - */ - - public boolean isRatioAccept(QueryStructReq queryStructCmd) { - Long ratioFuncNum = queryStructCmd.getAggregators().stream() - .filter(f -> f.getArgs() != null && f.getArgs().get(0) != null - && metricAggRatioRollName.equalsIgnoreCase(f.getArgs().get(0))).count(); - if (ratioFuncNum > 0) { - return true; - } - return false; - } - - public ParseSqlReq generateRatioSqlCommand(QueryStructReq queryStructCmd) throws Exception { - check(queryStructCmd); - ParseSqlReq sqlCommand = new ParseSqlReq(); - sqlCommand.setRootPath(catalog.getDomainFullPath(queryStructCmd.getDomainId())); - String metricTableName = "metric_tb"; - MetricTable metricTable = new MetricTable(); - metricTable.setAlias(metricTableName); - metricTable.setMetrics(queryStructCmd.getMetrics()); - metricTable.setDimensions(queryStructCmd.getGroups()); - String where = queryStructUtils.generateWhere(queryStructCmd); - log.info("in generateSqlCommend, complete where:{}", where); -// metricTable.setWhere(queryStructCmd.getWhereClause()); - metricTable.setWhere(where); - metricTable.setAgg(false); - sqlCommand.setTables(new ArrayList<>(Collections.singletonList(metricTable))); - String sqlInner = String.format("select %s from %s %s ", getSelect(queryStructCmd), metricTableName, - getGroupBy(queryStructCmd)); - String sql = String.format( - "select %s from ( select %s , %s from ( %s ) metric_tb_inner_1 ) metric_tb_src %s %s ", - getOverSelect(queryStructCmd), getSelect(queryStructCmd, true), getLeadSelect(queryStructCmd), sqlInner, - getOrderBy(queryStructCmd), getLimit(queryStructCmd)); - - sqlCommand.setSql(sql); - return sqlCommand; - } - - private String getOverSelect(QueryStructReq queryStructCmd) { - String timeDim = getTimeDim(queryStructCmd); - String timeSpan = "INTERVAL " + getTimeSpan(queryStructCmd); - String aggStr = queryStructCmd.getAggregators().stream().map(f -> { - if (f.getArgs() != null && f.getArgs().size() > 0) { - return String.format("if(%s = date_add(%s_roll,%s) and %s_roll!=0, (%s-%s_roll)/%s_roll , 0) as %s", - timeDim, timeDim, timeSpan, f.getColumn(), f.getColumn(), f.getColumn(), f.getColumn(), - f.getColumn()); - } else { - return f.getColumn(); - } - }).collect(Collectors.joining(",")); - return CollectionUtils.isEmpty(queryStructCmd.getGroups()) ? aggStr - : String.join(",", queryStructCmd.getGroups()) + "," + aggStr; - } - - private String getLeadSelect(QueryStructReq queryStructCmd) { - String timeDim = getTimeDim(queryStructCmd); - String groupDimWithOutTime = getGroupDimWithOutTime(queryStructCmd); - String aggStr = queryStructCmd.getAggregators().stream().map(f -> { - if (f.getArgs() != null && f.getArgs().size() > 0 && f.getArgs().get(0) - .equalsIgnoreCase(metricAggRatioRollName)) { - return String.format("lead(%s ,1,0) over ( %s order by %s desc) as %s_roll", f.getColumn(), - !groupDimWithOutTime.isEmpty() ? " partition by " + groupDimWithOutTime : "", timeDim, - f.getColumn()); - } else { - return ""; - } - }).filter(f -> !f.isEmpty()).collect(Collectors.joining(",")); - String timeDimLead = String.format("lead(cast(%s as string) ,1,'') over ( %s order by %s desc) as %s_roll", - timeDim, !groupDimWithOutTime.isEmpty() ? " partition by " + groupDimWithOutTime : "", timeDim, - timeDim); - return timeDimLead + " , " + aggStr; - } - - private String getTimeSpan(QueryStructReq queryStructCmd) { - String timeGrain = getTimeDimGrain(queryStructCmd).toLowerCase(); - if ("week".equalsIgnoreCase(timeGrain)) { - return "7 day"; - } - if ("quarter".equalsIgnoreCase(timeGrain)) { - return "3 month"; - } - return "1 " + timeGrain; - } - - private String getTimeDimGrain(QueryStructReq queryStructCmd) { - String grain = queryStructCmd.getAggregators().stream().map(f -> { - if (f.getArgs() != null && f.getArgs().size() > 1 && f.getArgs().get(0) - .equalsIgnoreCase(metricAggRatioRollName)) { - return f.getArgs().get(1); - } - return ""; - }).filter(f -> !f.isEmpty()).findFirst().orElse(""); - return grain.isEmpty() ? "day" : grain; - } - - private String getGroupDimWithOutTime(QueryStructReq queryStructCmd) { - String timeDim = getTimeDim(queryStructCmd); - return queryStructCmd.getGroups().stream().filter(f -> !f.equalsIgnoreCase(timeDim)) - .collect(Collectors.joining(",")); - } - - private String getTimeDim(QueryStructReq queryStructCmd) { - String dsField = ""; - String dsStart = ""; - String dsEnd = ""; - - for (Filter filter : queryStructCmd.getOriginalFilter()) { - if (Filter.Relation.FILTER.equals(filter.getRelation())) { - // TODO get parameters from DateInfo - if ("DATE".equalsIgnoreCase(filter.getRelation().name())) { - if (FilterOperatorEnum.GREATER_THAN_EQUALS.getValue() - .equalsIgnoreCase(filter.getOperator().toString()) - || FilterOperatorEnum.GREATER_THAN.getValue() - .equalsIgnoreCase(filter.getOperator().toString())) { - dsField = filter.getBizName(); - dsStart = filter.getValue().toString(); - } - if (FilterOperatorEnum.MINOR_THAN_EQUALS.getValue() - .equalsIgnoreCase(filter.getOperator().toString()) - || FilterOperatorEnum.MINOR_THAN.getValue() - .equalsIgnoreCase(filter.getOperator().toString())) { - dsField = filter.getBizName(); - dsEnd = filter.getValue().toString(); - } - } - - } - } - return dsField; - } - - private String getLimit(QueryStructReq queryStructCmd) { - if (queryStructCmd.getLimit() > 0) { - return " limit " + String.valueOf(queryStructCmd.getLimit()); - } - return ""; - } - - private String getSelect(QueryStructReq queryStructCmd) { - return getSelect(queryStructCmd, false); - } - - private String getSelect(QueryStructReq queryStructCmd, boolean isRatio) { - String aggStr = queryStructCmd.getAggregators().stream().map(f -> getSelectField(f, isRatio)) - .collect(Collectors.joining(",")); - return CollectionUtils.isEmpty(queryStructCmd.getGroups()) ? aggStr - : String.join(",", queryStructCmd.getGroups()) + "," + aggStr; - } - - private String getSelectField(final Aggregator agg, boolean isRatio) { - if (!CollectionUtils.isEmpty(agg.getArgs()) && agg.getArgs().size() > 0) { - if (agg.getArgs().get(0).equalsIgnoreCase(metricAggRatioRollName)) { - if (isRatio) { - return agg.getColumn(); - } - return agg.getFunc().name().isEmpty() ? agg.getColumn() - : agg.getFunc() + "( " + agg.getColumn() + " ) AS " + agg.getColumn() + " "; - } - } - if (CollectionUtils.isEmpty(agg.getArgs())) { - return agg.getFunc() + "( " + agg.getColumn() + " ) AS " + agg.getColumn() + " "; - } - return agg.getFunc() + "( " + agg.getArgs().stream().map(arg -> - arg.equals(agg.getColumn()) ? arg : (StringUtils.isNumeric(arg) ? arg : ("'" + arg + "'")) - ).collect(Collectors.joining(",")) + " ) AS " + agg.getColumn() + " "; - } - - private String getGroupBy(QueryStructReq queryStructCmd) { - if (CollectionUtils.isEmpty(queryStructCmd.getGroups())) { - return ""; - } - return "group by " + String.join(",", queryStructCmd.getGroups()); - } - - private String getOrderBy(QueryStructReq queryStructCmd) { - if (CollectionUtils.isEmpty(queryStructCmd.getOrders())) { - return ""; - } - return "order by " + queryStructCmd.getOrders().stream() - .map(order -> " " + order.getColumn() + " " + order.getDirection() + " ") - .collect(Collectors.joining(",")); - } - - private void check(QueryStructReq queryStructCmd) throws Exception { - Set aggFunctions = queryStructCmd.getAggregators().stream() - .filter(f -> f.getArgs() != null && f.getArgs().get(0) != null) - .map(agg -> agg.getArgs().get(0).toLowerCase()).collect(Collectors.toSet()); - Long ratioOverNum = aggFunctions.stream().filter(aggFunctionsOver::contains).count(); - if (ratioOverNum > 0) { - throw new Exception("not support over ratio"); - } - if (aggFunctions.contains(metricAggRatioRollName)) { - if (ratioOverNum > 0) { - throw new Exception("not support over ratio and roll ratio together "); - } - } - if (getTimeDim(queryStructCmd).isEmpty()) { - throw new Exception("miss time filter"); - } - String timeDimGrain = getTimeDimGrain(queryStructCmd).toLowerCase(); - if (!dateGrain.contains(timeDimGrain)) { - throw new Exception("second arg must be [day week month year quarter] "); - } - } -} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/SchemaService.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/SchemaService.java deleted file mode 100644 index 9a761e318..000000000 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/SchemaService.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.tencent.supersonic.semantic.query.domain; - -import com.github.pagehelper.PageInfo; -import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; - -import java.util.List; - -public interface SchemaService { - - List fetchDomainSchema(DomainSchemaFilterReq filter, User user); - - List getDomainListForAdmin(User user); - - List getDomainListForViewer(User user); - - PageInfo queryDimension(PageDimensionReq pageDimensionReq, User user); - - PageInfo queryMetric(PageMetricReq pageMetricReq, User user); -} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/executor/JdbcExecutor.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/executor/JdbcExecutor.java similarity index 73% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/executor/JdbcExecutor.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/executor/JdbcExecutor.java index ccfecd096..d029c01fc 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/executor/JdbcExecutor.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/executor/JdbcExecutor.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.semantic.query.application.executor; +package com.tencent.supersonic.semantic.query.executor; -import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.core.domain.utils.SqlUtils; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.model.domain.utils.SqlUtils; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.springframework.stereotype.Component; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/executor/QueryExecutor.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/executor/QueryExecutor.java new file mode 100644 index 000000000..7561c00f9 --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/executor/QueryExecutor.java @@ -0,0 +1,12 @@ +package com.tencent.supersonic.semantic.query.executor; + +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; + +public interface QueryExecutor { + + boolean accept(QueryStatement queryStatement); + + QueryResultWithSchemaResp execute(Catalog catalog,QueryStatement queryStatement); +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/optimizer/DetailQuery.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/optimizer/DetailQuery.java similarity index 91% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/optimizer/DetailQuery.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/optimizer/DetailQuery.java index 9de69bd7a..985c6cd6c 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/optimizer/DetailQuery.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/optimizer/DetailQuery.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.query.application.optimizer; +package com.tencent.supersonic.semantic.query.optimizer; import com.google.common.base.Strings; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; import java.util.Objects; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/optimizer/QueryOptimizer.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/optimizer/QueryOptimizer.java new file mode 100644 index 000000000..956e852d0 --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/optimizer/QueryOptimizer.java @@ -0,0 +1,8 @@ +package com.tencent.supersonic.semantic.query.optimizer; + +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; + +public interface QueryOptimizer { + void rewrite(QueryStructReq queryStructCmd, QueryStatement queryStatement); +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/QueryParser.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/QueryParser.java similarity index 79% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/QueryParser.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/QueryParser.java index 16dffe749..c2155807f 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/QueryParser.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/QueryParser.java @@ -1,14 +1,15 @@ -package com.tencent.supersonic.semantic.query.application.parser; +package com.tencent.supersonic.semantic.query.parser; import com.tencent.supersonic.semantic.api.query.pojo.MetricTable; import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; -import com.tencent.supersonic.semantic.query.domain.utils.ComponentFactory; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; +import com.tencent.supersonic.semantic.query.utils.ComponentFactory; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Primary; @@ -50,7 +51,7 @@ public class QueryParser { QueryStatement queryStatement = new QueryStatement(); try { if (!CollectionUtils.isEmpty(sqlCommend.getTables())) { - List tables = new ArrayList<>(); + List tables = new ArrayList<>(); String sourceId = ""; for (MetricTable metricTable : sqlCommend.getTables()) { MetricReq metricReq = new MetricReq(); @@ -64,12 +65,22 @@ public class QueryParser { tableSql.getErrMsg())); return queryStatement; } - tables.add(String.format("%s as (%s)", metricTable.getAlias(), tableSql.getSql())); + tables.add(new String[]{metricTable.getAlias(), tableSql.getSql()}); sourceId = tableSql.getSourceId(); } if (!tables.isEmpty()) { - String sql = "with " + String.join(",", tables) + "\n" + sqlCommend.getSql(); + String sql = ""; + if (sqlCommend.isSupportWith()) { + sql = "with " + String.join(",", + tables.stream().map(t -> String.format("%s as (%s)", t[0], t[1])).collect( + Collectors.toList())) + "\n" + sqlCommend.getSql(); + } else { + sql = sqlCommend.getSql(); + for (String[] tb : tables) { + sql = sql.replaceAll(tb[0], "(" + tb[1] + ")"); + } + } queryStatement.setSql(sql); queryStatement.setSourceId(sourceId); return queryStatement; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SemanticConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/SemanticConverter.java similarity index 78% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SemanticConverter.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/SemanticConverter.java index 86e7e255d..f01119b40 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SemanticConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/SemanticConverter.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.query.application.parser; +package com.tencent.supersonic.semantic.query.parser; import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; +import com.tencent.supersonic.semantic.model.domain.Catalog; public interface SemanticConverter { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SqlParser.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/SqlParser.java similarity index 50% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SqlParser.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/SqlParser.java index 32ee1a752..c68ec43ce 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SqlParser.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/SqlParser.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.query.application.parser; +package com.tencent.supersonic.semantic.query.parser; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; public interface SqlParser { QueryStatement explain(MetricReq metricReq, boolean isAgg, Catalog catalog) throws Exception; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/CalciteSqlParser.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/CalciteSqlParser.java similarity index 72% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/CalciteSqlParser.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/CalciteSqlParser.java index bf05a7ca2..a1b60c3c7 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/CalciteSqlParser.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/CalciteSqlParser.java @@ -1,14 +1,13 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite; +package com.tencent.supersonic.semantic.query.parser.calcite; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.application.parser.SqlParser; -import com.tencent.supersonic.semantic.query.application.parser.calcite.planner.AggPlanner; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.SemanticModel; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.parser.SqlParser; +import com.tencent.supersonic.semantic.query.parser.calcite.planner.AggPlanner; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.SemanticModel; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; @Component("CalciteSqlParser") public class CalciteSqlParser implements SqlParser { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/Configuration.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/Configuration.java similarity index 91% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/Configuration.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/Configuration.java index e1705bf16..4e66c1b26 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/Configuration.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/Configuration.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite; +package com.tencent.supersonic.semantic.query.parser.calcite; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.DSLSqlValidatorImpl; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSqlDialect; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.DSLSqlValidatorImpl; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSqlDialect; import java.util.Properties; import org.apache.calcite.avatica.util.Casing; import org.apache.calcite.avatica.util.Quoting; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/SemanticSchemaManager.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/SemanticSchemaManager.java similarity index 87% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/SemanticSchemaManager.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/SemanticSchemaManager.java index 676a5ee4f..5bed67838 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/SemanticSchemaManager.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/SemanticSchemaManager.java @@ -1,25 +1,25 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite; +package com.tencent.supersonic.semantic.query.parser.calcite; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DatasourceYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionTimeTypeParamsTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.IdentifyYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MeasureYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricTypeParamsYamlTpl; -import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Dimension; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DimensionTimeTypeParams; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Identify; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Measure; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Metric; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.MetricTypeParams; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.SemanticModel; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.api.model.yaml.DatasourceYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionTimeTypeParamsTpl; +import com.tencent.supersonic.semantic.api.model.yaml.DimensionYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.IdentifyYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MeasureYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricTypeParamsYamlTpl; +import com.tencent.supersonic.semantic.api.model.yaml.MetricYamlTpl; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Dimension; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DimensionTimeTypeParams; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Identify; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Measure; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Metric; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.MetricTypeParams; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.SemanticModel; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -68,7 +68,7 @@ public class SemanticSchemaManager { catalog.getModelYamlTplByDomainIds(domainIds, dimensionYamlTpls, datasourceYamlTpls, metricYamlTpls); if (!datasourceYamlTpls.isEmpty()) { Map dataSourceMap = datasourceYamlTpls.stream().map(d -> getDatasource(d)) - .collect(Collectors.toMap(DataSource::getName, item -> item)); + .collect(Collectors.toMap(DataSource::getName, item -> item, (k1, k2) -> k1)); semanticModel.setDatasourceMap(dataSourceMap); } if (!dimensionYamlTpls.isEmpty()) { @@ -267,8 +267,8 @@ public class SemanticSchemaManager { @EnableCaching public class GuavaCacheConfig { - @Value("${parser.cache.saveMinute:15}") - private Integer saveMinutes = 15; + @Value("${parser.cache.saveMinute:1}") + private Integer saveMinutes = 1; @Value("${parser.cache.maximumSize:1000}") private Integer maximumSize = 1000; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Constants.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Constants.java similarity index 86% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Constants.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Constants.java index 47f0e403b..5c9f755ac 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Constants.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Constants.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; public class Constants { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/DataSource.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/DataSource.java similarity index 80% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/DataSource.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/DataSource.java index 99bf2a7bc..9be8edde6 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/DataSource.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/DataSource.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; import java.util.List; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Dimension.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Dimension.java similarity index 64% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Dimension.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Dimension.java index ce4842a09..5f5fb9659 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Dimension.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Dimension.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticItem; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticItem; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/DimensionTimeTypeParams.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/DimensionTimeTypeParams.java similarity index 63% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/DimensionTimeTypeParams.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/DimensionTimeTypeParams.java index 2f9d2bd81..0ff1cc48b 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/DimensionTimeTypeParams.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/DimensionTimeTypeParams.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Identify.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Identify.java similarity index 75% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Identify.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Identify.java index ec35124b0..8dc4173d5 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Identify.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Identify.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Measure.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Measure.java similarity index 82% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Measure.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Measure.java index 4bb08eade..1f434d8ec 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Measure.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Measure.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Metric.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Metric.java similarity index 64% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Metric.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Metric.java index 5b73f8558..2683f940a 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/Metric.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/Metric.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticItem; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticItem; import java.util.List; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/MetricTypeParams.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/MetricTypeParams.java similarity index 65% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/MetricTypeParams.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/MetricTypeParams.java index 6a03246b1..7e2a60a71 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/MetricTypeParams.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/MetricTypeParams.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; import java.util.List; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/SemanticModel.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/SemanticModel.java similarity index 83% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/SemanticModel.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/SemanticModel.java index 53821b718..dc5f00987 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/dsl/SemanticModel.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/dsl/SemanticModel.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.dsl; +package com.tencent.supersonic.semantic.query.parser.calcite.dsl; import java.util.ArrayList; import java.util.HashMap; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/planner/AggPlanner.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/planner/AggPlanner.java similarity index 74% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/planner/AggPlanner.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/planner/AggPlanner.java index a9353887d..e4eb17197 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/planner/AggPlanner.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/planner/AggPlanner.java @@ -1,17 +1,17 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.planner; +package com.tencent.supersonic.semantic.query.parser.calcite.planner; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.Renderer; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.TableView; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.DataSourceNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SchemaBuilder; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.SemanticNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.render.FilterRender; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.render.OutputRender; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.render.SourceRender; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.Renderer; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.TableView; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.DataSourceNode; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SchemaBuilder; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.SemanticNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.render.FilterRender; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.render.OutputRender; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.render.SourceRender; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/planner/Planner.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/planner/Planner.java similarity index 75% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/planner/Planner.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/planner/Planner.java index 3310470dd..353e7bcda 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/planner/Planner.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/planner/Planner.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.planner; +package com.tencent.supersonic.semantic.query.parser.calcite.planner; import com.tencent.supersonic.semantic.api.query.request.MetricReq; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/DataSourceTable.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/DataSourceTable.java similarity index 98% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/DataSourceTable.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/DataSourceTable.java index de6fff0ad..26f22f37a 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/DataSourceTable.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/DataSourceTable.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.schema; +package com.tencent.supersonic.semantic.query.parser.calcite.schema; import java.util.ArrayList; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SchemaBuilder.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SchemaBuilder.java similarity index 82% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SchemaBuilder.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SchemaBuilder.java index 3094c763e..f40c2c988 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SchemaBuilder.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SchemaBuilder.java @@ -1,8 +1,8 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.schema; +package com.tencent.supersonic.semantic.query.parser.calcite.schema; -import com.tencent.supersonic.semantic.query.application.parser.calcite.Configuration; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.DSLSqlValidatorImpl; +import com.tencent.supersonic.semantic.query.parser.calcite.Configuration; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.DSLSqlValidatorImpl; import java.util.Collections; import java.util.HashMap; import java.util.Map; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticItem.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticItem.java new file mode 100644 index 000000000..887600da3 --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticItem.java @@ -0,0 +1,6 @@ +package com.tencent.supersonic.semantic.query.parser.calcite.schema; + +public interface SemanticItem { + + public String getName(); +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSchema.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSchema.java similarity index 85% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSchema.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSchema.java index 4649967d6..74eb7c683 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSchema.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSchema.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.schema; +package com.tencent.supersonic.semantic.query.parser.calcite.schema; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Dimension; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Metric; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.SemanticModel; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Dimension; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Metric; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.SemanticModel; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSqlConformance.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSqlConformance.java similarity index 97% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSqlConformance.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSqlConformance.java index a12ce7408..9c557c566 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSqlConformance.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSqlConformance.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.schema; +package com.tencent.supersonic.semantic.query.parser.calcite.schema; import org.apache.calcite.sql.fun.SqlLibrary; import org.apache.calcite.sql.validate.SqlConformance; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSqlDialect.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSqlDialect.java similarity index 90% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSqlDialect.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSqlDialect.java index af70ea537..979cda2d7 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/schema/SemanticSqlDialect.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/schema/SemanticSqlDialect.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.schema; +package com.tencent.supersonic.semantic.query.parser.calcite.schema; import com.google.common.base.Preconditions; import org.apache.calcite.avatica.util.Casing; @@ -35,16 +35,11 @@ public class SemanticSqlDialect extends SqlDialect { fetchFrame = writer.startList(SqlWriter.FrameTypeEnum.OFFSET); writer.keyword("LIMIT"); if (offset != null) { - //writer.keyword("OFFSET"); offset.unparse(writer, -1, -1); - //writer.keyword("ROWS"); } if (fetch != null) { - //writer.newlineAndIndent(); - //fetchFrame = writer.startList(SqlWriter.FrameTypeEnum.FETCH); writer.keyword(","); - //writer.keyword("NEXT"); fetch.unparse(writer, -1, -1); } @@ -92,4 +87,4 @@ public class SemanticSqlDialect extends SqlDialect { public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, @Nullable SqlNode fetch) { unparseFetchUsingAnsi(writer, offset, fetch); } -} \ No newline at end of file +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/DSLSqlValidatorImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/DSLSqlValidatorImpl.java similarity index 86% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/DSLSqlValidatorImpl.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/DSLSqlValidatorImpl.java index 91af8f280..d3a07d9be 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/DSLSqlValidatorImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/DSLSqlValidatorImpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql; +package com.tencent.supersonic.semantic.query.parser.calcite.sql; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.sql.SqlOperatorTable; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Optimization.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Optimization.java new file mode 100644 index 000000000..bd5602f33 --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Optimization.java @@ -0,0 +1,9 @@ +package com.tencent.supersonic.semantic.query.parser.calcite.sql; + + +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.SemanticNode; + +public interface Optimization { + + public void visit(SemanticNode semanticNode); +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/Renderer.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Renderer.java similarity index 83% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/Renderer.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Renderer.java index 4327d575e..f699e02bd 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/Renderer.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Renderer.java @@ -1,16 +1,16 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql; +package com.tencent.supersonic.semantic.query.parser.calcite.sql; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.MeasureNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.MetricNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.SemanticNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Dimension; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Identify; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Measure; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Metric; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.MeasureNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.MetricNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.SemanticNode; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Dimension; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Identify; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Measure; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Metric; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; import java.util.HashSet; import java.util.List; import java.util.Optional; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/TableView.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/TableView.java similarity index 95% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/TableView.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/TableView.java index 34a64d816..db6893612 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/TableView.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/TableView.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql; +package com.tencent.supersonic.semantic.query.parser.calcite.sql; import java.util.ArrayList; import java.util.List; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/AggFunctionNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/AggFunctionNode.java similarity index 88% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/AggFunctionNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/AggFunctionNode.java index a69425712..b1eda105d 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/AggFunctionNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/AggFunctionNode.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.validate.SqlValidatorScope; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/DataSourceNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DataSourceNode.java similarity index 83% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/DataSourceNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DataSourceNode.java index 50447310e..054f518eb 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/DataSourceNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DataSourceNode.java @@ -1,18 +1,19 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.query.application.parser.calcite.Configuration; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Constants; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Dimension; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.parser.calcite.Configuration; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Constants; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Dimension; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -20,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.validate.SqlValidatorScope; +import org.springframework.util.CollectionUtils; @Slf4j public class DataSourceNode extends SemanticNode { @@ -59,6 +61,24 @@ public class DataSourceNode extends SemanticNode { metricCommand.getMetrics().stream().filter(m -> !schemaMetricName.contains(m)).forEach(m -> measures.add(m)); } + public static void mergeQueryFilterDimensionMeasure(SemanticSchema schema, MetricReq metricCommand, + Set queryDimension, List measures,SqlValidatorScope scope) throws Exception { + if(Objects.nonNull(metricCommand.getWhere()) && !metricCommand.getWhere().isEmpty()) { + Set filterConditions = new HashSet<>(); + FilterNode.getFilterField(parse(metricCommand.getWhere(), scope), filterConditions); + Set queryMeasures = new HashSet<>(measures); + Set schemaMetricName = schema.getMetrics().stream().map(m -> m.getName()).collect(Collectors.toSet()); + for(String filterCondition : filterConditions) { + if(schemaMetricName.contains(filterCondition)) { + schema.getMetrics().stream().filter(m->m.getName().equalsIgnoreCase(filterCondition)).forEach(m -> m.getMetricTypeParams().getMeasures().stream().forEach(mm -> queryMeasures.add(mm.getName()))); + continue; + } + queryDimension.add(filterCondition); + } + measures.clear(); + measures.addAll(queryMeasures); + } + } public static List getMatchDataSources(SqlValidatorScope scope, SemanticSchema schema, MetricReq metricCommand) throws Exception { @@ -98,6 +118,7 @@ public class DataSourceNode extends SemanticNode { } filterMeasure.addAll(sourceMeasure); filterMeasure.addAll(dimension); + mergeQueryFilterDimensionMeasure(schema,metricCommand,queryDimension,measures,scope); boolean isAllMatch = checkMatch(sourceMeasure, queryDimension, measures, dimension, metricCommand, scope); if (isAllMatch) { log.info("baseDataSource match all "); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/DimensionNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DimensionNode.java similarity index 87% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/DimensionNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DimensionNode.java index 578769de6..394e56e35 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/DimensionNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DimensionNode.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Dimension; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Dimension; import java.util.List; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.validate.SqlValidatorScope; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/FilterNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/FilterNode.java similarity index 91% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/FilterNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/FilterNode.java index c923868c9..12709dceb 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/FilterNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/FilterNode.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; import java.util.Set; import org.apache.calcite.sql.SqlBasicCall; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/IdentifyNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/IdentifyNode.java similarity index 64% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/IdentifyNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/IdentifyNode.java index 762d81ea5..796edb35a 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/IdentifyNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/IdentifyNode.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Identify; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Identify; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.validate.SqlValidatorScope; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/JoinNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/JoinNode.java similarity index 72% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/JoinNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/JoinNode.java index 078f9dc4b..0dddc1de7 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/JoinNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/JoinNode.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; import lombok.Data; import org.apache.calcite.sql.SqlNode; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/MeasureNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/MeasureNode.java similarity index 92% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/MeasureNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/MeasureNode.java index d6a3072c0..777df9321 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/MeasureNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/MeasureNode.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Measure; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Measure; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.validate.SqlValidatorScope; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/MetricNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/MetricNode.java similarity index 85% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/MetricNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/MetricNode.java index 2265e01b7..081f35048 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/MetricNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/MetricNode.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Metric; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Metric; import java.util.HashMap; import java.util.Map; import lombok.Data; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/SemanticNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/SemanticNode.java similarity index 92% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/SemanticNode.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/SemanticNode.java index e57f84787..b143816cc 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/node/SemanticNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/SemanticNode.java @@ -1,9 +1,9 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.node; -import com.tencent.supersonic.semantic.query.application.parser.calcite.Configuration; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.Optimization; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSqlDialect; +import com.tencent.supersonic.semantic.query.parser.calcite.Configuration; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.Optimization; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSqlDialect; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/FilterRender.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/FilterRender.java similarity index 74% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/FilterRender.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/FilterRender.java index 579716aeb..ea34771f7 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/FilterRender.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/FilterRender.java @@ -1,16 +1,16 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.render; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.render; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.Renderer; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.FilterNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.MetricNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.TableView; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Constants; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Metric; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.SemanticNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.Renderer; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.FilterNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.MetricNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.TableView; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Constants; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Metric; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.SemanticNode; import java.util.ArrayList; import java.util.HashSet; import java.util.List; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/JoinRender.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/JoinRender.java similarity index 89% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/JoinRender.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/JoinRender.java index 8f12f1197..675a93f57 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/JoinRender.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/JoinRender.java @@ -1,19 +1,19 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.render; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.render; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.Renderer; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.AggFunctionNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.DataSourceNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.FilterNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.MetricNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.TableView; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Constants; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Dimension; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Identify; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Metric; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.SemanticNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.Renderer; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.AggFunctionNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.DataSourceNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.FilterNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.MetricNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.TableView; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Constants; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Dimension; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Identify; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Metric; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.SemanticNode; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -101,10 +101,7 @@ public class JoinRender extends Renderer { left = SemanticNode.buildAs(tableView.getAlias(), getTable(tableView, scope)); continue; } - if (!left.getKind().equals(SqlKind.AS)) { - left = SemanticNode.buildAs(Constants.JOIN_TABLE_LEFT_PREFIX + tableView.getAlias(), - getTable(tableView, scope)); - } + left = new SqlJoin( SqlParserPos.ZERO, left, diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/OutputRender.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/OutputRender.java similarity index 78% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/OutputRender.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/OutputRender.java index 8b7edc48f..bc1562cf4 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/OutputRender.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/OutputRender.java @@ -1,13 +1,13 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.render; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.render; import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.common.pojo.ColumnOrder; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.Renderer; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.TableView; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.SemanticNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.Renderer; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.TableView; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.SemanticNode; import java.util.ArrayList; import java.util.List; import org.apache.calcite.sql.SqlNode; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/SourceRender.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/SourceRender.java similarity index 89% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/SourceRender.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/SourceRender.java index b6ab13cdd..ae6d087d0 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/calcite/sql/render/SourceRender.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/render/SourceRender.java @@ -1,24 +1,23 @@ -package com.tencent.supersonic.semantic.query.application.parser.calcite.sql.render; +package com.tencent.supersonic.semantic.query.parser.calcite.sql.render; import com.tencent.supersonic.semantic.api.query.request.MetricReq; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.Renderer; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.DataSourceNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.DimensionNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.FilterNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.MetricNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.TableView; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Constants; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.DataSource; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Dimension; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Identify; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Measure; -import com.tencent.supersonic.semantic.query.application.parser.calcite.dsl.Metric; -import com.tencent.supersonic.semantic.query.application.parser.calcite.schema.SemanticSchema; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.IdentifyNode; -import com.tencent.supersonic.semantic.query.application.parser.calcite.sql.node.SemanticNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.Renderer; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.DataSourceNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.DimensionNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.FilterNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.MetricNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.TableView; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Constants; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.DataSource; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Dimension; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Identify; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Measure; +import com.tencent.supersonic.semantic.query.parser.calcite.dsl.Metric; +import com.tencent.supersonic.semantic.query.parser.calcite.schema.SemanticSchema; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.IdentifyNode; +import com.tencent.supersonic.semantic.query.parser.calcite.sql.node.SemanticNode; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -252,8 +251,12 @@ public class SourceRender extends Renderer { Optional datasourceMetric = schema.getMetrics() .stream().filter(m -> m.getName().equalsIgnoreCase(field)).findFirst(); if (datasourceMetric.isPresent()) { - metrics.add(oriField); - return; + Set measures = datasourceMetric.get().getMetricTypeParams().getMeasures().stream().map(m->m.getName()).collect( + Collectors.toSet()); + if(datasource.getMeasures().stream().map(m->m.getName()).collect(Collectors.toSet()).containsAll(measures)){ + metrics.add(oriField); + return; + } } } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/CalculateAggConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/CalculateAggConverter.java new file mode 100644 index 000000000..758ff94b7 --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/CalculateAggConverter.java @@ -0,0 +1,478 @@ +package com.tencent.supersonic.semantic.query.parser.convert; + + +import com.tencent.supersonic.common.pojo.Aggregator; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.query.pojo.MetricTable; +import com.tencent.supersonic.semantic.api.query.request.MetricReq; +import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.model.domain.pojo.EngineTypeEnum; +import com.tencent.supersonic.semantic.query.parser.SemanticConverter; +import com.tencent.supersonic.semantic.query.service.SemanticQueryEngine; +import com.tencent.supersonic.semantic.query.utils.DateUtils; +import com.tencent.supersonic.semantic.query.utils.QueryStructUtils; +import com.tencent.supersonic.semantic.query.utils.SqlGenerateUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + + +@Component("CalculateAggConverter") +@Slf4j +public class CalculateAggConverter implements SemanticConverter { + + + private final SemanticQueryEngine parserService; + private final QueryStructUtils queryStructUtils; + private final SqlGenerateUtils sqlGenerateUtils; + private final Catalog catalog; + + @Value("${metricParser.agg.default:sum}") + private String metricAggDefault; + + @Value("${metricParser.agg.mysql.lowVersion:5.7}") + private String mysqlLowVersion; + + + public CalculateAggConverter( + SemanticQueryEngine parserService, + @Lazy QueryStructUtils queryStructUtils, + SqlGenerateUtils sqlGenerateUtils, Catalog catalog) { + this.parserService = parserService; + this.queryStructUtils = queryStructUtils; + this.sqlGenerateUtils = sqlGenerateUtils; + this.catalog = catalog; + } + + public interface EngineSql { + + String sql(QueryStructReq queryStructCmd, boolean isOver, String metricSql); + } + + public ParseSqlReq generateSqlCommend(QueryStructReq queryStructCmd, EngineTypeEnum engineTypeEnum, String version) + throws Exception { + // 同环比 + if (isRatioAccept(queryStructCmd)) { + return generateRatioSqlCommand(queryStructCmd, engineTypeEnum, version); + } + ParseSqlReq sqlCommand = new ParseSqlReq(); + sqlCommand.setRootPath(catalog.getDomainFullPath(queryStructCmd.getDomainId())); + String metricTableName = "v_metric_tb_tmp"; + MetricTable metricTable = new MetricTable(); + metricTable.setAlias(metricTableName); + metricTable.setMetrics(queryStructCmd.getMetrics()); + metricTable.setDimensions(queryStructCmd.getGroups()); + String where = queryStructUtils.generateWhere(queryStructCmd); + log.info("in generateSqlCommand, complete where:{}", where); + metricTable.setWhere(where); + metricTable.setAgg(true); + sqlCommand.setTables(new ArrayList<>(Collections.singletonList(metricTable))); + String sql = String.format("select %s from %s %s %s %s", sqlGenerateUtils.getSelect(queryStructCmd), + metricTableName, + sqlGenerateUtils.getGroupBy(queryStructCmd), sqlGenerateUtils.getOrderBy(queryStructCmd), + sqlGenerateUtils.getLimit(queryStructCmd)); + if (engineTypeEnum.equals(engineTypeEnum.MYSQL) && Objects.nonNull(version) && version.startsWith( + mysqlLowVersion)) { + sqlCommand.setSupportWith(false); + sql = String.format("select %s from %s t0 %s %s %s", sqlGenerateUtils.getSelect(queryStructCmd), + metricTableName, + sqlGenerateUtils.getGroupBy(queryStructCmd), sqlGenerateUtils.getOrderBy(queryStructCmd), + sqlGenerateUtils.getLimit(queryStructCmd)); + } + sqlCommand.setSql(sql); + return sqlCommand; + } + + + @Override + public boolean accept(QueryStructReq queryStructCmd) { + if (queryStructCmd.getNativeQuery()) { + return false; + } + if (CollectionUtils.isEmpty(queryStructCmd.getAggregators())) { + return false; + } + //todo ck类型暂不拼with语句 + if (queryStructCmd.getDomainId().equals(34L)) { + return false; + } + int nonSumFunction = 0; + for (Aggregator agg : queryStructCmd.getAggregators()) { + if (agg.getFunc() == null || "".equals(agg.getFunc())) { + return false; + } + if (agg.getFunc().equals(AggOperatorEnum.UNKNOWN)) { + return false; + } + if (agg.getFunc() != null + // && !agg.getFunc().equalsIgnoreCase(MetricAggDefault) + ) { + nonSumFunction++; + } + } + return nonSumFunction > 0; + } + + @Override + public void converter(Catalog catalog, QueryStructReq queryStructCmd, ParseSqlReq sqlCommend, + MetricReq metricCommand) throws Exception { + DatabaseResp databaseResp = catalog.getDatabaseByDomainId(queryStructCmd.getDomainId()); + ParseSqlReq parseSqlReq = generateSqlCommend(queryStructCmd, + EngineTypeEnum.valueOf(databaseResp.getType().toUpperCase()), databaseResp.getVersion()); + sqlCommend.setSql(parseSqlReq.getSql()); + sqlCommend.setTables(parseSqlReq.getTables()); + sqlCommend.setRootPath(parseSqlReq.getRootPath()); + sqlCommend.setVariables(parseSqlReq.getVariables()); + sqlCommend.setSupportWith(parseSqlReq.isSupportWith()); + } + + + /** + * Ratio + */ + + public boolean isRatioAccept(QueryStructReq queryStructCmd) { + Long ratioFuncNum = queryStructCmd.getAggregators().stream() + .filter(f -> (f.getFunc().equals(AggOperatorEnum.RATIO_ROLL) || f.getFunc() + .equals(AggOperatorEnum.RATIO_OVER))).count(); + if (ratioFuncNum > 0) { + return true; + } + return false; + } + + public ParseSqlReq generateRatioSqlCommand(QueryStructReq queryStructCmd, EngineTypeEnum engineTypeEnum, + String version) + throws Exception { + check(queryStructCmd); + ParseSqlReq sqlCommand = new ParseSqlReq(); + sqlCommand.setRootPath(catalog.getDomainFullPath(queryStructCmd.getDomainId())); + String metricTableName = "v_metric_tb_tmp"; + MetricTable metricTable = new MetricTable(); + metricTable.setAlias(metricTableName); + metricTable.setMetrics(queryStructCmd.getMetrics()); + metricTable.setDimensions(queryStructCmd.getGroups()); + String where = queryStructUtils.generateWhere(queryStructCmd); + log.info("in generateSqlCommend, complete where:{}", where); + metricTable.setWhere(where); + metricTable.setAgg(true); + sqlCommand.setTables(new ArrayList<>(Collections.singletonList(metricTable))); + boolean isOver = isOverRatio(queryStructCmd); + String sql = ""; + switch (engineTypeEnum) { + case H2: + sql = new H2EngineSql().sql(queryStructCmd, isOver, metricTableName); + break; + case MYSQL: + if (Objects.nonNull(version) && version.startsWith(mysqlLowVersion)) { + sqlCommand.setSupportWith(false); + sql = new MysqlEngineSql().sql(queryStructCmd, isOver, metricTableName); + break; + } + case DORIS: + case CLICKHOUSE: + sql = new CkEngineSql().sql(queryStructCmd, isOver, metricTableName); + break; + } + sqlCommand.setSql(sql); + return sqlCommand; + } + + public class H2EngineSql implements EngineSql { + + public String getOverSelect(QueryStructReq queryStructCmd, boolean isOver) { + String aggStr = queryStructCmd.getAggregators().stream().map(f -> { + if (f.getFunc().equals(AggOperatorEnum.RATIO_OVER) || f.getFunc().equals(AggOperatorEnum.RATIO_ROLL)) { + return String.format("( (%s-%s_roll)/cast(%s_roll as DOUBLE) ) as %s", + f.getColumn(), f.getColumn(), f.getColumn(), f.getColumn(), + f.getColumn()); + } else { + return f.getColumn(); + } + }).collect(Collectors.joining(",")); + return CollectionUtils.isEmpty(queryStructCmd.getGroups()) ? aggStr + : String.join(",", queryStructCmd.getGroups()) + "," + aggStr; + } + + public String getTimeSpan(QueryStructReq queryStructCmd, boolean isOver, boolean isAdd) { + if (Objects.nonNull(queryStructCmd.getDateInfo())) { + String addStr = isAdd ? "" : "-"; + if (queryStructCmd.getDateInfo().getPeriod().equalsIgnoreCase(Constants.DAY)) { + return "day," + (isOver ? addStr + "7" : addStr + "1"); + } + if (queryStructCmd.getDateInfo().getPeriod().equalsIgnoreCase(Constants.WEEK)) { + return isOver ? "month," + addStr + "1" : "day," + addStr + "7"; + } + if (queryStructCmd.getDateInfo().getPeriod().equalsIgnoreCase(Constants.MONTH)) { + return isOver ? "year," + addStr + "1" : "month," + addStr + "1"; + } + } + return ""; + } + + public String getJoinOn(QueryStructReq queryStructCmd, boolean isOver, String aliasLeft, String aliasRight) { + String timeDim = getTimeDim(queryStructCmd); + String timeSpan = getTimeSpan(queryStructCmd, isOver, true); + String aggStr = queryStructCmd.getAggregators().stream().map(f -> { + if (f.getFunc().equals(AggOperatorEnum.RATIO_OVER) || f.getFunc().equals(AggOperatorEnum.RATIO_ROLL)) { + if (queryStructCmd.getDateInfo().getPeriod().equals(Constants.MONTH)) { + return String.format( + "%s is not null and %s = FORMATDATETIME(DATEADD(%s,CONCAT(%s,'-01')),'yyyy-MM') ", + aliasRight + timeDim, aliasLeft + timeDim, timeSpan, aliasRight + timeDim); + } + if (queryStructCmd.getDateInfo().getPeriod().equals(Constants.WEEK) && isOver) { + return String.format(" DATE_TRUNC('week',DATEADD(%s,%s) ) = %s ", + getTimeSpan(queryStructCmd, isOver, false), aliasLeft + timeDim, aliasRight + timeDim); + } + return String.format("%s = TIMESTAMPADD(%s,%s) ", + aliasLeft + timeDim, timeSpan, aliasRight + timeDim); + } else { + return f.getColumn(); + } + }).collect(Collectors.joining(" and ")); + List groups = new ArrayList<>(); + for (String group : queryStructCmd.getGroups()) { + if (group.equalsIgnoreCase(timeDim)) { + continue; + } + groups.add(aliasLeft + group + " = " + aliasRight + group); + } + return CollectionUtils.isEmpty(groups) ? aggStr + : String.join(" and ", groups) + " and " + aggStr + " "; + } + + @Override + public String sql(QueryStructReq queryStructCmd, boolean isOver, String metricSql) { + String sql = String.format( + "select %s from ( select %s , %s from %s t0 left join %s t1 on %s ) metric_tb_src %s %s ", + getOverSelect(queryStructCmd, isOver), getAllSelect(queryStructCmd, "t0."), + getAllJoinSelect(queryStructCmd, "t1."), metricSql, metricSql, + getJoinOn(queryStructCmd, isOver, "t0.", "t1."), + getOrderBy(queryStructCmd), getLimit(queryStructCmd)); + return sql; + } + } + + public class CkEngineSql extends MysqlEngineSql { + + public String getJoinOn(QueryStructReq queryStructCmd, boolean isOver, String aliasLeft, String aliasRight) { + String timeDim = getTimeDim(queryStructCmd); + String timeSpan = "INTERVAL " + getTimeSpan(queryStructCmd, isOver, true); + String aggStr = queryStructCmd.getAggregators().stream().map(f -> { + if (f.getFunc().equals(AggOperatorEnum.RATIO_OVER) || f.getFunc().equals(AggOperatorEnum.RATIO_ROLL)) { + if (queryStructCmd.getDateInfo().getPeriod().equals(Constants.MONTH)) { + return String.format("toDate(CONCAT(%s,'-01')) = date_add(toDate(CONCAT(%s','-01')),%s) ", + aliasLeft + timeDim, aliasRight + timeDim, timeSpan); + } + if (queryStructCmd.getDateInfo().getPeriod().equals(Constants.WEEK) && isOver) { + return String.format("toMonday(date_add(%s ,INTERVAL %s) ) = %s", + aliasLeft + timeDim, getTimeSpan(queryStructCmd, isOver, false), aliasRight + timeDim); + } + return String.format("%s = date_add(%s,%s) ", + aliasLeft + timeDim, aliasRight + timeDim, timeSpan); + } else { + return f.getColumn(); + } + }).collect(Collectors.joining(" and ")); + List groups = new ArrayList<>(); + for (String group : queryStructCmd.getGroups()) { + if (group.equalsIgnoreCase(timeDim)) { + continue; + } + groups.add(aliasLeft + group + " = " + aliasRight + group); + } + return CollectionUtils.isEmpty(groups) ? aggStr + : String.join(" and ", groups) + " and " + aggStr + " "; + } + + @Override + public String sql(QueryStructReq queryStructCmd, boolean isOver, String metricSql) { + String sql = String.format( + ",t0 as (select * from %s),t1 as (select * from %s) select %s from ( select %s , %s from t0 left join t1 on %s ) metric_tb_src %s %s ", + metricSql, metricSql, getOverSelect(queryStructCmd, isOver), getAllSelect(queryStructCmd, "t0."), + getAllJoinSelect(queryStructCmd, "t1."), + getJoinOn(queryStructCmd, isOver, "t0.", "t1."), + getOrderBy(queryStructCmd), getLimit(queryStructCmd)); + return sql; + } + } + + public class MysqlEngineSql implements EngineSql { + + public String getTimeSpan(QueryStructReq queryStructCmd, boolean isOver, boolean isAdd) { + if (Objects.nonNull(queryStructCmd.getDateInfo())) { + String addStr = isAdd ? "" : "-"; + if (queryStructCmd.getDateInfo().getPeriod().equalsIgnoreCase(Constants.DAY)) { + return isOver ? addStr + "7 day" : addStr + "1 day"; + } + if (queryStructCmd.getDateInfo().getPeriod().equalsIgnoreCase(Constants.WEEK)) { + return isOver ? addStr + "1 month" : addStr + "7 day"; + } + if (queryStructCmd.getDateInfo().getPeriod().equalsIgnoreCase(Constants.MONTH)) { + return isOver ? addStr + "1 year" : addStr + "1 month"; + } + } + return ""; + } + + public String getOverSelect(QueryStructReq queryStructCmd, boolean isOver) { + String timeDim = getTimeDim(queryStructCmd); + String timeSpan = "INTERVAL " + getTimeSpan(queryStructCmd, isOver, true); + String aggStr = queryStructCmd.getAggregators().stream().map(f -> { + if (f.getFunc().equals(AggOperatorEnum.RATIO_OVER) || f.getFunc().equals(AggOperatorEnum.RATIO_ROLL)) { + return String.format( + "if(%s_roll!=0, (%s-%s_roll)/%s_roll , 0) as %s", + f.getColumn(), f.getColumn(), f.getColumn(), f.getColumn(), + f.getColumn()); + } else { + return f.getColumn(); + } + }).collect(Collectors.joining(",")); + return CollectionUtils.isEmpty(queryStructCmd.getGroups()) ? aggStr + : String.join(",", queryStructCmd.getGroups()) + "," + aggStr; + } + + public String getJoinOn(QueryStructReq queryStructCmd, boolean isOver, String aliasLeft, String aliasRight) { + String timeDim = getTimeDim(queryStructCmd); + String timeSpan = "INTERVAL " + getTimeSpan(queryStructCmd, isOver, true); + String aggStr = queryStructCmd.getAggregators().stream().map(f -> { + if (f.getFunc().equals(AggOperatorEnum.RATIO_OVER) || f.getFunc().equals(AggOperatorEnum.RATIO_ROLL)) { + if (queryStructCmd.getDateInfo().getPeriod().equals(Constants.MONTH)) { + return String.format("%s = DATE_FORMAT(date_add(CONCAT(%s,'-01'), %s),'%Y-%m') ", + aliasLeft + timeDim, aliasRight + timeDim, timeSpan); + } + if (queryStructCmd.getDateInfo().getPeriod().equals(Constants.WEEK) && isOver) { + return String.format("to_monday(date_add(%s ,INTERVAL %s) ) = %s", + aliasLeft + timeDim, getTimeSpan(queryStructCmd, isOver, false), aliasRight + timeDim); + } + return String.format("%s = date_add(%s,%s) ", + aliasLeft + timeDim, aliasRight + timeDim, timeSpan); + } else { + return f.getColumn(); + } + }).collect(Collectors.joining(" and ")); + List groups = new ArrayList<>(); + for (String group : queryStructCmd.getGroups()) { + if (group.equalsIgnoreCase(timeDim)) { + continue; + } + groups.add(aliasLeft + group + " = " + aliasRight + group); + } + return CollectionUtils.isEmpty(groups) ? aggStr + : String.join(" and ", groups) + " and " + aggStr + " "; + } + + @Override + public String sql(QueryStructReq queryStructCmd, boolean isOver, String metricSql) { + String sql = String.format( + "select %s from ( select %s , %s from %s t0 left join %s t1 on %s ) metric_tb_src %s %s ", + getOverSelect(queryStructCmd, isOver), getAllSelect(queryStructCmd, "t0."), + getAllJoinSelect(queryStructCmd, "t1."), metricSql, metricSql, + getJoinOn(queryStructCmd, isOver, "t0.", "t1."), + getOrderBy(queryStructCmd), getLimit(queryStructCmd)); + return sql; + } + } + + + private static String getAllJoinSelect(QueryStructReq queryStructCmd, String alias) { + String aggStr = queryStructCmd.getAggregators().stream() + .map(f -> getSelectField(f, alias) + " as " + getSelectField(f, "") + + "_roll") + .collect(Collectors.joining(",")); + List groups = new ArrayList<>(); + for (String group : queryStructCmd.getGroups()) { + groups.add(alias + group + " as " + group + "_roll"); + } + return CollectionUtils.isEmpty(groups) ? aggStr + : String.join(",", groups) + "," + aggStr; + + } + + + private String getGroupDimWithOutTime(QueryStructReq queryStructCmd) { + String timeDim = getTimeDim(queryStructCmd); + return queryStructCmd.getGroups().stream().filter(f -> !f.equalsIgnoreCase(timeDim)) + .collect(Collectors.joining(",")); + } + + private static String getTimeDim(QueryStructReq queryStructCmd) { + DateUtils dateUtils = ContextUtils.getContext().getBean(DateUtils.class); + return dateUtils.getSysDateCol(queryStructCmd.getDateInfo()); + } + + private static String getLimit(QueryStructReq queryStructCmd) { + if (queryStructCmd.getLimit() > 0) { + return " limit " + String.valueOf(queryStructCmd.getLimit()); + } + return ""; + } + + + private static String getAllSelect(QueryStructReq queryStructCmd, String alias) { + String aggStr = queryStructCmd.getAggregators().stream().map(f -> getSelectField(f, alias)) + .collect(Collectors.joining(",")); + return CollectionUtils.isEmpty(queryStructCmd.getGroups()) ? aggStr + : alias + String.join("," + alias, queryStructCmd.getGroups()) + "," + aggStr; + } + + private static String getSelectField(final Aggregator agg, String alias) { + if (agg.getFunc().equals(AggOperatorEnum.RATIO_OVER) || agg.getFunc().equals(AggOperatorEnum.RATIO_ROLL)) { + return alias + agg.getColumn(); + } + if (CollectionUtils.isEmpty(agg.getArgs())) { + return agg.getFunc() + "( " + alias + agg.getColumn() + " ) AS " + agg.getColumn() + " "; + } + return agg.getFunc() + "( " + agg.getArgs().stream().map(arg -> + arg.equals(agg.getColumn()) ? arg : (StringUtils.isNumeric(arg) ? arg : ("'" + arg + "'")) + ).collect(Collectors.joining(",")) + " ) AS " + agg.getColumn() + " "; + } + + private String getGroupBy(QueryStructReq queryStructCmd) { + if (CollectionUtils.isEmpty(queryStructCmd.getGroups())) { + return ""; + } + return "group by " + String.join(",", queryStructCmd.getGroups()); + } + + private static String getOrderBy(QueryStructReq queryStructCmd) { + return "order by " + getTimeDim(queryStructCmd) + " desc"; + } + + private boolean isOverRatio(QueryStructReq queryStructCmd) { + Long overCt = queryStructCmd.getAggregators().stream() + .filter(f -> f.getFunc().equals(AggOperatorEnum.RATIO_OVER)).count(); + return overCt > 0; + } + + private void check(QueryStructReq queryStructCmd) throws Exception { + Set aggFunctions = queryStructCmd.getAggregators().stream() + .filter(f -> f.getArgs() != null && f.getArgs().get(0) != null) + .map(agg -> agg.getArgs().get(0).toLowerCase()).collect(Collectors.toSet()); + Long ratioOverNum = queryStructCmd.getAggregators().stream() + .filter(f -> f.getFunc().equals(AggOperatorEnum.RATIO_OVER)).count(); + Long ratioRollNum = queryStructCmd.getAggregators().stream() + .filter(f -> f.getFunc().equals(AggOperatorEnum.RATIO_ROLL)).count(); + if (ratioOverNum > 0 && ratioRollNum > 0) { + throw new Exception("not support over ratio and roll ratio together "); + } + if (getTimeDim(queryStructCmd).isEmpty()) { + throw new Exception("miss time filter"); + } + + } +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/DefaultDimValueConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/DefaultDimValueConverter.java similarity index 88% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/DefaultDimValueConverter.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/DefaultDimValueConverter.java index 530ea6079..d035a0a0a 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/DefaultDimValueConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/DefaultDimValueConverter.java @@ -1,13 +1,13 @@ -package com.tencent.supersonic.semantic.query.application.parser.convert; +package com.tencent.supersonic.semantic.query.parser.convert; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import com.tencent.supersonic.semantic.api.query.pojo.Filter; import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.application.parser.SemanticConverter; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.parser.SemanticConverter; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/MultiSourceJoin.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/MultiSourceJoin.java similarity index 89% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/MultiSourceJoin.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/MultiSourceJoin.java index 023988369..8d8f9225a 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/MultiSourceJoin.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/MultiSourceJoin.java @@ -1,21 +1,19 @@ -package com.tencent.supersonic.semantic.query.application.parser.convert; +package com.tencent.supersonic.semantic.query.parser.convert; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.tencent.supersonic.common.pojo.Aggregator; -import com.tencent.supersonic.semantic.api.core.pojo.Identify; -import com.tencent.supersonic.semantic.api.core.pojo.Measure; -import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; +import com.tencent.supersonic.semantic.api.model.pojo.Identify; +import com.tencent.supersonic.semantic.api.model.pojo.Measure; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; import com.tencent.supersonic.semantic.api.query.pojo.Filter; import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.application.parser.SemanticConverter; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.parser.SemanticConverter; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/ParserDefaultConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/ParserDefaultConverter.java similarity index 87% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/ParserDefaultConverter.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/ParserDefaultConverter.java index c6e3b3aca..2fa035396 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/convert/ParserDefaultConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/ParserDefaultConverter.java @@ -1,16 +1,16 @@ -package com.tencent.supersonic.semantic.query.application.parser.convert; +package com.tencent.supersonic.semantic.query.parser.convert; -import static com.tencent.supersonic.common.constant.Constants.UNDERLINE; +import static com.tencent.supersonic.common.pojo.Constants.UNDERLINE; import com.tencent.supersonic.common.pojo.ColumnOrder; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; import com.tencent.supersonic.semantic.api.query.pojo.Param; import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.application.parser.SemanticConverter; -import com.tencent.supersonic.semantic.query.domain.utils.QueryStructUtils; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.parser.SemanticConverter; +import com.tencent.supersonic.semantic.query.utils.QueryStructUtils; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; @@ -26,11 +26,11 @@ public class ParserDefaultConverter implements SemanticConverter { @Value("${internal.metric.cnt.suffix:internal_cnt}") private String internalMetricNameSuffix; - private final CalculateConverterAgg calculateCoverterAgg; + private final CalculateAggConverter calculateCoverterAgg; private final QueryStructUtils queryStructUtils; public ParserDefaultConverter( - CalculateConverterAgg calculateCoverterAgg, + CalculateAggConverter calculateCoverterAgg, QueryStructUtils queryStructUtils) { this.calculateCoverterAgg = calculateCoverterAgg; this.queryStructUtils = queryStructUtils; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/infrastructure/mapper/StatMapper.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/mapper/StatMapper.java similarity index 68% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/infrastructure/mapper/StatMapper.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/mapper/StatMapper.java index db0e3c5d8..e7507e8a0 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/infrastructure/mapper/StatMapper.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/mapper/StatMapper.java @@ -1,7 +1,7 @@ -package com.tencent.supersonic.semantic.query.infrastructure.mapper; +package com.tencent.supersonic.semantic.query.persistence.mapper; -import com.tencent.supersonic.semantic.api.core.pojo.QueryStat; +import com.tencent.supersonic.semantic.api.model.pojo.QueryStat; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import java.util.List; import org.apache.ibatis.annotations.Mapper; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/ParserSvrResponse.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/pojo/ParserSvrResponse.java similarity index 88% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/ParserSvrResponse.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/pojo/ParserSvrResponse.java index 70ba1ca3a..c9c3f4385 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/ParserSvrResponse.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/pojo/ParserSvrResponse.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.domain.pojo; +package com.tencent.supersonic.semantic.query.persistence.pojo; public class ParserSvrResponse { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/QueryStatement.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/pojo/QueryStatement.java similarity index 76% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/QueryStatement.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/pojo/QueryStatement.java index 9521839f7..e7e971cb9 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/QueryStatement.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/pojo/QueryStatement.java @@ -1,6 +1,5 @@ -package com.tencent.supersonic.semantic.query.domain.pojo; +package com.tencent.supersonic.semantic.query.persistence.pojo; -import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; import lombok.Data; @Data diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/repository/StatRepository.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/repository/StatRepository.java similarity index 74% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/repository/StatRepository.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/repository/StatRepository.java index 363b55426..00ff644c7 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/repository/StatRepository.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/repository/StatRepository.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.query.domain.repository; +package com.tencent.supersonic.semantic.query.persistence.repository; -import com.tencent.supersonic.semantic.api.core.pojo.QueryStat; +import com.tencent.supersonic.semantic.api.model.pojo.QueryStat; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; import java.util.List; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/infrastructure/repository/StatRepositoryImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/repository/StatRepositoryImpl.java similarity index 89% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/infrastructure/repository/StatRepositoryImpl.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/repository/StatRepositoryImpl.java index c90ccd221..2ea4c7a8c 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/infrastructure/repository/StatRepositoryImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/persistence/repository/StatRepositoryImpl.java @@ -1,15 +1,14 @@ -package com.tencent.supersonic.semantic.query.infrastructure.repository; +package com.tencent.supersonic.semantic.query.persistence.repository; -import static com.tencent.supersonic.common.constant.Constants.AT_SYMBOL; +import static com.tencent.supersonic.common.pojo.Constants.AT_SYMBOL; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.tencent.supersonic.semantic.api.core.pojo.QueryStat; +import com.tencent.supersonic.semantic.api.model.pojo.QueryStat; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; -import com.tencent.supersonic.common.enums.TypeEnums; -import com.tencent.supersonic.semantic.query.domain.repository.StatRepository; -import com.tencent.supersonic.semantic.query.infrastructure.mapper.StatMapper; +import com.tencent.supersonic.common.pojo.enums.TypeEnums; +import com.tencent.supersonic.semantic.query.persistence.mapper.StatMapper; import java.util.ArrayList; import java.util.Comparator; import java.util.List; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/QueryController.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/QueryController.java index f525fe729..cafcb9203 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/QueryController.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/QueryController.java @@ -2,12 +2,12 @@ package com.tencent.supersonic.semantic.query.rest; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; +import com.tencent.supersonic.semantic.api.model.response.SqlParserResp; import com.tencent.supersonic.semantic.api.query.request.*; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; -import com.tencent.supersonic.semantic.query.domain.SemanticQueryEngine; -import com.tencent.supersonic.semantic.query.domain.QueryService; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.query.service.SemanticQueryEngine; +import com.tencent.supersonic.semantic.query.service.QueryService; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -32,11 +32,11 @@ public class QueryController { @PostMapping("/sql") - public Object queryBySql(@RequestBody QuerySqlReq querySqlReq, + public Object queryBySql(@RequestBody QueryDslReq queryDslReq, HttpServletRequest request, HttpServletResponse response) throws Exception { User user = UserHolder.findUser(request, response); - Object queryBySql = queryService.queryBySql(querySqlReq, user); + Object queryBySql = queryService.queryBySql(queryDslReq, user); log.info("queryBySql:{},queryBySql"); return queryBySql; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/SchemaController.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/SchemaController.java index ae6aa5125..3ef7b88ca 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/SchemaController.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/SchemaController.java @@ -3,14 +3,14 @@ package com.tencent.supersonic.semantic.query.rest; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.query.domain.SchemaService; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.query.service.SchemaService; import java.util.List; import javax.servlet.http.HttpServletRequest; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/annotation/DataPermission.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/DataPermission.java similarity index 81% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/annotation/DataPermission.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/DataPermission.java index 40bfa988b..bf99309f8 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/annotation/DataPermission.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/DataPermission.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.semantic.query.domain.annotation; +package com.tencent.supersonic.semantic.query.service; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/QueryService.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryService.java similarity index 74% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/QueryService.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryService.java index 8415d6940..676f2a1f6 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/QueryService.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryService.java @@ -1,11 +1,11 @@ -package com.tencent.supersonic.semantic.query.domain; +package com.tencent.supersonic.semantic.query.service; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.pojo.QueryStat; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.pojo.QueryStat; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; +import com.tencent.supersonic.semantic.api.query.request.QueryDslReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; import java.util.List; @@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest; public interface QueryService { - Object queryBySql(QuerySqlReq querySqlCmd, User user) throws Exception; + Object queryBySql(QueryDslReq querySqlCmd, User user) throws Exception; QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructCmd, User user) throws Exception; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/QueryServiceImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryServiceImpl.java similarity index 79% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/QueryServiceImpl.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryServiceImpl.java index 062448581..0b2601c4b 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/QueryServiceImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryServiceImpl.java @@ -1,28 +1,24 @@ -package com.tencent.supersonic.semantic.query.application; +package com.tencent.supersonic.semantic.query.service; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.common.enums.TaskStatusEnum; +import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; import com.tencent.supersonic.common.util.cache.CacheUtils; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.semantic.api.core.pojo.QueryStat; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.semantic.api.model.pojo.QueryStat; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.pojo.Cache; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; +import com.tencent.supersonic.semantic.api.query.request.QueryDslReq; import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; -import com.tencent.supersonic.semantic.query.application.executor.QueryExecutor; -import com.tencent.supersonic.semantic.query.domain.QueryService; -import com.tencent.supersonic.semantic.query.domain.SchemaService; -import com.tencent.supersonic.semantic.query.domain.SemanticQueryEngine; -import com.tencent.supersonic.semantic.query.domain.annotation.DataPermission; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; -import com.tencent.supersonic.semantic.query.domain.utils.QueryReqConverter; -import com.tencent.supersonic.semantic.query.domain.utils.QueryUtils; -import com.tencent.supersonic.semantic.query.domain.utils.StatUtils; +import com.tencent.supersonic.semantic.query.executor.QueryExecutor; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; +import com.tencent.supersonic.semantic.query.utils.QueryReqConverter; +import com.tencent.supersonic.semantic.query.utils.QueryUtils; +import com.tencent.supersonic.semantic.query.utils.StatUtils; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -62,7 +58,7 @@ public class QueryServiceImpl implements QueryService { } @Override - public Object queryBySql(QuerySqlReq querySqlCmd, User user) throws Exception { + public Object queryBySql(QueryDslReq querySqlCmd, User user) throws Exception { DomainSchemaFilterReq filter = new DomainSchemaFilterReq(); List domainIds = new ArrayList<>(); domainIds.add(querySqlCmd.getDomainId()); @@ -121,38 +117,37 @@ public class QueryServiceImpl implements QueryService { @Override - public QueryResultWithSchemaResp queryByMultiStruct(QueryMultiStructReq queryMultiStructCmd, User user) + public QueryResultWithSchemaResp queryByMultiStruct(QueryMultiStructReq queryMultiStructReq, User user) throws Exception { - statUtils.initStatInfo(queryMultiStructCmd.getQueryStructCmds().get(0), user); + statUtils.initStatInfo(queryMultiStructReq.getQueryStructReqs().get(0), user); String cacheKey = cacheUtils.generateCacheKey( - queryMultiStructCmd.getQueryStructCmds().get(0).getDomainId().toString(), - queryMultiStructCmd.generateCommandMd5()); - boolean isCache = isCache(queryMultiStructCmd); + queryMultiStructReq.getQueryStructReqs().get(0).getDomainId().toString(), + queryMultiStructReq.generateCommandMd5()); + boolean isCache = isCache(queryMultiStructReq); QueryResultWithSchemaResp queryResultWithColumns; if (isCache) { - queryResultWithColumns = queryByCache(cacheKey, queryMultiStructCmd); + queryResultWithColumns = queryByCache(cacheKey, queryMultiStructReq); if (queryResultWithColumns != null) { statUtils.statInfo2DbAsync(TaskStatusEnum.SUCCESS); return queryResultWithColumns; } } - log.info("stat queryByStructWithoutCache, queryMultiStructCmd:{}", queryMultiStructCmd); + log.info("stat queryByStructWithoutCache, queryMultiStructReq:{}", queryMultiStructReq); try { List sqlParsers = new ArrayList<>(); - for (QueryStructReq queryStructCmd : queryMultiStructCmd.getQueryStructCmds()) { + for (QueryStructReq queryStructCmd : queryMultiStructReq.getQueryStructReqs()) { QueryStatement queryStatement = semanticQueryEngine.plan(queryStructCmd); queryUtils.checkSqlParse(queryStatement); sqlParsers.add(queryStatement); } log.info("multi sqlParser:{}", sqlParsers); - QueryStatement sqlParser = queryUtils.sqlParserUnion(queryMultiStructCmd, sqlParsers); + QueryStatement sqlParser = queryUtils.sqlParserUnion(queryMultiStructReq, sqlParsers); queryResultWithColumns = semanticQueryEngine.execute(sqlParser); if (queryResultWithColumns != null) { statUtils.statInfo2DbAsync(TaskStatusEnum.SUCCESS); - queryUtils.fillItemNameInfo(queryResultWithColumns, queryMultiStructCmd); + queryUtils.fillItemNameInfo(queryResultWithColumns, queryMultiStructReq); } - queryUtils.cacheResultLogic(cacheKey, queryResultWithColumns); return queryResultWithColumns; } catch (Exception e) { log.warn("exception in queryByMultiStruct, e: ", e); @@ -196,9 +191,9 @@ public class QueryServiceImpl implements QueryService { if (!cacheEnable) { return false; } - if (!CollectionUtils.isEmpty(queryStructCmd.getQueryStructCmds()) - && queryStructCmd.getQueryStructCmds().get(0).getCacheInfo() != null) { - return queryStructCmd.getQueryStructCmds().get(0).getCacheInfo().getCache(); + if (!CollectionUtils.isEmpty(queryStructCmd.getQueryStructReqs()) + && queryStructCmd.getQueryStructReqs().get(0).getCacheInfo() != null) { + return queryStructCmd.getQueryStructReqs().get(0).getCacheInfo().getCache(); } return false; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaService.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaService.java new file mode 100644 index 000000000..6e125621e --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaService.java @@ -0,0 +1,26 @@ +package com.tencent.supersonic.semantic.query.service; + +import com.github.pagehelper.PageInfo; +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; + +import java.util.List; + +public interface SchemaService { + + List fetchDomainSchema(DomainSchemaFilterReq filter, User user); + + List getDomainListForAdmin(User user); + + List getDomainListForViewer(User user); + + PageInfo queryDimension(PageDimensionReq pageDimensionReq, User user); + + PageInfo queryMetric(PageMetricReq pageMetricReq, User user); +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SchemaServiceImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaServiceImpl.java similarity index 78% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SchemaServiceImpl.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaServiceImpl.java index 4077b65b5..6617178bb 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SchemaServiceImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaServiceImpl.java @@ -1,29 +1,27 @@ -package com.tencent.supersonic.semantic.query.application; +package com.tencent.supersonic.semantic.query.service; -import static com.tencent.supersonic.common.constant.Constants.AT_SYMBOL; +import static com.tencent.supersonic.common.pojo.Constants.AT_SYMBOL; import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; -import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq; -import com.tencent.supersonic.semantic.api.core.request.PageMetricReq; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import com.tencent.supersonic.semantic.api.model.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; +import com.tencent.supersonic.semantic.api.model.request.PageMetricReq; +import com.tencent.supersonic.semantic.api.model.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; -import com.tencent.supersonic.common.enums.TypeEnums; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; +import com.tencent.supersonic.common.pojo.enums.TypeEnums; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import com.tencent.supersonic.semantic.query.domain.SchemaService; -import com.tencent.supersonic.semantic.query.domain.QueryService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -125,4 +123,4 @@ public class SchemaServiceImpl implements SchemaService { public PageInfo queryMetric(PageMetricReq pageMetricCmd, User user) { return metricService.queryMetric(pageMetricCmd); } -} \ No newline at end of file +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/SemanticQueryEngine.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SemanticQueryEngine.java similarity index 61% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/SemanticQueryEngine.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SemanticQueryEngine.java index 7305e7de8..d584e7f50 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/SemanticQueryEngine.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SemanticQueryEngine.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.semantic.query.domain; +package com.tencent.supersonic.semantic.query.service; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.query.application.executor.QueryExecutor; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.query.executor.QueryExecutor; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; public interface SemanticQueryEngine { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SemanticQueryEngineImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SemanticQueryEngineImpl.java similarity index 77% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SemanticQueryEngineImpl.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SemanticQueryEngineImpl.java index e1fb10db0..1b9a82f17 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SemanticQueryEngineImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SemanticQueryEngineImpl.java @@ -1,17 +1,16 @@ -package com.tencent.supersonic.semantic.query.application; +package com.tencent.supersonic.semantic.query.service; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.application.executor.QueryExecutor; -import com.tencent.supersonic.semantic.query.application.optimizer.QueryOptimizer; -import com.tencent.supersonic.semantic.query.application.parser.QueryParser; -import com.tencent.supersonic.semantic.query.domain.SemanticQueryEngine; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; -import com.tencent.supersonic.semantic.query.domain.utils.ComponentFactory; -import com.tencent.supersonic.semantic.query.domain.utils.QueryUtils; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.executor.QueryExecutor; +import com.tencent.supersonic.semantic.query.optimizer.QueryOptimizer; +import com.tencent.supersonic.semantic.query.parser.QueryParser; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; +import com.tencent.supersonic.semantic.query.utils.ComponentFactory; +import com.tencent.supersonic.semantic.query.utils.QueryUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/ComponentFactory.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/ComponentFactory.java similarity index 64% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/ComponentFactory.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/ComponentFactory.java index 1baa767f2..bcdbe9874 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/ComponentFactory.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/ComponentFactory.java @@ -1,17 +1,17 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; -import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.semantic.query.application.executor.JdbcExecutor; -import com.tencent.supersonic.semantic.query.application.executor.QueryExecutor; -import com.tencent.supersonic.semantic.query.application.optimizer.DetailQuery; -import com.tencent.supersonic.semantic.query.application.optimizer.QueryOptimizer; -import com.tencent.supersonic.semantic.query.application.parser.SemanticConverter; -import com.tencent.supersonic.semantic.query.application.parser.SqlParser; -import com.tencent.supersonic.semantic.query.application.parser.calcite.CalciteSqlParser; -import com.tencent.supersonic.semantic.query.application.parser.convert.CalculateConverterAgg; -import com.tencent.supersonic.semantic.query.application.parser.convert.DefaultDimValueConverter; -import com.tencent.supersonic.semantic.query.application.parser.convert.MultiSourceJoin; -import com.tencent.supersonic.semantic.query.application.parser.convert.ParserDefaultConverter; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.semantic.query.executor.JdbcExecutor; +import com.tencent.supersonic.semantic.query.executor.QueryExecutor; +import com.tencent.supersonic.semantic.query.optimizer.DetailQuery; +import com.tencent.supersonic.semantic.query.optimizer.QueryOptimizer; +import com.tencent.supersonic.semantic.query.parser.SemanticConverter; +import com.tencent.supersonic.semantic.query.parser.SqlParser; +import com.tencent.supersonic.semantic.query.parser.calcite.CalciteSqlParser; +import com.tencent.supersonic.semantic.query.parser.convert.CalculateAggConverter; +import com.tencent.supersonic.semantic.query.parser.convert.DefaultDimValueConverter; +import com.tencent.supersonic.semantic.query.parser.convert.MultiSourceJoin; +import com.tencent.supersonic.semantic.query.parser.convert.ParserDefaultConverter; import java.util.ArrayList; import java.util.List; @@ -64,7 +64,7 @@ public class ComponentFactory { } private static void initSemanticConverter() { semanticConverters.add(getBean("DefaultDimValueConverter", DefaultDimValueConverter.class)); - semanticConverters.add(getBean("CalculateConverterAgg", CalculateConverterAgg.class)); + semanticConverters.add(getBean("CalculateAggConverter", CalculateAggConverter.class)); semanticConverters.add(getBean("ParserDefaultConverter", ParserDefaultConverter.class)); semanticConverters.add(getBean("MultiSourceJoin", MultiSourceJoin.class)); } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DataPermissionAOP.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DataPermissionAOP.java similarity index 94% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DataPermissionAOP.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DataPermissionAOP.java index 1dc02c8b8..62e0f3782 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DataPermissionAOP.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DataPermissionAOP.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; -import static com.tencent.supersonic.common.constant.Constants.MINUS; +import static com.tencent.supersonic.common.pojo.Constants.MINUS; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -12,22 +12,18 @@ import com.tencent.supersonic.auth.api.authorization.pojo.DimensionFilter; import com.tencent.supersonic.auth.api.authorization.request.QueryAuthResReq; import com.tencent.supersonic.auth.api.authorization.response.AuthorizedResourceResp; import com.tencent.supersonic.auth.api.authorization.service.AuthService; -import com.tencent.supersonic.semantic.api.core.pojo.QueryAuthorization; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.DomainResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.common.pojo.QueryAuthorization; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import com.tencent.supersonic.semantic.api.query.pojo.Filter; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.exception.InvalidArgumentException; -import com.tencent.supersonic.common.exception.InvalidPermissionException; -import com.tencent.supersonic.semantic.core.domain.DimensionService; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.core.domain.MetricService; - +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.exception.InvalidArgumentException; +import com.tencent.supersonic.common.pojo.exception.InvalidPermissionException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; @@ -39,7 +35,9 @@ import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; - +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.MetricService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; @@ -72,7 +70,7 @@ public class DataPermissionAOP { @Value("${permission.data.enable:true}") private Boolean permissionDataEnable; - @Pointcut("@annotation(com.tencent.supersonic.semantic.query.domain.annotation.DataPermission)") + @Pointcut("@annotation(com.tencent.supersonic.semantic.query.service.DataPermission)") public void dataPermissionAOP() { } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DateUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DateUtils.java similarity index 86% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DateUtils.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DateUtils.java index 57046b5ad..978143f3e 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DateUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DateUtils.java @@ -1,16 +1,17 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; -import static com.tencent.supersonic.common.constant.Constants.APOSTROPHE; -import static com.tencent.supersonic.common.constant.Constants.COMMA; -import static com.tencent.supersonic.common.constant.Constants.DAY; -import static com.tencent.supersonic.common.constant.Constants.DAY_FORMAT; -import static com.tencent.supersonic.common.constant.Constants.MONTH; -import static com.tencent.supersonic.common.constant.Constants.MONTH_FORMAT; -import static com.tencent.supersonic.common.constant.Constants.WEEK; +import static com.tencent.supersonic.common.pojo.Constants.APOSTROPHE; +import static com.tencent.supersonic.common.pojo.Constants.COMMA; +import static com.tencent.supersonic.common.pojo.Constants.DAY; +import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT; +import static com.tencent.supersonic.common.pojo.Constants.MONTH; +import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT; +import static com.tencent.supersonic.common.pojo.Constants.WEEK; import com.google.common.base.Strings; import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; +import com.tencent.supersonic.semantic.api.model.response.ItemDateResp; + import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; @@ -19,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.StringJoiner; + import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -44,7 +46,7 @@ public class DateUtils { return false; } - public boolean hasDataMode(DateConf dateInfo) { + public boolean hasAvailableDataMode(DateConf dateInfo) { if (Objects.nonNull(dateInfo) && DateConf.DateMode.AVAILABLE_TIME == dateInfo.getDateMode()) { return true; } @@ -139,18 +141,16 @@ public class DateUtils { } public String recentMonthStr(ItemDateResp dateDate, DateConf dateInfo) { + LocalDate endData = LocalDate.parse(dateDate.getEndDate(), + DateTimeFormatter.ofPattern(dateDate.getDateFormat())); if (dateDate.getDatePeriod() != null && MONTH.equalsIgnoreCase(dateDate.getDatePeriod())) { Long unit = getInterval(dateInfo.getStartDate(), dateInfo.getEndDate(), dateDate.getDateFormat(), ChronoUnit.MONTHS); - LocalDate endData = LocalDate.parse(dateDate.getEndDate(), - DateTimeFormatter.ofPattern(dateDate.getDateFormat())); return generateMonthSql(endData, unit, dateDate.getDateFormat()); } String dateFormatStr = MONTH_FORMAT; - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormatStr); - LocalDate end = LocalDate.parse(dateDate.getEndDate(), formatter); Integer unit = dateInfo.getUnit() - 1; - return recentMonthStr(end, Long.valueOf(unit), dateFormatStr); + return recentMonthStr(endData, Long.valueOf(unit), dateFormatStr); } public String recentWeekStr(LocalDate endData, Long unit) { @@ -217,7 +217,14 @@ public class DateUtils { public String listDateStr(ItemDateResp dateDate, DateConf dateInfo) { StringJoiner joiner = new StringJoiner(COMMA); dateInfo.getDateList().stream().forEach(date -> joiner.add(APOSTROPHE + date + APOSTROPHE)); - return String.format("(%s in (%s))", sysDateCol, joiner.toString()); + String dateCol = sysDateCol; + if (MONTH.equalsIgnoreCase(dateInfo.getPeriod())) { + dateCol = sysDateMonthCol; + } + if (WEEK.equalsIgnoreCase(dateInfo.getPeriod())) { + dateCol = sysDateWeekCol; + } + return String.format("(%s in (%s))", dateCol, joiner.toString()); } /** @@ -275,4 +282,17 @@ public class DateUtils { return dateStr; } + + public String getSysDateCol(DateConf dateInfo) { + if (DAY.equalsIgnoreCase(dateInfo.getPeriod())) { + return sysDateCol; + } + if (WEEK.equalsIgnoreCase(dateInfo.getPeriod())) { + return sysDateWeekCol; + } + if (MONTH.equalsIgnoreCase(dateInfo.getPeriod())) { + return sysDateMonthCol; + } + return ""; + } } \ No newline at end of file diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DimValueAspect.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DimValueAspect.java new file mode 100644 index 000000000..942d525c2 --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DimValueAspect.java @@ -0,0 +1,178 @@ +package com.tencent.supersonic.semantic.query.utils; + +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.pojo.Filter; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Aspect +@Component +@Slf4j +public class DimValueAspect { + + @Value("${dimension.value.map.enable:true}") + private Boolean dimensionValueMapEnable; + + @Autowired + private DimensionService dimensionService; + + @Around("execution(* com.tencent.supersonic.semantic.query.rest.QueryController.queryByStruct(..))" + + " || execution(* com.tencent.supersonic.semantic.query.service.QueryService.queryByStruct(..))") + public Object handleDimValue(ProceedingJoinPoint joinPoint) throws Throwable { + + if (!dimensionValueMapEnable) { + log.debug("dimensionValueMapEnable is false, skip dimensionValueMap"); + QueryResultWithSchemaResp queryResultWithColumns = (QueryResultWithSchemaResp) joinPoint.proceed(); + return queryResultWithColumns; + } + + Object[] args = joinPoint.getArgs(); + QueryStructReq queryStructReq = (QueryStructReq) args[0]; + Long domainId = queryStructReq.getDomainId(); + + List dimensions = dimensionService.getDimensions(domainId); + Map> dimAndAliasAndTechNamePair = new ConcurrentHashMap<>(); + Map> dimAndTechNameAndBizNamePair = new ConcurrentHashMap<>(); + generateAliasAndTechNamePair(dimensions, dimAndAliasAndTechNamePair, dimAndTechNameAndBizNamePair); + + rewriteFilter(queryStructReq.getDimensionFilters(), dimAndAliasAndTechNamePair); + + QueryResultWithSchemaResp queryResultWithColumns = (QueryResultWithSchemaResp) joinPoint.proceed(); + if (Objects.nonNull(queryResultWithColumns)) { + rewriteDimValue(queryResultWithColumns, dimAndTechNameAndBizNamePair); + } + + return queryResultWithColumns; + } + + private void rewriteDimValue(QueryResultWithSchemaResp queryResultWithColumns, Map> dimAndTechNameAndBizNamePair) { + if (!selectDimValueMap(queryResultWithColumns.getColumns(), dimAndTechNameAndBizNamePair)) { + return; + } + log.debug("start rewriteDimValue for resultList"); + for (Map line : queryResultWithColumns.getResultList()) { + for (String bizName : line.keySet()) { + String techName = line.get(bizName).toString(); + if (dimAndTechNameAndBizNamePair.containsKey(bizName)) { + Map techAndBizPair = dimAndTechNameAndBizNamePair.get(bizName); + if (!CollectionUtils.isEmpty(techAndBizPair) && techAndBizPair.containsKey(techName)) { + String bizValueName = techAndBizPair.get(techName); + if (Strings.isNotEmpty(bizValueName)) { + line.put(bizName, bizValueName); + } + } + } + } + } + } + + private boolean selectDimValueMap(List columns, Map> dimAndTechNameAndBizNamePair) { + if (CollectionUtils.isEmpty(dimAndTechNameAndBizNamePair) || CollectionUtils.isEmpty(dimAndTechNameAndBizNamePair)) { + return false; + } + + for (QueryColumn queryColumn : columns) { + if (dimAndTechNameAndBizNamePair.containsKey(queryColumn.getNameEn())) { + return true; + } + } + return false; + } + + + private void rewriteFilter(List dimensionFilters, Map> aliasAndTechNamePair) { + for (Filter filter : dimensionFilters) { + if (Objects.isNull(filter)) { + continue; + } + + if (CollectionUtils.isEmpty(filter.getChildren())) { + Object value = filter.getValue(); + String bizName = filter.getBizName(); + if (aliasAndTechNamePair.containsKey(bizName)) { + Map aliasPair = aliasAndTechNamePair.get(bizName); + if (Objects.nonNull(value)) { + if (value instanceof List) { + List values = (List) value; + List valuesNew = new ArrayList<>(); + for (String valueSingle : values) { + boolean f = aliasPair.containsKey(valueSingle) ? valuesNew.add(aliasPair.get(valueSingle)) : valuesNew.add(valueSingle); + } + filter.setValue(valuesNew); + } + if (value instanceof String) { + if (aliasPair.containsKey(value)) { + filter.setValue(aliasPair.get(value)); + } + } + } + } + return; + } + + rewriteFilter(filter.getChildren(), aliasAndTechNamePair); + } + } + + private void generateAliasAndTechNamePair(List dimensions + , Map> dimAndAliasAndTechNamePair + , Map> dimAndTechNameAndBizNamePair) { + if (CollectionUtils.isEmpty(dimensions)) { + return; + } + dimensions.stream().forEach(dimension -> { + if (Objects.nonNull(dimension) && Strings.isNotEmpty(dimension.getBizName()) + && !CollectionUtils.isEmpty(dimension.getDimValueMaps())) { + String bizName = dimension.getBizName(); + + List dimValueMaps = dimension.getDimValueMaps(); + Map innerPairTech = new HashMap<>(); + Map innerPairBiz = new HashMap<>(); + + dimValueMaps.stream().forEach(dimValueMap -> { + if (Objects.nonNull(dimValueMap) && !CollectionUtils.isEmpty(dimValueMap.getAlias()) + && Strings.isNotEmpty(dimValueMap.getTechName())) { + + // add bizName and techName pair + if (Strings.isNotEmpty(dimValueMap.getBizName())) { + innerPairTech.put(dimValueMap.getBizName(), dimValueMap.getTechName()); + } + + dimValueMap.getAlias().stream().forEach(alias -> { + if (Strings.isNotEmpty(alias)) { + innerPairTech.put(alias, dimValueMap.getTechName()); + } + }); + } + if (Objects.nonNull(dimValueMap) && Strings.isNotEmpty(dimValueMap.getTechName())) { + innerPairBiz.put(dimValueMap.getTechName(), dimValueMap.getBizName()); + } + }); + + if (!CollectionUtils.isEmpty(innerPairTech)) { + dimAndAliasAndTechNamePair.put(bizName, innerPairTech); + } + + if (!CollectionUtils.isEmpty(innerPairBiz)) { + dimAndTechNameAndBizNamePair.put(bizName, innerPairBiz); + } + } + }); + + } +} \ No newline at end of file diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryReqConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryReqConverter.java similarity index 77% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryReqConverter.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryReqConverter.java index 6323d199f..eedad9e29 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryReqConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryReqConverter.java @@ -1,15 +1,15 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; import com.tencent.supersonic.common.util.calcite.SqlParseUtils; import com.tencent.supersonic.common.util.calcite.SqlParserInfo; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; +import com.tencent.supersonic.semantic.api.model.request.SqlExecuteReq; +import com.tencent.supersonic.semantic.api.model.response.DomainSchemaResp; import com.tencent.supersonic.semantic.api.query.pojo.MetricTable; import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; -import com.tencent.supersonic.semantic.core.domain.DomainService; -import com.tencent.supersonic.semantic.query.domain.SemanticQueryEngine; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.api.query.request.QueryDslReq; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.query.service.SemanticQueryEngine; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -28,7 +28,7 @@ public class QueryReqConverter { @Autowired private SemanticQueryEngine parserService; - public QueryStatement convert(QuerySqlReq databaseReq, List domainSchemas) throws Exception { + public QueryStatement convert(QueryDslReq databaseReq, List domainSchemas) throws Exception { List tables = new ArrayList<>(); MetricTable metricTable = new MetricTable(); @@ -67,7 +67,9 @@ public class QueryReqConverter { result.setRootPath(domainService.getDomainFullPath(databaseReq.getDomainId())); result.setTables(tables); - return parserService.physicalSql(result); + QueryStatement queryStatement = parserService.physicalSql(result); + queryStatement.setSql(String.format(SqlExecuteReq.LIMIT_WRAPPER, queryStatement.getSql())); + return queryStatement; } } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryStructUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryStructUtils.java similarity index 85% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryStructUtils.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryStructUtils.java index 5b4be5766..2b7f87ac8 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryStructUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryStructUtils.java @@ -1,15 +1,17 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; -import com.tencent.supersonic.common.enums.TypeEnums; +import com.tencent.supersonic.common.pojo.DateConf.DateMode; +import com.tencent.supersonic.common.pojo.enums.TypeEnums; import com.tencent.supersonic.common.pojo.Aggregator; import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.semantic.api.core.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.ItemDateResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; +import com.tencent.supersonic.semantic.model.domain.Catalog; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -18,6 +20,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.springframework.stereotype.Component; @@ -92,15 +95,22 @@ public class QueryStructUtils { List dimensionIds = getDimensionIds(queryStructCmd); List metricIds = getMetricIds(queryStructCmd); - ItemDateResp dateDate = catalog.getDateDate( + ItemDateResp dateDate = catalog.getItemDate( new ItemDateFilter(dimensionIds, TypeEnums.DIMENSION.getName()), new ItemDateFilter(metricIds, TypeEnums.METRIC.getName())); if (Objects.isNull(dateDate) || Strings.isEmpty(dateDate.getStartDate()) && Strings.isEmpty(dateDate.getEndDate())) { - if (dateUtils.hasDataMode(dateInfo)) { + if (dateInfo.getDateMode().equals(DateMode.LIST_DISCRETE)) { + return dateUtils.listDateStr(dateDate, dateInfo); + } + if (dateInfo.getDateMode().equals(DateMode.BETWEEN_CONTINUOUS)) { + return dateUtils.betweenDateStr(dateDate, dateInfo); + } + if (dateUtils.hasAvailableDataMode(dateInfo)) { return dateUtils.hasDataModeStr(dateDate, dateInfo); } + return dateUtils.defaultRecentDateInfo(queryStructCmd.getDateInfo()); } log.info("dateDate:{}", dateDate); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryUtils.java similarity index 89% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryUtils.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryUtils.java index 9e9b0ae6a..c185aa141 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryUtils.java @@ -1,20 +1,19 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; -import static com.tencent.supersonic.common.constant.Constants.JOIN_UNDERLINE; -import static com.tencent.supersonic.common.constant.Constants.UNIONALL; +import static com.tencent.supersonic.common.pojo.Constants.JOIN_UNDERLINE; +import static com.tencent.supersonic.common.pojo.Constants.UNIONALL; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import com.tencent.supersonic.common.pojo.Aggregator; import com.tencent.supersonic.common.util.cache.CacheUtils; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.semantic.api.core.response.MetricResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; +import com.tencent.supersonic.common.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; -import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.semantic.core.domain.Catalog; -import com.tencent.supersonic.semantic.query.domain.pojo.QueryStatement; +import com.tencent.supersonic.semantic.model.domain.Catalog; +import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -102,7 +101,7 @@ public class QueryUtils { public void fillItemNameInfo(QueryResultWithSchemaResp queryResultWithColumns, QueryMultiStructReq queryMultiStructCmd) { - List aggregators = queryMultiStructCmd.getQueryStructCmds().stream() + List aggregators = queryMultiStructCmd.getQueryStructReqs().stream() .flatMap(queryStructCmd -> queryStructCmd.getAggregators().stream()) .collect(Collectors.toList()); log.info("multi agg merge:{}", aggregators); @@ -174,7 +173,7 @@ public class QueryUtils { QueryStatement sqlParser = new QueryStatement(); StringBuilder unionSqlBuilder = new StringBuilder(); for (int i = 0; i < sqlParsers.size(); i++) { - String selectStr = SqlGenerateUtils.getUnionSelect(queryMultiStructCmd.getQueryStructCmds().get(i)); + String selectStr = SqlGenerateUtils.getUnionSelect(queryMultiStructCmd.getQueryStructReqs().get(i)); unionSqlBuilder.append(String.format("select %s from ( %s ) sub_sql_%s", selectStr, sqlParsers.get(i).getSql(), i)); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlFilterUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/SqlFilterUtils.java similarity index 95% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlFilterUtils.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/SqlFilterUtils.java index 4b3916e0f..40f8caa93 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlFilterUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/SqlFilterUtils.java @@ -1,14 +1,14 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; -import static com.tencent.supersonic.common.constant.Constants.PARENTHESES_END; -import static com.tencent.supersonic.common.constant.Constants.PARENTHESES_START; -import static com.tencent.supersonic.common.constant.Constants.SPACE; -import static com.tencent.supersonic.common.constant.Constants.SYS_VAR; +import static com.tencent.supersonic.common.pojo.Constants.PARENTHESES_END; +import static com.tencent.supersonic.common.pojo.Constants.PARENTHESES_START; +import static com.tencent.supersonic.common.pojo.Constants.SPACE; +import static com.tencent.supersonic.common.pojo.Constants.SYS_VAR; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import com.tencent.supersonic.semantic.api.query.pojo.Criterion; import com.tencent.supersonic.semantic.api.query.pojo.Filter; -import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.Constants; import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlGenerateUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/SqlGenerateUtils.java similarity index 88% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlGenerateUtils.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/SqlGenerateUtils.java index 7dff2bc09..9ebd14765 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlGenerateUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/SqlGenerateUtils.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; -import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import com.tencent.supersonic.common.pojo.Aggregator; import java.util.stream.Collectors; @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import static com.tencent.supersonic.common.pojo.Constants.JOIN_UNDERLINE; @Component @Slf4j @@ -17,6 +18,9 @@ public class SqlGenerateUtils { StringBuilder sb = new StringBuilder(); int locate = 0; for (String group : queryStructCmd.getGroups()) { + if (group.contains(JOIN_UNDERLINE)) { + group = group.split(JOIN_UNDERLINE)[1]; + } if (!TimeDimensionEnum.getNameList().contains(group)) { locate++; sb.append(group).append(" as ").append("name").append(locate).append(","); @@ -36,7 +40,7 @@ public class SqlGenerateUtils { public String getLimit(QueryStructReq queryStructCmd) { if (queryStructCmd.getLimit() > 0) { - return " limit " + String.valueOf(queryStructCmd.getLimit()); + return " limit " + queryStructCmd.getLimit(); } return ""; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/StatUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/StatUtils.java similarity index 91% rename from semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/StatUtils.java rename to semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/StatUtils.java index 88fd39543..bea256fb0 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/StatUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/StatUtils.java @@ -1,17 +1,17 @@ -package com.tencent.supersonic.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.utils; import com.alibaba.ttl.TransmittableThreadLocal; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.semantic.api.core.enums.QueryTypeBackEnum; -import com.tencent.supersonic.semantic.api.core.enums.QueryTypeEnum; -import com.tencent.supersonic.semantic.api.core.pojo.QueryStat; +import com.tencent.supersonic.semantic.api.model.enums.QueryTypeBackEnum; +import com.tencent.supersonic.semantic.api.model.enums.QueryTypeEnum; +import com.tencent.supersonic.semantic.api.model.pojo.QueryStat; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; -import com.tencent.supersonic.common.enums.TaskStatusEnum; -import com.tencent.supersonic.semantic.query.domain.repository.StatRepository; +import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; +import com.tencent.supersonic.semantic.query.persistence.repository.StatRepository; import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/semantic/query/src/main/resources/mapper/StatMapper.xml b/semantic/query/src/main/resources/mapper/StatMapper.xml index 999dae0b1..1276db21b 100644 --- a/semantic/query/src/main/resources/mapper/StatMapper.xml +++ b/semantic/query/src/main/resources/mapper/StatMapper.xml @@ -2,10 +2,10 @@ - + + type="com.tencent.supersonic.semantic.api.model.pojo.QueryStat"> @@ -54,7 +54,7 @@ ",La.querySelectorAll("[selected]").length||en.push("\\["+ge+"*(?:value|"+Ni+")"),La.querySelectorAll("[id~="+Jn+"-]").length||en.push("~="),La.querySelectorAll("a#"+Jn+"+*").length||en.push(".#.+[+~]"),La.querySelectorAll(":checked").length||en.push(":checked"),Nr=zn.createElement("input"),Nr.setAttribute("type","hidden"),La.appendChild(Nr).setAttribute("name","D"),xr.appendChild(La).disabled=!0,La.querySelectorAll(":disabled").length!==2&&en.push(":enabled",":disabled"),Nr=zn.createElement("input"),Nr.setAttribute("name",""),La.appendChild(Nr),La.querySelectorAll("[name='']").length||en.push("\\["+ge+"*name"+ge+"*="+ge+`*(?:''|"")`)}),B.cssHas||en.push(":has"),en=en.length&&new RegExp(en.join("|")),_o=function(Nr,ua){if(Nr===ua)return wn=!0,0;var ra=!Nr.compareDocumentPosition-!ua.compareDocumentPosition;return ra||(ra=(Nr.ownerDocument||Nr)==(ua.ownerDocument||ua)?Nr.compareDocumentPosition(ua):1,ra&1||!B.sortDetached&&ua.compareDocumentPosition(Nr)===ra?Nr===zn||Nr.ownerDocument==Ee&&js.contains(Ee,Nr)?-1:ua===zn||ua.ownerDocument==Ee&&js.contains(Ee,ua)?1:tn?x.call(tn,Nr)-x.call(tn,ua):0:ra&4?-1:1)}),zn}js.matches=function(zr,wr){return js(zr,null,null,wr)},js.matchesSelector=function(zr,wr){if(Pl(zr),da&&!Ya[wr+" "]&&(!en||!en.test(wr)))try{var Ua=Fn.call(zr,wr);if(Ua||B.disconnectedMatch||zr.document&&zr.document.nodeType!==11)return Ua}catch(La){Ya(wr,!0)}return js(wr,zn,null,[zr]).length>0},js.contains=function(zr,wr){return(zr.ownerDocument||zr)!=zn&&Pl(zr),W.contains(zr,wr)},js.attr=function(zr,wr){(zr.ownerDocument||zr)!=zn&&Pl(zr);var Ua=rt.attrHandle[wr.toLowerCase()],La=Ua&&D.call(rt.attrHandle,wr.toLowerCase())?Ua(zr,wr,!da):void 0;return La!==void 0?La:zr.getAttribute(wr)},js.error=function(zr){throw new Error("Syntax error, unrecognized expression: "+zr)},W.uniqueSort=function(zr){var wr,Ua=[],La=0,Nr=0;if(wn=!B.sortStable,tn=!B.sortStable&&S.call(zr,0),he.call(zr,_o),wn){for(;wr=zr[Nr++];)wr===zr[Nr]&&(La=Ua.push(Nr));for(;La--;)oe.call(zr,Ua[La],1)}return tn=null,zr},W.fn.uniqueSort=function(){return this.pushStack(W.uniqueSort(S.apply(this)))},rt=W.expr={cacheLength:50,createPseudo:gc,match:fo,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(wr){return wr[1]=wr[1].replace(xc,kc),wr[3]=(wr[3]||wr[4]||wr[5]||"").replace(xc,kc),wr[2]==="~="&&(wr[3]=" "+wr[3]+" "),wr.slice(0,4)},CHILD:function(wr){return wr[1]=wr[1].toLowerCase(),wr[1].slice(0,3)==="nth"?(wr[3]||js.error(wr[0]),wr[4]=+(wr[4]?wr[5]+(wr[6]||1):2*(wr[3]==="even"||wr[3]==="odd")),wr[5]=+(wr[7]+wr[8]||wr[3]==="odd")):wr[3]&&js.error(wr[0]),wr},PSEUDO:function(wr){var Ua,La=!wr[6]&&wr[2];return fo.CHILD.test(wr[0])?null:(wr[3]?wr[2]=wr[4]||wr[5]||"":La&&Ei.test(La)&&(Ua=Ml(La,!0))&&(Ua=La.indexOf(")",La.length-Ua)-La.length)&&(wr[0]=wr[0].slice(0,Ua),wr[2]=La.slice(0,Ua)),wr.slice(0,3))}},filter:{TAG:function(wr){var Ua=wr.replace(xc,kc).toLowerCase();return wr==="*"?function(){return!0}:function(La){return te(La,Ua)}},CLASS:function(wr){var Ua=ga[wr+" "];return Ua||(Ua=new RegExp("(^|"+ge+")"+wr+"("+ge+"|$)"))&&ga(wr,function(La){return Ua.test(typeof La.className=="string"&&La.className||typeof La.getAttribute!="undefined"&&La.getAttribute("class")||"")})},ATTR:function(wr,Ua,La){return function(Nr){var ua=js.attr(Nr,wr);return ua==null?Ua==="!=":Ua?(ua+="",Ua==="="?ua===La:Ua==="!="?ua!==La:Ua==="^="?La&&ua.indexOf(La)===0:Ua==="*="?La&&ua.indexOf(La)>-1:Ua==="$="?La&&ua.slice(-La.length)===La:Ua==="~="?(" "+ua.replace(Qn," ")+" ").indexOf(La)>-1:Ua==="|="?ua===La||ua.slice(0,La.length+1)===La+"-":!1):!0}},CHILD:function(wr,Ua,La,Nr,ua){var ra=wr.slice(0,3)!=="nth",ri=wr.slice(-4)!=="last",li=Ua==="of-type";return Nr===1&&ua===0?function(hi){return!!hi.parentNode}:function(hi,ii,Di){var Xo,ps,mc,Ts,Ar,Gs=ra!==ri?"nextSibling":"previousSibling",Nc=hi.parentNode,Jc=li&&hi.nodeName.toLowerCase(),Fc=!Di&&!li,Ro=!1;if(Nc){if(ra){for(;Gs;){for(mc=hi;mc=mc[Gs];)if(li?te(mc,Jc):mc.nodeType===1)return!1;Ar=Gs=wr==="only"&&!Ar&&"nextSibling"}return!0}if(Ar=[ri?Nc.firstChild:Nc.lastChild],ri&&Fc){for(ps=Nc[Jn]||(Nc[Jn]={}),Xo=ps[wr]||[],Ts=Xo[0]===Ir&&Xo[1],Ro=Ts&&Xo[2],mc=Ts&&Nc.childNodes[Ts];mc=++Ts&&mc&&mc[Gs]||(Ro=Ts=0)||Ar.pop();)if(mc.nodeType===1&&++Ro&&mc===hi){ps[wr]=[Ir,Ts,Ro];break}}else if(Fc&&(ps=hi[Jn]||(hi[Jn]={}),Xo=ps[wr]||[],Ts=Xo[0]===Ir&&Xo[1],Ro=Ts),Ro===!1)for(;(mc=++Ts&&mc&&mc[Gs]||(Ro=Ts=0)||Ar.pop())&&!((li?te(mc,Jc):mc.nodeType===1)&&++Ro&&(Fc&&(ps=mc[Jn]||(mc[Jn]={}),ps[wr]=[Ir,Ro]),mc===hi)););return Ro-=ua,Ro===Nr||Ro%Nr==0&&Ro/Nr>=0}}},PSEUDO:function(wr,Ua){var La,Nr=rt.pseudos[wr]||rt.setFilters[wr.toLowerCase()]||js.error("unsupported pseudo: "+wr);return Nr[Jn]?Nr(Ua):Nr.length>1?(La=[wr,wr,"",Ua],rt.setFilters.hasOwnProperty(wr.toLowerCase())?gc(function(ua,ra){for(var ri,li=Nr(ua,Ua),hi=li.length;hi--;)ri=x.call(ua,li[hi]),ua[ri]=!(ra[ri]=li[hi])}):function(ua){return Nr(ua,0,La)}):Nr}},pseudos:{not:gc(function(zr){var wr=[],Ua=[],La=ni(zr.replace(me,"$1"));return La[Jn]?gc(function(Nr,ua,ra,ri){for(var li,hi=La(Nr,null,ri,[]),ii=Nr.length;ii--;)(li=hi[ii])&&(Nr[ii]=!(ua[ii]=li))}):function(Nr,ua,ra){return wr[0]=Nr,La(wr,null,ra,Ua),wr[0]=null,!Ua.pop()}}),has:gc(function(zr){return function(wr){return js(zr,wr).length>0}}),contains:gc(function(zr){return zr=zr.replace(xc,kc),function(wr){return(wr.textContent||W.text(wr)).indexOf(zr)>-1}}),lang:gc(function(zr){return zo.test(zr||"")||js.error("unsupported lang: "+zr),zr=zr.replace(xc,kc).toLowerCase(),function(wr){var Ua;do if(Ua=da?wr.lang:wr.getAttribute("xml:lang")||wr.getAttribute("lang"))return Ua=Ua.toLowerCase(),Ua===zr||Ua.indexOf(zr+"-")===0;while((wr=wr.parentNode)&&wr.nodeType===1);return!1}}),target:function(wr){var Ua=O.location&&O.location.hash;return Ua&&Ua.slice(1)===wr.id},root:function(wr){return wr===xr},focus:function(wr){return wr===Mo()&&zn.hasFocus()&&!!(wr.type||wr.href||~wr.tabIndex)},enabled:nl(!1),disabled:nl(!0),checked:function(wr){return te(wr,"input")&&!!wr.checked||te(wr,"option")&&!!wr.selected},selected:function(wr){return wr.parentNode&&wr.parentNode.selectedIndex,wr.selected===!0},empty:function(wr){for(wr=wr.firstChild;wr;wr=wr.nextSibling)if(wr.nodeType<6)return!1;return!0},parent:function(wr){return!rt.pseudos.empty(wr)},header:function(wr){return Ks.test(wr.nodeName)},input:function(wr){return gs.test(wr.nodeName)},button:function(wr){return te(wr,"input")&&wr.type==="button"||te(wr,"button")},text:function(wr){var Ua;return te(wr,"input")&&wr.type==="text"&&((Ua=wr.getAttribute("type"))==null||Ua.toLowerCase()==="text")},first:Rc(function(){return[0]}),last:Rc(function(zr,wr){return[wr-1]}),eq:Rc(function(zr,wr,Ua){return[Ua<0?Ua+wr:Ua]}),even:Rc(function(zr,wr){for(var Ua=0;Uawr?La=wr:La=Ua;--La>=0;)zr.push(La);return zr}),gt:Rc(function(zr,wr,Ua){for(var La=Ua<0?Ua+wr:Ua;++La1?function(wr,Ua,La){for(var Nr=zr.length;Nr--;)if(!zr[Nr](wr,Ua,La))return!1;return!0}:zr[0]}function dl(zr,wr,Ua){for(var La=0,Nr=wr.length;La-1&&(ra[ii]=!(ri[ii]=Xo))}}else ps=qt(ps===ri?ps.splice(Ar,ps.length):ps),Nr?Nr(null,ri,ps,hi):qn.apply(ri,ps)})}function Ur(zr){for(var wr,Ua,La,Nr=zr.length,ua=rt.relative[zr[0].type],ra=ua||rt.relative[" "],ri=ua?1:0,li=td(function(Di){return Di===wr},ra,!0),hi=td(function(Di){return x.call(wr,Di)>-1},ra,!0),ii=[function(Di,Xo,ps){var mc=!ua&&(ps||Xo!=Vt)||((wr=Xo).nodeType?li(Di,Xo,ps):hi(Di,Xo,ps));return wr=null,mc}];ri1&&rl(ii),ri>1&&Tl(zr.slice(0,ri-1).concat({value:zr[ri-2].type===" "?"*":""})).replace(me,"$1"),Ua,ri0,La=zr.length>0,Nr=function(ra,ri,li,hi,ii){var Di,Xo,ps,mc=0,Ts="0",Ar=ra&&[],Gs=[],Nc=Vt,Jc=ra||La&&rt.find.TAG("*",ii),Fc=Ir+=Nc==null?1:Math.random()||.1,Ro=Jc.length;for(ii&&(Vt=ri==zn||ri||ii);Ts!==Ro&&(Di=Jc[Ts])!=null;Ts++){if(La&&Di){for(Xo=0,!ri&&Di.ownerDocument!=zn&&(Pl(Di),li=!da);ps=zr[Xo++];)if(ps(Di,ri||zn,li)){qn.call(hi,Di);break}ii&&(Ir=Fc)}Ua&&((Di=!ps&&Di)&&mc--,ra&&Ar.push(Di))}if(mc+=Ts,Ua&&Ts!==mc){for(Xo=0;ps=wr[Xo++];)ps(Ar,Gs,ri,li);if(ra){if(mc>0)for(;Ts--;)Ar[Ts]||Gs[Ts]||(Gs[Ts]=_e.call(hi));Gs=qt(Gs)}qn.apply(hi,Gs),ii&&!ra&&Gs.length>0&&mc+wr.length>1&&W.uniqueSort(hi)}return ii&&(Ir=Fc,Vt=Nc),Ar};return Ua?gc(Nr):Nr}function ni(zr,wr){var Ua,La=[],Nr=[],ua=$a[zr+" "];if(!ua){for(wr||(wr=Ml(zr)),Ua=wr.length;Ua--;)ua=Ur(wr[Ua]),ua[Jn]?La.push(ua):Nr.push(ua);ua=$a(zr,Yr(Nr,La)),ua.selector=zr}return ua}function vi(zr,wr,Ua,La){var Nr,ua,ra,ri,li,hi=typeof zr=="function"&&zr,ii=!La&&Ml(zr=hi.selector||zr);if(Ua=Ua||[],ii.length===1){if(ua=ii[0]=ii[0].slice(0),ua.length>2&&(ra=ua[0]).type==="ID"&&wr.nodeType===9&&da&&rt.relative[ua[1].type]){if(wr=(rt.find.ID(ra.matches[0].replace(xc,kc),wr)||[])[0],wr)hi&&(wr=wr.parentNode);else return Ua;zr=zr.slice(ua.shift().value.length)}for(Nr=fo.needsContext.test(zr)?0:ua.length;Nr--&&(ra=ua[Nr],!rt.relative[ri=ra.type]);)if((li=rt.find[ri])&&(La=li(ra.matches[0].replace(xc,kc),tc.test(ua[0].type)&&su(wr.parentNode)||wr))){if(ua.splice(Nr,1),zr=La.length&&Tl(ua),!zr)return qn.apply(Ua,La),Ua;break}}return(hi||ni(zr,ii))(La,wr,!da,Ua,!wr||tc.test(zr)&&su(wr.parentNode)||wr),Ua}B.sortStable=Jn.split("").sort(_o).join("")===Jn,Pl(),B.sortDetached=Cl(function(zr){return zr.compareDocumentPosition(zn.createElement("fieldset"))&1}),W.find=js,W.expr[":"]=W.expr.pseudos,W.unique=W.uniqueSort,js.compile=ni,js.select=vi,js.setDocument=Pl,js.escape=W.escapeSelector,js.getText=W.text,js.isXML=W.isXMLDoc,js.selectors=W.expr,js.support=W.support,js.uniqueSort=W.uniqueSort})();var we=function(rt,Vt,tn){for(var wn=[],qn=tn!==void 0;(rt=rt[Vt])&&rt.nodeType!==9;)if(rt.nodeType===1){if(qn&&W(rt).is(tn))break;wn.push(rt)}return wn},fe=function(rt,Vt){for(var tn=[];rt;rt=rt.nextSibling)rt.nodeType===1&&rt!==Vt&&tn.push(rt);return tn},pe=W.expr.match.needsContext,Ke=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function Me($t,rt,Vt){return U(rt)?W.grep($t,function(tn,wn){return!!rt.call(tn,wn,tn)!==Vt}):rt.nodeType?W.grep($t,function(tn){return tn===rt!==Vt}):typeof rt!="string"?W.grep($t,function(tn){return x.call(rt,tn)>-1!==Vt}):W.filter(rt,$t,Vt)}W.filter=function($t,rt,Vt){var tn=rt[0];return Vt&&($t=":not("+$t+")"),rt.length===1&&tn.nodeType===1?W.find.matchesSelector(tn,$t)?[tn]:[]:W.find.matches($t,W.grep(rt,function(wn){return wn.nodeType===1}))},W.fn.extend({find:function(rt){var Vt,tn,wn=this.length,qn=this;if(typeof rt!="string")return this.pushStack(W(rt).filter(function(){for(Vt=0;Vt1?W.uniqueSort(tn):tn},filter:function(rt){return this.pushStack(Me(this,rt||[],!1))},not:function(rt){return this.pushStack(Me(this,rt||[],!0))},is:function(rt){return!!Me(this,typeof rt=="string"&&pe.test(rt)?W(rt):rt||[],!1).length}});var ze,Ue=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,He=W.fn.init=function($t,rt,Vt){var tn,wn;if(!$t)return this;if(Vt=Vt||ze,typeof $t=="string")if($t[0]==="<"&&$t[$t.length-1]===">"&&$t.length>=3?tn=[null,$t,null]:tn=Ue.exec($t),tn&&(tn[1]||!rt))if(tn[1]){if(rt=rt instanceof W?rt[0]:rt,W.merge(this,W.parseHTML(tn[1],rt&&rt.nodeType?rt.ownerDocument||rt:$,!0)),Ke.test(tn[1])&&W.isPlainObject(rt))for(tn in rt)U(this[tn])?this[tn](rt[tn]):this.attr(tn,rt[tn]);return this}else return wn=$.getElementById(tn[2]),wn&&(this[0]=wn,this.length=1),this;else return!rt||rt.jquery?(rt||Vt).find($t):this.constructor(rt).find($t);else{if($t.nodeType)return this[0]=$t,this.length=1,this;if(U($t))return Vt.ready!==void 0?Vt.ready($t):$t(W)}return W.makeArray($t,this)};He.prototype=W.fn,ze=W($);var Ne=/^(?:parents|prev(?:Until|All))/,it={children:!0,contents:!0,next:!0,prev:!0};W.fn.extend({has:function(rt){var Vt=W(rt,this),tn=Vt.length;return this.filter(function(){for(var wn=0;wn-1:tn.nodeType===1&&W.find.matchesSelector(tn,rt))){zn.push(tn);break}}return this.pushStack(zn.length>1?W.uniqueSort(zn):zn)},index:function(rt){return rt?typeof rt=="string"?x.call(W(rt),this[0]):x.call(this,rt.jquery?rt[0]:rt):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(rt,Vt){return this.pushStack(W.uniqueSort(W.merge(this.get(),W(rt,Vt))))},addBack:function(rt){return this.add(rt==null?this.prevObject:this.prevObject.filter(rt))}});function Xe($t,rt){for(;($t=$t[rt])&&$t.nodeType!==1;);return $t}W.each({parent:function(rt){var Vt=rt.parentNode;return Vt&&Vt.nodeType!==11?Vt:null},parents:function(rt){return we(rt,"parentNode")},parentsUntil:function(rt,Vt,tn){return we(rt,"parentNode",tn)},next:function(rt){return Xe(rt,"nextSibling")},prev:function(rt){return Xe(rt,"previousSibling")},nextAll:function(rt){return we(rt,"nextSibling")},prevAll:function(rt){return we(rt,"previousSibling")},nextUntil:function(rt,Vt,tn){return we(rt,"nextSibling",tn)},prevUntil:function(rt,Vt,tn){return we(rt,"previousSibling",tn)},siblings:function(rt){return fe((rt.parentNode||{}).firstChild,rt)},children:function(rt){return fe(rt.firstChild)},contents:function(rt){return rt.contentDocument!=null&&A(rt.contentDocument)?rt.contentDocument:(te(rt,"template")&&(rt=rt.content||rt),W.merge([],rt.childNodes))}},function($t,rt){W.fn[$t]=function(Vt,tn){var wn=W.map(this,rt,Vt);return $t.slice(-5)!=="Until"&&(tn=Vt),tn&&typeof tn=="string"&&(wn=W.filter(tn,wn)),this.length>1&&(it[$t]||W.uniqueSort(wn),Ne.test($t)&&wn.reverse()),this.pushStack(wn)}});var ht=/[^\x20\t\r\n\f]+/g;function lt($t){var rt={};return W.each($t.match(ht)||[],function(Vt,tn){rt[tn]=!0}),rt}W.Callbacks=function($t){$t=typeof $t=="string"?lt($t):W.extend({},$t);var rt,Vt,tn,wn,qn=[],zn=[],xr=-1,da=function(){for(wn=wn||$t.once,tn=rt=!0;zn.length;xr=-1)for(Vt=zn.shift();++xr-1;)qn.splice(Gr,1),Gr<=xr&&xr--}),this},has:function(Jn){return Jn?W.inArray(Jn,qn)>-1:qn.length>0},empty:function(){return qn&&(qn=[]),this},disable:function(){return wn=zn=[],qn=Vt="",this},disabled:function(){return!qn},lock:function(){return wn=zn=[],!Vt&&!rt&&(qn=Vt=""),this},locked:function(){return!!wn},fireWith:function(Jn,Ir){return wn||(Ir=Ir||[],Ir=[Jn,Ir.slice?Ir.slice():Ir],zn.push(Ir),rt||da()),this},fire:function(){return en.fireWith(this,arguments),this},fired:function(){return!!tn}};return en};function Et($t){return $t}function tt($t){throw $t}function mt($t,rt,Vt,tn){var wn;try{$t&&U(wn=$t.promise)?wn.call($t).done(rt).fail(Vt):$t&&U(wn=$t.then)?wn.call($t,rt,Vt):rt.apply(void 0,[$t].slice(tn))}catch(qn){Vt.apply(void 0,[qn])}}W.extend({Deferred:function(rt){var Vt=[["notify","progress",W.Callbacks("memory"),W.Callbacks("memory"),2],["resolve","done",W.Callbacks("once memory"),W.Callbacks("once memory"),0,"resolved"],["reject","fail",W.Callbacks("once memory"),W.Callbacks("once memory"),1,"rejected"]],tn="pending",wn={state:function(){return tn},always:function(){return qn.done(arguments).fail(arguments),this},catch:function(xr){return wn.then(null,xr)},pipe:function(){var xr=arguments;return W.Deferred(function(da){W.each(Vt,function(en,Fn){var Jn=U(xr[Fn[4]])&&xr[Fn[4]];qn[Fn[1]](function(){var Ir=Jn&&Jn.apply(this,arguments);Ir&&U(Ir.promise)?Ir.promise().progress(da.notify).done(da.resolve).fail(da.reject):da[Fn[0]+"With"](this,Jn?[Ir]:arguments)})}),xr=null}).promise()},then:function(xr,da,en){var Fn=0;function Jn(Ir,Gr,ga,Mr){return function(){var $a=this,Ya=arguments,_o=function(){var ks,jo;if(!(Ir=Fn&&(ga!==tt&&($a=void 0,Ya=[ec]),Gr.rejectWith($a,Ya))}};Ir?Ni():(W.Deferred.getErrorHook?Ni.error=W.Deferred.getErrorHook():W.Deferred.getStackHook&&(Ni.error=W.Deferred.getStackHook()),O.setTimeout(Ni))}}return W.Deferred(function(Ir){Vt[0][3].add(Jn(0,Ir,U(en)?en:Et,Ir.notifyWith)),Vt[1][3].add(Jn(0,Ir,U(xr)?xr:Et)),Vt[2][3].add(Jn(0,Ir,U(da)?da:tt))}).promise()},promise:function(xr){return xr!=null?W.extend(xr,wn):wn}},qn={};return W.each(Vt,function(zn,xr){var da=xr[2],en=xr[5];wn[xr[1]]=da.add,en&&da.add(function(){tn=en},Vt[3-zn][2].disable,Vt[3-zn][3].disable,Vt[0][2].lock,Vt[0][3].lock),da.add(xr[3].fire),qn[xr[0]]=function(){return qn[xr[0]+"With"](this===qn?void 0:this,arguments),this},qn[xr[0]+"With"]=da.fireWith}),wn.promise(qn),rt&&rt.call(qn,qn),qn},when:function(rt){var Vt=arguments.length,tn=Vt,wn=Array(tn),qn=S.call(arguments),zn=W.Deferred(),xr=function(en){return function(Fn){wn[en]=this,qn[en]=arguments.length>1?S.call(arguments):Fn,--Vt||zn.resolveWith(wn,qn)}};if(Vt<=1&&(mt(rt,zn.done(xr(tn)).resolve,zn.reject,!Vt),zn.state()==="pending"||U(qn[tn]&&qn[tn].then)))return zn.then();for(;tn--;)mt(qn[tn],xr(tn),zn.reject);return zn.promise()}});var xt=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;W.Deferred.exceptionHook=function($t,rt){O.console&&O.console.warn&&$t&&xt.test($t.name)&&O.console.warn("jQuery.Deferred exception: "+$t.message,$t.stack,rt)},W.readyException=function($t){O.setTimeout(function(){throw $t})};var Xt=W.Deferred();W.fn.ready=function($t){return Xt.then($t).catch(function(rt){W.readyException(rt)}),this},W.extend({isReady:!1,readyWait:1,ready:function(rt){(rt===!0?--W.readyWait:W.isReady)||(W.isReady=!0,!(rt!==!0&&--W.readyWait>0)&&Xt.resolveWith($,[W]))}}),W.ready.then=Xt.then;function vt(){$.removeEventListener("DOMContentLoaded",vt),O.removeEventListener("load",vt),W.ready()}$.readyState==="complete"||$.readyState!=="loading"&&!$.documentElement.doScroll?O.setTimeout(W.ready):($.addEventListener("DOMContentLoaded",vt),O.addEventListener("load",vt));var qe=function $t(rt,Vt,tn,wn,qn,zn,xr){var da=0,en=rt.length,Fn=tn==null;if(ie(tn)==="object"){qn=!0;for(da in tn)$t(rt,Vt,da,tn[da],!0,zn,xr)}else if(wn!==void 0&&(qn=!0,U(wn)||(xr=!0),Fn&&(xr?(Vt.call(rt,wn),Vt=null):(Fn=Vt,Vt=function(Ir,Gr,ga){return Fn.call(W(Ir),ga)})),Vt))for(;da1,null,!0)},removeData:function(rt){return this.each(function(){at.remove(this,rt)})}}),W.extend({queue:function(rt,Vt,tn){var wn;if(rt)return Vt=(Vt||"fx")+"queue",wn=gt.get(rt,Vt),tn&&(!wn||Array.isArray(tn)?wn=gt.access(rt,Vt,W.makeArray(tn)):wn.push(tn)),wn||[]},dequeue:function(rt,Vt){Vt=Vt||"fx";var tn=W.queue(rt,Vt),wn=tn.length,qn=tn.shift(),zn=W._queueHooks(rt,Vt),xr=function(){W.dequeue(rt,Vt)};qn==="inprogress"&&(qn=tn.shift(),wn--),qn&&(Vt==="fx"&&tn.unshift("inprogress"),delete zn.stop,qn.call(rt,xr,zn)),!wn&&zn&&zn.empty.fire()},_queueHooks:function(rt,Vt){var tn=Vt+"queueHooks";return gt.get(rt,tn)||gt.access(rt,tn,{empty:W.Callbacks("once memory").add(function(){gt.remove(rt,[Vt+"queue",tn])})})}}),W.fn.extend({queue:function(rt,Vt){var tn=2;return typeof rt!="string"&&(Vt=rt,rt="fx",tn--),arguments.length\x20\t\r\n\f]*)/i,_n=/^$|^module$|\/(?:java|ecma)script/i;(function(){var $t=$.createDocumentFragment(),rt=$t.appendChild($.createElement("div")),Vt=$.createElement("input");Vt.setAttribute("type","radio"),Vt.setAttribute("checked","checked"),Vt.setAttribute("name","t"),rt.appendChild(Vt),B.checkClone=rt.cloneNode(!0).cloneNode(!0).lastChild.checked,rt.innerHTML="",B.noCloneChecked=!!rt.cloneNode(!0).lastChild.defaultValue,rt.innerHTML="",B.option=!!rt.lastChild})();var bn={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};bn.tbody=bn.tfoot=bn.colgroup=bn.caption=bn.thead,bn.th=bn.td,B.option||(bn.optgroup=bn.option=[1,""]);function Bn($t,rt){var Vt;return typeof $t.getElementsByTagName!="undefined"?Vt=$t.getElementsByTagName(rt||"*"):typeof $t.querySelectorAll!="undefined"?Vt=$t.querySelectorAll(rt||"*"):Vt=[],rt===void 0||rt&&te($t,rt)?W.merge([$t],Vt):Vt}function Tn($t,rt){for(var Vt=0,tn=$t.length;Vt-1){wn&&wn.push(qn);continue}if(en=Ot(qn),zn=Bn(Jn.appendChild(qn),"script"),en&&Tn(zn),Vt)for(Fn=0;qn=zn[Fn++];)_n.test(qn.type||"")&&Vt.push(qn)}return Jn}var Wr=/^([^.]*)(?:\.(.+)|)/;function br(){return!0}function Wn(){return!1}function gr($t,rt,Vt,tn,wn,qn){var zn,xr;if(typeof rt=="object"){typeof Vt!="string"&&(tn=tn||Vt,Vt=void 0);for(xr in rt)gr($t,xr,Vt,tn,rt[xr],qn);return $t}if(tn==null&&wn==null?(wn=Vt,tn=Vt=void 0):wn==null&&(typeof Vt=="string"?(wn=tn,tn=void 0):(wn=tn,tn=Vt,Vt=void 0)),wn===!1)wn=Wn;else if(!wn)return $t;return qn===1&&(zn=wn,wn=function(en){return W().off(en),zn.apply(this,arguments)},wn.guid=zn.guid||(zn.guid=W.guid++)),$t.each(function(){W.event.add(this,rt,wn,tn,Vt)})}W.event={global:{},add:function(rt,Vt,tn,wn,qn){var zn,xr,da,en,Fn,Jn,Ir,Gr,ga,Mr,$a,Ya=gt.get(rt);if(!!_t(rt))for(tn.handler&&(zn=tn,tn=zn.handler,qn=zn.selector),qn&&W.find.matchesSelector(Tt,qn),tn.guid||(tn.guid=W.guid++),(en=Ya.events)||(en=Ya.events=Object.create(null)),(xr=Ya.handle)||(xr=Ya.handle=function(_o){return typeof W!="undefined"&&W.event.triggered!==_o.type?W.event.dispatch.apply(rt,arguments):void 0}),Vt=(Vt||"").match(ht)||[""],Fn=Vt.length;Fn--;)da=Wr.exec(Vt[Fn])||[],ga=$a=da[1],Mr=(da[2]||"").split(".").sort(),!!ga&&(Ir=W.event.special[ga]||{},ga=(qn?Ir.delegateType:Ir.bindType)||ga,Ir=W.event.special[ga]||{},Jn=W.extend({type:ga,origType:$a,data:wn,handler:tn,guid:tn.guid,selector:qn,needsContext:qn&&W.expr.match.needsContext.test(qn),namespace:Mr.join(".")},zn),(Gr=en[ga])||(Gr=en[ga]=[],Gr.delegateCount=0,(!Ir.setup||Ir.setup.call(rt,wn,Mr,xr)===!1)&&rt.addEventListener&&rt.addEventListener(ga,xr)),Ir.add&&(Ir.add.call(rt,Jn),Jn.handler.guid||(Jn.handler.guid=tn.guid)),qn?Gr.splice(Gr.delegateCount++,0,Jn):Gr.push(Jn),W.event.global[ga]=!0)},remove:function(rt,Vt,tn,wn,qn){var zn,xr,da,en,Fn,Jn,Ir,Gr,ga,Mr,$a,Ya=gt.hasData(rt)&>.get(rt);if(!(!Ya||!(en=Ya.events))){for(Vt=(Vt||"").match(ht)||[""],Fn=Vt.length;Fn--;){if(da=Wr.exec(Vt[Fn])||[],ga=$a=da[1],Mr=(da[2]||"").split(".").sort(),!ga){for(ga in en)W.event.remove(rt,ga+Vt[Fn],tn,wn,!0);continue}for(Ir=W.event.special[ga]||{},ga=(wn?Ir.delegateType:Ir.bindType)||ga,Gr=en[ga]||[],da=da[2]&&new RegExp("(^|\\.)"+Mr.join("\\.(?:.*\\.|)")+"(\\.|$)"),xr=zn=Gr.length;zn--;)Jn=Gr[zn],(qn||$a===Jn.origType)&&(!tn||tn.guid===Jn.guid)&&(!da||da.test(Jn.namespace))&&(!wn||wn===Jn.selector||wn==="**"&&Jn.selector)&&(Gr.splice(zn,1),Jn.selector&&Gr.delegateCount--,Ir.remove&&Ir.remove.call(rt,Jn));xr&&!Gr.length&&((!Ir.teardown||Ir.teardown.call(rt,Mr,Ya.handle)===!1)&&W.removeEvent(rt,ga,Ya.handle),delete en[ga])}W.isEmptyObject(en)&>.remove(rt,"handle events")}},dispatch:function(rt){var Vt,tn,wn,qn,zn,xr,da=new Array(arguments.length),en=W.event.fix(rt),Fn=(gt.get(this,"events")||Object.create(null))[en.type]||[],Jn=W.event.special[en.type]||{};for(da[0]=en,Vt=1;Vt=1)){for(;Fn!==this;Fn=Fn.parentNode||this)if(Fn.nodeType===1&&!(rt.type==="click"&&Fn.disabled===!0)){for(zn=[],xr={},tn=0;tn-1:W.find(qn,this,null,[Fn]).length),xr[qn]&&zn.push(wn);zn.length&&da.push({elem:Fn,handlers:zn})}}return Fn=this,en\s*$/g;function Bt($t,rt){return te($t,"table")&&te(rt.nodeType!==11?rt:rt.firstChild,"tr")&&W($t).children("tbody")[0]||$t}function H($t){return $t.type=($t.getAttribute("type")!==null)+"/"+$t.type,$t}function ot($t){return($t.type||"").slice(0,5)==="true/"?$t.type=$t.type.slice(5):$t.removeAttribute("type"),$t}function nt($t,rt){var Vt,tn,wn,qn,zn,xr,da;if(rt.nodeType===1){if(gt.hasData($t)&&(qn=gt.get($t),da=qn.events,da)){gt.remove(rt,"handle events");for(wn in da)for(Vt=0,tn=da[wn].length;Vt1&&typeof Gr=="string"&&!B.checkClone&&un.test(Gr))return $t.each(function(Mr){var $a=$t.eq(Mr);ga&&(rt[0]=Gr.call(this,Mr,$a.html())),Wt($a,rt,Vt,tn)});if(Jn&&(wn=Sr(rt,$t[0].ownerDocument,!1,$t,tn),qn=wn.firstChild,wn.childNodes.length===1&&(wn=qn),qn||tn)){for(zn=W.map(Bn(wn,"script"),H),xr=zn.length;Fn0&&Tn(xr,!en&&Bn(rt,"script")),da},cleanData:function(rt){for(var Vt,tn,wn,qn=W.event.special,zn=0;(tn=rt[zn])!==void 0;zn++)if(_t(tn)){if(Vt=tn[gt.expando]){if(Vt.events)for(wn in Vt.events)qn[wn]?W.event.remove(tn,wn):W.removeEvent(tn,wn,Vt.handle);tn[gt.expando]=void 0}tn[at.expando]&&(tn[at.expando]=void 0)}}}),W.fn.extend({detach:function(rt){return kn(this,rt,!0)},remove:function(rt){return kn(this,rt)},text:function(rt){return qe(this,function(Vt){return Vt===void 0?W.text(this):this.empty().each(function(){(this.nodeType===1||this.nodeType===11||this.nodeType===9)&&(this.textContent=Vt)})},null,rt,arguments.length)},append:function(){return Wt(this,arguments,function(rt){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var Vt=Bt(this,rt);Vt.appendChild(rt)}})},prepend:function(){return Wt(this,arguments,function(rt){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var Vt=Bt(this,rt);Vt.insertBefore(rt,Vt.firstChild)}})},before:function(){return Wt(this,arguments,function(rt){this.parentNode&&this.parentNode.insertBefore(rt,this)})},after:function(){return Wt(this,arguments,function(rt){this.parentNode&&this.parentNode.insertBefore(rt,this.nextSibling)})},empty:function(){for(var rt,Vt=0;(rt=this[Vt])!=null;Vt++)rt.nodeType===1&&(W.cleanData(Bn(rt,!1)),rt.textContent="");return this},clone:function(rt,Vt){return rt=rt==null?!1:rt,Vt=Vt==null?rt:Vt,this.map(function(){return W.clone(this,rt,Vt)})},html:function(rt){return qe(this,function(Vt){var tn=this[0]||{},wn=0,qn=this.length;if(Vt===void 0&&tn.nodeType===1)return tn.innerHTML;if(typeof Vt=="string"&&!jn.test(Vt)&&!bn[(hn.exec(Vt)||["",""])[1].toLowerCase()]){Vt=W.htmlPrefilter(Vt);try{for(;wn=0&&(da+=Math.max(0,Math.ceil($t["offset"+rt[0].toUpperCase()+rt.slice(1)]-qn-da-xr-.5))||0),da+en}function Ma($t,rt,Vt){var tn=Or($t),wn=!B.boxSizingReliable()||Vt,qn=wn&&W.css($t,"boxSizing",!1,tn)==="border-box",zn=qn,xr=Zt($t,rt,tn),da="offset"+rt[0].toUpperCase()+rt.slice(1);if(Sn.test(xr)){if(!Vt)return xr;xr="auto"}return(!B.boxSizingReliable()&&qn||!B.reliableTrDimensions()&&te($t,"tr")||xr==="auto"||!parseFloat(xr)&&W.css($t,"display",!1,tn)==="inline")&&$t.getClientRects().length&&(qn=W.css($t,"boxSizing",!1,tn)==="border-box",zn=da in $t,zn&&(xr=$t[da])),xr=parseFloat(xr)||0,xr+za($t,rt,Vt||(qn?"border":"content"),zn,tn,xr)+"px"}W.extend({cssHooks:{opacity:{get:function(rt,Vt){if(Vt){var tn=Zt(rt,"opacity");return tn===""?"1":tn}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(rt,Vt,tn,wn){if(!(!rt||rt.nodeType===3||rt.nodeType===8||!rt.style)){var qn,zn,xr,da=Ge(Vt),en=Zn.test(Vt),Fn=rt.style;if(en||(Vt=fr(da)),xr=W.cssHooks[Vt]||W.cssHooks[da],tn!==void 0){if(zn=typeof tn,zn==="string"&&(qn=$e.exec(tn))&&qn[1]&&(tn=Pt(rt,Vt,qn),zn="number"),tn==null||tn!==tn)return;zn==="number"&&!en&&(tn+=qn&&qn[3]||(W.cssNumber[da]?"":"px")),!B.clearCloneStyle&&tn===""&&Vt.indexOf("background")===0&&(Fn[Vt]="inherit"),(!xr||!("set"in xr)||(tn=xr.set(rt,tn,wn))!==void 0)&&(en?Fn.setProperty(Vt,tn):Fn[Vt]=tn)}else return xr&&"get"in xr&&(qn=xr.get(rt,!1,wn))!==void 0?qn:Fn[Vt]}},css:function(rt,Vt,tn,wn){var qn,zn,xr,da=Ge(Vt),en=Zn.test(Vt);return en||(Vt=fr(da)),xr=W.cssHooks[Vt]||W.cssHooks[da],xr&&"get"in xr&&(qn=xr.get(rt,!0,tn)),qn===void 0&&(qn=Zt(rt,Vt,wn)),qn==="normal"&&Vt in Lr&&(qn=Lr[Vt]),tn===""||tn?(zn=parseFloat(qn),tn===!0||isFinite(zn)?zn||0:qn):qn}}),W.each(["height","width"],function($t,rt){W.cssHooks[rt]={get:function(tn,wn,qn){if(wn)return Hn.test(W.css(tn,"display"))&&(!tn.getClientRects().length||!tn.getBoundingClientRect().width)?Yn(tn,Sa,function(){return Ma(tn,rt,qn)}):Ma(tn,rt,qn)},set:function(tn,wn,qn){var zn,xr=Or(tn),da=!B.scrollboxSize()&&xr.position==="absolute",en=da||qn,Fn=en&&W.css(tn,"boxSizing",!1,xr)==="border-box",Jn=qn?za(tn,rt,qn,Fn,xr):0;return Fn&&da&&(Jn-=Math.ceil(tn["offset"+rt[0].toUpperCase()+rt.slice(1)]-parseFloat(xr[rt])-za(tn,rt,"border",!1,xr)-.5)),Jn&&(zn=$e.exec(wn))&&(zn[3]||"px")!=="px"&&(tn.style[rt]=wn,wn=W.css(tn,rt)),Ca(tn,wn,Jn)}}}),W.cssHooks.marginLeft=rr(B.reliableMarginLeft,function($t,rt){if(rt)return(parseFloat(Zt($t,"marginLeft"))||$t.getBoundingClientRect().left-Yn($t,{marginLeft:0},function(){return $t.getBoundingClientRect().left}))+"px"}),W.each({margin:"",padding:"",border:"Width"},function($t,rt){W.cssHooks[$t+rt]={expand:function(tn){for(var wn=0,qn={},zn=typeof tn=="string"?tn.split(" "):[tn];wn<4;wn++)qn[$t+Qe[wn]+rt]=zn[wn]||zn[wn-2]||zn[0];return qn}},$t!=="margin"&&(W.cssHooks[$t+rt].set=Ca)}),W.fn.extend({css:function(rt,Vt){return qe(this,function(tn,wn,qn){var zn,xr,da={},en=0;if(Array.isArray(wn)){for(zn=Or(tn),xr=wn.length;en1)}});function va($t,rt,Vt,tn,wn){return new va.prototype.init($t,rt,Vt,tn,wn)}W.Tween=va,va.prototype={constructor:va,init:function(rt,Vt,tn,wn,qn,zn){this.elem=rt,this.prop=tn,this.easing=qn||W.easing._default,this.options=Vt,this.start=this.now=this.cur(),this.end=wn,this.unit=zn||(W.cssNumber[tn]?"":"px")},cur:function(){var rt=va.propHooks[this.prop];return rt&&rt.get?rt.get(this):va.propHooks._default.get(this)},run:function(rt){var Vt,tn=va.propHooks[this.prop];return this.options.duration?this.pos=Vt=W.easing[this.easing](rt,this.options.duration*rt,0,1,this.options.duration):this.pos=Vt=rt,this.now=(this.end-this.start)*Vt+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),tn&&tn.set?tn.set(this):va.propHooks._default.set(this),this}},va.prototype.init.prototype=va.prototype,va.propHooks={_default:{get:function(rt){var Vt;return rt.elem.nodeType!==1||rt.elem[rt.prop]!=null&&rt.elem.style[rt.prop]==null?rt.elem[rt.prop]:(Vt=W.css(rt.elem,rt.prop,""),!Vt||Vt==="auto"?0:Vt)},set:function(rt){W.fx.step[rt.prop]?W.fx.step[rt.prop](rt):rt.elem.nodeType===1&&(W.cssHooks[rt.prop]||rt.elem.style[fr(rt.prop)]!=null)?W.style(rt.elem,rt.prop,rt.now+rt.unit):rt.elem[rt.prop]=rt.now}}},va.propHooks.scrollTop=va.propHooks.scrollLeft={set:function(rt){rt.elem.nodeType&&rt.elem.parentNode&&(rt.elem[rt.prop]=rt.now)}},W.easing={linear:function(rt){return rt},swing:function(rt){return .5-Math.cos(rt*Math.PI)/2},_default:"swing"},W.fx=va.prototype.init,W.fx.step={};var qa,gi,Qi=/^(?:toggle|show|hide)$/,mi=/queueHooks$/;function Cr(){gi&&($.hidden===!1&&O.requestAnimationFrame?O.requestAnimationFrame(Cr):O.setTimeout(Cr,W.fx.interval),W.fx.tick())}function Un(){return O.setTimeout(function(){qa=void 0}),qa=Date.now()}function Lt($t,rt){var Vt,tn=0,wn={height:$t};for(rt=rt?1:0;tn<4;tn+=2-rt)Vt=Qe[tn],wn["margin"+Vt]=wn["padding"+Vt]=$t;return rt&&(wn.opacity=wn.width=$t),wn}function gn($t,rt,Vt){for(var tn,wn=(ea.tweeners[rt]||[]).concat(ea.tweeners["*"]),qn=0,zn=wn.length;qn1)},removeAttr:function(rt){return this.each(function(){W.removeAttr(this,rt)})}}),W.extend({attr:function(rt,Vt,tn){var wn,qn,zn=rt.nodeType;if(!(zn===3||zn===8||zn===2)){if(typeof rt.getAttribute=="undefined")return W.prop(rt,Vt,tn);if((zn!==1||!W.isXMLDoc(rt))&&(qn=W.attrHooks[Vt.toLowerCase()]||(W.expr.match.bool.test(Vt)?Qr:void 0)),tn!==void 0){if(tn===null){W.removeAttr(rt,Vt);return}return qn&&"set"in qn&&(wn=qn.set(rt,tn,Vt))!==void 0?wn:(rt.setAttribute(Vt,tn+""),tn)}return qn&&"get"in qn&&(wn=qn.get(rt,Vt))!==null?wn:(wn=W.find.attr(rt,Vt),wn==null?void 0:wn)}},attrHooks:{type:{set:function(rt,Vt){if(!B.radioValue&&Vt==="radio"&&te(rt,"input")){var tn=rt.value;return rt.setAttribute("type",Vt),tn&&(rt.value=tn),Vt}}}},removeAttr:function(rt,Vt){var tn,wn=0,qn=Vt&&Vt.match(ht);if(qn&&rt.nodeType===1)for(;tn=qn[wn++];)rt.removeAttribute(tn)}}),Qr={set:function(rt,Vt,tn){return Vt===!1?W.removeAttr(rt,tn):rt.setAttribute(tn,tn),tn}},W.each(W.expr.match.bool.source.match(/\w+/g),function($t,rt){var Vt=Na[rt]||W.find.attr;Na[rt]=function(tn,wn,qn){var zn,xr,da=wn.toLowerCase();return qn||(xr=Na[da],Na[da]=zn,zn=Vt(tn,wn,qn)!=null?da:null,Na[da]=xr),zn}});var ar=/^(?:input|select|textarea|button)$/i,pi=/^(?:a|area)$/i;W.fn.extend({prop:function(rt,Vt){return qe(this,W.prop,rt,Vt,arguments.length>1)},removeProp:function(rt){return this.each(function(){delete this[W.propFix[rt]||rt]})}}),W.extend({prop:function(rt,Vt,tn){var wn,qn,zn=rt.nodeType;if(!(zn===3||zn===8||zn===2))return(zn!==1||!W.isXMLDoc(rt))&&(Vt=W.propFix[Vt]||Vt,qn=W.propHooks[Vt]),tn!==void 0?qn&&"set"in qn&&(wn=qn.set(rt,tn,Vt))!==void 0?wn:rt[Vt]=tn:qn&&"get"in qn&&(wn=qn.get(rt,Vt))!==null?wn:rt[Vt]},propHooks:{tabIndex:{get:function(rt){var Vt=W.find.attr(rt,"tabindex");return Vt?parseInt(Vt,10):ar.test(rt.nodeName)||pi.test(rt.nodeName)&&rt.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),B.optSelected||(W.propHooks.selected={get:function(rt){var Vt=rt.parentNode;return Vt&&Vt.parentNode&&Vt.parentNode.selectedIndex,null},set:function(rt){var Vt=rt.parentNode;Vt&&(Vt.selectedIndex,Vt.parentNode&&Vt.parentNode.selectedIndex)}}),W.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){W.propFix[this.toLowerCase()]=this});function _i($t){var rt=$t.match(ht)||[];return rt.join(" ")}function ti($t){return $t.getAttribute&&$t.getAttribute("class")||""}function ui($t){return Array.isArray($t)?$t:typeof $t=="string"?$t.match(ht)||[]:[]}W.fn.extend({addClass:function(rt){var Vt,tn,wn,qn,zn,xr;return U(rt)?this.each(function(da){W(this).addClass(rt.call(this,da,ti(this)))}):(Vt=ui(rt),Vt.length?this.each(function(){if(wn=ti(this),tn=this.nodeType===1&&" "+_i(wn)+" ",tn){for(zn=0;zn-1;)tn=tn.replace(" "+qn+" "," ");xr=_i(tn),wn!==xr&&this.setAttribute("class",xr)}}):this):this.attr("class","")},toggleClass:function(rt,Vt){var tn,wn,qn,zn,xr=typeof rt,da=xr==="string"||Array.isArray(rt);return U(rt)?this.each(function(en){W(this).toggleClass(rt.call(this,en,ti(this),Vt),Vt)}):typeof Vt=="boolean"&&da?Vt?this.addClass(rt):this.removeClass(rt):(tn=ui(rt),this.each(function(){if(da)for(zn=W(this),qn=0;qn-1)return!0;return!1}});var Ri=/\r/g;W.fn.extend({val:function(rt){var Vt,tn,wn,qn=this[0];return arguments.length?(wn=U(rt),this.each(function(zn){var xr;this.nodeType===1&&(wn?xr=rt.call(this,zn,W(this).val()):xr=rt,xr==null?xr="":typeof xr=="number"?xr+="":Array.isArray(xr)&&(xr=W.map(xr,function(da){return da==null?"":da+""})),Vt=W.valHooks[this.type]||W.valHooks[this.nodeName.toLowerCase()],(!Vt||!("set"in Vt)||Vt.set(this,xr,"value")===void 0)&&(this.value=xr))})):qn?(Vt=W.valHooks[qn.type]||W.valHooks[qn.nodeName.toLowerCase()],Vt&&"get"in Vt&&(tn=Vt.get(qn,"value"))!==void 0?tn:(tn=qn.value,typeof tn=="string"?tn.replace(Ri,""):tn==null?"":tn)):void 0}}),W.extend({valHooks:{option:{get:function(rt){var Vt=W.find.attr(rt,"value");return Vt!=null?Vt:_i(W.text(rt))}},select:{get:function(rt){var Vt,tn,wn,qn=rt.options,zn=rt.selectedIndex,xr=rt.type==="select-one",da=xr?null:[],en=xr?zn+1:qn.length;for(zn<0?wn=en:wn=xr?zn:0;wn-1)&&(tn=!0);return tn||(rt.selectedIndex=-1),zn}}}}),W.each(["radio","checkbox"],function(){W.valHooks[this]={set:function(rt,Vt){if(Array.isArray(Vt))return rt.checked=W.inArray(W(rt).val(),Vt)>-1}},B.checkOn||(W.valHooks[this].get=function($t){return $t.getAttribute("value")===null?"on":$t.value})});var ao=O.location,Zi={guid:Date.now()},Fi=/\?/;W.parseXML=function($t){var rt,Vt;if(!$t||typeof $t!="string")return null;try{rt=new O.DOMParser().parseFromString($t,"text/xml")}catch(tn){}return Vt=rt&&rt.getElementsByTagName("parsererror")[0],(!rt||Vt)&&W.error("Invalid XML: "+(Vt?W.map(Vt.childNodes,function(tn){return tn.textContent}).join(` -`):$t)),rt};var Si=/^(?:focusinfocus|focusoutblur)$/,qi=function(rt){rt.stopPropagation()};W.extend(W.event,{trigger:function(rt,Vt,tn,wn){var qn,zn,xr,da,en,Fn,Jn,Ir,Gr=[tn||$],ga=D.call(rt,"type")?rt.type:rt,Mr=D.call(rt,"namespace")?rt.namespace.split("."):[];if(zn=Ir=xr=tn=tn||$,!(tn.nodeType===3||tn.nodeType===8)&&!Si.test(ga+W.event.triggered)&&(ga.indexOf(".")>-1&&(Mr=ga.split("."),ga=Mr.shift(),Mr.sort()),en=ga.indexOf(":")<0&&"on"+ga,rt=rt[W.expando]?rt:new W.Event(ga,typeof rt=="object"&&rt),rt.isTrigger=wn?2:3,rt.namespace=Mr.join("."),rt.rnamespace=rt.namespace?new RegExp("(^|\\.)"+Mr.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,rt.result=void 0,rt.target||(rt.target=tn),Vt=Vt==null?[rt]:W.makeArray(Vt,[rt]),Jn=W.event.special[ga]||{},!(!wn&&Jn.trigger&&Jn.trigger.apply(tn,Vt)===!1))){if(!wn&&!Jn.noBubble&&!J(tn)){for(da=Jn.delegateType||ga,Si.test(da+ga)||(zn=zn.parentNode);zn;zn=zn.parentNode)Gr.push(zn),xr=zn;xr===(tn.ownerDocument||$)&&Gr.push(xr.defaultView||xr.parentWindow||O)}for(qn=0;(zn=Gr[qn++])&&!rt.isPropagationStopped();)Ir=zn,rt.type=qn>1?da:Jn.bindType||ga,Fn=(gt.get(zn,"events")||Object.create(null))[rt.type]&>.get(zn,"handle"),Fn&&Fn.apply(zn,Vt),Fn=en&&zn[en],Fn&&Fn.apply&&_t(zn)&&(rt.result=Fn.apply(zn,Vt),rt.result===!1&&rt.preventDefault());return rt.type=ga,!wn&&!rt.isDefaultPrevented()&&(!Jn._default||Jn._default.apply(Gr.pop(),Vt)===!1)&&_t(tn)&&en&&U(tn[ga])&&!J(tn)&&(xr=tn[en],xr&&(tn[en]=null),W.event.triggered=ga,rt.isPropagationStopped()&&Ir.addEventListener(ga,qi),tn[ga](),rt.isPropagationStopped()&&Ir.removeEventListener(ga,qi),W.event.triggered=void 0,xr&&(tn[en]=xr)),rt.result}},simulate:function(rt,Vt,tn){var wn=W.extend(new W.Event,tn,{type:rt,isSimulated:!0});W.event.trigger(wn,null,Vt)}}),W.fn.extend({trigger:function(rt,Vt){return this.each(function(){W.event.trigger(rt,Vt,this)})},triggerHandler:function(rt,Vt){var tn=this[0];if(tn)return W.event.trigger(rt,Vt,tn,!0)}});var eo=/\[\]$/,xo=/\r?\n/g,cs=/^(?:submit|button|image|reset|file)$/i,ba=/^(?:input|select|textarea|keygen)/i;function sa($t,rt,Vt,tn){var wn;if(Array.isArray(rt))W.each(rt,function(qn,zn){Vt||eo.test($t)?tn($t,zn):sa($t+"["+(typeof zn=="object"&&zn!=null?qn:"")+"]",zn,Vt,tn)});else if(!Vt&&ie(rt)==="object")for(wn in rt)sa($t+"["+wn+"]",rt[wn],Vt,tn);else tn($t,rt)}W.param=function($t,rt){var Vt,tn=[],wn=function(zn,xr){var da=U(xr)?xr():xr;tn[tn.length]=encodeURIComponent(zn)+"="+encodeURIComponent(da==null?"":da)};if($t==null)return"";if(Array.isArray($t)||$t.jquery&&!W.isPlainObject($t))W.each($t,function(){wn(this.name,this.value)});else for(Vt in $t)sa(Vt,$t[Vt],rt,wn);return tn.join("&")},W.fn.extend({serialize:function(){return W.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var rt=W.prop(this,"elements");return rt?W.makeArray(rt):this}).filter(function(){var rt=this.type;return this.name&&!W(this).is(":disabled")&&ba.test(this.nodeName)&&!cs.test(rt)&&(this.checked||!$n.test(rt))}).map(function(rt,Vt){var tn=W(this).val();return tn==null?null:Array.isArray(tn)?W.map(tn,function(wn){return{name:Vt.name,value:wn.replace(xo,`\r -`)}}):{name:Vt.name,value:tn.replace(xo,`\r -`)}}).get()}});var Da=/%20/g,On=/#.*$/,xn=/([?&])_=[^&]*/,Rt=/^(.*?):[ \t]*([^\r\n]*)$/mg,mr=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ta=/^(?:GET|HEAD)$/,ma=/^\/\//,Oa={},Pn={},Kr="*/".concat("*"),Vn=$.createElement("a");Vn.href=ao.href;function tr($t){return function(rt,Vt){typeof rt!="string"&&(Vt=rt,rt="*");var tn,wn=0,qn=rt.toLowerCase().match(ht)||[];if(U(Vt))for(;tn=qn[wn++];)tn[0]==="+"?(tn=tn.slice(1)||"*",($t[tn]=$t[tn]||[]).unshift(Vt)):($t[tn]=$t[tn]||[]).push(Vt)}}function Ea($t,rt,Vt,tn){var wn={},qn=$t===Pn;function zn(xr){var da;return wn[xr]=!0,W.each($t[xr]||[],function(en,Fn){var Jn=Fn(rt,Vt,tn);if(typeof Jn=="string"&&!qn&&!wn[Jn])return rt.dataTypes.unshift(Jn),zn(Jn),!1;if(qn)return!(da=Jn)}),da}return zn(rt.dataTypes[0])||!wn["*"]&&zn("*")}function Ja($t,rt){var Vt,tn,wn=W.ajaxSettings.flatOptions||{};for(Vt in rt)rt[Vt]!==void 0&&((wn[Vt]?$t:tn||(tn={}))[Vt]=rt[Vt]);return tn&&W.extend(!0,$t,tn),$t}function go($t,rt,Vt){for(var tn,wn,qn,zn,xr=$t.contents,da=$t.dataTypes;da[0]==="*";)da.shift(),tn===void 0&&(tn=$t.mimeType||rt.getResponseHeader("Content-Type"));if(tn){for(wn in xr)if(xr[wn]&&xr[wn].test(tn)){da.unshift(wn);break}}if(da[0]in Vt)qn=da[0];else{for(wn in Vt){if(!da[0]||$t.converters[wn+" "+da[0]]){qn=wn;break}zn||(zn=wn)}qn=qn||zn}if(qn)return qn!==da[0]&&da.unshift(qn),Vt[qn]}function fi($t,rt,Vt,tn){var wn,qn,zn,xr,da,en={},Fn=$t.dataTypes.slice();if(Fn[1])for(zn in $t.converters)en[zn.toLowerCase()]=$t.converters[zn];for(qn=Fn.shift();qn;)if($t.responseFields[qn]&&(Vt[$t.responseFields[qn]]=rt),!da&&tn&&$t.dataFilter&&(rt=$t.dataFilter(rt,$t.dataType)),da=qn,qn=Fn.shift(),qn){if(qn==="*")qn=da;else if(da!=="*"&&da!==qn){if(zn=en[da+" "+qn]||en["* "+qn],!zn){for(wn in en)if(xr=wn.split(" "),xr[1]===qn&&(zn=en[da+" "+xr[0]]||en["* "+xr[0]],zn)){zn===!0?zn=en[wn]:en[wn]!==!0&&(qn=xr[0],Fn.unshift(xr[1]));break}}if(zn!==!0)if(zn&&$t.throws)rt=zn(rt);else try{rt=zn(rt)}catch(Jn){return{state:"parsererror",error:zn?Jn:"No conversion from "+da+" to "+qn}}}}return{state:"success",data:rt}}W.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ao.href,type:"GET",isLocal:mr.test(ao.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kr,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":W.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(rt,Vt){return Vt?Ja(Ja(rt,W.ajaxSettings),Vt):Ja(W.ajaxSettings,rt)},ajaxPrefilter:tr(Oa),ajaxTransport:tr(Pn),ajax:function(rt,Vt){typeof rt=="object"&&(Vt=rt,rt=void 0),Vt=Vt||{};var tn,wn,qn,zn,xr,da,en,Fn,Jn,Ir,Gr=W.ajaxSetup({},Vt),ga=Gr.context||Gr,Mr=Gr.context&&(ga.nodeType||ga.jquery)?W(ga):W.event,$a=W.Deferred(),Ya=W.Callbacks("once memory"),_o=Gr.statusCode||{},Ni={},ec={},ks="canceled",jo={readyState:0,getResponseHeader:function(Pa){var Qa;if(en){if(!zn)for(zn={};Qa=Rt.exec(qn);)zn[Qa[1].toLowerCase()+" "]=(zn[Qa[1].toLowerCase()+" "]||[]).concat(Qa[2]);Qa=zn[Pa.toLowerCase()+" "]}return Qa==null?null:Qa.join(", ")},getAllResponseHeaders:function(){return en?qn:null},setRequestHeader:function(Pa,Qa){return en==null&&(Pa=ec[Pa.toLowerCase()]=ec[Pa.toLowerCase()]||Pa,Ni[Pa]=Qa),this},overrideMimeType:function(Pa){return en==null&&(Gr.mimeType=Pa),this},statusCode:function(Pa){var Qa;if(Pa)if(en)jo.always(Pa[jo.status]);else for(Qa in Pa)_o[Qa]=[_o[Qa],Pa[Qa]];return this},abort:function(Pa){var Qa=Pa||ks;return tn&&tn.abort(Qa),Qn(0,Qa),this}};if($a.promise(jo),Gr.url=((rt||Gr.url||ao.href)+"").replace(ma,ao.protocol+"//"),Gr.type=Vt.method||Vt.type||Gr.method||Gr.type,Gr.dataTypes=(Gr.dataType||"*").toLowerCase().match(ht)||[""],Gr.crossDomain==null){da=$.createElement("a");try{da.href=Gr.url,da.href=da.href,Gr.crossDomain=Vn.protocol+"//"+Vn.host!=da.protocol+"//"+da.host}catch(ka){Gr.crossDomain=!0}}if(Gr.data&&Gr.processData&&typeof Gr.data!="string"&&(Gr.data=W.param(Gr.data,Gr.traditional)),Ea(Oa,Gr,Vt,jo),en)return jo;Fn=W.event&&Gr.global,Fn&&W.active++==0&&W.event.trigger("ajaxStart"),Gr.type=Gr.type.toUpperCase(),Gr.hasContent=!ta.test(Gr.type),wn=Gr.url.replace(On,""),Gr.hasContent?Gr.data&&Gr.processData&&(Gr.contentType||"").indexOf("application/x-www-form-urlencoded")===0&&(Gr.data=Gr.data.replace(Da,"+")):(Ir=Gr.url.slice(wn.length),Gr.data&&(Gr.processData||typeof Gr.data=="string")&&(wn+=(Fi.test(wn)?"&":"?")+Gr.data,delete Gr.data),Gr.cache===!1&&(wn=wn.replace(xn,"$1"),Ir=(Fi.test(wn)?"&":"?")+"_="+Zi.guid+++Ir),Gr.url=wn+Ir),Gr.ifModified&&(W.lastModified[wn]&&jo.setRequestHeader("If-Modified-Since",W.lastModified[wn]),W.etag[wn]&&jo.setRequestHeader("If-None-Match",W.etag[wn])),(Gr.data&&Gr.hasContent&&Gr.contentType!==!1||Vt.contentType)&&jo.setRequestHeader("Content-Type",Gr.contentType),jo.setRequestHeader("Accept",Gr.dataTypes[0]&&Gr.accepts[Gr.dataTypes[0]]?Gr.accepts[Gr.dataTypes[0]]+(Gr.dataTypes[0]!=="*"?", "+Kr+"; q=0.01":""):Gr.accepts["*"]);for(Jn in Gr.headers)jo.setRequestHeader(Jn,Gr.headers[Jn]);if(Gr.beforeSend&&(Gr.beforeSend.call(ga,jo,Gr)===!1||en))return jo.abort();if(ks="abort",Ya.add(Gr.complete),jo.done(Gr.success),jo.fail(Gr.error),tn=Ea(Pn,Gr,Vt,jo),!tn)Qn(-1,"No Transport");else{if(jo.readyState=1,Fn&&Mr.trigger("ajaxSend",[jo,Gr]),en)return jo;Gr.async&&Gr.timeout>0&&(xr=O.setTimeout(function(){jo.abort("timeout")},Gr.timeout));try{en=!1,tn.send(Ni,Qn)}catch(ka){if(en)throw ka;Qn(-1,ka)}}function Qn(ka,Pa,Qa,Ei){var zo,fo,gs,Ks,pc,tc=Pa;en||(en=!0,xr&&O.clearTimeout(xr),tn=void 0,qn=Ei||"",jo.readyState=ka>0?4:0,zo=ka>=200&&ka<300||ka===304,Qa&&(Ks=go(Gr,jo,Qa)),!zo&&W.inArray("script",Gr.dataTypes)>-1&&W.inArray("json",Gr.dataTypes)<0&&(Gr.converters["text script"]=function(){}),Ks=fi(Gr,Ks,jo,zo),zo?(Gr.ifModified&&(pc=jo.getResponseHeader("Last-Modified"),pc&&(W.lastModified[wn]=pc),pc=jo.getResponseHeader("etag"),pc&&(W.etag[wn]=pc)),ka===204||Gr.type==="HEAD"?tc="nocontent":ka===304?tc="notmodified":(tc=Ks.state,fo=Ks.data,gs=Ks.error,zo=!gs)):(gs=tc,(ka||!tc)&&(tc="error",ka<0&&(ka=0))),jo.status=ka,jo.statusText=(Pa||tc)+"",zo?$a.resolveWith(ga,[fo,tc,jo]):$a.rejectWith(ga,[jo,tc,gs]),jo.statusCode(_o),_o=void 0,Fn&&Mr.trigger(zo?"ajaxSuccess":"ajaxError",[jo,Gr,zo?fo:gs]),Ya.fireWith(ga,[jo,tc]),Fn&&(Mr.trigger("ajaxComplete",[jo,Gr]),--W.active||W.event.trigger("ajaxStop")))}return jo},getJSON:function(rt,Vt,tn){return W.get(rt,Vt,tn,"json")},getScript:function(rt,Vt){return W.get(rt,void 0,Vt,"script")}}),W.each(["get","post"],function($t,rt){W[rt]=function(Vt,tn,wn,qn){return U(tn)&&(qn=qn||wn,wn=tn,tn=void 0),W.ajax(W.extend({url:Vt,type:rt,dataType:qn,data:tn,success:wn},W.isPlainObject(Vt)&&Vt))}}),W.ajaxPrefilter(function($t){var rt;for(rt in $t.headers)rt.toLowerCase()==="content-type"&&($t.contentType=$t.headers[rt]||"")}),W._evalUrl=function($t,rt,Vt){return W.ajax({url:$t,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(wn){W.globalEval(wn,rt,Vt)}})},W.fn.extend({wrapAll:function(rt){var Vt;return this[0]&&(U(rt)&&(rt=rt.call(this[0])),Vt=W(rt,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&Vt.insertBefore(this[0]),Vt.map(function(){for(var tn=this;tn.firstElementChild;)tn=tn.firstElementChild;return tn}).append(this)),this},wrapInner:function(rt){return U(rt)?this.each(function(Vt){W(this).wrapInner(rt.call(this,Vt))}):this.each(function(){var Vt=W(this),tn=Vt.contents();tn.length?tn.wrapAll(rt):Vt.append(rt)})},wrap:function(rt){var Vt=U(rt);return this.each(function(tn){W(this).wrapAll(Vt?rt.call(this,tn):rt)})},unwrap:function(rt){return this.parent(rt).not("body").each(function(){W(this).replaceWith(this.childNodes)}),this}}),W.expr.pseudos.hidden=function($t){return!W.expr.pseudos.visible($t)},W.expr.pseudos.visible=function($t){return!!($t.offsetWidth||$t.offsetHeight||$t.getClientRects().length)},W.ajaxSettings.xhr=function(){try{return new O.XMLHttpRequest}catch($t){}};var lo={0:200,1223:204},Oi=W.ajaxSettings.xhr();B.cors=!!Oi&&"withCredentials"in Oi,B.ajax=Oi=!!Oi,W.ajaxTransport(function($t){var rt,Vt;if(B.cors||Oi&&!$t.crossDomain)return{send:function(wn,qn){var zn,xr=$t.xhr();if(xr.open($t.type,$t.url,$t.async,$t.username,$t.password),$t.xhrFields)for(zn in $t.xhrFields)xr[zn]=$t.xhrFields[zn];$t.mimeType&&xr.overrideMimeType&&xr.overrideMimeType($t.mimeType),!$t.crossDomain&&!wn["X-Requested-With"]&&(wn["X-Requested-With"]="XMLHttpRequest");for(zn in wn)xr.setRequestHeader(zn,wn[zn]);rt=function(en){return function(){rt&&(rt=Vt=xr.onload=xr.onerror=xr.onabort=xr.ontimeout=xr.onreadystatechange=null,en==="abort"?xr.abort():en==="error"?typeof xr.status!="number"?qn(0,"error"):qn(xr.status,xr.statusText):qn(lo[xr.status]||xr.status,xr.statusText,(xr.responseType||"text")!=="text"||typeof xr.responseText!="string"?{binary:xr.response}:{text:xr.responseText},xr.getAllResponseHeaders()))}},xr.onload=rt(),Vt=xr.onerror=xr.ontimeout=rt("error"),xr.onabort!==void 0?xr.onabort=Vt:xr.onreadystatechange=function(){xr.readyState===4&&O.setTimeout(function(){rt&&Vt()})},rt=rt("abort");try{xr.send($t.hasContent&&$t.data||null)}catch(da){if(rt)throw da}},abort:function(){rt&&rt()}}}),W.ajaxPrefilter(function($t){$t.crossDomain&&($t.contents.script=!1)}),W.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(rt){return W.globalEval(rt),rt}}}),W.ajaxPrefilter("script",function($t){$t.cache===void 0&&($t.cache=!1),$t.crossDomain&&($t.type="GET")}),W.ajaxTransport("script",function($t){if($t.crossDomain||$t.scriptAttrs){var rt,Vt;return{send:function(wn,qn){rt=W("",de=de.removeChild(de.firstChild)):typeof Kt.is=="string"?de=ja.createElement(Je,{is:Kt.is}):(de=ja.createElement(Je),Je==="select"&&(ja=de,Kt.multiple?ja.multiple=!0:Kt.size&&(ja.size=Kt.size))):de=ja.createElementNS(de,Je),de[Jo]=Ce,de[dn]=Kt,wv(de,Ce,!1,!1),Ce.stateNode=de,ja=$n(Je,Kt),Je){case"dialog":Hl("cancel",de),Hl("close",de),Mn=Kt;break;case"iframe":case"object":case"embed":Hl("load",de),Mn=Kt;break;case"video":case"audio":for(Mn=0;MnOc&&(Ce.flags|=64,Rr=!0,Hp(Kt,!1),Ce.lanes=33554432)}else{if(!Rr)if(de=Il(ja),de!==null){if(Ce.flags|=64,Rr=!0,Je=de.updateQueue,Je!==null&&(Ce.updateQueue=Je,Ce.flags|=4),Hp(Kt,!0),Kt.tail===null&&Kt.tailMode==="hidden"&&!ja.alternate&&!Du)return Ce=Ce.lastEffect=Kt.lastEffect,Ce!==null&&(Ce.nextEffect=null),null}else 2*ji()-Kt.renderingStartTime>Oc&&Je!==1073741824&&(Ce.flags|=64,Rr=!0,Hp(Kt,!1),Ce.lanes=33554432);Kt.isBackwards?(ja.sibling=Ce.child,Ce.child=ja):(Je=Kt.last,Je!==null?Je.sibling=ja:Ce.child=ja,Kt.last=ja)}return Kt.tail!==null?(Je=Kt.tail,Kt.rendering=Je,Kt.tail=Je.sibling,Kt.lastEffect=Ce.lastEffect,Kt.renderingStartTime=ji(),Je.sibling=null,Ce=oc.current,Fo(oc,Rr?Ce&1|2:Ce&1),Je):null;case 23:case 24:return Xl(),de!==null&&de.memoizedState!==null!=(Ce.memoizedState!==null)&&Kt.mode!=="unstable-defer-without-hiding"&&(Ce.flags|=4),null}throw Error(C(156,Ce.tag))}function Gp(de){switch(de.tag){case 1:yr(de.type)&&Ls();var Ce=de.flags;return Ce&4096?(de.flags=Ce&-4097|64,de):null;case 3:if(Yo(),Io(ys),Io(ms),wt(),Ce=de.flags,(Ce&64)!=0)throw Error(C(285));return de.flags=Ce&-4097|64,de;case 5:return ds(de),null;case 13:return Io(oc),Ce=de.flags,Ce&4096?(de.flags=Ce&-4097|64,de):null;case 19:return Io(oc),null;case 4:return Yo(),null;case 10:return Lu(de),null;case 23:case 24:return Xl(),null;default:return null}}function Ap(de,Ce){try{var Je="",Kt=Ce;do Je+=Xe(Kt),Kt=Kt.return;while(Kt);var Mn=Je}catch(Rr){Mn=` -Error generating stack: `+Rr.message+` -`+Rr.stack}return{value:de,source:Ce,stack:Mn}}function hv(de,Ce){try{console.error(Ce.value)}catch(Je){setTimeout(function(){throw Je})}}var kp=typeof WeakMap=="function"?WeakMap:Map;function bp(de,Ce,Je){Je=Bd(-1,Je),Je.tag=3,Je.payload={element:null};var Kt=Ce.value;return Je.callback=function(){No||(No=!0,vc=Kt),hv(de,Ce)},Je}function jf(de,Ce,Je){Je=Bd(-1,Je),Je.tag=3;var Kt=de.type.getDerivedStateFromError;if(typeof Kt=="function"){var Mn=Ce.value;Je.payload=function(){return hv(de,Ce),Kt(Mn)}}var Rr=de.stateNode;return Rr!==null&&typeof Rr.componentDidCatch=="function"&&(Je.callback=function(){typeof Kt!="function"&&(kt===null?kt=new Set([this]):kt.add(this),hv(de,Ce));var ja=Ce.stack;this.componentDidCatch(Ce.value,{componentStack:ja!==null?ja:""})}),Je}var qf=typeof WeakSet=="function"?WeakSet:Set;function Eh(de){var Ce=de.ref;if(Ce!==null)if(typeof Ce=="function")try{Ce(null)}catch(Je){xu(de,Je)}else Ce.current=null}function Av(de,Ce){switch(Ce.tag){case 0:case 11:case 15:case 22:return;case 1:if(Ce.flags&256&&de!==null){var Je=de.memoizedProps,Kt=de.memoizedState;de=Ce.stateNode,Ce=de.getSnapshotBeforeUpdate(Ce.elementType===Ce.type?Je:Rl(Ce.type,Je),Kt),de.__reactInternalSnapshotBeforeUpdate=Ce}return;case 3:Ce.flags&256&&Ra(Ce.stateNode.containerInfo);return;case 5:case 6:case 4:case 17:return}throw Error(C(163))}function Lg(de,Ce,Je){switch(Je.tag){case 0:case 11:case 15:case 22:if(Ce=Je.updateQueue,Ce=Ce!==null?Ce.lastEffect:null,Ce!==null){de=Ce=Ce.next;do{if((de.tag&3)==3){var Kt=de.create;de.destroy=Kt()}de=de.next}while(de!==Ce)}if(Ce=Je.updateQueue,Ce=Ce!==null?Ce.lastEffect:null,Ce!==null){de=Ce=Ce.next;do{var Mn=de;Kt=Mn.next,Mn=Mn.tag,(Mn&4)!=0&&(Mn&1)!=0&&(rs(Je,de),oi(Je,de)),de=Kt}while(de!==Ce)}return;case 1:de=Je.stateNode,Je.flags&4&&(Ce===null?de.componentDidMount():(Kt=Je.elementType===Je.type?Ce.memoizedProps:Rl(Je.type,Ce.memoizedProps),de.componentDidUpdate(Kt,Ce.memoizedState,de.__reactInternalSnapshotBeforeUpdate))),Ce=Je.updateQueue,Ce!==null&&ld(Je,Ce,de);return;case 3:if(Ce=Je.updateQueue,Ce!==null){if(de=null,Je.child!==null)switch(Je.child.tag){case 5:de=Je.child.stateNode;break;case 1:de=Je.child.stateNode}ld(Je,Ce,de)}return;case 5:de=Je.stateNode,Ce===null&&Je.flags&4&&yn(Je.type,Je.memoizedProps)&&de.focus();return;case 6:return;case 4:return;case 12:return;case 13:Je.memoizedState===null&&(Je=Je.alternate,Je!==null&&(Je=Je.memoizedState,Je!==null&&(Je=Je.dehydrated,Je!==null&&ar(Je))));return;case 19:case 17:case 20:case 21:case 23:case 24:return}throw Error(C(163))}function Fg(de,Ce){for(var Je=de;;){if(Je.tag===5){var Kt=Je.stateNode;if(Ce)Kt=Kt.style,typeof Kt.setProperty=="function"?Kt.setProperty("display","none","important"):Kt.display="none";else{Kt=Je.stateNode;var Mn=Je.memoizedProps.style;Mn=Mn!=null&&Mn.hasOwnProperty("display")?Mn.display:null,Kt.style.display=Pt("display",Mn)}}else if(Je.tag===6)Je.stateNode.nodeValue=Ce?"":Je.memoizedProps;else if((Je.tag!==23&&Je.tag!==24||Je.memoizedState===null||Je===de)&&Je.child!==null){Je.child.return=Je,Je=Je.child;continue}if(Je===de)break;for(;Je.sibling===null;){if(Je.return===null||Je.return===de)return;Je=Je.return}Je.sibling.return=Je.return,Je=Je.sibling}}function xh(de,Ce){if(qr&&typeof qr.onCommitFiberUnmount=="function")try{qr.onCommitFiberUnmount(cr,Ce)}catch(Rr){}switch(Ce.tag){case 0:case 11:case 14:case 15:case 22:if(de=Ce.updateQueue,de!==null&&(de=de.lastEffect,de!==null)){var Je=de=de.next;do{var Kt=Je,Mn=Kt.destroy;if(Kt=Kt.tag,Mn!==void 0)if((Kt&4)!=0)rs(Ce,Je);else{Kt=Ce;try{Mn()}catch(Rr){xu(Kt,Rr)}}Je=Je.next}while(Je!==de)}break;case 1:if(Eh(Ce),de=Ce.stateNode,typeof de.componentWillUnmount=="function")try{de.props=Ce.memoizedProps,de.state=Ce.memoizedState,de.componentWillUnmount()}catch(Rr){xu(Ce,Rr)}break;case 5:Eh(Ce);break;case 4:Jv(de,Ce)}}function gv(de){de.alternate=null,de.child=null,de.dependencies=null,de.firstEffect=null,de.lastEffect=null,de.memoizedProps=null,de.memoizedState=null,de.pendingProps=null,de.return=null,de.updateQueue=null}function vh(de){return de.tag===5||de.tag===3||de.tag===4}function Uh(de){e:{for(var Ce=de.return;Ce!==null;){if(vh(Ce))break e;Ce=Ce.return}throw Error(C(160))}var Je=Ce;switch(Ce=Je.stateNode,Je.tag){case 5:var Kt=!1;break;case 3:Ce=Ce.containerInfo,Kt=!0;break;case 4:Ce=Ce.containerInfo,Kt=!0;break;default:throw Error(C(161))}Je.flags&16&&(Ot(Ce,""),Je.flags&=-17);e:t:for(Je=de;;){for(;Je.sibling===null;){if(Je.return===null||vh(Je.return)){Je=null;break e}Je=Je.return}for(Je.sibling.return=Je.return,Je=Je.sibling;Je.tag!==5&&Je.tag!==6&&Je.tag!==18;){if(Je.flags&2||Je.child===null||Je.tag===4)continue t;Je.child.return=Je,Je=Je.child}if(!(Je.flags&2)){Je=Je.stateNode;break e}}Kt?Sh(de,Je,Ce):mv(de,Je,Ce)}function Sh(de,Ce,Je){var Kt=de.tag,Mn=Kt===5||Kt===6;if(Mn)de=Mn?de.stateNode:de.stateNode.instance,Ce?Je.nodeType===8?Je.parentNode.insertBefore(de,Ce):Je.insertBefore(de,Ce):(Je.nodeType===8?(Ce=Je.parentNode,Ce.insertBefore(de,Je)):(Ce=Je,Ce.appendChild(de)),Je=Je._reactRootContainer,Je!=null||Ce.onclick!==null||(Ce.onclick=El));else if(Kt!==4&&(de=de.child,de!==null))for(Sh(de,Ce,Je),de=de.sibling;de!==null;)Sh(de,Ce,Je),de=de.sibling}function mv(de,Ce,Je){var Kt=de.tag,Mn=Kt===5||Kt===6;if(Mn)de=Mn?de.stateNode:de.stateNode.instance,Ce?Je.insertBefore(de,Ce):Je.appendChild(de);else if(Kt!==4&&(de=de.child,de!==null))for(mv(de,Ce,Je),de=de.sibling;de!==null;)mv(de,Ce,Je),de=de.sibling}function Jv(de,Ce){for(var Je=Ce,Kt=!1,Mn,Rr;;){if(!Kt){Kt=Je.return;e:for(;;){if(Kt===null)throw Error(C(160));switch(Mn=Kt.stateNode,Kt.tag){case 5:Rr=!1;break e;case 3:Mn=Mn.containerInfo,Rr=!0;break e;case 4:Mn=Mn.containerInfo,Rr=!0;break e}Kt=Kt.return}Kt=!0}if(Je.tag===5||Je.tag===6){e:for(var ja=de,ci=Je,yo=ci;;)if(xh(ja,yo),yo.child!==null&&yo.tag!==4)yo.child.return=yo,yo=yo.child;else{if(yo===ci)break e;for(;yo.sibling===null;){if(yo.return===null||yo.return===ci)break e;yo=yo.return}yo.sibling.return=yo.return,yo=yo.sibling}Rr?(ja=Mn,ci=Je.stateNode,ja.nodeType===8?ja.parentNode.removeChild(ci):ja.removeChild(ci)):Mn.removeChild(Je.stateNode)}else if(Je.tag===4){if(Je.child!==null){Mn=Je.stateNode.containerInfo,Rr=!0,Je.child.return=Je,Je=Je.child;continue}}else if(xh(de,Je),Je.child!==null){Je.child.return=Je,Je=Je.child;continue}if(Je===Ce)break;for(;Je.sibling===null;){if(Je.return===null||Je.return===Ce)return;Je=Je.return,Je.tag===4&&(Kt=!1)}Je.sibling.return=Je.return,Je=Je.sibling}}function mg(de,Ce){switch(Ce.tag){case 0:case 11:case 14:case 15:case 22:var Je=Ce.updateQueue;if(Je=Je!==null?Je.lastEffect:null,Je!==null){var Kt=Je=Je.next;do(Kt.tag&3)==3&&(de=Kt.destroy,Kt.destroy=void 0,de!==void 0&&de()),Kt=Kt.next;while(Kt!==Je)}return;case 1:return;case 5:if(Je=Ce.stateNode,Je!=null){Kt=Ce.memoizedProps;var Mn=de!==null?de.memoizedProps:Kt;de=Ce.type;var Rr=Ce.updateQueue;if(Ce.updateQueue=null,Rr!==null){for(Je[dn]=Kt,de==="input"&&Kt.type==="radio"&&Kt.name!=null&&Re(Je,Kt),$n(de,Mn),Ce=$n(de,Kt),Mn=0;MnMn&&(Mn=ja),Je&=~Rr}if(Je=Mn,Je=ji()-Je,Je=(120>Je?120:480>Je?480:1080>Je?1080:1920>Je?1920:3e3>Je?3e3:4320>Je?4320:1960*gh(Je/1960))-Je,10 component higher in the tree to provide a loading indicator or placeholder to display.`)}So!==5&&(So=2),yo=Ap(yo,ci),Gc=ja;do{switch(Gc.tag){case 3:Rr=yo,Gc.flags|=4096,Ce&=-Ce,Gc.lanes|=Ce;var Td=bp(Gc,Rr,Ce);xd(Gc,Td);break e;case 1:Rr=yo;var Ou=Gc.type,Sd=Gc.stateNode;if((Gc.flags&64)==0&&(typeof Ou.getDerivedStateFromError=="function"||Sd!==null&&typeof Sd.componentDidCatch=="function"&&(kt===null||!kt.has(Sd)))){Gc.flags|=4096,Ce&=-Ce,Gc.lanes|=Ce;var Vd=jf(Gc,Rr,Ce);xd(Gc,Vd);break e}}Gc=Gc.return}while(Gc!==null)}Jl(Je)}catch(Rd){Ce=Rd,Br===Je&&Je!==null&&(Br=Je=Je.return);continue}break}while(1)}function Zd(){var de=kv.current;return kv.current=Gu,de===null?Gu:de}function Zl(de,Ce){var Je=od;od|=16;var Kt=Zd();_r===de&&ei===Ce||vd(de,Ce);do try{wf();break}catch(Mn){ff(de,Mn)}while(1);if(Od(),od=Je,kv.current=Kt,Br!==null)throw Error(C(261));return _r=null,ei=0,So}function wf(){for(;Br!==null;)Al(Br)}function Wd(){for(;Br!==null&&!As();)Al(Br)}function Al(de){var Ce=Ai(de.alternate,de,Ao);de.memoizedProps=de.pendingProps,Ce===null?Jl(de):Br=Ce,$p.current=null}function Jl(de){var Ce=de;do{var Je=Ce.alternate;if(de=Ce.return,(Ce.flags&2048)==0){if(Je=Tv(Je,Ce,Ao),Je!==null){Br=Je;return}if(Je=Ce,Je.tag!==24&&Je.tag!==23||Je.memoizedState===null||(Ao&1073741824)!=0||(Je.mode&4)==0){for(var Kt=0,Mn=Je.child;Mn!==null;)Kt|=Mn.lanes|Mn.childLanes,Mn=Mn.sibling;Je.childLanes=Kt}de!==null&&(de.flags&2048)==0&&(de.firstEffect===null&&(de.firstEffect=Ce.firstEffect),Ce.lastEffect!==null&&(de.lastEffect!==null&&(de.lastEffect.nextEffect=Ce.firstEffect),de.lastEffect=Ce.lastEffect),1ja&&(ci=ja,ja=Td,Td=ci),ci=ps(Wo,Td),Rr=ps(Wo,ja),ci&&Rr&&(jc.rangeCount!==1||jc.anchorNode!==ci.node||jc.anchorOffset!==ci.offset||jc.focusNode!==Rr.node||jc.focusOffset!==Rr.offset)&&(ic=ic.createRange(),ic.setStart(ci.node,ci.offset),jc.removeAllRanges(),Td>ja?(jc.addRange(ic),jc.extend(Rr.node,Rr.offset)):(ic.setEnd(Rr.node,Rr.offset),jc.addRange(ic)))))),ic=[],jc=Wo;jc=jc.parentNode;)jc.nodeType===1&&ic.push({element:jc,left:jc.scrollLeft,top:jc.scrollTop});for(typeof Wo.focus=="function"&&Wo.focus(),Wo=0;Woji()-Hc?vd(de,0):qs|=Je),ac(de,Ce)}function wa(de,Ce){var Je=de.stateNode;Je!==null&&Je.delete(Ce),Ce=0,Ce===0&&(Ce=de.mode,(Ce&2)==0?Ce=1:(Ce&4)==0?Ce=xa()===99?1:2:(ha===0&&(ha=Fs),Ce=ma(62914560&~ha),Ce===0&&(Ce=4194304))),Je=Xi(),de=Os(de,Ce),de!==null&&(Pn(de,Ce,Je),ac(de,Je))}var Ai;Ai=function(de,Ce,Je){var Kt=Ce.lanes;if(de!==null)if(de.memoizedProps!==Ce.pendingProps||ys.current)Vu=!0;else if((Je&Kt)!=0)Vu=(de.flags&16384)!=0;else{switch(Vu=!1,Ce.tag){case 3:ph(Ce),Ae();break;case 5:Mi(Ce);break;case 1:yr(Ce.type)&&Hs(Ce);break;case 4:Vr(Ce,Ce.stateNode.containerInfo);break;case 10:Kt=Ce.memoizedProps.value;var Mn=Ce.type._context;Fo(Ol,Mn._currentValue),Mn._currentValue=Kt;break;case 13:if(Ce.memoizedState!==null)return(Je&Ce.child.childLanes)!=0?Xv(de,Ce,Je):(Fo(oc,oc.current&1),Ce=Pp(de,Ce,Je),Ce!==null?Ce.sibling:null);Fo(oc,oc.current&1);break;case 19:if(Kt=(Je&Ce.childLanes)!=0,(de.flags&64)!=0){if(Kt)return Sv(de,Ce,Je);Ce.flags|=64}if(Mn=Ce.memoizedState,Mn!==null&&(Mn.rendering=null,Mn.tail=null,Mn.lastEffect=null),Fo(oc,oc.current),Kt)break;return null;case 23:case 24:return Ce.lanes=0,Tp(de,Ce,Je)}return Pp(de,Ce,Je)}else Vu=!1;switch(Ce.lanes=0,Ce.tag){case 2:if(Kt=Ce.type,de!==null&&(de.alternate=null,Ce.alternate=null,Ce.flags|=2),de=Ce.pendingProps,Mn=Po(Ce,ms.current),af(Ce,Je),Mn=ev(null,Ce,Kt,de,Mn,Je),Ce.flags|=1,typeof Mn=="object"&&Mn!==null&&typeof Mn.render=="function"&&Mn.$$typeof===void 0){if(Ce.tag=1,Ce.memoizedState=null,Ce.updateQueue=null,yr(Kt)){var Rr=!0;Hs(Ce)}else Rr=!1;Ce.memoizedState=Mn.state!==null&&Mn.state!==void 0?Mn.state:null,kd(Ce);var ja=Kt.getDerivedStateFromProps;typeof ja=="function"&&ll(Ce,Kt,ja,de),Mn.updater=ad,Ce.stateNode=Mn,Mn._reactInternals=Ce,Uu(Ce,Kt,de,Je),Ce=tv(null,Ce,Kt,!0,Rr,Je)}else Ce.tag=0,lf(null,Ce,Mn,Je),Ce=Ce.child;return Ce;case 16:Mn=Ce.elementType;e:{switch(de!==null&&(de.alternate=null,Ce.alternate=null,Ce.flags|=2),de=Ce.pendingProps,Rr=Mn._init,Mn=Rr(Mn._payload),Ce.type=Mn,Rr=Ce.tag=ki(Mn),de=Rl(Mn,de),Rr){case 0:Ce=vp(null,Ce,Mn,de,Je);break e;case 1:Ce=Uv(null,Ce,Mn,de,Je);break e;case 11:Ce=cp(null,Ce,Mn,de,Je);break e;case 14:Ce=Gf(null,Ce,Mn,Rl(Mn.type,de),Kt,Je);break e}throw Error(C(306,Mn,""))}return Ce;case 0:return Kt=Ce.type,Mn=Ce.pendingProps,Mn=Ce.elementType===Kt?Mn:Rl(Kt,Mn),vp(de,Ce,Kt,Mn,Je);case 1:return Kt=Ce.type,Mn=Ce.pendingProps,Mn=Ce.elementType===Kt?Mn:Rl(Kt,Mn),Uv(de,Ce,Kt,Mn,Je);case 3:if(ph(Ce),Kt=Ce.updateQueue,de===null||Kt===null)throw Error(C(282));if(Kt=Ce.pendingProps,Mn=Ce.memoizedState,Mn=Mn!==null?Mn.element:null,xf(de,Ce),of(Ce,Kt,null,Je),Kt=Ce.memoizedState.element,Kt===Mn)Ae(),Ce=Pp(de,Ce,Je);else{if(Mn=Ce.stateNode,(Rr=Mn.hydrate)&&(Nl=wi(Ce.stateNode.containerInfo.firstChild),pu=Ce,Rr=Du=!0),Rr){if(de=Mn.mutableSourceEagerHydrationData,de!=null)for(Mn=0;MnA;)O(y,A,arguments[A++]);return y.length=S,y}})},"z+Cf":function(ce,R,l){"use strict";Object.defineProperty(R,"__esModule",{value:!0}),R.cssValue=R.parseLengthAndUnit=void 0;var E={cm:!0,mm:!0,in:!0,px:!0,pt:!0,pc:!0,em:!0,ex:!0,ch:!0,rem:!0,vw:!0,vh:!0,vmin:!0,vmax:!0,"%":!0};function m(C){if(typeof C=="number")return{value:C,unit:"px"};var k,A=(C.match(/^[0-9.]*/)||"").toString();A.includes(".")?k=parseFloat(A):k=parseInt(A,10);var S=(C.match(/[^0-9]*$/)||"").toString();return E[S]?{value:k,unit:S}:(console.warn("React Spinners: "+C+" is not a valid css value. Defaulting to "+k+"px."),{value:k,unit:"px"})}R.parseLengthAndUnit=m;function O(C){var k=m(C);return""+k.value+k.unit}R.cssValue=O},"z/XJ":function(ce,R,l){"use strict";var E=l("TqRt"),m=l("cDf5");Object.defineProperty(R,"__esModule",{value:!0}),R.default=void 0;var O=E(l("3tO9")),C=y(l("q1tI")),k=E(l("g4LC")),A=E(l("KQxl"));function S(T){if(typeof WeakMap!="function")return null;var j=new WeakMap,D=new WeakMap;return(S=function(F){return F?D:j})(T)}function y(T,j){if(!j&&T&&T.__esModule)return T;if(T===null||m(T)!=="object"&&typeof T!="function")return{default:T};var D=S(j);if(D&&D.has(T))return D.get(T);var N={},F=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var B in T)if(B!=="default"&&Object.prototype.hasOwnProperty.call(T,B)){var U=F?Object.getOwnPropertyDescriptor(T,B):null;U&&(U.get||U.set)?Object.defineProperty(N,B,U):N[B]=T[B]}return N.default=T,D&&D.set(T,N),N}var w=function(j,D){return C.createElement(A.default,(0,O.default)((0,O.default)({},j),{},{ref:D,icon:k.default}))};w.displayName="CloseCircleOutlined";var x=C.forwardRef(w);R.default=x},"z01/":function(ce,R){function l(E){return ce.exports=l=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(m){return typeof m}:function(m){return m&&typeof Symbol=="function"&&m.constructor===Symbol&&m!==Symbol.prototype?"symbol":typeof m},ce.exports.__esModule=!0,ce.exports.default=ce.exports,l(E)}ce.exports=l,ce.exports.__esModule=!0,ce.exports.default=ce.exports},z4Hk:function(ce,R,l){"use strict";Object.defineProperty(R,"__esModule",{value:!0}),R.BindingWhenSyntax=void 0;var E=l("406g"),m=l("RR/i"),O=function(){function C(k){this._binding=k}return C.prototype.when=function(k){return this._binding.constraint=k,new E.BindingOnSyntax(this._binding)},C.prototype.whenTargetNamed=function(k){return this._binding.constraint=m.namedConstraint(k),new E.BindingOnSyntax(this._binding)},C.prototype.whenTargetIsDefault=function(){return this._binding.constraint=function(k){var A=k.target!==null&&!k.target.isNamed()&&!k.target.isTagged();return A},new E.BindingOnSyntax(this._binding)},C.prototype.whenTargetTagged=function(k,A){return this._binding.constraint=m.taggedConstraint(k)(A),new E.BindingOnSyntax(this._binding)},C.prototype.whenInjectedInto=function(k){return this._binding.constraint=function(A){return m.typeConstraint(k)(A.parentRequest)},new E.BindingOnSyntax(this._binding)},C.prototype.whenParentNamed=function(k){return this._binding.constraint=function(A){return m.namedConstraint(k)(A.parentRequest)},new E.BindingOnSyntax(this._binding)},C.prototype.whenParentTagged=function(k,A){return this._binding.constraint=function(S){return m.taggedConstraint(k)(A)(S.parentRequest)},new E.BindingOnSyntax(this._binding)},C.prototype.whenAnyAncestorIs=function(k){return this._binding.constraint=function(A){return m.traverseAncerstors(A,m.typeConstraint(k))},new E.BindingOnSyntax(this._binding)},C.prototype.whenNoAncestorIs=function(k){return this._binding.constraint=function(A){return!m.traverseAncerstors(A,m.typeConstraint(k))},new E.BindingOnSyntax(this._binding)},C.prototype.whenAnyAncestorNamed=function(k){return this._binding.constraint=function(A){return m.traverseAncerstors(A,m.namedConstraint(k))},new E.BindingOnSyntax(this._binding)},C.prototype.whenNoAncestorNamed=function(k){return this._binding.constraint=function(A){return!m.traverseAncerstors(A,m.namedConstraint(k))},new E.BindingOnSyntax(this._binding)},C.prototype.whenAnyAncestorTagged=function(k,A){return this._binding.constraint=function(S){return m.traverseAncerstors(S,m.taggedConstraint(k)(A))},new E.BindingOnSyntax(this._binding)},C.prototype.whenNoAncestorTagged=function(k,A){return this._binding.constraint=function(S){return!m.traverseAncerstors(S,m.taggedConstraint(k)(A))},new E.BindingOnSyntax(this._binding)},C.prototype.whenAnyAncestorMatches=function(k){return this._binding.constraint=function(A){return m.traverseAncerstors(A,k)},new E.BindingOnSyntax(this._binding)},C.prototype.whenNoAncestorMatches=function(k){return this._binding.constraint=function(A){return!m.traverseAncerstors(A,k)},new E.BindingOnSyntax(this._binding)},C}();R.BindingWhenSyntax=O},z9fm:function(ce,R,l){"use strict";var E=l("ENif"),m=l("f1E4"),O=l("oa35"),C=l("FCfD"),k=l("xH5X"),A=l("dagG");E("match",1,function(S,y,w){return[function(T){var j=C(this),D=T==null?void 0:T[S];return D!==void 0?D.call(T,j):new RegExp(T)[S](String(j))},function(x){var T=w(y,x,this);if(T.done)return T.value;var j=m(x),D=String(this);if(!j.global)return A(j,D);var N=j.unicode;j.lastIndex=0;for(var F=[],B=0,U;(U=A(j,D))!==null;){var J=String(U[0]);F[B]=J,J===""&&(j.lastIndex=k(D,O(j.lastIndex),N)),B++}return B===0?null:F}]})},zEVN:function(ce,R,l){var E=l("Gi0A"),m=l("sEf8"),O=l("mdPL"),C=O&&O.isMap,k=C?m(C):E;ce.exports=k},zLVn:function(ce,R,l){"use strict";l.d(R,"a",function(){return E});function E(m,O){if(m==null)return{};var C={},k=Object.keys(m),A,S;for(S=0;S=0)&&(C[A]=m[A]);return C}},zP5H:function(ce,R,l){"use strict";l.d(R,"a",function(){return m});var E=l("q1tI");function m(C){var k=E.createContext(null);function A(y){var w=C(y.initialState);return E.createElement(k.Provider,{value:w},y.children)}function S(){var y=E.useContext(k);if(y===null)throw new Error("Component must be wrapped with ");return y}return{Provider:A,useContainer:S}}function O(C){return C.useContainer()}},zTPR:function(ce,R,l){"use strict";var E=l("/gva"),m=l("vO0A");ce.exports=E("Set",function(O){return function(){return O(this,arguments.length?arguments[0]:void 0)}},m)},zZ0H:function(ce,R){function l(E){return E}ce.exports=l},zbpD:function(ce,R,l){"use strict";var E=l("284h").default,m=l("TqRt").default;Object.defineProperty(R,"__esModule",{value:!0}),Object.defineProperty(R,"List",{enumerable:!0,get:function(){return y.List}}),R.default=void 0,Object.defineProperty(R,"useForm",{enumerable:!0,get:function(){return F.default}}),Object.defineProperty(R,"useWatch",{enumerable:!0,get:function(){return y.useWatch}});var O=m(l("pVnL")),C=m(l("cDf5")),k=m(l("J4zp")),A=m(l("lSNA")),S=m(l("TSYQ")),y=E(l("85Yc")),w=E(l("q1tI")),x=l("vgIT"),T=E(l("i4Ex")),j=E(l("fVhf")),D=l("Gi/T"),N=m(l("aWDn")),F=m(l("hpdD")),B=function(X,ee){var ie={};for(var G in X)Object.prototype.hasOwnProperty.call(X,G)&&ee.indexOf(G)<0&&(ie[G]=X[G]);if(X!=null&&typeof Object.getOwnPropertySymbols=="function")for(var Q=0,G=Object.getOwnPropertySymbols(X);Q=0)&&(pe[Me]=we[Me]);return pe}function F(we,fe){if(we==null)return{};var pe=N(we,fe),Ke,Me;if(Object.getOwnPropertySymbols){var ze=Object.getOwnPropertySymbols(we);for(Me=0;Me=0)&&(!Object.prototype.propertyIsEnumerable.call(we,Ke)||(pe[Ke]=we[Ke]))}return pe}function B(we,fe){return U(we)||J(we,fe)||$(we,fe)||ee()}function U(we){if(Array.isArray(we))return we}function J(we,fe){var pe=we==null?null:typeof Symbol!="undefined"&&we[Symbol.iterator]||we["@@iterator"];if(pe!=null){var Ke=[],Me=!0,ze=!1,Ue,He;try{for(pe=pe.call(we);!(Me=(Ue=pe.next()).done)&&(Ke.push(Ue.value),!(fe&&Ke.length===fe));Me=!0);}catch(Ne){ze=!0,He=Ne}finally{try{!Me&&pe.return!=null&&pe.return()}finally{if(ze)throw He}}return Ke}}function $(we,fe){if(!!we){if(typeof we=="string")return X(we,fe);var pe=Object.prototype.toString.call(we).slice(8,-1);if(pe==="Object"&&we.constructor&&(pe=we.constructor.name),pe==="Map"||pe==="Set")return Array.from(we);if(pe==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(pe))return X(we,fe)}}function X(we,fe){(fe==null||fe>we.length)&&(fe=we.length);for(var pe=0,Ke=new Array(fe);pe=we.length?{done:!0}:{done:!1,value:we[Ke++]}},e:function(it){throw it},f:Me}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var ze=!0,Ue=!1,He;return{s:function(){pe=pe.call(we)},n:function(){var it=pe.next();return ze=it.done,it},e:function(it){Ue=!0,He=it},f:function(){try{!ze&&pe.return!=null&&pe.return()}finally{if(Ue)throw He}}}}function G(we){return S.default.createElement(m.__RouterContext.Consumer,null,function(fe){var pe=we.location||fe.location,Ke=we.computedMatch,Me=w(w({},fe),{},{location:pe,match:Ke}),ze=we.render;return S.default.createElement(m.__RouterContext.Provider,{value:Me},Me.match?ze(w(w({},we.layoutProps),Me)):null)})}var Q=["children"];function W(we){return S.default.createElement(m.__RouterContext.Consumer,null,function(fe){var pe=we.children,Ke=F(we,Q),Me=we.location||fe.location,ze,Ue=null;return O.Children.forEach(pe,function(He){if(Ue===null&&O.isValidElement(He)){ze=He;var Ne=He.props.path||He.props.from;Ue=Ne?m.matchPath(Me.pathname,w(w({},He.props),{},{path:Ne})):fe.match}}),Ue?O.cloneElement(ze,{location:Me,computedMatch:Ue,layoutProps:Ke}):null})}var ne=["component"];function te(we,fe){var pe=we.component,Ke=F(we,ne),Me=we.component;function ze(Ue){var He=O.useState(function(){return window.g_initialProps}),Ne=B(He,2),it=Ne[0],Xe=Ne[1];return O.useEffect(function(){var ht=function(){var lt=T(E().mark(function Et(){var tt,mt,xt,Xt,vt;return E().wrap(function(Re){for(;;)switch(Re.prev=Re.next){case 0:if(mt=Me,!Me.preload){Re.next=6;break}return Re.next=4,Me.preload();case 4:mt=Re.sent,mt=mt.default||mt;case 6:if(xt=w(w({isServer:!1,match:Ue==null?void 0:Ue.match,history:Ue==null?void 0:Ue.history,route:we},fe.getInitialPropsCtx||{}),Ke),!((tt=mt)===null||tt===void 0?void 0:tt.getInitialProps)){Re.next=15;break}return Re.next=10,fe.plugin.applyPlugins({key:"ssr.modifyGetInitialPropsCtx",type:m.ApplyPluginsType.modify,initialValue:xt,async:!0});case 10:return Xt=Re.sent,Re.next=13,mt.getInitialProps(Xt||xt);case 13:vt=Re.sent,Xe(vt);case 15:case"end":return Re.stop()}},Et)}));return function(){return lt.apply(this,arguments)}}();window.g_initialProps||ht()},[window.location.pathname,window.location.search]),S.default.createElement(Me,D({},Ue,it))}return ze.wrapInitialPropsLoaded=!0,ze.displayName="ComponentWithInitialPropsFetch",ze}function _e(we){var fe=we.route,pe=we.opts,Ke=we.props,Me=oe(w(w({},pe),{},{routes:fe.routes||[],rootRoutes:pe.rootRoutes}),{location:Ke.location}),ze=fe.component,Ue=fe.wrappers;if(ze){var He=pe.isServer?{}:window.g_initialProps,Ne=w(w(w(w({},Ke),pe.extraProps),pe.pageInitialProps||He),{},{route:fe,routes:pe.rootRoutes}),it=S.default.createElement(ze,Ne,Me);if(Ue)for(var Xe=Ue.length-1;Xe>=0;)it=O.createElement(Ue[Xe],Ne,it),Xe-=1;return it}else return Me}function he(we){var fe=we.route,pe=we.index,Ke=we.opts,Me={key:fe.key||pe,exact:fe.exact,strict:fe.strict,sensitive:fe.sensitive,path:fe.path};if(fe.redirect)return S.default.createElement(m.Redirect,D({},Me,{from:fe.path,to:fe.redirect}));var ze,Ue,He;return Ke.ssrProps&&!Ke.isServer&&!((ze=fe.component)===null||ze===void 0?void 0:ze.wrapInitialPropsLoaded)&&(((Ue=fe.component)===null||Ue===void 0?void 0:Ue.getInitialProps)||((He=fe.component)===null||He===void 0?void 0:He.preload))&&(fe.component=te(fe,Ke)),S.default.createElement(G,D({},Me,{render:function(it){return _e({route:fe,opts:Ke,props:it})}}))}function oe(we){var fe=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return we.routes?S.default.createElement(W,fe,we.routes.map(function(pe,Ke){return he({route:pe,index:Ke,opts:w(w({},we),{},{rootRoutes:we.rootRoutes||we.routes})})})):null}var ge=["history"];function me(we){var fe=we.history,pe=F(we,ge);return O.useEffect(function(){window.g_useSSR&&(window.g_initialProps=null);function Ke(Me,ze){var Ue=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1,He=k.matchRoutes(we.routes,Me.pathname);typeof document!="undefined"&&pe.defaultTitle!==void 0&&(document.title=He.length&&He[He.length-1].route.title||pe.defaultTitle||""),we.plugin.applyPlugins({key:"onRouteChange",type:m.ApplyPluginsType.event,args:{routes:we.routes,matchedRoutes:He,location:Me,action:ze,isFirst:Ue}})}return Ke(fe.location,"POP",!0),fe.listen(Ke)},[fe]),S.default.createElement(m.Router,{history:fe},oe(pe))}function Z(we){return we.plugin.applyPlugins({type:m.ApplyPluginsType.modify,key:"rootContainer",initialValue:S.default.createElement(me,{history:we.history,routes:we.routes,plugin:we.plugin,ssrProps:we.ssrProps,defaultTitle:we.defaultTitle}),args:{history:we.history,routes:we.routes,plugin:we.plugin}})}function xe(we){return Ee.apply(this,arguments)}function Ee(){return Ee=T(E().mark(function we(fe){var pe,Ke,Me,ze,Ue,He,Ne,it,Xe=arguments;return E().wrap(function(lt){for(;;)switch(lt.prev=lt.next){case 0:pe=Xe.length>1&&Xe[1]!==void 0?Xe[1]:window.location.pathname,Ke=k.matchRoutes(fe,pe),Me=ie(Ke),lt.prev=3,Me.s();case 5:if((ze=Me.n()).done){lt.next=19;break}if(He=ze.value,Ne=He.route,!(typeof Ne.component!="string"&&((Ue=Ne.component)===null||Ue===void 0?void 0:Ue.preload))){lt.next=13;break}return lt.next=11,Ne.component.preload();case 11:it=lt.sent,Ne.component=it.default||it;case 13:if(!Ne.routes){lt.next=17;break}return lt.next=16,xe(Ne.routes,pe);case 16:Ne.routes=lt.sent;case 17:lt.next=5;break;case 19:lt.next=24;break;case 21:lt.prev=21,lt.t0=lt.catch(3),Me.e(lt.t0);case 24:return lt.prev=24,Me.f(),lt.finish(24);case 27:return lt.abrupt("return",fe);case 28:case"end":return lt.stop()}},we,null,[[3,21,24,27]])})),Ee.apply(this,arguments)}function Le(we){var fe=Z(we);if(we.rootElement){var pe=typeof we.rootElement=="string"?document.getElementById(we.rootElement):we.rootElement,Ke=we.callback||function(){};window.g_useSSR?we.dynamicImport?xe(we.routes).then(function(){C.hydrate(fe,pe,Ke)}):C.hydrate(fe,pe,Ke):C.render(fe,pe,Ke)}else return fe}R.renderClient=Le,R.renderRoutes=oe},zoYe:function(ce,R,l){var E=l("nmnc"),m=l("eUgh"),O=l("Z0cm"),C=l("/9aa"),k=1/0,A=E?E.prototype:void 0,S=A?A.toString:void 0;function y(w){if(typeof w=="string")return w;if(O(w))return m(w,y)+"";if(C(w))return S?S.call(w):"";var x=w+"";return x=="0"&&1/w==-k?"-0":x}ce.exports=y},"zpY+":function(ce,R,l){"use strict";function E(m){for(var O=0,C,k=0,A=m.length;A>=4;++k,A-=4)C=m.charCodeAt(k)&255|(m.charCodeAt(++k)&255)<<8|(m.charCodeAt(++k)&255)<<16|(m.charCodeAt(++k)&255)<<24,C=(C&65535)*1540483477+((C>>>16)*59797<<16),C^=C>>>24,O=(C&65535)*1540483477+((C>>>16)*59797<<16)^(O&65535)*1540483477+((O>>>16)*59797<<16);switch(A){case 3:O^=(m.charCodeAt(k+2)&255)<<16;case 2:O^=(m.charCodeAt(k+1)&255)<<8;case 1:O^=m.charCodeAt(k)&255,O=(O&65535)*1540483477+((O>>>16)*59797<<16)}return O^=O>>>13,O=(O&65535)*1540483477+((O>>>16)*59797<<16),((O^O>>>15)>>>0).toString(36)}R.a=E},zqxM:function(ce,R,l){var E=l("LqpT"),m=l("XGnz"),O=l("EA7m"),C=l("3L66"),k=O(function(A,S){return C(A)?E(A,m(S,1,C,!0)):[]});ce.exports=k},zs7G:function(ce,R,l){"use strict";var E=l("VTBJ"),m=l("q1tI"),O={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M533.2 492.3L277.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H188c-6.7 0-10.4 7.7-6.3 12.9L447.1 512 181.7 851.1A7.98 7.98 0 00188 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5zm304 0L581.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H492c-6.7 0-10.4 7.7-6.3 12.9L751.1 512 485.7 851.1A7.98 7.98 0 00492 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5z"}}]},name:"double-right",theme:"outlined"},C=O,k=l("6VBw"),A=function(w,x){return m.createElement(k.a,Object(E.a)(Object(E.a)({},w),{},{ref:x,icon:C}))};A.displayName="DoubleRightOutlined";var S=R.a=m.forwardRef(A)},zsCH:function(ce,R,l){var E=l("MMxC"),m=l("tSXo"),O=l("f1E4"),C=l("jtLI"),k=l("g8rt"),A=l("Acmb");function S(y,w){var x=arguments.length<3?y:arguments[2],T,j;if(O(y)===x)return y[w];if(T=k.f(y,w))return C(T,"value")?T.value:T.get===void 0?void 0:T.get.call(x);if(m(j=A(y)))return S(j,w,x)}E({target:"Reflect",stat:!0},{get:S})},zueq:function(ce,R,l){"use strict";var E=l("VTBJ"),m=l("q1tI"),O={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"}}]},name:"info-circle",theme:"filled"},C=O,k=l("6VBw"),A=function(w,x){return m.createElement(k.a,Object(E.a)(Object(E.a)({},w),{},{ref:x,icon:C}))};A.displayName="InfoCircleFilled";var S=R.a=m.forwardRef(A)},zv1X:function(ce,R,l){var E=l("7BAe"),m=l("EzR6"),O=l("cTDu"),C=l("oa35"),k=l("nMuc"),A=[].push,S=function(y){var w=y==1,x=y==2,T=y==3,j=y==4,D=y==6,N=y==5||D;return function(F,B,U,J){for(var $=O(F),X=m($),ee=E(B,U,3),ie=C(X.length),G=0,Q=J||k,W=w?Q(F,ie):x?Q(F,0):void 0,ne,te;ie>G;G++)if((N||G in X)&&(ne=X[G],te=ee(ne,G,$),y)){if(w)W[G]=te;else if(te)switch(y){case 3:return!0;case 5:return ne;case 6:return G;case 2:A.call(W,ne)}else if(j)return!1}return D?-1:T||j?j:W}};ce.exports={forEach:S(0),map:S(1),filter:S(2),some:S(3),every:S(4),find:S(5),findIndex:S(6)}},zvFY:function(ce,R,l){"use strict";l.d(R,"a",function(){return we});var E=l("wx14"),m=l("rePB"),O=l("ODXe"),C=l("U8pU"),k=l("TSYQ"),A=l.n(k),S=l("Ya77"),y=l("q1tI"),w=l.n(y),x=l("H84U"),T=l("caoh"),j=l("3Nzz"),D=l("+f9I"),N=l("0n0R"),F=l("CWQg"),B=l("g0mS"),U=function(Me,ze){var Ue={};for(var He in Me)Object.prototype.hasOwnProperty.call(Me,He)&&ze.indexOf(He)<0&&(Ue[He]=Me[He]);if(Me!=null&&typeof Object.getOwnPropertySymbols=="function")for(var Ne=0,He=Object.getOwnPropertySymbols(Me);Ne*{line-height:1}.anticon svg{display:inline-block}.anticon:before{display:none}.anticon .anticon-icon{display:block}.anticon>.anticon{line-height:0;vertical-align:0}.anticon[tabindex]{cursor:pointer}.anticon-spin,.anticon-spin:before{display:inline-block;animation:loadingCircle 1s linear infinite}.ant-fade-appear,.ant-fade-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-fade-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-fade-appear.ant-fade-appear-active,.ant-fade-enter.ant-fade-enter-active{animation-name:antFadeIn;animation-play-state:running}.ant-fade-leave.ant-fade-leave-active{animation-name:antFadeOut;animation-play-state:running;pointer-events:none}.ant-fade-appear,.ant-fade-enter{opacity:0;animation-timing-function:linear}.ant-fade-leave{animation-timing-function:linear}@keyframes antFadeIn{0%{opacity:0}to{opacity:1}}@keyframes antFadeOut{0%{opacity:1}to{opacity:0}}.ant-move-up-appear,.ant-move-up-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-up-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-up-appear.ant-move-up-appear-active,.ant-move-up-enter.ant-move-up-enter-active{animation-name:antMoveUpIn;animation-play-state:running}.ant-move-up-leave.ant-move-up-leave-active{animation-name:antMoveUpOut;animation-play-state:running;pointer-events:none}.ant-move-up-appear,.ant-move-up-enter{opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-move-up-leave{animation-timing-function:cubic-bezier(.6,.04,.98,.34)}.ant-move-down-appear,.ant-move-down-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-down-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-down-appear.ant-move-down-appear-active,.ant-move-down-enter.ant-move-down-enter-active{animation-name:antMoveDownIn;animation-play-state:running}.ant-move-down-leave.ant-move-down-leave-active{animation-name:antMoveDownOut;animation-play-state:running;pointer-events:none}.ant-move-down-appear,.ant-move-down-enter{opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-move-down-leave{animation-timing-function:cubic-bezier(.6,.04,.98,.34)}.ant-move-left-appear,.ant-move-left-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-left-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-left-appear.ant-move-left-appear-active,.ant-move-left-enter.ant-move-left-enter-active{animation-name:antMoveLeftIn;animation-play-state:running}.ant-move-left-leave.ant-move-left-leave-active{animation-name:antMoveLeftOut;animation-play-state:running;pointer-events:none}.ant-move-left-appear,.ant-move-left-enter{opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-move-left-leave{animation-timing-function:cubic-bezier(.6,.04,.98,.34)}.ant-move-right-appear,.ant-move-right-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-right-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-move-right-appear.ant-move-right-appear-active,.ant-move-right-enter.ant-move-right-enter-active{animation-name:antMoveRightIn;animation-play-state:running}.ant-move-right-leave.ant-move-right-leave-active{animation-name:antMoveRightOut;animation-play-state:running;pointer-events:none}.ant-move-right-appear,.ant-move-right-enter{opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-move-right-leave{animation-timing-function:cubic-bezier(.6,.04,.98,.34)}@keyframes antMoveDownIn{0%{transform:translateY(100%);transform-origin:0 0;opacity:0}to{transform:translateY(0);transform-origin:0 0;opacity:1}}@keyframes antMoveDownOut{0%{transform:translateY(0);transform-origin:0 0;opacity:1}to{transform:translateY(100%);transform-origin:0 0;opacity:0}}@keyframes antMoveLeftIn{0%{transform:translateX(-100%);transform-origin:0 0;opacity:0}to{transform:translateX(0);transform-origin:0 0;opacity:1}}@keyframes antMoveLeftOut{0%{transform:translateX(0);transform-origin:0 0;opacity:1}to{transform:translateX(-100%);transform-origin:0 0;opacity:0}}@keyframes antMoveRightIn{0%{transform:translateX(100%);transform-origin:0 0;opacity:0}to{transform:translateX(0);transform-origin:0 0;opacity:1}}@keyframes antMoveRightOut{0%{transform:translateX(0);transform-origin:0 0;opacity:1}to{transform:translateX(100%);transform-origin:0 0;opacity:0}}@keyframes antMoveUpIn{0%{transform:translateY(-100%);transform-origin:0 0;opacity:0}to{transform:translateY(0);transform-origin:0 0;opacity:1}}@keyframes antMoveUpOut{0%{transform:translateY(0);transform-origin:0 0;opacity:1}to{transform:translateY(-100%);transform-origin:0 0;opacity:0}}@keyframes loadingCircle{to{transform:rotate(1turn)}}[ant-click-animating-without-extra-node=true],[ant-click-animating=true]{position:relative}html{--antd-wave-shadow-color:#296df3;--scroll-bar:0}.ant-click-animating-node,[ant-click-animating-without-extra-node=true]:after{position:absolute;top:0;right:0;bottom:0;left:0;display:block;border-radius:inherit;box-shadow:0 0 0 0 #296df3;box-shadow:0 0 0 0 var(--antd-wave-shadow-color);opacity:.2;animation:fadeEffect 2s cubic-bezier(.08,.82,.17,1),waveEffect .4s cubic-bezier(.08,.82,.17,1);animation-fill-mode:forwards;content:"";pointer-events:none}@keyframes waveEffect{to{box-shadow:0 0 0 #296df3;box-shadow:0 0 0 6px #296df3;box-shadow:0 0 0 6px var(--antd-wave-shadow-color)}}@keyframes fadeEffect{to{opacity:0}}.ant-slide-up-appear,.ant-slide-up-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-up-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-up-appear.ant-slide-up-appear-active,.ant-slide-up-enter.ant-slide-up-enter-active{animation-name:antSlideUpIn;animation-play-state:running}.ant-slide-up-leave.ant-slide-up-leave-active{animation-name:antSlideUpOut;animation-play-state:running;pointer-events:none}.ant-slide-up-appear,.ant-slide-up-enter{transform:scale(0);transform-origin:0 0;opacity:0;animation-timing-function:cubic-bezier(.23,1,.32,1)}.ant-slide-up-leave{animation-timing-function:cubic-bezier(.755,.05,.855,.06)}.ant-slide-down-appear,.ant-slide-down-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-down-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-down-appear.ant-slide-down-appear-active,.ant-slide-down-enter.ant-slide-down-enter-active{animation-name:antSlideDownIn;animation-play-state:running}.ant-slide-down-leave.ant-slide-down-leave-active{animation-name:antSlideDownOut;animation-play-state:running;pointer-events:none}.ant-slide-down-appear,.ant-slide-down-enter{transform:scale(0);transform-origin:0 0;opacity:0;animation-timing-function:cubic-bezier(.23,1,.32,1)}.ant-slide-down-leave{animation-timing-function:cubic-bezier(.755,.05,.855,.06)}.ant-slide-left-appear,.ant-slide-left-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-left-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-left-appear.ant-slide-left-appear-active,.ant-slide-left-enter.ant-slide-left-enter-active{animation-name:antSlideLeftIn;animation-play-state:running}.ant-slide-left-leave.ant-slide-left-leave-active{animation-name:antSlideLeftOut;animation-play-state:running;pointer-events:none}.ant-slide-left-appear,.ant-slide-left-enter{transform:scale(0);transform-origin:0 0;opacity:0;animation-timing-function:cubic-bezier(.23,1,.32,1)}.ant-slide-left-leave{animation-timing-function:cubic-bezier(.755,.05,.855,.06)}.ant-slide-right-appear,.ant-slide-right-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-right-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-slide-right-appear.ant-slide-right-appear-active,.ant-slide-right-enter.ant-slide-right-enter-active{animation-name:antSlideRightIn;animation-play-state:running}.ant-slide-right-leave.ant-slide-right-leave-active{animation-name:antSlideRightOut;animation-play-state:running;pointer-events:none}.ant-slide-right-appear,.ant-slide-right-enter{transform:scale(0);transform-origin:0 0;opacity:0;animation-timing-function:cubic-bezier(.23,1,.32,1)}.ant-slide-right-leave{animation-timing-function:cubic-bezier(.755,.05,.855,.06)}@keyframes antSlideUpIn{0%{transform:scaleY(.8);transform-origin:0 0;opacity:0}to{transform:scaleY(1);transform-origin:0 0;opacity:1}}@keyframes antSlideUpOut{0%{transform:scaleY(1);transform-origin:0 0;opacity:1}to{transform:scaleY(.8);transform-origin:0 0;opacity:0}}@keyframes antSlideDownIn{0%{transform:scaleY(.8);transform-origin:100% 100%;opacity:0}to{transform:scaleY(1);transform-origin:100% 100%;opacity:1}}@keyframes antSlideDownOut{0%{transform:scaleY(1);transform-origin:100% 100%;opacity:1}to{transform:scaleY(.8);transform-origin:100% 100%;opacity:0}}@keyframes antSlideLeftIn{0%{transform:scaleX(.8);transform-origin:0 0;opacity:0}to{transform:scaleX(1);transform-origin:0 0;opacity:1}}@keyframes antSlideLeftOut{0%{transform:scaleX(1);transform-origin:0 0;opacity:1}to{transform:scaleX(.8);transform-origin:0 0;opacity:0}}@keyframes antSlideRightIn{0%{transform:scaleX(.8);transform-origin:100% 0;opacity:0}to{transform:scaleX(1);transform-origin:100% 0;opacity:1}}@keyframes antSlideRightOut{0%{transform:scaleX(1);transform-origin:100% 0;opacity:1}to{transform:scaleX(.8);transform-origin:100% 0;opacity:0}}.ant-zoom-appear,.ant-zoom-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-appear.ant-zoom-appear-active,.ant-zoom-enter.ant-zoom-enter-active{animation-name:antZoomIn;animation-play-state:running}.ant-zoom-leave.ant-zoom-leave-active{animation-name:antZoomOut;animation-play-state:running;pointer-events:none}.ant-zoom-appear,.ant-zoom-enter{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-zoom-appear-prepare,.ant-zoom-enter-prepare{transform:none}.ant-zoom-leave{animation-timing-function:cubic-bezier(.78,.14,.15,.86)}.ant-zoom-big-appear,.ant-zoom-big-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-big-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-big-appear.ant-zoom-big-appear-active,.ant-zoom-big-enter.ant-zoom-big-enter-active{animation-name:antZoomBigIn;animation-play-state:running}.ant-zoom-big-leave.ant-zoom-big-leave-active{animation-name:antZoomBigOut;animation-play-state:running;pointer-events:none}.ant-zoom-big-appear,.ant-zoom-big-enter{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-zoom-big-appear-prepare,.ant-zoom-big-enter-prepare{transform:none}.ant-zoom-big-leave{animation-timing-function:cubic-bezier(.78,.14,.15,.86)}.ant-zoom-big-fast-appear,.ant-zoom-big-fast-enter{animation-duration:.1s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-big-fast-leave{animation-duration:.1s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-big-fast-appear.ant-zoom-big-fast-appear-active,.ant-zoom-big-fast-enter.ant-zoom-big-fast-enter-active{animation-name:antZoomBigIn;animation-play-state:running}.ant-zoom-big-fast-leave.ant-zoom-big-fast-leave-active{animation-name:antZoomBigOut;animation-play-state:running;pointer-events:none}.ant-zoom-big-fast-appear,.ant-zoom-big-fast-enter{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-zoom-big-fast-appear-prepare,.ant-zoom-big-fast-enter-prepare{transform:none}.ant-zoom-big-fast-leave{animation-timing-function:cubic-bezier(.78,.14,.15,.86)}.ant-zoom-up-appear,.ant-zoom-up-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-up-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-up-appear.ant-zoom-up-appear-active,.ant-zoom-up-enter.ant-zoom-up-enter-active{animation-name:antZoomUpIn;animation-play-state:running}.ant-zoom-up-leave.ant-zoom-up-leave-active{animation-name:antZoomUpOut;animation-play-state:running;pointer-events:none}.ant-zoom-up-appear,.ant-zoom-up-enter{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-zoom-up-appear-prepare,.ant-zoom-up-enter-prepare{transform:none}.ant-zoom-up-leave{animation-timing-function:cubic-bezier(.78,.14,.15,.86)}.ant-zoom-down-appear,.ant-zoom-down-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-down-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-down-appear.ant-zoom-down-appear-active,.ant-zoom-down-enter.ant-zoom-down-enter-active{animation-name:antZoomDownIn;animation-play-state:running}.ant-zoom-down-leave.ant-zoom-down-leave-active{animation-name:antZoomDownOut;animation-play-state:running;pointer-events:none}.ant-zoom-down-appear,.ant-zoom-down-enter{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-zoom-down-appear-prepare,.ant-zoom-down-enter-prepare{transform:none}.ant-zoom-down-leave{animation-timing-function:cubic-bezier(.78,.14,.15,.86)}.ant-zoom-left-appear,.ant-zoom-left-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-left-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-left-appear.ant-zoom-left-appear-active,.ant-zoom-left-enter.ant-zoom-left-enter-active{animation-name:antZoomLeftIn;animation-play-state:running}.ant-zoom-left-leave.ant-zoom-left-leave-active{animation-name:antZoomLeftOut;animation-play-state:running;pointer-events:none}.ant-zoom-left-appear,.ant-zoom-left-enter{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-zoom-left-appear-prepare,.ant-zoom-left-enter-prepare{transform:none}.ant-zoom-left-leave{animation-timing-function:cubic-bezier(.78,.14,.15,.86)}.ant-zoom-right-appear,.ant-zoom-right-enter{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-right-leave{animation-duration:.2s;animation-fill-mode:both;animation-play-state:paused}.ant-zoom-right-appear.ant-zoom-right-appear-active,.ant-zoom-right-enter.ant-zoom-right-enter-active{animation-name:antZoomRightIn;animation-play-state:running}.ant-zoom-right-leave.ant-zoom-right-leave-active{animation-name:antZoomRightOut;animation-play-state:running;pointer-events:none}.ant-zoom-right-appear,.ant-zoom-right-enter{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.08,.82,.17,1)}.ant-zoom-right-appear-prepare,.ant-zoom-right-enter-prepare{transform:none}.ant-zoom-right-leave{animation-timing-function:cubic-bezier(.78,.14,.15,.86)}@keyframes antZoomIn{0%{transform:scale(.2);opacity:0}to{transform:scale(1);opacity:1}}@keyframes antZoomOut{0%{transform:scale(1)}to{transform:scale(.2);opacity:0}}@keyframes antZoomBigIn{0%{transform:scale(.8);opacity:0}to{transform:scale(1);opacity:1}}@keyframes antZoomBigOut{0%{transform:scale(1)}to{transform:scale(.8);opacity:0}}@keyframes antZoomUpIn{0%{transform:scale(.8);transform-origin:50% 0;opacity:0}to{transform:scale(1);transform-origin:50% 0}}@keyframes antZoomUpOut{0%{transform:scale(1);transform-origin:50% 0}to{transform:scale(.8);transform-origin:50% 0;opacity:0}}@keyframes antZoomLeftIn{0%{transform:scale(.8);transform-origin:0 50%;opacity:0}to{transform:scale(1);transform-origin:0 50%}}@keyframes antZoomLeftOut{0%{transform:scale(1);transform-origin:0 50%}to{transform:scale(.8);transform-origin:0 50%;opacity:0}}@keyframes antZoomRightIn{0%{transform:scale(.8);transform-origin:100% 50%;opacity:0}to{transform:scale(1);transform-origin:100% 50%}}@keyframes antZoomRightOut{0%{transform:scale(1);transform-origin:100% 50%}to{transform:scale(.8);transform-origin:100% 50%;opacity:0}}@keyframes antZoomDownIn{0%{transform:scale(.8);transform-origin:50% 100%;opacity:0}to{transform:scale(1);transform-origin:50% 100%}}@keyframes antZoomDownOut{0%{transform:scale(1);transform-origin:50% 100%}to{transform:scale(.8);transform-origin:50% 100%;opacity:0}}.ant-motion-collapse-legacy{overflow:hidden}.ant-motion-collapse-legacy-active{transition:height .2s cubic-bezier(.645,.045,.355,1),opacity .2s cubic-bezier(.645,.045,.355,1)!important}.ant-motion-collapse{overflow:hidden;transition:height .2s cubic-bezier(.645,.045,.355,1),opacity .2s cubic-bezier(.645,.045,.355,1)!important}.ant-btn{line-height:1.5715;position:relative;display:inline-block;font-weight:400;white-space:nowrap;text-align:center;background-image:none;box-shadow:0 2px 0 rgba(0,0,0,.015);cursor:pointer;transition:all .3s cubic-bezier(.645,.045,.355,1);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;touch-action:manipulation;height:32px;padding:4px 16px;font-size:14px;border-radius:4px;color:rgba(0,10,36,.65);border:1px solid rgba(0,0,0,.15);background:#fff}.ant-btn>.anticon{line-height:1}.ant-btn,.ant-btn:active,.ant-btn:focus{outline:0}.ant-btn:not([disabled]):hover{text-decoration:none}.ant-btn:not([disabled]):active{outline:0;box-shadow:none}.ant-btn[disabled]{cursor:not-allowed}.ant-btn[disabled]>*{pointer-events:none}.ant-btn-lg{height:40px;padding:6.4px 16px;font-size:16px;border-radius:4px}.ant-btn-sm{height:24px;padding:0 8px;font-size:14px;border-radius:4px}.ant-btn>a:only-child{color:currentcolor}.ant-btn>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn:focus,.ant-btn:hover{color:#5493ff;border-color:#5493ff;background:#fff}.ant-btn:focus>a:only-child,.ant-btn:hover>a:only-child{color:currentcolor}.ant-btn:focus>a:only-child:after,.ant-btn:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn:active{color:#184ecc;border-color:#184ecc;background:#fff}.ant-btn:active>a:only-child{color:currentcolor}.ant-btn:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn[disabled],.ant-btn[disabled]:active,.ant-btn[disabled]:focus,.ant-btn[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn[disabled]:active>a:only-child,.ant-btn[disabled]:focus>a:only-child,.ant-btn[disabled]:hover>a:only-child,.ant-btn[disabled]>a:only-child{color:currentcolor}.ant-btn[disabled]:active>a:only-child:after,.ant-btn[disabled]:focus>a:only-child:after,.ant-btn[disabled]:hover>a:only-child:after,.ant-btn[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn:active,.ant-btn:focus,.ant-btn:hover{text-decoration:none;background:#fff}.ant-btn>span{display:inline-block}.ant-btn-primary{color:#fff;border-color:#296df3;background:#296df3;text-shadow:0 -1px 0 rgba(0,0,0,.12);box-shadow:0 2px 0 rgba(0,0,0,.045)}.ant-btn-primary>a:only-child{color:currentcolor}.ant-btn-primary>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-primary:focus,.ant-btn-primary:hover{color:#fff;border-color:#5493ff;background:#5493ff}.ant-btn-primary:focus>a:only-child,.ant-btn-primary:hover>a:only-child{color:currentcolor}.ant-btn-primary:focus>a:only-child:after,.ant-btn-primary:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-primary:active{color:#fff;border-color:#184ecc;background:#184ecc}.ant-btn-primary:active>a:only-child{color:currentcolor}.ant-btn-primary:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-primary[disabled],.ant-btn-primary[disabled]:active,.ant-btn-primary[disabled]:focus,.ant-btn-primary[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-primary[disabled]:active>a:only-child,.ant-btn-primary[disabled]:focus>a:only-child,.ant-btn-primary[disabled]:hover>a:only-child,.ant-btn-primary[disabled]>a:only-child{color:currentcolor}.ant-btn-primary[disabled]:active>a:only-child:after,.ant-btn-primary[disabled]:focus>a:only-child:after,.ant-btn-primary[disabled]:hover>a:only-child:after,.ant-btn-primary[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-group .ant-btn-primary:not(:first-child):not(:last-child){border-right-color:#4e86f5;border-left-color:#4e86f5}.ant-btn-group .ant-btn-primary:not(:first-child):not(:last-child):disabled{border-color:rgba(0,0,0,.15)}.ant-btn-group .ant-btn-primary:first-child:not(:last-child){border-right-color:#4e86f5}.ant-btn-group .ant-btn-primary:first-child:not(:last-child)[disabled]{border-right-color:rgba(0,0,0,.15)}.ant-btn-group .ant-btn-primary+.ant-btn-primary,.ant-btn-group .ant-btn-primary:last-child:not(:first-child){border-left-color:#4e86f5}.ant-btn-group .ant-btn-primary+.ant-btn-primary[disabled],.ant-btn-group .ant-btn-primary:last-child:not(:first-child)[disabled]{border-left-color:rgba(0,0,0,.15)}.ant-btn-ghost{color:rgba(0,10,36,.85);border-color:#d9d9d9;background:transparent}.ant-btn-ghost>a:only-child{color:currentcolor}.ant-btn-ghost>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-ghost:focus,.ant-btn-ghost:hover{color:#5493ff;border-color:#5493ff;background:transparent}.ant-btn-ghost:focus>a:only-child,.ant-btn-ghost:hover>a:only-child{color:currentcolor}.ant-btn-ghost:focus>a:only-child:after,.ant-btn-ghost:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-ghost:active{color:#184ecc;border-color:#184ecc;background:transparent}.ant-btn-ghost:active>a:only-child{color:currentcolor}.ant-btn-ghost:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-ghost[disabled],.ant-btn-ghost[disabled]:active,.ant-btn-ghost[disabled]:focus,.ant-btn-ghost[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-ghost[disabled]:active>a:only-child,.ant-btn-ghost[disabled]:focus>a:only-child,.ant-btn-ghost[disabled]:hover>a:only-child,.ant-btn-ghost[disabled]>a:only-child{color:currentcolor}.ant-btn-ghost[disabled]:active>a:only-child:after,.ant-btn-ghost[disabled]:focus>a:only-child:after,.ant-btn-ghost[disabled]:hover>a:only-child:after,.ant-btn-ghost[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dashed{color:rgba(0,10,36,.65);border-color:rgba(0,0,0,.15);background:#fff;border-style:dashed}.ant-btn-dashed>a:only-child{color:currentcolor}.ant-btn-dashed>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dashed:focus,.ant-btn-dashed:hover{color:#5493ff;border-color:#5493ff;background:#fff}.ant-btn-dashed:focus>a:only-child,.ant-btn-dashed:hover>a:only-child{color:currentcolor}.ant-btn-dashed:focus>a:only-child:after,.ant-btn-dashed:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dashed:active{color:#184ecc;border-color:#184ecc;background:#fff}.ant-btn-dashed:active>a:only-child{color:currentcolor}.ant-btn-dashed:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dashed[disabled],.ant-btn-dashed[disabled]:active,.ant-btn-dashed[disabled]:focus,.ant-btn-dashed[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-dashed[disabled]:active>a:only-child,.ant-btn-dashed[disabled]:focus>a:only-child,.ant-btn-dashed[disabled]:hover>a:only-child,.ant-btn-dashed[disabled]>a:only-child{color:currentcolor}.ant-btn-dashed[disabled]:active>a:only-child:after,.ant-btn-dashed[disabled]:focus>a:only-child:after,.ant-btn-dashed[disabled]:hover>a:only-child:after,.ant-btn-dashed[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-danger{color:#fff;border-color:#ef4872;background:#ef4872;text-shadow:0 -1px 0 rgba(0,0,0,.12);box-shadow:0 2px 0 rgba(0,0,0,.045)}.ant-btn-danger>a:only-child{color:currentcolor}.ant-btn-danger>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-danger:focus,.ant-btn-danger:hover{color:#fff;border-color:#fc7492;background:#fc7492}.ant-btn-danger:focus>a:only-child,.ant-btn-danger:hover>a:only-child{color:currentcolor}.ant-btn-danger:focus>a:only-child:after,.ant-btn-danger:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-danger:active{color:#fff;border-color:#c9325d;background:#c9325d}.ant-btn-danger:active>a:only-child{color:currentcolor}.ant-btn-danger:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-danger[disabled],.ant-btn-danger[disabled]:active,.ant-btn-danger[disabled]:focus,.ant-btn-danger[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-danger[disabled]:active>a:only-child,.ant-btn-danger[disabled]:focus>a:only-child,.ant-btn-danger[disabled]:hover>a:only-child,.ant-btn-danger[disabled]>a:only-child{color:currentcolor}.ant-btn-danger[disabled]:active>a:only-child:after,.ant-btn-danger[disabled]:focus>a:only-child:after,.ant-btn-danger[disabled]:hover>a:only-child:after,.ant-btn-danger[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-link{color:#296df3;border-color:transparent;background:transparent;box-shadow:none}.ant-btn-link>a:only-child{color:currentcolor}.ant-btn-link>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-link:focus,.ant-btn-link:hover{color:#5493ff;border-color:#5493ff;background:transparent}.ant-btn-link:focus>a:only-child,.ant-btn-link:hover>a:only-child{color:currentcolor}.ant-btn-link:focus>a:only-child:after,.ant-btn-link:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-link:active{color:#184ecc;border-color:#184ecc;background:transparent}.ant-btn-link:active>a:only-child{color:currentcolor}.ant-btn-link:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-link[disabled],.ant-btn-link[disabled]:active,.ant-btn-link[disabled]:focus,.ant-btn-link[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04)}.ant-btn-link:hover{background:transparent}.ant-btn-link:active,.ant-btn-link:focus,.ant-btn-link:hover{border-color:transparent}.ant-btn-link[disabled],.ant-btn-link[disabled]:active,.ant-btn-link[disabled]:focus,.ant-btn-link[disabled]:hover{color:rgba(0,0,0,.25);border-color:transparent;background:transparent;text-shadow:none;box-shadow:none}.ant-btn-link[disabled]:active>a:only-child,.ant-btn-link[disabled]:focus>a:only-child,.ant-btn-link[disabled]:hover>a:only-child,.ant-btn-link[disabled]>a:only-child{color:currentcolor}.ant-btn-link[disabled]:active>a:only-child:after,.ant-btn-link[disabled]:focus>a:only-child:after,.ant-btn-link[disabled]:hover>a:only-child:after,.ant-btn-link[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-text{color:rgba(0,10,36,.85);border-color:transparent;background:transparent;box-shadow:none}.ant-btn-text>a:only-child{color:currentcolor}.ant-btn-text>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-text:focus,.ant-btn-text:hover{color:#5493ff;border-color:#5493ff;background:transparent}.ant-btn-text:focus>a:only-child,.ant-btn-text:hover>a:only-child{color:currentcolor}.ant-btn-text:focus>a:only-child:after,.ant-btn-text:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-text:active{color:#184ecc;border-color:#184ecc;background:transparent}.ant-btn-text:active>a:only-child{color:currentcolor}.ant-btn-text:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-text[disabled],.ant-btn-text[disabled]:active,.ant-btn-text[disabled]:focus,.ant-btn-text[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04)}.ant-btn-text:focus,.ant-btn-text:hover{color:rgba(0,10,36,.85);background:rgba(0,0,0,.018);border-color:transparent}.ant-btn-text:active{color:rgba(0,10,36,.85);background:rgba(0,0,0,.028);border-color:transparent}.ant-btn-text[disabled],.ant-btn-text[disabled]:active,.ant-btn-text[disabled]:focus,.ant-btn-text[disabled]:hover{color:rgba(0,0,0,.25);border-color:transparent;background:transparent;text-shadow:none;box-shadow:none}.ant-btn-text[disabled]:active>a:only-child,.ant-btn-text[disabled]:focus>a:only-child,.ant-btn-text[disabled]:hover>a:only-child,.ant-btn-text[disabled]>a:only-child{color:currentcolor}.ant-btn-text[disabled]:active>a:only-child:after,.ant-btn-text[disabled]:focus>a:only-child:after,.ant-btn-text[disabled]:hover>a:only-child:after,.ant-btn-text[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous{color:#ef4872;border-color:#ef4872;background:#fff}.ant-btn-dangerous>a:only-child{color:currentcolor}.ant-btn-dangerous>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous:focus,.ant-btn-dangerous:hover{color:#fc7492;border-color:#fc7492;background:#fff}.ant-btn-dangerous:focus>a:only-child,.ant-btn-dangerous:hover>a:only-child{color:currentcolor}.ant-btn-dangerous:focus>a:only-child:after,.ant-btn-dangerous:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous:active{color:#c9325d;border-color:#c9325d;background:#fff}.ant-btn-dangerous:active>a:only-child{color:currentcolor}.ant-btn-dangerous:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous[disabled],.ant-btn-dangerous[disabled]:active,.ant-btn-dangerous[disabled]:focus,.ant-btn-dangerous[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-dangerous[disabled]:active>a:only-child,.ant-btn-dangerous[disabled]:focus>a:only-child,.ant-btn-dangerous[disabled]:hover>a:only-child,.ant-btn-dangerous[disabled]>a:only-child{color:currentcolor}.ant-btn-dangerous[disabled]:active>a:only-child:after,.ant-btn-dangerous[disabled]:focus>a:only-child:after,.ant-btn-dangerous[disabled]:hover>a:only-child:after,.ant-btn-dangerous[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-primary{color:#fff;border-color:#ef4872;background:#ef4872;text-shadow:0 -1px 0 rgba(0,0,0,.12);box-shadow:0 2px 0 rgba(0,0,0,.045)}.ant-btn-dangerous.ant-btn-primary>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-primary>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-primary:focus,.ant-btn-dangerous.ant-btn-primary:hover{color:#fff;border-color:#fc7492;background:#fc7492}.ant-btn-dangerous.ant-btn-primary:focus>a:only-child,.ant-btn-dangerous.ant-btn-primary:hover>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-primary:focus>a:only-child:after,.ant-btn-dangerous.ant-btn-primary:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-primary:active{color:#fff;border-color:#c9325d;background:#c9325d}.ant-btn-dangerous.ant-btn-primary:active>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-primary:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-primary[disabled],.ant-btn-dangerous.ant-btn-primary[disabled]:active,.ant-btn-dangerous.ant-btn-primary[disabled]:focus,.ant-btn-dangerous.ant-btn-primary[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-dangerous.ant-btn-primary[disabled]:active>a:only-child,.ant-btn-dangerous.ant-btn-primary[disabled]:focus>a:only-child,.ant-btn-dangerous.ant-btn-primary[disabled]:hover>a:only-child,.ant-btn-dangerous.ant-btn-primary[disabled]>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-primary[disabled]:active>a:only-child:after,.ant-btn-dangerous.ant-btn-primary[disabled]:focus>a:only-child:after,.ant-btn-dangerous.ant-btn-primary[disabled]:hover>a:only-child:after,.ant-btn-dangerous.ant-btn-primary[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-link{color:#ef4872;border-color:transparent;background:transparent;box-shadow:none}.ant-btn-dangerous.ant-btn-link>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-link>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-link:focus,.ant-btn-dangerous.ant-btn-link:hover{color:#5493ff;border-color:#5493ff}.ant-btn-dangerous.ant-btn-link:active{color:#184ecc;border-color:#184ecc}.ant-btn-dangerous.ant-btn-link[disabled],.ant-btn-dangerous.ant-btn-link[disabled]:active,.ant-btn-dangerous.ant-btn-link[disabled]:focus,.ant-btn-dangerous.ant-btn-link[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04)}.ant-btn-dangerous.ant-btn-link:focus,.ant-btn-dangerous.ant-btn-link:hover{color:#fc7492;border-color:transparent;background:transparent}.ant-btn-dangerous.ant-btn-link:focus>a:only-child,.ant-btn-dangerous.ant-btn-link:hover>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-link:focus>a:only-child:after,.ant-btn-dangerous.ant-btn-link:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-link:active{color:#c9325d;border-color:transparent;background:transparent}.ant-btn-dangerous.ant-btn-link:active>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-link:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-link[disabled],.ant-btn-dangerous.ant-btn-link[disabled]:active,.ant-btn-dangerous.ant-btn-link[disabled]:focus,.ant-btn-dangerous.ant-btn-link[disabled]:hover{color:rgba(0,0,0,.25);border-color:transparent;background:transparent;text-shadow:none;box-shadow:none}.ant-btn-dangerous.ant-btn-link[disabled]:active>a:only-child,.ant-btn-dangerous.ant-btn-link[disabled]:focus>a:only-child,.ant-btn-dangerous.ant-btn-link[disabled]:hover>a:only-child,.ant-btn-dangerous.ant-btn-link[disabled]>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-link[disabled]:active>a:only-child:after,.ant-btn-dangerous.ant-btn-link[disabled]:focus>a:only-child:after,.ant-btn-dangerous.ant-btn-link[disabled]:hover>a:only-child:after,.ant-btn-dangerous.ant-btn-link[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-text{color:#ef4872;border-color:transparent;background:transparent;box-shadow:none}.ant-btn-dangerous.ant-btn-text>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-text>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-text:focus,.ant-btn-dangerous.ant-btn-text:hover{color:#5493ff;border-color:#5493ff;background:transparent}.ant-btn-dangerous.ant-btn-text:active{color:#184ecc;border-color:#184ecc;background:transparent}.ant-btn-dangerous.ant-btn-text[disabled],.ant-btn-dangerous.ant-btn-text[disabled]:active,.ant-btn-dangerous.ant-btn-text[disabled]:focus,.ant-btn-dangerous.ant-btn-text[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04)}.ant-btn-dangerous.ant-btn-text:focus,.ant-btn-dangerous.ant-btn-text:hover{color:#fc7492;border-color:transparent;background:rgba(0,0,0,.018)}.ant-btn-dangerous.ant-btn-text:focus>a:only-child,.ant-btn-dangerous.ant-btn-text:hover>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-text:focus>a:only-child:after,.ant-btn-dangerous.ant-btn-text:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-text:active{color:#c9325d;border-color:transparent;background:rgba(0,0,0,.028)}.ant-btn-dangerous.ant-btn-text:active>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-text:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-dangerous.ant-btn-text[disabled],.ant-btn-dangerous.ant-btn-text[disabled]:active,.ant-btn-dangerous.ant-btn-text[disabled]:focus,.ant-btn-dangerous.ant-btn-text[disabled]:hover{color:rgba(0,0,0,.25);border-color:transparent;background:transparent;text-shadow:none;box-shadow:none}.ant-btn-dangerous.ant-btn-text[disabled]:active>a:only-child,.ant-btn-dangerous.ant-btn-text[disabled]:focus>a:only-child,.ant-btn-dangerous.ant-btn-text[disabled]:hover>a:only-child,.ant-btn-dangerous.ant-btn-text[disabled]>a:only-child{color:currentcolor}.ant-btn-dangerous.ant-btn-text[disabled]:active>a:only-child:after,.ant-btn-dangerous.ant-btn-text[disabled]:focus>a:only-child:after,.ant-btn-dangerous.ant-btn-text[disabled]:hover>a:only-child:after,.ant-btn-dangerous.ant-btn-text[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-icon-only{width:32px;height:32px;padding:2.4px 0;font-size:16px;border-radius:4px;vertical-align:-3px}.ant-btn-icon-only>*{font-size:16px}.ant-btn-icon-only.ant-btn-lg{width:40px;height:40px;padding:4.9px 0;font-size:18px;border-radius:4px}.ant-btn-icon-only.ant-btn-lg>*{font-size:18px}.ant-btn-icon-only.ant-btn-sm{width:24px;height:24px;padding:0;font-size:14px;border-radius:4px}.ant-btn-icon-only.ant-btn-sm>*{font-size:14px}.ant-btn-icon-only>.anticon{display:flex;justify-content:center}.ant-btn-icon-only .anticon-loading{padding:0!important}a.ant-btn-icon-only{vertical-align:-1px}a.ant-btn-icon-only>.anticon{display:inline}.ant-btn-round{height:32px;padding:4px 16px;font-size:14px;border-radius:32px}.ant-btn-round.ant-btn-lg{height:40px;padding:6.4px 20px;font-size:16px;border-radius:40px}.ant-btn-round.ant-btn-sm{height:24px;padding:0 12px;font-size:14px;border-radius:24px}.ant-btn-round.ant-btn-icon-only{width:auto}.ant-btn-circle{min-width:32px;padding-right:0;padding-left:0;text-align:center;border-radius:50%}.ant-btn-circle.ant-btn-lg{min-width:40px;border-radius:50%}.ant-btn-circle.ant-btn-sm{min-width:24px;border-radius:50%}.ant-btn:before{position:absolute;top:-1px;right:-1px;bottom:-1px;left:-1px;z-index:1;display:none;background:#fff;border-radius:inherit;opacity:.35;transition:opacity .2s;content:"";pointer-events:none}.ant-btn .anticon{transition:margin-left .3s cubic-bezier(.645,.045,.355,1)}.ant-btn .anticon.anticon-minus>svg,.ant-btn .anticon.anticon-plus>svg{shape-rendering:optimizespeed}.ant-btn.ant-btn-loading{position:relative;cursor:default}.ant-btn.ant-btn-loading:before{display:block}.ant-btn>.ant-btn-loading-icon{transition:width .3s cubic-bezier(.645,.045,.355,1),opacity .3s cubic-bezier(.645,.045,.355,1)}.ant-btn>.ant-btn-loading-icon .anticon{padding-right:8px;animation:none}.ant-btn>.ant-btn-loading-icon .anticon svg{animation:loadingCircle 1s linear infinite}.ant-btn-group{position:relative;display:inline-flex}.ant-btn-group>.ant-btn,.ant-btn-group>span>.ant-btn{position:relative}.ant-btn-group>.ant-btn:active,.ant-btn-group>.ant-btn:focus,.ant-btn-group>.ant-btn:hover,.ant-btn-group>span>.ant-btn:active,.ant-btn-group>span>.ant-btn:focus,.ant-btn-group>span>.ant-btn:hover{z-index:2}.ant-btn-group>.ant-btn[disabled],.ant-btn-group>span>.ant-btn[disabled]{z-index:0}.ant-btn-group .ant-btn-icon-only{font-size:14px}.ant-btn+.ant-btn-group,.ant-btn-group+.ant-btn,.ant-btn-group+.ant-btn-group,.ant-btn-group .ant-btn+.ant-btn,.ant-btn-group .ant-btn+span,.ant-btn-group>span+span,.ant-btn-group span+.ant-btn{margin-left:-1px}.ant-btn-group .ant-btn-primary+.ant-btn:not(.ant-btn-primary):not([disabled]){border-left-color:transparent}.ant-btn-group .ant-btn{border-radius:0}.ant-btn-group>.ant-btn:first-child,.ant-btn-group>span:first-child>.ant-btn{margin-left:0}.ant-btn-group>.ant-btn:only-child{border-radius:4px}.ant-btn-group>span:only-child>.ant-btn{border-radius:4px}.ant-btn-group>.ant-btn:first-child:not(:last-child),.ant-btn-group>span:first-child:not(:last-child)>.ant-btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.ant-btn-group>.ant-btn:last-child:not(:first-child),.ant-btn-group>span:last-child:not(:first-child)>.ant-btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.ant-btn-group-sm>.ant-btn:only-child{border-radius:4px}.ant-btn-group-sm>span:only-child>.ant-btn{border-radius:4px}.ant-btn-group-sm>.ant-btn:first-child:not(:last-child),.ant-btn-group-sm>span:first-child:not(:last-child)>.ant-btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.ant-btn-group-sm>.ant-btn:last-child:not(:first-child),.ant-btn-group-sm>span:last-child:not(:first-child)>.ant-btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.ant-btn-group>.ant-btn-group{float:left}.ant-btn-group>.ant-btn-group:not(:first-child):not(:last-child)>.ant-btn{border-radius:0}.ant-btn-group>.ant-btn-group:first-child:not(:last-child)>.ant-btn:last-child{padding-right:8px;border-top-right-radius:0;border-bottom-right-radius:0}.ant-btn-group>.ant-btn-group:last-child:not(:first-child)>.ant-btn:first-child{padding-left:8px;border-top-left-radius:0;border-bottom-left-radius:0}.ant-btn-group-rtl.ant-btn+.ant-btn-group,.ant-btn-group-rtl.ant-btn-group+.ant-btn,.ant-btn-group-rtl.ant-btn-group+.ant-btn-group,.ant-btn-group-rtl.ant-btn-group .ant-btn+.ant-btn,.ant-btn-group-rtl.ant-btn-group .ant-btn+span,.ant-btn-group-rtl.ant-btn-group>span+span,.ant-btn-group-rtl.ant-btn-group span+.ant-btn,.ant-btn-rtl.ant-btn+.ant-btn-group,.ant-btn-rtl.ant-btn-group+.ant-btn,.ant-btn-rtl.ant-btn-group+.ant-btn-group,.ant-btn-rtl.ant-btn-group .ant-btn+.ant-btn,.ant-btn-rtl.ant-btn-group .ant-btn+span,.ant-btn-rtl.ant-btn-group>span+span,.ant-btn-rtl.ant-btn-group span+.ant-btn{margin-right:-1px;margin-left:auto}.ant-btn-group.ant-btn-group-rtl{direction:rtl}.ant-btn-group-rtl.ant-btn-group>.ant-btn:first-child:not(:last-child),.ant-btn-group-rtl.ant-btn-group>span:first-child:not(:last-child)>.ant-btn{border-radius:0 4px 4px 0}.ant-btn-group-rtl.ant-btn-group>.ant-btn:last-child:not(:first-child),.ant-btn-group-rtl.ant-btn-group>span:last-child:not(:first-child)>.ant-btn{border-radius:4px 0 0 4px}.ant-btn-group-rtl.ant-btn-group-sm>.ant-btn:first-child:not(:last-child),.ant-btn-group-rtl.ant-btn-group-sm>span:first-child:not(:last-child)>.ant-btn{border-radius:0 4px 4px 0}.ant-btn-group-rtl.ant-btn-group-sm>.ant-btn:last-child:not(:first-child),.ant-btn-group-rtl.ant-btn-group-sm>span:last-child:not(:first-child)>.ant-btn{border-radius:4px 0 0 4px}.ant-btn:active>span,.ant-btn:focus>span{position:relative}.ant-btn>.anticon+span,.ant-btn>span+.anticon{margin-left:8px}.ant-btn.ant-btn-background-ghost{color:#fff;border-color:#fff}.ant-btn.ant-btn-background-ghost,.ant-btn.ant-btn-background-ghost:active,.ant-btn.ant-btn-background-ghost:focus,.ant-btn.ant-btn-background-ghost:hover{background:transparent}.ant-btn.ant-btn-background-ghost:focus,.ant-btn.ant-btn-background-ghost:hover{color:#5493ff;border-color:#5493ff}.ant-btn.ant-btn-background-ghost:active{color:#184ecc;border-color:#184ecc}.ant-btn.ant-btn-background-ghost[disabled]{color:rgba(0,0,0,.25);background:transparent;border-color:rgba(0,0,0,.15)}.ant-btn-background-ghost.ant-btn-primary{color:#296df3;border-color:#296df3;text-shadow:none}.ant-btn-background-ghost.ant-btn-primary>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-primary>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-primary:focus,.ant-btn-background-ghost.ant-btn-primary:hover{color:#5493ff;border-color:#5493ff}.ant-btn-background-ghost.ant-btn-primary:focus>a:only-child,.ant-btn-background-ghost.ant-btn-primary:hover>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-primary:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-primary:active{color:#184ecc;border-color:#184ecc}.ant-btn-background-ghost.ant-btn-primary:active>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-primary:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-primary[disabled],.ant-btn-background-ghost.ant-btn-primary[disabled]:active,.ant-btn-background-ghost.ant-btn-primary[disabled]:focus,.ant-btn-background-ghost.ant-btn-primary[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-background-ghost.ant-btn-primary[disabled]:active>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled]:focus>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled]:hover>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled]>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-primary[disabled]:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled]:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled]:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-danger{color:#ef4872;border-color:#ef4872;text-shadow:none}.ant-btn-background-ghost.ant-btn-danger>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-danger>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-danger:focus,.ant-btn-background-ghost.ant-btn-danger:hover{color:#fc7492;border-color:#fc7492}.ant-btn-background-ghost.ant-btn-danger:focus>a:only-child,.ant-btn-background-ghost.ant-btn-danger:hover>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-danger:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-danger:active{color:#c9325d;border-color:#c9325d}.ant-btn-background-ghost.ant-btn-danger:active>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-danger:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-danger[disabled],.ant-btn-background-ghost.ant-btn-danger[disabled]:active,.ant-btn-background-ghost.ant-btn-danger[disabled]:focus,.ant-btn-background-ghost.ant-btn-danger[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-background-ghost.ant-btn-danger[disabled]:active>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled]:focus>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled]:hover>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled]>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-danger[disabled]:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled]:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled]:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous{color:#ef4872;border-color:#ef4872;text-shadow:none}.ant-btn-background-ghost.ant-btn-dangerous>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous:focus,.ant-btn-background-ghost.ant-btn-dangerous:hover{color:#fc7492;border-color:#fc7492}.ant-btn-background-ghost.ant-btn-dangerous:focus>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous:hover>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous:active{color:#c9325d;border-color:#c9325d}.ant-btn-background-ghost.ant-btn-dangerous:active>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous[disabled],.ant-btn-background-ghost.ant-btn-dangerous[disabled]:active,.ant-btn-background-ghost.ant-btn-dangerous[disabled]:focus,.ant-btn-background-ghost.ant-btn-dangerous[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-background-ghost.ant-btn-dangerous[disabled]:active>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous[disabled]:focus>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous[disabled]:hover>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous[disabled]>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous[disabled]:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous[disabled]:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous[disabled]:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link{color:#ef4872;border-color:transparent;text-shadow:none}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:focus,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:hover{color:#fc7492;border-color:transparent}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:focus>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:hover>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:hover>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:active{color:#c9325d;border-color:transparent}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:active>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link:active>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled],.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:active,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:focus,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:hover{color:rgba(0,10,36,.25);border-color:rgba(0,10,36,.15);background:rgba(0,10,36,.04);text-shadow:none;box-shadow:none}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:active>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:focus>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:hover>a:only-child,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]>a:only-child{color:currentcolor}.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-dangerous.ant-btn-link[disabled]>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}.ant-btn-two-chinese-chars:first-letter{letter-spacing:.34em}.ant-btn-two-chinese-chars>:not(.anticon){margin-right:-.34em;letter-spacing:.34em}.ant-btn.ant-btn-block{width:100%}.ant-btn:empty{display:inline-block;width:0;visibility:hidden;content:"\a0"}a.ant-btn{padding-top:.01px!important;line-height:30px}a.ant-btn-disabled{cursor:not-allowed}a.ant-btn-disabled>*{pointer-events:none}a.ant-btn-disabled,a.ant-btn-disabled:active,a.ant-btn-disabled:focus,a.ant-btn-disabled:hover{color:rgba(0,10,36,.25);border-color:transparent;background:transparent;text-shadow:none;box-shadow:none}a.ant-btn-disabled:active>a:only-child,a.ant-btn-disabled:focus>a:only-child,a.ant-btn-disabled:hover>a:only-child,a.ant-btn-disabled>a:only-child{color:currentcolor}a.ant-btn-disabled:active>a:only-child:after,a.ant-btn-disabled:focus>a:only-child:after,a.ant-btn-disabled:hover>a:only-child:after,a.ant-btn-disabled>a:only-child:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;content:""}a.ant-btn-lg{line-height:38px}a.ant-btn-sm{line-height:22px}.ant-btn-compact-item:not(.ant-btn-compact-last-item):not(.ant-btn-compact-item-rtl){margin-right:-1px}.ant-btn-compact-item:not(.ant-btn-compact-last-item).ant-btn-compact-item-rtl{margin-left:-1px}.ant-btn-compact-item:active,.ant-btn-compact-item:focus,.ant-btn-compact-item:hover{z-index:2}.ant-btn-compact-item[disabled]{z-index:0}.ant-btn-compact-item:not(.ant-btn-compact-first-item):not(.ant-btn-compact-last-item).ant-btn{border-radius:0}.ant-btn-compact-item.ant-btn.ant-btn-compact-first-item:not(.ant-btn-compact-last-item):not(.ant-btn-compact-item-rtl){border-top-right-radius:0;border-bottom-right-radius:0}.ant-btn-compact-item.ant-btn.ant-btn-compact-last-item:not(.ant-btn-compact-first-item):not(.ant-btn-compact-item-rtl){border-top-left-radius:0;border-bottom-left-radius:0}.ant-btn-compact-item.ant-btn.ant-btn-compact-item-rtl.ant-btn-compact-first-item:not(.ant-btn-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-btn-compact-item.ant-btn.ant-btn-compact-item-rtl.ant-btn-compact-last-item:not(.ant-btn-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-btn-icon-only.ant-btn-compact-item{flex:none}.ant-btn-compact-item.ant-btn-primary:not([disabled])+.ant-btn-compact-item.ant-btn-primary:not([disabled]){position:relative}.ant-btn-compact-item.ant-btn-primary:not([disabled])+.ant-btn-compact-item.ant-btn-primary:not([disabled]):after{position:absolute;top:-1px;left:-1px;display:inline-block;width:1px;height:calc(100% + 2px);background-color:#4e86f5;content:" "}.ant-btn-compact-item-rtl.ant-btn-compact-first-item.ant-btn-compact-item-rtl:not(.ant-btn-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-btn-compact-item-rtl.ant-btn-compact-last-item.ant-btn-compact-item-rtl:not(.ant-btn-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-btn-compact-item-rtl.ant-btn-sm.ant-btn-compact-first-item.ant-btn-compact-item-rtl.ant-btn-sm:not(.ant-btn-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-btn-compact-item-rtl.ant-btn-sm.ant-btn-compact-last-item.ant-btn-compact-item-rtl.ant-btn-sm:not(.ant-btn-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-btn-compact-item-rtl.ant-btn-primary:not([disabled])+.ant-btn-compact-item-rtl.ant-btn-primary:not([disabled]):after{right:-1px}.ant-btn-compact-vertical-item:not(.ant-btn-compact-vertical-last-item){margin-bottom:-1px}.ant-btn-compact-vertical-item:active,.ant-btn-compact-vertical-item:focus,.ant-btn-compact-vertical-item:hover{z-index:2}.ant-btn-compact-vertical-item[disabled]{z-index:0}.ant-btn-compact-vertical-item:not(.ant-btn-compact-vertical-first-item):not(.ant-btn-compact-vertical-last-item){border-radius:0}.ant-btn-compact-vertical-item.ant-btn-compact-vertical-first-item:not(.ant-btn-compact-vertical-last-item){border-bottom-right-radius:0;border-bottom-left-radius:0}.ant-btn-compact-vertical-item.ant-btn-compact-vertical-last-item:not(.ant-btn-compact-vertical-first-item){border-top-left-radius:0;border-top-right-radius:0}.ant-btn-compact-vertical-item.ant-btn-primary:not([disabled])+.ant-btn-compact-vertical-item.ant-btn-primary:not([disabled]){position:relative}.ant-btn-compact-vertical-item.ant-btn-primary:not([disabled])+.ant-btn-compact-vertical-item.ant-btn-primary:not([disabled]):after{position:absolute;top:-1px;left:-1px;display:inline-block;width:calc(100% + 2px);height:1px;background-color:#4e86f5;content:" "}.ant-btn-rtl{direction:rtl}.ant-btn-group-rtl.ant-btn-group .ant-btn-primary+.ant-btn-primary,.ant-btn-group-rtl.ant-btn-group .ant-btn-primary:last-child:not(:first-child){border-right-color:#4e86f5;border-left-color:rgba(0,0,0,.15)}.ant-btn-group-rtl.ant-btn-group .ant-btn-primary+.ant-btn-primary[disabled],.ant-btn-group-rtl.ant-btn-group .ant-btn-primary:last-child:not(:first-child)[disabled]{border-right-color:rgba(0,0,0,.15);border-left-color:#4e86f5}.ant-btn-rtl.ant-btn>.ant-btn-loading-icon .anticon{padding-right:0;padding-left:8px}.ant-btn-rtl.ant-btn>.anticon+span,.ant-btn-rtl.ant-btn>span+.anticon{margin-right:8px;margin-left:0}.ant-notification{box-sizing:border-box;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:fixed;z-index:1010;margin:0 24px 0 0}.ant-notification-close-icon{font-size:14px;cursor:pointer}.ant-notification-hook-holder{position:relative}.ant-notification-notice{position:relative;width:384px;max-width:calc(100vw - 48px);margin-bottom:16px;margin-left:auto;padding:16px 24px;overflow:hidden;line-height:1.5715;word-wrap:break-word;background:#fff;border-radius:4px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}.ant-notification-bottom .ant-notification-notice,.ant-notification-top .ant-notification-notice{margin-right:auto;margin-left:auto}.ant-notification-bottomLeft .ant-notification-notice,.ant-notification-topLeft .ant-notification-notice{margin-right:auto;margin-left:0}.ant-notification-notice-message{margin-bottom:8px;color:rgba(0,10,36,.85);font-size:16px;line-height:24px}.ant-notification-notice-message-single-line-auto-margin{display:block;width:calc(264px - 100%);max-width:4px;background-color:transparent;pointer-events:none}.ant-notification-notice-message-single-line-auto-margin:before{display:block;content:""}.ant-notification-notice-description{font-size:14px}.ant-notification-notice-closable .ant-notification-notice-message{padding-right:24px}.ant-notification-notice-with-icon .ant-notification-notice-message{margin-bottom:4px;margin-left:48px;font-size:16px}.ant-notification-notice-with-icon .ant-notification-notice-description{margin-left:48px;font-size:14px}.ant-notification-notice-icon{position:absolute;margin-left:4px;font-size:24px;line-height:24px}.anticon.ant-notification-notice-icon-success{color:#26c992}.anticon.ant-notification-notice-icon-info{color:#296df3}.anticon.ant-notification-notice-icon-warning{color:#ffb924}.anticon.ant-notification-notice-icon-error{color:#ef4872}.ant-notification-notice-close{position:absolute;top:16px;right:22px;color:rgba(0,10,36,.65);outline:none}.ant-notification-notice-close:hover{color:rgba(0,4,15,.79)}.ant-notification-notice-btn{float:right;margin-top:16px}.ant-notification .notification-fade-effect{animation-duration:.24s;animation-timing-function:cubic-bezier(.645,.045,.355,1);animation-fill-mode:both}.ant-notification-fade-appear,.ant-notification-fade-enter{animation-duration:.24s;animation-timing-function:cubic-bezier(.645,.045,.355,1);animation-fill-mode:both;opacity:0;animation-play-state:paused}.ant-notification-fade-leave{animation-duration:.24s;animation-timing-function:cubic-bezier(.645,.045,.355,1);animation-fill-mode:both;animation-duration:.2s;animation-play-state:paused}.ant-notification-fade-appear.ant-notification-fade-appear-active,.ant-notification-fade-enter.ant-notification-fade-enter-active{animation-name:NotificationFadeIn;animation-play-state:running}.ant-notification-fade-leave.ant-notification-fade-leave-active{animation-name:NotificationFadeOut;animation-play-state:running}@keyframes NotificationFadeIn{0%{left:384px;opacity:0}to{left:0;opacity:1}}@keyframes NotificationFadeOut{0%{max-height:150px;margin-bottom:16px;opacity:1}to{max-height:0;margin-bottom:0;padding-top:0;padding-bottom:0;opacity:0}}.ant-notification-rtl{direction:rtl}.ant-notification-rtl .ant-notification-notice-closable .ant-notification-notice-message{padding-right:0;padding-left:24px}.ant-notification-rtl .ant-notification-notice-with-icon .ant-notification-notice-message{margin-right:48px;margin-left:0}.ant-notification-rtl .ant-notification-notice-with-icon .ant-notification-notice-description{margin-right:48px;margin-left:0}.ant-notification-rtl .ant-notification-notice-icon{margin-right:4px;margin-left:0}.ant-notification-rtl .ant-notification-notice-close{right:auto;left:22px}.ant-notification-rtl .ant-notification-notice-btn{float:left}.ant-notification-bottom,.ant-notification-top{margin-right:0;margin-left:0}.ant-notification-top .ant-notification-fade-appear.ant-notification-fade-appear-active,.ant-notification-top .ant-notification-fade-enter.ant-notification-fade-enter-active{animation-name:NotificationTopFadeIn}.ant-notification-bottom .ant-notification-fade-appear.ant-notification-fade-appear-active,.ant-notification-bottom .ant-notification-fade-enter.ant-notification-fade-enter-active{animation-name:NotificationBottomFadeIn}.ant-notification-bottomLeft,.ant-notification-topLeft{margin-right:0;margin-left:24px}.ant-notification-bottomLeft .ant-notification-fade-appear.ant-notification-fade-appear-active,.ant-notification-bottomLeft .ant-notification-fade-enter.ant-notification-fade-enter-active,.ant-notification-topLeft .ant-notification-fade-appear.ant-notification-fade-appear-active,.ant-notification-topLeft .ant-notification-fade-enter.ant-notification-fade-enter-active{animation-name:NotificationLeftFadeIn}@keyframes NotificationTopFadeIn{0%{margin-top:-100%;opacity:0}to{margin-top:0;opacity:1}}@keyframes NotificationBottomFadeIn{0%{margin-bottom:-100%;opacity:0}to{margin-bottom:0;opacity:1}}@keyframes NotificationLeftFadeIn{0%{right:384px;opacity:0}to{right:0;opacity:1}}.ant-message{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:fixed;top:8px;left:0;z-index:1010;width:100%;pointer-events:none}.ant-message-notice{padding:8px;text-align:center}.ant-message-notice-content{display:inline-block;padding:10px 16px;background:#fff;border-radius:4px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);pointer-events:all}.ant-message-success .anticon{color:#26c992}.ant-message-error .anticon{color:#ef4872}.ant-message-warning .anticon{color:#ffb924}.ant-message-info .anticon,.ant-message-loading .anticon{color:#296df3}.ant-message .anticon{position:relative;top:1px;margin-right:8px;font-size:16px}.ant-message-notice.ant-move-up-leave.ant-move-up-leave-active{animation-name:MessageMoveOut;animation-duration:.3s}@keyframes MessageMoveOut{0%{max-height:150px;padding:8px;opacity:1}to{max-height:0;padding:0;opacity:0}}.ant-message-rtl{direction:rtl}.ant-message-rtl span{direction:rtl}.ant-message-rtl .anticon{margin-right:0;margin-left:8px}.ant-dropdown-menu-item.ant-dropdown-menu-item-danger{color:#ef4872}.ant-dropdown-menu-item.ant-dropdown-menu-item-danger:hover{color:#fff;background-color:#ef4872}.ant-dropdown{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:absolute;top:-9999px;left:-9999px;z-index:1050;display:block}.ant-dropdown:before{position:absolute;top:-4px;right:0;bottom:-4px;left:-7px;z-index:-9999;opacity:.0001;content:" "}.ant-dropdown-wrap{position:relative}.ant-dropdown-wrap .ant-btn>.anticon-down{font-size:10px}.ant-dropdown-wrap .anticon-down:before{transition:transform .2s}.ant-dropdown-wrap-open .anticon-down:before{transform:rotate(180deg)}.ant-dropdown-hidden,.ant-dropdown-menu-hidden,.ant-dropdown-menu-submenu-hidden{display:none}.ant-dropdown-show-arrow.ant-dropdown-placement-top,.ant-dropdown-show-arrow.ant-dropdown-placement-topLeft,.ant-dropdown-show-arrow.ant-dropdown-placement-topRight{padding-bottom:15.3137085px}.ant-dropdown-show-arrow.ant-dropdown-placement-bottom,.ant-dropdown-show-arrow.ant-dropdown-placement-bottomLeft,.ant-dropdown-show-arrow.ant-dropdown-placement-bottomRight{padding-top:15.3137085px}.ant-dropdown-arrow{position:absolute;z-index:1;display:block;width:11.3137085px;height:11.3137085px;border-radius:0 0 2px;pointer-events:none}.ant-dropdown-arrow:before{position:absolute;top:-11.3137085px;left:-11.3137085px;width:33.9411255px;height:33.9411255px;background:#fff;background-repeat:no-repeat;background-position:-10px -10px;content:"";-webkit-clip-path:inset(33% 33%);clip-path:inset(33% 33%);-webkit-clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z");clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z")}.ant-dropdown-placement-top>.ant-dropdown-arrow,.ant-dropdown-placement-topLeft>.ant-dropdown-arrow,.ant-dropdown-placement-topRight>.ant-dropdown-arrow{bottom:10px;box-shadow:3px 3px 7px -3px rgba(0,0,0,.1);transform:rotate(45deg)}.ant-dropdown-placement-top>.ant-dropdown-arrow{left:50%;transform:translateX(-50%) rotate(45deg)}.ant-dropdown-placement-topLeft>.ant-dropdown-arrow{left:16px}.ant-dropdown-placement-topRight>.ant-dropdown-arrow{right:16px}.ant-dropdown-placement-bottom>.ant-dropdown-arrow,.ant-dropdown-placement-bottomLeft>.ant-dropdown-arrow,.ant-dropdown-placement-bottomRight>.ant-dropdown-arrow{top:9.41421356px;box-shadow:2px 2px 5px -2px rgba(0,0,0,.1);transform:rotate(-135deg) translateY(-.5px)}.ant-dropdown-placement-bottom>.ant-dropdown-arrow{left:50%;transform:translateX(-50%) rotate(-135deg) translateY(-.5px)}.ant-dropdown-placement-bottomLeft>.ant-dropdown-arrow{left:16px}.ant-dropdown-placement-bottomRight>.ant-dropdown-arrow{right:16px}.ant-dropdown-menu{position:relative;margin:0;padding:4px 0;text-align:left;list-style-type:none;background-color:#fff;background-clip:padding-box;border-radius:4px;outline:none;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}.ant-dropdown-menu-item-group-title{padding:5px 12px;color:rgba(0,10,36,.65);transition:all .3s}.ant-dropdown-menu-submenu-popup{position:absolute;z-index:1050;background:transparent;box-shadow:none;transform-origin:0 0}.ant-dropdown-menu-submenu-popup li,.ant-dropdown-menu-submenu-popup ul{list-style:none}.ant-dropdown-menu-submenu-popup ul{margin-right:.3em;margin-left:.3em}.ant-dropdown-menu-item{position:relative;display:flex;align-items:center}.ant-dropdown-menu-item-icon{min-width:12px;margin-right:8px;font-size:12px}.ant-dropdown-menu-title-content{flex:auto}.ant-dropdown-menu-title-content>a{color:inherit;transition:all .3s}.ant-dropdown-menu-title-content>a:hover{color:inherit}.ant-dropdown-menu-title-content>a:after{position:absolute;top:0;right:0;bottom:0;left:0;content:""}.ant-dropdown-menu-item,.ant-dropdown-menu-submenu-title{clear:both;margin:0;padding:5px 12px;color:rgba(0,10,36,.85);font-weight:400;font-size:14px;line-height:22px;cursor:pointer;transition:all .3s}.ant-dropdown-menu-item-selected,.ant-dropdown-menu-submenu-title-selected{color:#296df3;background-color:#e3ecfd}.ant-dropdown-menu-item.ant-dropdown-menu-item-active,.ant-dropdown-menu-item.ant-dropdown-menu-submenu-title-active,.ant-dropdown-menu-item:hover,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-item-active,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-submenu-title-active,.ant-dropdown-menu-submenu-title:hover{background-color:#f5f5f5}.ant-dropdown-menu-item.ant-dropdown-menu-item-disabled,.ant-dropdown-menu-item.ant-dropdown-menu-submenu-title-disabled,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-item-disabled,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-submenu-title-disabled{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-dropdown-menu-item.ant-dropdown-menu-item-disabled:hover,.ant-dropdown-menu-item.ant-dropdown-menu-submenu-title-disabled:hover,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-item-disabled:hover,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-submenu-title-disabled:hover{color:rgba(0,0,0,.25);background-color:#fff;cursor:not-allowed}.ant-dropdown-menu-item.ant-dropdown-menu-item-disabled a,.ant-dropdown-menu-item.ant-dropdown-menu-submenu-title-disabled a,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-item-disabled a,.ant-dropdown-menu-submenu-title.ant-dropdown-menu-submenu-title-disabled a{pointer-events:none}.ant-dropdown-menu-item-divider,.ant-dropdown-menu-submenu-title-divider{height:1px;margin:4px 0;overflow:hidden;line-height:0;background-color:#f0f0f0}.ant-dropdown-menu-item .ant-dropdown-menu-submenu-expand-icon,.ant-dropdown-menu-submenu-title .ant-dropdown-menu-submenu-expand-icon{position:absolute;right:8px}.ant-dropdown-menu-item .ant-dropdown-menu-submenu-expand-icon .ant-dropdown-menu-submenu-arrow-icon,.ant-dropdown-menu-submenu-title .ant-dropdown-menu-submenu-expand-icon .ant-dropdown-menu-submenu-arrow-icon{margin-right:0!important;color:rgba(0,10,36,.65);font-size:10px;font-style:normal}.ant-dropdown-menu-item-group-list{margin:0 8px;padding:0;list-style:none}.ant-dropdown-menu-submenu-title{padding-right:24px}.ant-dropdown-menu-submenu-vertical{position:relative}.ant-dropdown-menu-submenu-vertical>.ant-dropdown-menu{position:absolute;top:0;left:100%;min-width:100%;margin-left:4px;transform-origin:0 0}.ant-dropdown-menu-submenu.ant-dropdown-menu-submenu-disabled .ant-dropdown-menu-submenu-title,.ant-dropdown-menu-submenu.ant-dropdown-menu-submenu-disabled .ant-dropdown-menu-submenu-title .ant-dropdown-menu-submenu-arrow-icon{color:rgba(0,0,0,.25);background-color:#fff;cursor:not-allowed}.ant-dropdown-menu-submenu-selected .ant-dropdown-menu-submenu-title{color:#296df3}.ant-dropdown.ant-slide-down-appear.ant-slide-down-appear-active.ant-dropdown-placement-bottom,.ant-dropdown.ant-slide-down-appear.ant-slide-down-appear-active.ant-dropdown-placement-bottomLeft,.ant-dropdown.ant-slide-down-appear.ant-slide-down-appear-active.ant-dropdown-placement-bottomRight,.ant-dropdown.ant-slide-down-enter.ant-slide-down-enter-active.ant-dropdown-placement-bottom,.ant-dropdown.ant-slide-down-enter.ant-slide-down-enter-active.ant-dropdown-placement-bottomLeft,.ant-dropdown.ant-slide-down-enter.ant-slide-down-enter-active.ant-dropdown-placement-bottomRight{animation-name:antSlideUpIn}.ant-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-dropdown-placement-top,.ant-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-dropdown-placement-topLeft,.ant-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-dropdown-placement-topRight,.ant-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-dropdown-placement-top,.ant-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-dropdown-placement-topLeft,.ant-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-dropdown-placement-topRight{animation-name:antSlideDownIn}.ant-dropdown.ant-slide-down-leave.ant-slide-down-leave-active.ant-dropdown-placement-bottom,.ant-dropdown.ant-slide-down-leave.ant-slide-down-leave-active.ant-dropdown-placement-bottomLeft,.ant-dropdown.ant-slide-down-leave.ant-slide-down-leave-active.ant-dropdown-placement-bottomRight{animation-name:antSlideUpOut}.ant-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-dropdown-placement-top,.ant-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-dropdown-placement-topLeft,.ant-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-dropdown-placement-topRight{animation-name:antSlideDownOut}.ant-dropdown-button>.anticon.anticon-down,.ant-dropdown-link>.anticon.anticon-down,.ant-dropdown-trigger>.anticon.anticon-down{font-size:10px;vertical-align:baseline}.ant-dropdown-button{white-space:nowrap}.ant-dropdown-button.ant-btn-group>.ant-btn-loading,.ant-dropdown-button.ant-btn-group>.ant-btn-loading+.ant-btn{cursor:default;pointer-events:none}.ant-dropdown-button.ant-btn-group>.ant-btn-loading+.ant-btn:before{display:block}.ant-dropdown-button.ant-btn-group>.ant-btn:last-child:not(:first-child):not(.ant-btn-icon-only){padding-right:8px;padding-left:8px}.ant-dropdown-menu-dark,.ant-dropdown-menu-dark .ant-dropdown-menu{background:#001529}.ant-dropdown-menu-dark .ant-dropdown-menu-item,.ant-dropdown-menu-dark .ant-dropdown-menu-item>.anticon+span>a,.ant-dropdown-menu-dark .ant-dropdown-menu-item>a,.ant-dropdown-menu-dark .ant-dropdown-menu-submenu-title{color:hsla(0,0%,100%,.65)}.ant-dropdown-menu-dark .ant-dropdown-menu-item .ant-dropdown-menu-submenu-arrow:after,.ant-dropdown-menu-dark .ant-dropdown-menu-item>.anticon+span>a .ant-dropdown-menu-submenu-arrow:after,.ant-dropdown-menu-dark .ant-dropdown-menu-item>a .ant-dropdown-menu-submenu-arrow:after,.ant-dropdown-menu-dark .ant-dropdown-menu-submenu-title .ant-dropdown-menu-submenu-arrow:after{color:hsla(0,0%,100%,.65)}.ant-dropdown-menu-dark .ant-dropdown-menu-item:hover,.ant-dropdown-menu-dark .ant-dropdown-menu-item>.anticon+span>a:hover,.ant-dropdown-menu-dark .ant-dropdown-menu-item>a:hover,.ant-dropdown-menu-dark .ant-dropdown-menu-submenu-title:hover{color:#fff;background:transparent}.ant-dropdown-menu-dark .ant-dropdown-menu-item-selected,.ant-dropdown-menu-dark .ant-dropdown-menu-item-selected:hover,.ant-dropdown-menu-dark .ant-dropdown-menu-item-selected>a{color:#fff;background:#296df3}.ant-dropdown-rtl{direction:rtl}.ant-dropdown-rtl.ant-dropdown:before{right:-7px;left:0}.ant-dropdown-menu.ant-dropdown-menu-rtl{direction:rtl;text-align:right}.ant-dropdown-menu-submenu-rtl .ant-dropdown-menu-item-group-title,.ant-dropdown-rtl .ant-dropdown-menu-item-group-title{direction:rtl;text-align:right}.ant-dropdown-menu-submenu-popup.ant-dropdown-menu-submenu-rtl{transform-origin:100% 0}.ant-dropdown-rtl .ant-dropdown-menu-submenu-popup li,.ant-dropdown-rtl .ant-dropdown-menu-submenu-popup ul{text-align:right}.ant-dropdown-rtl .ant-dropdown-menu-item,.ant-dropdown-rtl .ant-dropdown-menu-submenu-title{text-align:right}.ant-dropdown-rtl .ant-dropdown-menu-item>.anticon:first-child,.ant-dropdown-rtl .ant-dropdown-menu-item>span>.anticon:first-child,.ant-dropdown-rtl .ant-dropdown-menu-submenu-title>.anticon:first-child,.ant-dropdown-rtl .ant-dropdown-menu-submenu-title>span>.anticon:first-child{margin-right:0;margin-left:8px}.ant-dropdown-rtl .ant-dropdown-menu-item .ant-dropdown-menu-submenu-expand-icon,.ant-dropdown-rtl .ant-dropdown-menu-submenu-title .ant-dropdown-menu-submenu-expand-icon{right:auto;left:8px}.ant-dropdown-rtl .ant-dropdown-menu-item .ant-dropdown-menu-submenu-expand-icon .ant-dropdown-menu-submenu-arrow-icon,.ant-dropdown-rtl .ant-dropdown-menu-submenu-title .ant-dropdown-menu-submenu-expand-icon .ant-dropdown-menu-submenu-arrow-icon{margin-left:0!important;transform:scaleX(-1)}.ant-dropdown-rtl .ant-dropdown-menu-submenu-title{padding-right:12px;padding-left:24px}.ant-dropdown-rtl .ant-dropdown-menu-submenu-vertical>.ant-dropdown-menu{right:100%;left:0;margin-right:4px;margin-left:0}.ant-menu-item-danger.ant-menu-item{color:#ef4872}.ant-menu-item-danger.ant-menu-item-active,.ant-menu-item-danger.ant-menu-item:hover{color:#ef4872}.ant-menu-item-danger.ant-menu-item:active{background:#fff1f0}.ant-menu-item-danger.ant-menu-item-selected{color:#ef4872}.ant-menu-item-danger.ant-menu-item-selected>a,.ant-menu-item-danger.ant-menu-item-selected>a:hover{color:#ef4872}.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected{background-color:#fff1f0}.ant-menu-inline .ant-menu-item-danger.ant-menu-item:after{border-right-color:#ef4872}.ant-menu-dark .ant-menu-item-danger.ant-menu-item,.ant-menu-dark .ant-menu-item-danger.ant-menu-item:hover,.ant-menu-dark .ant-menu-item-danger.ant-menu-item>a{color:#ef4872}.ant-menu-dark.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected{color:#fff;background-color:#ef4872}.ant-menu{box-sizing:border-box;font-variant:tabular-nums;line-height:1.5715;font-feature-settings:"tnum","tnum";margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;line-height:0;text-align:left;list-style:none;background:#fff;outline:none;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);transition:background .3s,width .3s cubic-bezier(.2,0,0,1) 0s}.ant-menu:before{display:table;content:""}.ant-menu:after{display:table;clear:both;content:""}.ant-menu.ant-menu-root:focus-visible{box-shadow:0 0 0 2px #bed2fb}.ant-menu ol,.ant-menu ul{margin:0;padding:0;list-style:none}.ant-menu-overflow{display:flex}.ant-menu-overflow-item{flex:none}.ant-menu-hidden,.ant-menu-submenu-hidden{display:none}.ant-menu-item-group-title{height:1.5715;padding:8px 16px;color:rgba(0,10,36,.65);font-size:14px;line-height:1.5715;transition:all .3s}.ant-menu-horizontal .ant-menu-submenu{transition:border-color .3s cubic-bezier(.645,.045,.355,1),background .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-submenu,.ant-menu-submenu-inline{transition:border-color .3s cubic-bezier(.645,.045,.355,1),background .3s cubic-bezier(.645,.045,.355,1),padding .15s cubic-bezier(.645,.045,.355,1)}.ant-menu-submenu-selected{color:#296df3}.ant-menu-item:active,.ant-menu-submenu-title:active{background:#e3ecfd}.ant-menu-submenu .ant-menu-sub{cursor:auto;transition:background .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-title-content{transition:color .3s}.ant-menu-item a{color:rgba(0,10,36,.85)}.ant-menu-item a:hover{color:#296df3}.ant-menu-item a:before{position:absolute;top:0;right:0;bottom:0;left:0;background-color:transparent;content:""}.ant-menu-item>.ant-badge a{color:rgba(0,10,36,.85)}.ant-menu-item>.ant-badge a:hover{color:#296df3}.ant-menu-item-divider{overflow:hidden;line-height:0;border:solid #f0f0f0;border-width:1px 0 0}.ant-menu-item-divider-dashed{border-style:dashed}.ant-menu-horizontal .ant-menu-item,.ant-menu-horizontal .ant-menu-submenu{margin-top:-1px}.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu .ant-menu-submenu-title:hover{background-color:transparent}.ant-menu-item-selected{color:#296df3}.ant-menu-item-selected a,.ant-menu-item-selected a:hover{color:#296df3}.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{background-color:#e3ecfd}.ant-menu-inline,.ant-menu-vertical,.ant-menu-vertical-left{border-right:1px solid #f0f0f0}.ant-menu-vertical-right{border-left:1px solid #f0f0f0}.ant-menu-vertical-left.ant-menu-sub,.ant-menu-vertical-right.ant-menu-sub,.ant-menu-vertical.ant-menu-sub{min-width:160px;max-height:calc(100vh - 100px);padding:0;overflow:hidden;border-right:0}.ant-menu-vertical-left.ant-menu-sub:not([class*=-active]),.ant-menu-vertical-right.ant-menu-sub:not([class*=-active]),.ant-menu-vertical.ant-menu-sub:not([class*=-active]){overflow-x:hidden;overflow-y:auto}.ant-menu-vertical-left.ant-menu-sub .ant-menu-item,.ant-menu-vertical-right.ant-menu-sub .ant-menu-item,.ant-menu-vertical.ant-menu-sub .ant-menu-item{left:0;margin-left:0;border-right:0}.ant-menu-vertical-left.ant-menu-sub .ant-menu-item:after,.ant-menu-vertical-right.ant-menu-sub .ant-menu-item:after,.ant-menu-vertical.ant-menu-sub .ant-menu-item:after{border-right:0}.ant-menu-vertical-left.ant-menu-sub>.ant-menu-item,.ant-menu-vertical-left.ant-menu-sub>.ant-menu-submenu,.ant-menu-vertical-right.ant-menu-sub>.ant-menu-item,.ant-menu-vertical-right.ant-menu-sub>.ant-menu-submenu,.ant-menu-vertical.ant-menu-sub>.ant-menu-item,.ant-menu-vertical.ant-menu-sub>.ant-menu-submenu{transform-origin:0 0}.ant-menu-horizontal.ant-menu-sub{min-width:114px}.ant-menu-horizontal .ant-menu-item,.ant-menu-horizontal .ant-menu-submenu-title{transition:border-color .3s,background .3s}.ant-menu-item,.ant-menu-submenu-title{position:relative;display:block;margin:0;padding:0 20px;white-space:nowrap;cursor:pointer;transition:border-color .3s,background .3s,padding .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-item .ant-menu-item-icon,.ant-menu-item .anticon,.ant-menu-submenu-title .ant-menu-item-icon,.ant-menu-submenu-title .anticon{min-width:14px;font-size:14px;transition:font-size .15s cubic-bezier(.215,.61,.355,1),margin .3s cubic-bezier(.645,.045,.355,1),color .3s}.ant-menu-item .ant-menu-item-icon+span,.ant-menu-item .anticon+span,.ant-menu-submenu-title .ant-menu-item-icon+span,.ant-menu-submenu-title .anticon+span{margin-left:10px;opacity:1;transition:opacity .3s cubic-bezier(.645,.045,.355,1),margin .3s,color .3s}.ant-menu-item .ant-menu-item-icon.svg,.ant-menu-submenu-title .ant-menu-item-icon.svg{vertical-align:-.125em}.ant-menu-item.ant-menu-item-only-child>.ant-menu-item-icon,.ant-menu-item.ant-menu-item-only-child>.anticon,.ant-menu-submenu-title.ant-menu-item-only-child>.ant-menu-item-icon,.ant-menu-submenu-title.ant-menu-item-only-child>.anticon{margin-right:0}.ant-menu-item:not(.ant-menu-item-disabled):focus-visible,.ant-menu-submenu-title:not(.ant-menu-item-disabled):focus-visible{box-shadow:0 0 0 2px #bed2fb}.ant-menu>.ant-menu-item-divider{margin:1px 0;padding:0}.ant-menu-submenu-popup{position:absolute;z-index:1050;background:transparent;border-radius:4px;box-shadow:none;transform-origin:0 0}.ant-menu-submenu-popup:before{position:absolute;top:-7px;right:0;bottom:0;left:0;z-index:-1;width:100%;height:100%;opacity:.0001;content:" "}.ant-menu-submenu-placement-rightTop:before{top:0;left:-7px}.ant-menu-submenu>.ant-menu{background-color:#fff;border-radius:4px}.ant-menu-submenu>.ant-menu-submenu-title:after{transition:transform .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-submenu-popup>.ant-menu{background-color:#fff}.ant-menu-submenu-arrow,.ant-menu-submenu-expand-icon{position:absolute;top:50%;right:16px;width:10px;color:rgba(0,10,36,.85);transform:translateY(-50%);transition:transform .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-submenu-arrow:after,.ant-menu-submenu-arrow:before{position:absolute;width:6px;height:1.5px;background-color:currentcolor;border-radius:2px;transition:background .3s cubic-bezier(.645,.045,.355,1),transform .3s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1),color .3s cubic-bezier(.645,.045,.355,1);content:""}.ant-menu-submenu-arrow:before{transform:rotate(45deg) translateY(-2.5px)}.ant-menu-submenu-arrow:after{transform:rotate(-45deg) translateY(2.5px)}.ant-menu-submenu:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-submenu:hover>.ant-menu-submenu-title>.ant-menu-submenu-expand-icon{color:#296df3}.ant-menu-inline-collapsed .ant-menu-submenu-arrow:before,.ant-menu-submenu-inline .ant-menu-submenu-arrow:before{transform:rotate(-45deg) translateX(2.5px)}.ant-menu-inline-collapsed .ant-menu-submenu-arrow:after,.ant-menu-submenu-inline .ant-menu-submenu-arrow:after{transform:rotate(45deg) translateX(-2.5px)}.ant-menu-submenu-horizontal .ant-menu-submenu-arrow{display:none}.ant-menu-submenu-open.ant-menu-submenu-inline>.ant-menu-submenu-title>.ant-menu-submenu-arrow{transform:translateY(-2px)}.ant-menu-submenu-open.ant-menu-submenu-inline>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after{transform:rotate(-45deg) translateX(-2.5px)}.ant-menu-submenu-open.ant-menu-submenu-inline>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{transform:rotate(45deg) translateX(2.5px)}.ant-menu-vertical-left .ant-menu-submenu-selected,.ant-menu-vertical-right .ant-menu-submenu-selected,.ant-menu-vertical .ant-menu-submenu-selected{color:#296df3}.ant-menu-horizontal{line-height:46px;border:0;border-bottom:1px solid #f0f0f0;box-shadow:none}.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu{margin-top:-1px;margin-bottom:0;padding:0 20px}.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item-active,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item-open,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item:hover,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu-active,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu:hover{color:#296df3}.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item-active:after,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item-open:after,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item-selected:after,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-item:hover:after,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu-active:after,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu-open:after,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu-selected:after,.ant-menu-horizontal:not(.ant-menu-dark)>.ant-menu-submenu:hover:after{border-bottom:2px solid #296df3}.ant-menu-horizontal>.ant-menu-item,.ant-menu-horizontal>.ant-menu-submenu{position:relative;top:1px;display:inline-block;vertical-align:bottom}.ant-menu-horizontal>.ant-menu-item:after,.ant-menu-horizontal>.ant-menu-submenu:after{position:absolute;right:20px;bottom:0;left:20px;border-bottom:2px solid transparent;transition:border-color .3s cubic-bezier(.645,.045,.355,1);content:""}.ant-menu-horizontal>.ant-menu-submenu>.ant-menu-submenu-title{padding:0}.ant-menu-horizontal>.ant-menu-item a{color:rgba(0,10,36,.85)}.ant-menu-horizontal>.ant-menu-item a:hover{color:#296df3}.ant-menu-horizontal>.ant-menu-item a:before{bottom:-2px}.ant-menu-horizontal>.ant-menu-item-selected a{color:#296df3}.ant-menu-horizontal:after{display:block;clear:both;height:0;content:"\20"}.ant-menu-inline .ant-menu-item,.ant-menu-vertical-left .ant-menu-item,.ant-menu-vertical-right .ant-menu-item,.ant-menu-vertical .ant-menu-item{position:relative}.ant-menu-inline .ant-menu-item:after,.ant-menu-vertical-left .ant-menu-item:after,.ant-menu-vertical-right .ant-menu-item:after,.ant-menu-vertical .ant-menu-item:after{position:absolute;top:0;right:0;bottom:0;border-right:3px solid #296df3;transform:scaleY(.0001);opacity:0;transition:transform .15s cubic-bezier(.215,.61,.355,1),opacity .15s cubic-bezier(.215,.61,.355,1);content:""}.ant-menu-inline .ant-menu-item,.ant-menu-inline .ant-menu-submenu-title,.ant-menu-vertical-left .ant-menu-item,.ant-menu-vertical-left .ant-menu-submenu-title,.ant-menu-vertical-right .ant-menu-item,.ant-menu-vertical-right .ant-menu-submenu-title,.ant-menu-vertical .ant-menu-item,.ant-menu-vertical .ant-menu-submenu-title{height:40px;margin-top:4px;margin-bottom:4px;padding:0 16px;overflow:hidden;line-height:40px;text-overflow:ellipsis}.ant-menu-inline .ant-menu-submenu,.ant-menu-vertical-left .ant-menu-submenu,.ant-menu-vertical-right .ant-menu-submenu,.ant-menu-vertical .ant-menu-submenu{padding-bottom:.02px}.ant-menu-inline .ant-menu-item:not(:last-child),.ant-menu-vertical-left .ant-menu-item:not(:last-child),.ant-menu-vertical-right .ant-menu-item:not(:last-child),.ant-menu-vertical .ant-menu-item:not(:last-child){margin-bottom:8px}.ant-menu-inline>.ant-menu-item,.ant-menu-inline>.ant-menu-submenu>.ant-menu-submenu-title,.ant-menu-vertical-left>.ant-menu-item,.ant-menu-vertical-left>.ant-menu-submenu>.ant-menu-submenu-title,.ant-menu-vertical-right>.ant-menu-item,.ant-menu-vertical-right>.ant-menu-submenu>.ant-menu-submenu-title,.ant-menu-vertical>.ant-menu-item,.ant-menu-vertical>.ant-menu-submenu>.ant-menu-submenu-title{height:40px;line-height:40px}.ant-menu-vertical .ant-menu-item-group-list .ant-menu-submenu-title,.ant-menu-vertical .ant-menu-submenu-title{padding-right:34px}.ant-menu-inline{width:100%}.ant-menu-inline .ant-menu-item-selected:after,.ant-menu-inline .ant-menu-selected:after{transform:scaleY(1);opacity:1;transition:transform .15s cubic-bezier(.645,.045,.355,1),opacity .15s cubic-bezier(.645,.045,.355,1)}.ant-menu-inline .ant-menu-item,.ant-menu-inline .ant-menu-submenu-title{width:calc(100% + 1px)}.ant-menu-inline .ant-menu-item-group-list .ant-menu-submenu-title,.ant-menu-inline .ant-menu-submenu-title{padding-right:34px}.ant-menu-inline.ant-menu-root .ant-menu-item,.ant-menu-inline.ant-menu-root .ant-menu-submenu-title{display:flex;align-items:center;transition:border-color .3s,background .3s,padding .1s cubic-bezier(.215,.61,.355,1)}.ant-menu-inline.ant-menu-root .ant-menu-item>.ant-menu-title-content,.ant-menu-inline.ant-menu-root .ant-menu-submenu-title>.ant-menu-title-content{flex:auto;min-width:0;overflow:hidden;text-overflow:ellipsis}.ant-menu-inline.ant-menu-root .ant-menu-item>*,.ant-menu-inline.ant-menu-root .ant-menu-submenu-title>*{flex:none}.ant-menu.ant-menu-inline-collapsed{width:80px}.ant-menu.ant-menu-inline-collapsed>.ant-menu-item,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title,.ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title{left:0;padding:0 calc(50% - 8px);text-overflow:clip}.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .ant-menu-submenu-arrow,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item .ant-menu-submenu-arrow,.ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .ant-menu-submenu-arrow{opacity:0}.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .ant-menu-item-icon,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .anticon,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title .ant-menu-item-icon,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title .anticon,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item .ant-menu-item-icon,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item .anticon,.ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .ant-menu-item-icon,.ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .anticon{margin:0;font-size:16px;line-height:40px}.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .ant-menu-item-icon+span,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .anticon+span,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title .ant-menu-item-icon+span,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title .anticon+span,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item .ant-menu-item-icon+span,.ant-menu.ant-menu-inline-collapsed>.ant-menu-item .anticon+span,.ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .ant-menu-item-icon+span,.ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .anticon+span{display:inline-block;opacity:0}.ant-menu.ant-menu-inline-collapsed .ant-menu-item-icon,.ant-menu.ant-menu-inline-collapsed .anticon{display:inline-block}.ant-menu.ant-menu-inline-collapsed-tooltip{pointer-events:none}.ant-menu.ant-menu-inline-collapsed-tooltip .ant-menu-item-icon,.ant-menu.ant-menu-inline-collapsed-tooltip .anticon{display:none}.ant-menu.ant-menu-inline-collapsed-tooltip a{color:hsla(0,0%,100%,.85)}.ant-menu.ant-menu-inline-collapsed .ant-menu-item-group-title{padding-right:4px;padding-left:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-menu-item-group-list{margin:0;padding:0}.ant-menu-item-group-list .ant-menu-item,.ant-menu-item-group-list .ant-menu-submenu-title{padding:0 16px 0 28px}.ant-menu-root.ant-menu-inline,.ant-menu-root.ant-menu-vertical,.ant-menu-root.ant-menu-vertical-left,.ant-menu-root.ant-menu-vertical-right{box-shadow:none}.ant-menu-root.ant-menu-inline-collapsed .ant-menu-item>.ant-menu-inline-collapsed-noicon,.ant-menu-root.ant-menu-inline-collapsed .ant-menu-submenu .ant-menu-submenu-title>.ant-menu-inline-collapsed-noicon{font-size:16px;text-align:center}.ant-menu-sub.ant-menu-inline{padding:0;background:#fafafa;border-radius:0;box-shadow:none}.ant-menu-sub.ant-menu-inline>.ant-menu-item,.ant-menu-sub.ant-menu-inline>.ant-menu-submenu>.ant-menu-submenu-title{height:40px;line-height:40px;list-style-position:inside;list-style-type:disc}.ant-menu-sub.ant-menu-inline .ant-menu-item-group-title{padding-left:32px}.ant-menu-item-disabled,.ant-menu-submenu-disabled{color:rgba(0,0,0,.25)!important;background:none;cursor:not-allowed}.ant-menu-item-disabled:after,.ant-menu-submenu-disabled:after{border-color:transparent!important}.ant-menu-item-disabled a,.ant-menu-submenu-disabled a{color:rgba(0,0,0,.25)!important;pointer-events:none}.ant-menu-item-disabled>.ant-menu-submenu-title,.ant-menu-submenu-disabled>.ant-menu-submenu-title{color:rgba(0,0,0,.25)!important;cursor:not-allowed}.ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:rgba(0,0,0,.25)!important}.ant-layout-header .ant-menu{line-height:inherit}.ant-menu-inline-collapsed-tooltip a,.ant-menu-inline-collapsed-tooltip a:hover{color:#fff}.ant-menu-light .ant-menu-item-active,.ant-menu-light .ant-menu-item:hover,.ant-menu-light .ant-menu-submenu-active,.ant-menu-light .ant-menu-submenu-title:hover,.ant-menu-light .ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open{color:#296df3}.ant-menu.ant-menu-root:focus-visible{box-shadow:0 0 0 2px #0d57e8}.ant-menu-dark .ant-menu-item:focus-visible,.ant-menu-dark .ant-menu-submenu-title:focus-visible{box-shadow:0 0 0 2px #0d57e8}.ant-menu-dark .ant-menu-sub,.ant-menu.ant-menu-dark,.ant-menu.ant-menu-dark .ant-menu-sub{color:hsla(0,0%,100%,.65);background:#001529}.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu.ant-menu-dark .ant-menu-submenu-title .ant-menu-submenu-arrow{opacity:.45;transition:all .3s}.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu.ant-menu-dark .ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu.ant-menu-dark .ant-menu-submenu-title .ant-menu-submenu-arrow:before{background:#fff}.ant-menu-dark.ant-menu-submenu-popup{background:transparent}.ant-menu-dark .ant-menu-inline.ant-menu-sub{background:#000c17}.ant-menu-dark.ant-menu-horizontal{border-bottom:0}.ant-menu-dark.ant-menu-horizontal>.ant-menu-item,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu{top:0;margin-top:0;padding:0 20px;border-color:#001529;border-bottom:0}.ant-menu-dark.ant-menu-horizontal>.ant-menu-item:hover{background-color:#296df3}.ant-menu-dark.ant-menu-horizontal>.ant-menu-item>a:before{bottom:0}.ant-menu-dark .ant-menu-item,.ant-menu-dark .ant-menu-item-group-title,.ant-menu-dark .ant-menu-item>a,.ant-menu-dark .ant-menu-item>span>a{color:hsla(0,0%,100%,.65)}.ant-menu-dark.ant-menu-inline,.ant-menu-dark.ant-menu-vertical,.ant-menu-dark.ant-menu-vertical-left,.ant-menu-dark.ant-menu-vertical-right{border-right:0}.ant-menu-dark.ant-menu-inline .ant-menu-item,.ant-menu-dark.ant-menu-vertical-left .ant-menu-item,.ant-menu-dark.ant-menu-vertical-right .ant-menu-item,.ant-menu-dark.ant-menu-vertical .ant-menu-item{left:0;margin-left:0;border-right:0}.ant-menu-dark.ant-menu-inline .ant-menu-item:after,.ant-menu-dark.ant-menu-vertical-left .ant-menu-item:after,.ant-menu-dark.ant-menu-vertical-right .ant-menu-item:after,.ant-menu-dark.ant-menu-vertical .ant-menu-item:after{border-right:0}.ant-menu-dark.ant-menu-inline .ant-menu-item,.ant-menu-dark.ant-menu-inline .ant-menu-submenu-title{width:100%}.ant-menu-dark .ant-menu-item-active,.ant-menu-dark .ant-menu-item:hover,.ant-menu-dark .ant-menu-submenu-active,.ant-menu-dark .ant-menu-submenu-open,.ant-menu-dark .ant-menu-submenu-selected,.ant-menu-dark .ant-menu-submenu-title:hover{color:#fff;background-color:transparent}.ant-menu-dark .ant-menu-item-active>a,.ant-menu-dark .ant-menu-item-active>span>a,.ant-menu-dark .ant-menu-item:hover>a,.ant-menu-dark .ant-menu-item:hover>span>a,.ant-menu-dark .ant-menu-submenu-active>a,.ant-menu-dark .ant-menu-submenu-active>span>a,.ant-menu-dark .ant-menu-submenu-open>a,.ant-menu-dark .ant-menu-submenu-open>span>a,.ant-menu-dark .ant-menu-submenu-selected>a,.ant-menu-dark .ant-menu-submenu-selected>span>a,.ant-menu-dark .ant-menu-submenu-title:hover>a,.ant-menu-dark .ant-menu-submenu-title:hover>span>a{color:#fff}.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow{opacity:1}.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:#fff}.ant-menu-dark .ant-menu-item:hover{background-color:transparent}.ant-menu-dark.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected{background-color:#296df3}.ant-menu-dark .ant-menu-item-selected{color:#fff;border-right:0}.ant-menu-dark .ant-menu-item-selected:after{border-right:0}.ant-menu-dark .ant-menu-item-selected>a,.ant-menu-dark .ant-menu-item-selected>a:hover,.ant-menu-dark .ant-menu-item-selected>span>a,.ant-menu-dark .ant-menu-item-selected>span>a:hover{color:#fff}.ant-menu-dark .ant-menu-item-selected .ant-menu-item-icon,.ant-menu-dark .ant-menu-item-selected .anticon{color:#fff}.ant-menu-dark .ant-menu-item-selected .ant-menu-item-icon+span,.ant-menu-dark .ant-menu-item-selected .anticon+span{color:#fff}.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,.ant-menu.ant-menu-dark .ant-menu-item-selected{background-color:#296df3}.ant-menu-dark .ant-menu-item-disabled,.ant-menu-dark .ant-menu-item-disabled>a,.ant-menu-dark .ant-menu-item-disabled>span>a,.ant-menu-dark .ant-menu-submenu-disabled,.ant-menu-dark .ant-menu-submenu-disabled>a,.ant-menu-dark .ant-menu-submenu-disabled>span>a{color:hsla(0,0%,100%,.35)!important;opacity:.8}.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title{color:hsla(0,0%,100%,.35)!important}.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:hsla(0,0%,100%,.35)!important}.ant-menu.ant-menu-rtl{direction:rtl;text-align:right}.ant-menu-rtl .ant-menu-item-group-title{text-align:right}.ant-menu-rtl.ant-menu-inline,.ant-menu-rtl.ant-menu-vertical{border-right:none;border-left:1px solid #f0f0f0}.ant-menu-rtl.ant-menu-dark.ant-menu-inline,.ant-menu-rtl.ant-menu-dark.ant-menu-vertical{border-left:none}.ant-menu-rtl.ant-menu-vertical-left.ant-menu-sub>.ant-menu-item,.ant-menu-rtl.ant-menu-vertical-left.ant-menu-sub>.ant-menu-submenu,.ant-menu-rtl.ant-menu-vertical-right.ant-menu-sub>.ant-menu-item,.ant-menu-rtl.ant-menu-vertical-right.ant-menu-sub>.ant-menu-submenu,.ant-menu-rtl.ant-menu-vertical.ant-menu-sub>.ant-menu-item,.ant-menu-rtl.ant-menu-vertical.ant-menu-sub>.ant-menu-submenu{transform-origin:top right}.ant-menu-rtl .ant-menu-item .ant-menu-item-icon,.ant-menu-rtl .ant-menu-item .anticon,.ant-menu-rtl .ant-menu-submenu-title .ant-menu-item-icon,.ant-menu-rtl .ant-menu-submenu-title .anticon{margin-right:auto;margin-left:10px}.ant-menu-rtl .ant-menu-item.ant-menu-item-only-child>.ant-menu-item-icon,.ant-menu-rtl .ant-menu-item.ant-menu-item-only-child>.anticon,.ant-menu-rtl .ant-menu-submenu-title.ant-menu-item-only-child>.ant-menu-item-icon,.ant-menu-rtl .ant-menu-submenu-title.ant-menu-item-only-child>.anticon{margin-left:0}.ant-menu-submenu-rtl.ant-menu-submenu-popup{transform-origin:100% 0}.ant-menu-rtl .ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu-rtl .ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu-rtl .ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu-rtl .ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow{right:auto;left:16px}.ant-menu-rtl .ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-rtl .ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-rtl .ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow:before{transform:rotate(-45deg) translateY(-2px)}.ant-menu-rtl .ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-rtl .ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-rtl .ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow:after{transform:rotate(45deg) translateY(2px)}.ant-menu-rtl.ant-menu-inline .ant-menu-item:after,.ant-menu-rtl.ant-menu-vertical-left .ant-menu-item:after,.ant-menu-rtl.ant-menu-vertical-right .ant-menu-item:after,.ant-menu-rtl.ant-menu-vertical .ant-menu-item:after{right:auto;left:0}.ant-menu-rtl.ant-menu-inline .ant-menu-item,.ant-menu-rtl.ant-menu-inline .ant-menu-submenu-title,.ant-menu-rtl.ant-menu-vertical-left .ant-menu-item,.ant-menu-rtl.ant-menu-vertical-left .ant-menu-submenu-title,.ant-menu-rtl.ant-menu-vertical-right .ant-menu-item,.ant-menu-rtl.ant-menu-vertical-right .ant-menu-submenu-title,.ant-menu-rtl.ant-menu-vertical .ant-menu-item,.ant-menu-rtl.ant-menu-vertical .ant-menu-submenu-title{text-align:right}.ant-menu-rtl.ant-menu-inline .ant-menu-submenu-title{padding-right:0;padding-left:34px}.ant-menu-rtl.ant-menu-vertical .ant-menu-submenu-title{padding-right:16px;padding-left:34px}.ant-menu-rtl.ant-menu-inline-collapsed.ant-menu-vertical .ant-menu-submenu-title{padding:0 calc(50% - 8px)}.ant-menu-rtl .ant-menu-item-group-list .ant-menu-item,.ant-menu-rtl .ant-menu-item-group-list .ant-menu-submenu-title{padding:0 28px 0 16px}.ant-menu-sub.ant-menu-inline{border:0}.ant-menu-rtl.ant-menu-sub.ant-menu-inline .ant-menu-item-group-title{padding-right:32px;padding-left:0}.ant-tooltip{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:absolute;z-index:1070;display:block;width:-webkit-max-content;width:-moz-max-content;width:max-content;width:intrinsic;max-width:250px;visibility:visible}.ant-tooltip-content{position:relative}.ant-tooltip-hidden{display:none}.ant-tooltip-placement-top,.ant-tooltip-placement-topLeft,.ant-tooltip-placement-topRight{padding-bottom:14.3137085px}.ant-tooltip-placement-right,.ant-tooltip-placement-rightBottom,.ant-tooltip-placement-rightTop{padding-left:14.3137085px}.ant-tooltip-placement-bottom,.ant-tooltip-placement-bottomLeft,.ant-tooltip-placement-bottomRight{padding-top:14.3137085px}.ant-tooltip-placement-left,.ant-tooltip-placement-leftBottom,.ant-tooltip-placement-leftTop{padding-right:14.3137085px}.ant-tooltip-inner{min-width:30px;min-height:32px;padding:6px 8px;color:#fff;text-align:left;text-decoration:none;word-wrap:break-word;background-color:rgba(0,0,0,.75);border-radius:4px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}.ant-tooltip-arrow{position:absolute;z-index:2;display:block;width:22px;height:22px;overflow:hidden;background:transparent;pointer-events:none}.ant-tooltip-arrow-content{--antd-arrow-background-color:linear-gradient(to right bottom,rgba(0,0,0,0.65),rgba(0,0,0,0.75));position:absolute;top:0;right:0;bottom:0;left:0;display:block;width:11.3137085px;height:11.3137085px;margin:auto;content:"";pointer-events:auto;border-radius:0 0 2px;pointer-events:none}.ant-tooltip-arrow-content:before{position:absolute;top:-11.3137085px;left:-11.3137085px;width:33.9411255px;height:33.9411255px;background:var(--antd-arrow-background-color);background-repeat:no-repeat;background-position:-10px -10px;content:"";-webkit-clip-path:inset(33% 33%);clip-path:inset(33% 33%);-webkit-clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z");clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z")}.ant-tooltip-placement-top .ant-tooltip-arrow,.ant-tooltip-placement-topLeft .ant-tooltip-arrow,.ant-tooltip-placement-topRight .ant-tooltip-arrow{bottom:0;transform:translateY(100%)}.ant-tooltip-placement-top .ant-tooltip-arrow-content,.ant-tooltip-placement-topLeft .ant-tooltip-arrow-content,.ant-tooltip-placement-topRight .ant-tooltip-arrow-content{box-shadow:3px 3px 7px rgba(0,0,0,.07);transform:translateY(-11px) rotate(45deg)}.ant-tooltip-placement-top .ant-tooltip-arrow{left:50%;transform:translateY(100%) translateX(-50%)}.ant-tooltip-placement-topLeft .ant-tooltip-arrow{left:13px}.ant-tooltip-placement-topRight .ant-tooltip-arrow{right:13px}.ant-tooltip-placement-right .ant-tooltip-arrow,.ant-tooltip-placement-rightBottom .ant-tooltip-arrow,.ant-tooltip-placement-rightTop .ant-tooltip-arrow{left:0;transform:translateX(-100%)}.ant-tooltip-placement-right .ant-tooltip-arrow-content,.ant-tooltip-placement-rightBottom .ant-tooltip-arrow-content,.ant-tooltip-placement-rightTop .ant-tooltip-arrow-content{box-shadow:-3px 3px 7px rgba(0,0,0,.07);transform:translateX(11px) rotate(135deg)}.ant-tooltip-placement-right .ant-tooltip-arrow{top:50%;transform:translateX(-100%) translateY(-50%)}.ant-tooltip-placement-rightTop .ant-tooltip-arrow{top:5px}.ant-tooltip-placement-rightBottom .ant-tooltip-arrow{bottom:5px}.ant-tooltip-placement-left .ant-tooltip-arrow,.ant-tooltip-placement-leftBottom .ant-tooltip-arrow,.ant-tooltip-placement-leftTop .ant-tooltip-arrow{right:0;transform:translateX(100%)}.ant-tooltip-placement-left .ant-tooltip-arrow-content,.ant-tooltip-placement-leftBottom .ant-tooltip-arrow-content,.ant-tooltip-placement-leftTop .ant-tooltip-arrow-content{box-shadow:3px -3px 7px rgba(0,0,0,.07);transform:translateX(-11px) rotate(315deg)}.ant-tooltip-placement-left .ant-tooltip-arrow{top:50%;transform:translateX(100%) translateY(-50%)}.ant-tooltip-placement-leftTop .ant-tooltip-arrow{top:5px}.ant-tooltip-placement-leftBottom .ant-tooltip-arrow{bottom:5px}.ant-tooltip-placement-bottom .ant-tooltip-arrow,.ant-tooltip-placement-bottomLeft .ant-tooltip-arrow,.ant-tooltip-placement-bottomRight .ant-tooltip-arrow{top:0;transform:translateY(-100%)}.ant-tooltip-placement-bottom .ant-tooltip-arrow-content,.ant-tooltip-placement-bottomLeft .ant-tooltip-arrow-content,.ant-tooltip-placement-bottomRight .ant-tooltip-arrow-content{box-shadow:-3px -3px 7px rgba(0,0,0,.07);transform:translateY(11px) rotate(225deg)}.ant-tooltip-placement-bottom .ant-tooltip-arrow{left:50%;transform:translateY(-100%) translateX(-50%)}.ant-tooltip-placement-bottomLeft .ant-tooltip-arrow{left:13px}.ant-tooltip-placement-bottomRight .ant-tooltip-arrow{right:13px}.ant-tooltip-pink .ant-tooltip-inner{background-color:#eb2f96}.ant-tooltip-pink .ant-tooltip-arrow-content:before{background:#eb2f96}.ant-tooltip-magenta .ant-tooltip-inner{background-color:#eb2f96}.ant-tooltip-magenta .ant-tooltip-arrow-content:before{background:#eb2f96}.ant-tooltip-red .ant-tooltip-inner{background-color:#f5222d}.ant-tooltip-red .ant-tooltip-arrow-content:before{background:#f5222d}.ant-tooltip-volcano .ant-tooltip-inner{background-color:#fa541c}.ant-tooltip-volcano .ant-tooltip-arrow-content:before{background:#fa541c}.ant-tooltip-orange .ant-tooltip-inner{background-color:#fa8c16}.ant-tooltip-orange .ant-tooltip-arrow-content:before{background:#fa8c16}.ant-tooltip-yellow .ant-tooltip-inner{background-color:#fadb14}.ant-tooltip-yellow .ant-tooltip-arrow-content:before{background:#fadb14}.ant-tooltip-gold .ant-tooltip-inner{background-color:#ffb924}.ant-tooltip-gold .ant-tooltip-arrow-content:before{background:#ffb924}.ant-tooltip-cyan .ant-tooltip-inner{background-color:#13c2c2}.ant-tooltip-cyan .ant-tooltip-arrow-content:before{background:#13c2c2}.ant-tooltip-lime .ant-tooltip-inner{background-color:#a0d911}.ant-tooltip-lime .ant-tooltip-arrow-content:before{background:#a0d911}.ant-tooltip-green .ant-tooltip-inner{background-color:#26c992}.ant-tooltip-green .ant-tooltip-arrow-content:before{background:#26c992}.ant-tooltip-blue .ant-tooltip-inner{background-color:#296df3}.ant-tooltip-blue .ant-tooltip-arrow-content:before{background:#296df3}.ant-tooltip-geekblue .ant-tooltip-inner{background-color:#2f54eb}.ant-tooltip-geekblue .ant-tooltip-arrow-content:before{background:#2f54eb}.ant-tooltip-purple .ant-tooltip-inner{background-color:#722ed1}.ant-tooltip-purple .ant-tooltip-arrow-content:before{background:#722ed1}.ant-tooltip-rtl{direction:rtl}.ant-tooltip-rtl .ant-tooltip-inner{text-align:right}.ant-space{display:inline-flex}.ant-space-vertical{flex-direction:column}.ant-space-align-center{align-items:center}.ant-space-align-start{align-items:flex-start}.ant-space-align-end{align-items:flex-end}.ant-space-align-baseline{align-items:baseline}.ant-space-item:empty{display:none}.ant-space-compact{display:inline-flex}.ant-space-compact-block{display:flex;width:100%}.ant-space-compact-vertical{flex-direction:column}.ant-space-rtl{direction:rtl}.ant-space-compact-rtl{direction:rtl}.ant-spin{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:absolute;display:none;color:#296df3;font-size:0;text-align:center;vertical-align:middle;opacity:0;transition:transform .3s cubic-bezier(.78,.14,.15,.86)}.ant-spin-spinning{position:static;display:inline-block;opacity:1}.ant-spin-nested-loading{position:relative}.ant-spin-nested-loading>div>.ant-spin{position:absolute;top:0;left:0;z-index:4;display:block;width:100%;height:100%;max-height:400px}.ant-spin-nested-loading>div>.ant-spin .ant-spin-dot{position:absolute;top:50%;left:50%;margin:-10px}.ant-spin-nested-loading>div>.ant-spin .ant-spin-text{position:absolute;top:50%;width:100%;padding-top:5px;font-size:14px;text-shadow:0 1px 2px #fff}.ant-spin-nested-loading>div>.ant-spin.ant-spin-show-text .ant-spin-dot{margin-top:-20px}.ant-spin-nested-loading>div>.ant-spin-sm .ant-spin-dot{margin:-7px}.ant-spin-nested-loading>div>.ant-spin-sm .ant-spin-text{padding-top:2px}.ant-spin-nested-loading>div>.ant-spin-sm.ant-spin-show-text .ant-spin-dot{margin-top:-17px}.ant-spin-nested-loading>div>.ant-spin-lg .ant-spin-dot{margin:-16px}.ant-spin-nested-loading>div>.ant-spin-lg .ant-spin-text{padding-top:11px}.ant-spin-nested-loading>div>.ant-spin-lg.ant-spin-show-text .ant-spin-dot{margin-top:-26px}.ant-spin-container{position:relative;transition:opacity .3s}.ant-spin-container:after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:10;display:none\9;width:100%;height:100%;background:#fff;opacity:0;transition:all .3s;content:"";pointer-events:none}.ant-spin-blur{clear:both;opacity:.5;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}.ant-spin-blur:after{opacity:.4;pointer-events:auto}.ant-spin-tip{color:rgba(0,10,36,.65)}.ant-spin-dot{position:relative;display:inline-block;font-size:20px;width:1em;height:1em}.ant-spin-dot-item{position:absolute;display:block;width:9px;height:9px;background-color:#296df3;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s linear infinite alternate}.ant-spin-dot-item:first-child{top:0;left:0}.ant-spin-dot-item:nth-child(2){top:0;right:0;animation-delay:.4s}.ant-spin-dot-item:nth-child(3){right:0;bottom:0;animation-delay:.8s}.ant-spin-dot-item:nth-child(4){bottom:0;left:0;animation-delay:1.2s}.ant-spin-dot-spin{transform:rotate(0deg);animation:antRotate 1.2s linear infinite}.ant-spin-sm .ant-spin-dot{font-size:14px}.ant-spin-sm .ant-spin-dot i{width:6px;height:6px}.ant-spin-lg .ant-spin-dot{font-size:32px}.ant-spin-lg .ant-spin-dot i{width:14px;height:14px}.ant-spin.ant-spin-show-text .ant-spin-text{display:block}@media (-ms-high-contrast:active),(-ms-high-contrast:none){.ant-spin-blur{background:#fff;opacity:.5}}@keyframes antSpinMove{to{opacity:1}}@keyframes antRotate{to{transform:rotate(1turn)}}.ant-spin-rtl{direction:rtl}.ant-spin-rtl .ant-spin-dot-spin{transform:rotate(-45deg);animation-name:antRotateRtl}@keyframes antRotateRtl{to{transform:rotate(-405deg)}}.container___1Rq3A>*{background-color:#fff;border-radius:4px;box-shadow:0 6px 16px -8px rgba(0,0,0,.08),0 9px 28px 0 rgba(0,0,0,.05),0 12px 48px 16px rgba(0,0,0,.03)}@media screen and (max-width:480px){.container___1Rq3A{width:100%!important}.container___1Rq3A>*{border-radius:0!important}}.menu___1L63y .anticon{margin-right:8px}.menu___1L63y .ant-dropdown-menu-item{min-width:160px}.right___3L8KG{display:flex;float:right;height:48px;margin-left:auto;overflow:hidden}.right___3L8KG .action___LP4_P{display:flex;align-items:center;height:48px;padding:0 12px;cursor:pointer;transition:all .3s}.right___3L8KG .action___LP4_P>span{vertical-align:middle}.right___3L8KG .action___LP4_P:hover{background:rgba(0,0,0,.025)}.right___3L8KG .action___LP4_P.opened{background:rgba(0,0,0,.025)}.right___3L8KG .search___2W0sJ{padding:0 12px}.right___3L8KG .search___2W0sJ:hover{background:transparent}.right___3L8KG .account___6HXOq .avatar___2cOWV{margin-right:8px;color:#296df3;vertical-align:top;background:hsla(0,0%,100%,.85)}.dark___1NwCY .action___LP4_P .download___3EyS7{display:flex;align-items:center}.dark___1NwCY .action___LP4_P .menuName___avsrP{margin-left:5px;color:#fff;font-size:13px}.dark___1NwCY .action___LP4_P:hover{background:#296df3}.dark___1NwCY .action___LP4_P.opened{background:#252a3d}.actionIcon___29O_9{font-size:20px}.tooltip___OioLL{padding-top:0!important;font-size:12px!important}.tooltip___OioLL .ant-tooltip-arrow{display:none}.tooltip___OioLL .ant-tooltip-inner{min-height:0!important;padding:3px 6px!important}.ant-avatar{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:inline-block;overflow:hidden;color:#fff;white-space:nowrap;text-align:center;vertical-align:middle;background:#ccc;width:32px;height:32px;line-height:32px;border-radius:50%}.ant-avatar-image{background:transparent}.ant-avatar .ant-image-img{display:block}.ant-avatar-string{position:absolute;left:50%;transform-origin:0 center}.ant-avatar.ant-avatar-icon{font-size:18px}.ant-avatar.ant-avatar-icon>.anticon{margin:0}.ant-avatar-lg{width:40px;height:40px;line-height:40px;border-radius:50%}.ant-avatar-lg-string{position:absolute;left:50%;transform-origin:0 center}.ant-avatar-lg.ant-avatar-icon{font-size:24px}.ant-avatar-lg.ant-avatar-icon>.anticon{margin:0}.ant-avatar-sm{width:24px;height:24px;line-height:24px;border-radius:50%}.ant-avatar-sm-string{position:absolute;left:50%;transform-origin:0 center}.ant-avatar-sm.ant-avatar-icon{font-size:14px}.ant-avatar-sm.ant-avatar-icon>.anticon{margin:0}.ant-avatar-square{border-radius:4px}.ant-avatar>img{display:block;width:100%;height:100%;object-fit:cover}.ant-avatar-group{display:inline-flex}.ant-avatar-group .ant-avatar{border:1px solid #fff}.ant-avatar-group .ant-avatar:not(:first-child){margin-left:-8px}.ant-avatar-group-popover .ant-avatar+.ant-avatar{margin-left:3px}.ant-avatar-group-rtl .ant-avatar:not(:first-child){margin-right:-8px;margin-left:0}.ant-avatar-group-popover.ant-popover-rtl .ant-avatar+.ant-avatar{margin-right:3px;margin-left:0}.ant-popover{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:absolute;top:0;left:0;z-index:1030;max-width:100vw;font-weight:400;white-space:normal;text-align:left;cursor:auto;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ant-popover-content{position:relative}.ant-popover:after{position:absolute;background:hsla(0,0%,100%,.01);content:""}.ant-popover-hidden{display:none}.ant-popover-placement-top,.ant-popover-placement-topLeft,.ant-popover-placement-topRight{padding-bottom:15.3137085px}.ant-popover-placement-right,.ant-popover-placement-rightBottom,.ant-popover-placement-rightTop{padding-left:15.3137085px}.ant-popover-placement-bottom,.ant-popover-placement-bottomLeft,.ant-popover-placement-bottomRight{padding-top:15.3137085px}.ant-popover-placement-left,.ant-popover-placement-leftBottom,.ant-popover-placement-leftTop{padding-right:15.3137085px}.ant-popover-inner{background-color:#fff;background-clip:padding-box;border-radius:4px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}@media (-ms-high-contrast:none),screen and (-ms-high-contrast:active){.ant-popover-inner{box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}}.ant-popover-title{min-width:177px;min-height:32px;margin:0;padding:5px 16px 4px;color:rgba(0,10,36,.85);font-weight:500;border-bottom:1px solid #f0f0f0}.ant-popover-inner-content{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;padding:12px 16px;color:rgba(0,10,36,.85)}.ant-popover-message{display:flex;padding:4px 0 12px;color:rgba(0,10,36,.85);font-size:14px}.ant-popover-message-icon{display:inline-block;margin-right:8px;color:#ffb924;font-size:14px}.ant-popover-buttons{margin-bottom:4px;text-align:right}.ant-popover-buttons button:not(:first-child){margin-left:8px}.ant-popover-arrow{position:absolute;display:block;width:22px;height:22px;overflow:hidden;background:transparent;pointer-events:none}.ant-popover-arrow-content{--antd-arrow-background-color:#fff;position:absolute;top:0;right:0;bottom:0;left:0;display:block;width:11.3137085px;height:11.3137085px;margin:auto;content:"";pointer-events:auto;border-radius:0 0 2px;pointer-events:none}.ant-popover-arrow-content:before{position:absolute;top:-11.3137085px;left:-11.3137085px;width:33.9411255px;height:33.9411255px;background:var(--antd-arrow-background-color);background-repeat:no-repeat;background-position:-10px -10px;content:"";-webkit-clip-path:inset(33% 33%);clip-path:inset(33% 33%);-webkit-clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z");clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z")}.ant-popover-placement-top .ant-popover-arrow,.ant-popover-placement-topLeft .ant-popover-arrow,.ant-popover-placement-topRight .ant-popover-arrow{bottom:0;transform:translateY(100%)}.ant-popover-placement-top .ant-popover-arrow-content,.ant-popover-placement-topLeft .ant-popover-arrow-content,.ant-popover-placement-topRight .ant-popover-arrow-content{box-shadow:3px 3px 7px rgba(0,0,0,.07);transform:translateY(-11px) rotate(45deg)}.ant-popover-placement-top .ant-popover-arrow{left:50%;transform:translateY(100%) translateX(-50%)}.ant-popover-placement-topLeft .ant-popover-arrow{left:16px}.ant-popover-placement-topRight .ant-popover-arrow{right:16px}.ant-popover-placement-right .ant-popover-arrow,.ant-popover-placement-rightBottom .ant-popover-arrow,.ant-popover-placement-rightTop .ant-popover-arrow{left:0;transform:translateX(-100%)}.ant-popover-placement-right .ant-popover-arrow-content,.ant-popover-placement-rightBottom .ant-popover-arrow-content,.ant-popover-placement-rightTop .ant-popover-arrow-content{box-shadow:3px 3px 7px rgba(0,0,0,.07);transform:translateX(11px) rotate(135deg)}.ant-popover-placement-right .ant-popover-arrow{top:50%;transform:translateX(-100%) translateY(-50%)}.ant-popover-placement-rightTop .ant-popover-arrow{top:12px}.ant-popover-placement-rightBottom .ant-popover-arrow{bottom:12px}.ant-popover-placement-bottom .ant-popover-arrow,.ant-popover-placement-bottomLeft .ant-popover-arrow,.ant-popover-placement-bottomRight .ant-popover-arrow{top:0;transform:translateY(-100%)}.ant-popover-placement-bottom .ant-popover-arrow-content,.ant-popover-placement-bottomLeft .ant-popover-arrow-content,.ant-popover-placement-bottomRight .ant-popover-arrow-content{box-shadow:2px 2px 5px rgba(0,0,0,.06);transform:translateY(11px) rotate(-135deg)}.ant-popover-placement-bottom .ant-popover-arrow{left:50%;transform:translateY(-100%) translateX(-50%)}.ant-popover-placement-bottomLeft .ant-popover-arrow{left:16px}.ant-popover-placement-bottomRight .ant-popover-arrow{right:16px}.ant-popover-placement-left .ant-popover-arrow,.ant-popover-placement-leftBottom .ant-popover-arrow,.ant-popover-placement-leftTop .ant-popover-arrow{right:0;transform:translateX(100%)}.ant-popover-placement-left .ant-popover-arrow-content,.ant-popover-placement-leftBottom .ant-popover-arrow-content,.ant-popover-placement-leftTop .ant-popover-arrow-content{box-shadow:3px 3px 7px rgba(0,0,0,.07);transform:translateX(-11px) rotate(-45deg)}.ant-popover-placement-left .ant-popover-arrow{top:50%;transform:translateX(100%) translateY(-50%)}.ant-popover-placement-leftTop .ant-popover-arrow{top:12px}.ant-popover-placement-leftBottom .ant-popover-arrow{bottom:12px}.ant-popover-pink .ant-popover-inner{background-color:#eb2f96}.ant-popover-pink .ant-popover-arrow-content{background-color:#eb2f96}.ant-popover-magenta .ant-popover-inner{background-color:#eb2f96}.ant-popover-magenta .ant-popover-arrow-content{background-color:#eb2f96}.ant-popover-red .ant-popover-inner{background-color:#f5222d}.ant-popover-red .ant-popover-arrow-content{background-color:#f5222d}.ant-popover-volcano .ant-popover-inner{background-color:#fa541c}.ant-popover-volcano .ant-popover-arrow-content{background-color:#fa541c}.ant-popover-orange .ant-popover-inner{background-color:#fa8c16}.ant-popover-orange .ant-popover-arrow-content{background-color:#fa8c16}.ant-popover-yellow .ant-popover-inner{background-color:#fadb14}.ant-popover-yellow .ant-popover-arrow-content{background-color:#fadb14}.ant-popover-gold .ant-popover-inner{background-color:#ffb924}.ant-popover-gold .ant-popover-arrow-content{background-color:#ffb924}.ant-popover-cyan .ant-popover-inner{background-color:#13c2c2}.ant-popover-cyan .ant-popover-arrow-content{background-color:#13c2c2}.ant-popover-lime .ant-popover-inner{background-color:#a0d911}.ant-popover-lime .ant-popover-arrow-content{background-color:#a0d911}.ant-popover-green .ant-popover-inner{background-color:#26c992}.ant-popover-green .ant-popover-arrow-content{background-color:#26c992}.ant-popover-blue .ant-popover-inner{background-color:#296df3}.ant-popover-blue .ant-popover-arrow-content{background-color:#296df3}.ant-popover-geekblue .ant-popover-inner{background-color:#2f54eb}.ant-popover-geekblue .ant-popover-arrow-content{background-color:#2f54eb}.ant-popover-purple .ant-popover-inner{background-color:#722ed1}.ant-popover-purple .ant-popover-arrow-content{background-color:#722ed1}.ant-popover-rtl{direction:rtl;text-align:right}.ant-popover-rtl .ant-popover-message-icon{margin-right:0;margin-left:8px}.ant-popover-rtl .ant-popover-message-title{padding-left:16px}.ant-popover-rtl .ant-popover-buttons{text-align:left}.ant-popover-rtl .ant-popover-buttons button{margin-right:8px;margin-left:0}@font-face{font-family:"iconfont";src:url(static/iconfont.0ac2d58a.woff2) format("woff2"),url(static/iconfont.0de60a33.woff) format("woff"),url(static/iconfont.7ae6e4e0.ttf) format("truetype"),url(static/iconfont.92a3f736.svg#iconfont) format("svg")}.iconfont___1fcw4{font-family:"iconfont"!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.iconbaobiaokanban___DR4U5:before{content:"\e66b"}.iconkanban___IWq2H:before{content:"\e638"}.iconyunyingkanban___14Q9Y:before{content:"\e608"}.iconshujukanban1___16Nzt:before{content:"\eb66"}.iconjingqingqidai01___310Aa:before{content:"\e607"}.icontouzi___381YH:before{content:"\e67a"}.iconriqi___2aj5n:before{content:"\e609"}.iconyinleren____3AoFi:before{content:"\e606"}.icondapan___3Qdzn:before{content:"\e668"}.iconbangdan___fr8LR:before{content:"\e669"}.iconshujuwajue___1s5Ck:before{content:"\e667"}.iconshoucang1___2lxZQ:before{content:"\e600"}.icontianjiazhibiao___1oZVf:before{content:"\e632"}.icontianjiafenzu___2ond3:before{content:"\e666"}.iconyouxiajiaogouxuan___3Z1by:before{content:"\e8b7"}.iconxiaoshouzhibiaoshezhi___1TLhk:before{content:"\e665"}.iconyingyongbiaoge___3zN8L:before{content:"\e6ae"}.iconzhibiao____6qJe:before{content:"\e66a"}.iconsearch___1joAc:before{content:"\e7c9"}.iconfactory-color___2JEj0:before{content:"\e69d"}.iconportray-color___7pSrY:before{content:"\e69e"}.iconvisualize-color___zOv2M:before{content:"\e69f"}.iconamount-color___Jji4q:before{content:"\e68f"}.iconapi-color___397Gu:before{content:"\e690"}.iconcontent-color___2Qofk:before{content:"\e691"}.iconbox-color___1pb-b:before{content:"\e692"}.iconchat-color___25UvW:before{content:"\e693"}.iconclient-color___W3t54:before{content:"\e694"}.icondata-process___3Flot:before{content:"\e695"}.iconbi-color___3Yki1:before{content:"\e696"}.iconfiled-color___1bkOK:before{content:"\e697"}.iconinvoking-color___jnm66:before{content:"\e698"}.iconissue-color___1D8Jy:before{content:"\e699"}.iconplatform-color___39LXE:before{content:"\e69a"}.iconfile-color___1pueQ:before{content:"\e69b"}.iconname-color___pm4p9:before{content:"\e69c"}.icondraft___2wSyM:before{content:"\e605"}.iconunknown___29KoO:before{content:"\e604"}.iconnormal___39WGI:before{content:"\e603"}.iconfreezed___3HYp5:before{content:"\e602"}.iconlogowenzi___1Cqhp:before{content:"\e660"}.iconlogobiaoshi___2hx1_:before{content:"\e664"}.iconchaoyinshuxitonglogo___1AMzn:before{content:"\e663"}.iconzanwuquanxiandianjishenqing_1___1SBfE:before{content:"\e662"}.iconqingchuangjianmuluhuokanban___1norf:before{content:"\e661"}.iconzichan___3twqW:before{content:"\e65f"}.iconhangweifenxi___3n1jk:before{content:"\e65e"}.iconshujuzichan___1iKwI:before{content:"\e65d"}.iconshujukanban___4BASP:before{content:"\e659"}.iconshujujieru___1l_6a:before{content:"\e65a"}.iconshujutansuo___3Iy5X:before{content:"\e65b"}.iconminjiefenxi___CRxBx:before{content:"\e65c"}.iconyanfagongju___1oGmZ:before{content:"\e658"}.iconshujuanquan___22tW_:before{content:"\e614"}.iconCE___2mRLn:before{content:"\e601"}.iconkanbantu-shuaxin___16YQf:before{content:"\e657"}.icondaohang-sousuo___1wNGK:before{content:"\e63e"}.icondaohang-bangzhu___1KLsE:before{content:"\e63f"}.iconkanbantu-fenxiang___3WwdQ:before{content:"\e640"}.iconquanju-riqi___A41DI:before{content:"\e641"}.icondaohang-shezhi___1ljpY:before{content:"\e642"}.icondaohang-zichangouwuche___k4UwW:before{content:"\e643"}.iconquanju-xiazai___2X4jV:before{content:"\e644"}.iconkanbantu-quanping___2DvgF:before{content:"\e645"}.iconshujuzichan-yewushujuzichan___3Hzfq:before{content:"\e646"}.iconshujukanban-tianjiakanban___2q82r:before{content:"\e647"}.iconqingkong___2Xgqr:before{content:"\e648"}.iconshujuzichan-jishushujuzichan___3bZh5:before{content:"\e649"}.iconshujuzichan-zichanfaxian___3T4LE:before{content:"\e64a"}.icontishi-beizhu1___10Rgg:before{content:"\e64b"}.iconshujukanban-tianjiamulu___17x-o:before{content:"\e64c"}.icontubiao-zhuzhuangtu___3HRWi:before{content:"\e64d"}.icondaohang-xiaoxitishi___1cqbc:before{content:"\e64e"}.icontubiao-bingtu___1ZnTb:before{content:"\e64f"}.icontishi-beizhu2___1T1U0:before{content:"\e650"}.iconshezhi-quanxianshezhi___33vY2:before{content:"\e651"}.iconhangweifenxi-mokuaifenxi___3wDS8:before{content:"\e652"}.icontubiao-loudoutu___3VAKj:before{content:"\e653"}.icontubiao-zhexiantu___3Rs-l:before{content:"\e654"}.icontubiao-biaoge___14GNX:before{content:"\e655"}.iconhangweifenxi-baobiaoliebiao___1cwXt:before{content:"\e656"}.s2icon___10AEz{line-height:1}@media screen and (max-width:480px){.umi-plugin-layout-container{width:100%!important}.umi-plugin-layout-container>*{border-radius:0!important}}.umi-plugin-layout-menu :global(.anticon){margin-right:8px}.umi-plugin-layout-menu :global(.ant-dropdown-menu-item){min-width:160px}.umi-plugin-layout-right{display:flex;float:right;height:100%;margin-left:auto;overflow:hidden}.umi-plugin-layout-right .umi-plugin-layout-action{display:flex;align-items:center;height:100%;padding:0 12px;cursor:pointer;transition:all .3s}.umi-plugin-layout-right .umi-plugin-layout-action>i{color:rgba(0,10,36,.85);vertical-align:middle}.umi-plugin-layout-right .umi-plugin-layout-action:hover{background:rgba(0,0,0,.025)}.umi-plugin-layout-right .umi-plugin-layout-action:global(.opened){background:rgba(0,0,0,.025)}.umi-plugin-layout-right .umi-plugin-layout-search{padding:0 12px}.umi-plugin-layout-right .umi-plugin-layout-search:hover{background:transparent}.umi-plugin-layout-name{margin-left:8px}.ant-result{padding:48px 32px}.ant-result-success .ant-result-icon>.anticon{color:#26c992}.ant-result-error .ant-result-icon>.anticon{color:#ef4872}.ant-result-info .ant-result-icon>.anticon{color:#296df3}.ant-result-warning .ant-result-icon>.anticon{color:#ffb924}.ant-result-image{width:250px;height:295px;margin:auto}.ant-result-icon{margin-bottom:24px;text-align:center}.ant-result-icon>.anticon{font-size:72px}.ant-result-title{color:rgba(0,10,36,.85);font-size:24px;line-height:1.8;text-align:center}.ant-result-subtitle{color:rgba(0,10,36,.65);font-size:14px;line-height:1.6;text-align:center}.ant-result-extra{margin:24px 0 0;text-align:center}.ant-result-extra>*{margin-right:8px}.ant-result-extra>:last-child{margin-right:0}.ant-result-content{margin-top:24px;padding:24px 40px;background-color:#fafafa}.ant-result-rtl{direction:rtl}.ant-result-rtl .ant-result-extra>*{margin-right:0;margin-left:8px}.ant-result-rtl .ant-result-extra>:last-child{margin-left:0}.ant-affix{position:fixed;z-index:10}.ant-page-header{box-sizing:border-box;margin:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;padding:16px 24px;background-color:#fff}.ant-page-header-ghost{background-color:inherit}.ant-page-header.has-breadcrumb{padding-top:12px}.ant-page-header.has-footer{padding-bottom:0}.ant-page-header-back{margin-right:16px;font-size:16px;line-height:1}.ant-page-header-back-button{color:#296df3;outline:none;cursor:pointer;transition:color .3s;color:#000}.ant-page-header-back-button:focus-visible,.ant-page-header-back-button:hover{color:#5493ff}.ant-page-header-back-button:active{color:#184ecc}.ant-page-header .ant-divider-vertical{height:14px;margin:0 12px;vertical-align:middle}.ant-breadcrumb+.ant-page-header-heading{margin-top:8px}.ant-page-header-heading{display:flex;justify-content:space-between}.ant-page-header-heading-left{display:flex;align-items:center;margin:4px 0;overflow:hidden}.ant-page-header-heading-title{margin-right:12px;margin-bottom:0;color:rgba(0,10,36,.85);font-weight:600;font-size:20px;line-height:32px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-page-header-heading .ant-avatar{margin-right:12px}.ant-page-header-heading-sub-title{margin-right:12px;color:rgba(0,10,36,.65);font-size:14px;line-height:1.5715;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-page-header-heading-extra{margin:4px 0;white-space:nowrap}.ant-page-header-heading-extra>*{white-space:unset}.ant-page-header-content{padding-top:12px}.ant-page-header-footer{margin-top:16px}.ant-page-header-footer .ant-tabs>.ant-tabs-nav{margin:0}.ant-page-header-footer .ant-tabs>.ant-tabs-nav:before{border:none}.ant-page-header-footer .ant-tabs .ant-tabs-tab{padding-top:8px;padding-bottom:8px;font-size:16px}.ant-page-header-compact .ant-page-header-heading{flex-wrap:wrap}.ant-page-header-rtl{direction:rtl}.ant-page-header-rtl .ant-page-header-back{float:right;margin-right:0;margin-left:16px}.ant-page-header-rtl .ant-page-header-heading-title{margin-right:0;margin-left:12px}.ant-page-header-rtl .ant-page-header-heading .ant-avatar{margin-right:0;margin-left:12px}.ant-page-header-rtl .ant-page-header-heading-sub-title{float:right;margin-right:0;margin-left:12px}.ant-page-header-rtl .ant-page-header-heading-tags{float:right}.ant-page-header-rtl .ant-page-header-heading-extra{float:left}.ant-page-header-rtl .ant-page-header-heading-extra>*{margin-right:12px;margin-left:0}.ant-page-header-rtl .ant-page-header-heading-extra>:first-child{margin-right:0}.ant-page-header-rtl .ant-page-header-footer .ant-tabs-bar .ant-tabs-nav{float:right}.ant-breadcrumb{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";color:rgba(0,10,36,.65);font-size:14px}.ant-breadcrumb .anticon{font-size:14px}.ant-breadcrumb ol{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none}.ant-breadcrumb a{color:rgba(0,10,36,.65);transition:color .3s}.ant-breadcrumb a:hover{color:rgba(0,10,36,.85)}.ant-breadcrumb li:last-child{color:rgba(0,10,36,.85)}.ant-breadcrumb li:last-child a{color:rgba(0,10,36,.85)}li:last-child>.ant-breadcrumb-separator{display:none}.ant-breadcrumb-separator{margin:0 8px;color:rgba(0,10,36,.65)}.ant-breadcrumb-link>.anticon+a,.ant-breadcrumb-link>.anticon+span{margin-left:4px}.ant-breadcrumb-overlay-link>.anticon{margin-left:4px}.ant-breadcrumb-rtl{direction:rtl}.ant-breadcrumb-rtl:before{display:table;content:""}.ant-breadcrumb-rtl:after{display:table;clear:both;content:""}.ant-breadcrumb-rtl>span{float:right}.ant-breadcrumb-rtl .ant-breadcrumb-link>.anticon+a,.ant-breadcrumb-rtl .ant-breadcrumb-link>.anticon+span{margin-right:4px;margin-left:0}.ant-breadcrumb-rtl .ant-breadcrumb-overlay-link>.anticon{margin-right:4px;margin-left:0}.ant-tabs-small>.ant-tabs-nav .ant-tabs-tab{padding:8px 0;font-size:14px}.ant-tabs-large>.ant-tabs-nav .ant-tabs-tab{padding:16px 0;font-size:16px}.ant-tabs-card.ant-tabs-small>.ant-tabs-nav .ant-tabs-tab{padding:6px 16px}.ant-tabs-card.ant-tabs-large>.ant-tabs-nav .ant-tabs-tab{padding:7px 16px 6px}.ant-tabs-rtl{direction:rtl}.ant-tabs-rtl .ant-tabs-nav .ant-tabs-tab{margin:0 0 0 32px}.ant-tabs-rtl .ant-tabs-nav .ant-tabs-tab:last-of-type{margin-left:0}.ant-tabs-rtl .ant-tabs-nav .ant-tabs-tab .anticon{margin-right:0;margin-left:12px}.ant-tabs-rtl .ant-tabs-nav .ant-tabs-tab .ant-tabs-tab-remove{margin-right:8px;margin-left:-4px}.ant-tabs-rtl .ant-tabs-nav .ant-tabs-tab .ant-tabs-tab-remove .anticon{margin:0}.ant-tabs-rtl.ant-tabs-left>.ant-tabs-nav{order:1}.ant-tabs-rtl.ant-tabs-left>.ant-tabs-content-holder{order:0}.ant-tabs-rtl.ant-tabs-right>.ant-tabs-nav{order:0}.ant-tabs-rtl.ant-tabs-right>.ant-tabs-content-holder{order:1}.ant-tabs-rtl.ant-tabs-card.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-rtl.ant-tabs-card.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-rtl.ant-tabs-card.ant-tabs-top>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-rtl.ant-tabs-card.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab{margin-right:2px;margin-left:0}.ant-tabs-rtl.ant-tabs-card.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-add,.ant-tabs-rtl.ant-tabs-card.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-nav-add,.ant-tabs-rtl.ant-tabs-card.ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-add,.ant-tabs-rtl.ant-tabs-card.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-nav-add{margin-right:2px;margin-left:0}.ant-tabs-dropdown-rtl{direction:rtl}.ant-tabs-dropdown-rtl .ant-tabs-dropdown-menu-item{text-align:right}.ant-tabs-bottom,.ant-tabs-top{flex-direction:column}.ant-tabs-bottom>.ant-tabs-nav,.ant-tabs-bottom>div>.ant-tabs-nav,.ant-tabs-top>.ant-tabs-nav,.ant-tabs-top>div>.ant-tabs-nav{margin:0 0 16px}.ant-tabs-bottom>.ant-tabs-nav:before,.ant-tabs-bottom>div>.ant-tabs-nav:before,.ant-tabs-top>.ant-tabs-nav:before,.ant-tabs-top>div>.ant-tabs-nav:before{position:absolute;right:0;left:0;border-bottom:1px solid #f0f0f0;content:""}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-top>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-ink-bar{height:2px}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-ink-bar-animated,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-ink-bar-animated,.ant-tabs-top>.ant-tabs-nav .ant-tabs-ink-bar-animated,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-ink-bar-animated{transition:width .3s,left .3s,right .3s}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-nav-wrap:before{top:0;bottom:0;width:30px}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-nav-wrap:before{left:0;box-shadow:inset 10px 0 8px -8px rgba(0,0,0,.08)}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-nav-wrap:after{right:0;box-shadow:inset -10px 0 8px -8px rgba(0,0,0,.08)}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-left:before,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-left:before,.ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-left:before,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-left:before{opacity:1}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-right:after,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-right:after,.ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-right:after,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-right:after{opacity:1}.ant-tabs-top>.ant-tabs-nav:before,.ant-tabs-top>div>.ant-tabs-nav:before{bottom:0}.ant-tabs-top>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-ink-bar{bottom:0}.ant-tabs-bottom>.ant-tabs-nav,.ant-tabs-bottom>div>.ant-tabs-nav{order:1;margin-top:16px;margin-bottom:0}.ant-tabs-bottom>.ant-tabs-nav:before,.ant-tabs-bottom>div>.ant-tabs-nav:before{top:0}.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-ink-bar{top:0}.ant-tabs-bottom>.ant-tabs-content-holder,.ant-tabs-bottom>div>.ant-tabs-content-holder{order:0}.ant-tabs-left>.ant-tabs-nav,.ant-tabs-left>div>.ant-tabs-nav,.ant-tabs-right>.ant-tabs-nav,.ant-tabs-right>div>.ant-tabs-nav{flex-direction:column;min-width:50px}.ant-tabs-left>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-right>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-tab{padding:8px 24px;text-align:center}.ant-tabs-left>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-right>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab{margin:16px 0 0}.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-wrap,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-wrap,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-wrap,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-wrap{flex-direction:column}.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-wrap:before{right:0;left:0;height:30px}.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-wrap:before{top:0;box-shadow:inset 0 10px 8px -8px rgba(0,0,0,.08)}.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-wrap:after{bottom:0;box-shadow:inset 0 -10px 8px -8px rgba(0,0,0,.08)}.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-top:before,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-top:before,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-top:before,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-top:before{opacity:1}.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-bottom:after,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-bottom:after,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-bottom:after,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-wrap.ant-tabs-nav-wrap-ping-bottom:after{opacity:1}.ant-tabs-left>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-right>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-ink-bar{width:2px}.ant-tabs-left>.ant-tabs-nav .ant-tabs-ink-bar-animated,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-ink-bar-animated,.ant-tabs-right>.ant-tabs-nav .ant-tabs-ink-bar-animated,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-ink-bar-animated{transition:height .3s,top .3s}.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-list,.ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-operations,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-list,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-nav-operations,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-list,.ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-operations,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-list,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-nav-operations{flex:1 0 auto;flex-direction:column}.ant-tabs-left>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-ink-bar{right:0}.ant-tabs-left>.ant-tabs-content-holder,.ant-tabs-left>div>.ant-tabs-content-holder{margin-left:-1px;border-left:1px solid #f0f0f0}.ant-tabs-left>.ant-tabs-content-holder>.ant-tabs-content>.ant-tabs-tabpane,.ant-tabs-left>div>.ant-tabs-content-holder>.ant-tabs-content>.ant-tabs-tabpane{padding-left:24px}.ant-tabs-right>.ant-tabs-nav,.ant-tabs-right>div>.ant-tabs-nav{order:1}.ant-tabs-right>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-ink-bar{left:0}.ant-tabs-right>.ant-tabs-content-holder,.ant-tabs-right>div>.ant-tabs-content-holder{order:0;margin-right:-1px;border-right:1px solid #f0f0f0}.ant-tabs-right>.ant-tabs-content-holder>.ant-tabs-content>.ant-tabs-tabpane,.ant-tabs-right>div>.ant-tabs-content-holder>.ant-tabs-content>.ant-tabs-tabpane{padding-right:24px}.ant-tabs-dropdown{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:absolute;top:-9999px;left:-9999px;z-index:1050;display:block}.ant-tabs-dropdown-hidden{display:none}.ant-tabs-dropdown-menu{max-height:200px;margin:0;padding:4px 0;overflow-x:hidden;overflow-y:auto;text-align:left;list-style-type:none;background-color:#fff;background-clip:padding-box;border-radius:4px;outline:none;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}.ant-tabs-dropdown-menu-item{display:flex;align-items:center;min-width:120px;margin:0;padding:5px 12px;overflow:hidden;color:rgba(0,10,36,.85);font-weight:400;font-size:14px;line-height:22px;white-space:nowrap;text-overflow:ellipsis;cursor:pointer;transition:all .3s}.ant-tabs-dropdown-menu-item>span{flex:1 1;white-space:nowrap}.ant-tabs-dropdown-menu-item-remove{flex:none;margin-left:12px;color:rgba(0,10,36,.65);font-size:12px;background:transparent;border:0;cursor:pointer}.ant-tabs-dropdown-menu-item-remove:hover{color:#4e86f5}.ant-tabs-dropdown-menu-item:hover{background:#f5f5f5}.ant-tabs-dropdown-menu-item-disabled,.ant-tabs-dropdown-menu-item-disabled:hover{color:rgba(0,0,0,.25);background:transparent;cursor:not-allowed}.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab{margin:0;padding:8px 16px;background:#fafafa;border:1px solid #f0f0f0;transition:all .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab-active,.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab-active{color:#296df3;background:#fff}.ant-tabs-card>.ant-tabs-nav .ant-tabs-ink-bar,.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-ink-bar{visibility:hidden}.ant-tabs-card.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-card.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-card.ant-tabs-top>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-card.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab{margin-left:2px}.ant-tabs-card.ant-tabs-top>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-card.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-tab{border-radius:4px 4px 0 0}.ant-tabs-card.ant-tabs-top>.ant-tabs-nav .ant-tabs-tab-active,.ant-tabs-card.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-tab-active{border-bottom-color:#fff}.ant-tabs-card.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-card.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-tab{border-radius:0 0 4px 4px}.ant-tabs-card.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-tab-active,.ant-tabs-card.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-tab-active{border-top-color:#fff}.ant-tabs-card.ant-tabs-left>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-card.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-card.ant-tabs-right>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.ant-tabs-card.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab{margin-top:2px}.ant-tabs-card.ant-tabs-left>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-card.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-tab{border-radius:4px 0 0 4px}.ant-tabs-card.ant-tabs-left>.ant-tabs-nav .ant-tabs-tab-active,.ant-tabs-card.ant-tabs-left>div>.ant-tabs-nav .ant-tabs-tab-active{border-right-color:#fff}.ant-tabs-card.ant-tabs-right>.ant-tabs-nav .ant-tabs-tab,.ant-tabs-card.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-tab{border-radius:0 4px 4px 0}.ant-tabs-card.ant-tabs-right>.ant-tabs-nav .ant-tabs-tab-active,.ant-tabs-card.ant-tabs-right>div>.ant-tabs-nav .ant-tabs-tab-active{border-left-color:#fff}.ant-tabs{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:flex}.ant-tabs>.ant-tabs-nav,.ant-tabs>div>.ant-tabs-nav{position:relative;display:flex;flex:none;align-items:center}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-wrap,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-wrap{position:relative;display:inline-block;display:flex;flex:auto;align-self:stretch;overflow:hidden;white-space:nowrap;transform:translate(0)}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs>.ant-tabs-nav .ant-tabs-nav-wrap:before,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-wrap:after,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-wrap:before{position:absolute;z-index:1;opacity:0;transition:opacity .3s;content:"";pointer-events:none}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-list,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-list{position:relative;display:flex;transition:transform .3s}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-operations,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-operations{display:flex;align-self:stretch}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-operations-hidden,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-operations-hidden{position:absolute;visibility:hidden;pointer-events:none}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-more,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-more{position:relative;padding:8px 16px;background:transparent;border:0}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-more:after,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-more:after{position:absolute;right:0;bottom:0;left:0;height:5px;transform:translateY(100%);content:""}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-add,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-add{min-width:40px;margin-left:2px;padding:0 8px;background:#fafafa;border:1px solid #f0f0f0;border-radius:4px 4px 0 0;outline:none;cursor:pointer;transition:all .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-add:hover,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-add:hover{color:#4e86f5}.ant-tabs>.ant-tabs-nav .ant-tabs-nav-add:active,.ant-tabs>.ant-tabs-nav .ant-tabs-nav-add:focus,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-add:active,.ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-add:focus{color:#0d57e8}.ant-tabs-extra-content{flex:none}.ant-tabs-centered>.ant-tabs-nav .ant-tabs-nav-wrap:not([class*=ant-tabs-nav-wrap-ping]),.ant-tabs-centered>div>.ant-tabs-nav .ant-tabs-nav-wrap:not([class*=ant-tabs-nav-wrap-ping]){justify-content:center}.ant-tabs-ink-bar{position:absolute;background:#296df3;pointer-events:none}.ant-tabs-tab{position:relative;display:inline-flex;align-items:center;padding:12px 0;font-size:14px;background:transparent;border:0;outline:none;cursor:pointer}.ant-tabs-tab-btn:active,.ant-tabs-tab-btn:focus,.ant-tabs-tab-remove:active,.ant-tabs-tab-remove:focus{color:#0d57e8}.ant-tabs-tab-btn{outline:none;transition:all .3s}.ant-tabs-tab-remove{flex:none;margin-right:-4px;margin-left:8px;color:rgba(0,10,36,.65);font-size:12px;background:transparent;border:none;outline:none;cursor:pointer;transition:all .3s}.ant-tabs-tab-remove:hover{color:rgba(0,10,36,.85)}.ant-tabs-tab:hover{color:#4e86f5}.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{color:#296df3;text-shadow:0 0 .25px currentcolor}.ant-tabs-tab.ant-tabs-tab-disabled{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-tabs-tab.ant-tabs-tab-disabled .ant-tabs-tab-btn:active,.ant-tabs-tab.ant-tabs-tab-disabled .ant-tabs-tab-btn:focus,.ant-tabs-tab.ant-tabs-tab-disabled .ant-tabs-tab-remove:active,.ant-tabs-tab.ant-tabs-tab-disabled .ant-tabs-tab-remove:focus{color:rgba(0,0,0,.25)}.ant-tabs-tab .ant-tabs-tab-remove .anticon{margin:0}.ant-tabs-tab .anticon{margin-right:12px}.ant-tabs-tab+.ant-tabs-tab{margin:0 0 0 32px}.ant-tabs-content{position:relative;width:100%}.ant-tabs-content-holder{flex:auto;min-width:0;min-height:0}.ant-tabs-tabpane{outline:none}.ant-tabs-tabpane-hidden{display:none}.ant-tabs-switch-appear,.ant-tabs-switch-enter{transition:none}.ant-tabs-switch-appear-start,.ant-tabs-switch-enter-start{opacity:0}.ant-tabs-switch-appear-active,.ant-tabs-switch-enter-active{opacity:1;transition:opacity .3s}.ant-tabs-switch-leave{position:absolute;transition:none;inset:0}.ant-tabs-switch-leave-start{opacity:1}.ant-tabs-switch-leave-active{opacity:0;transition:opacity .3s}.ant-pro-page-container-children-content{margin:24px 24px 0;padding:inherit}.ant-pro-page-container{background-color:inherit}.ant-pro-page-container-warp{background-color:#fff}.ant-pro-page-container-warp .ant-tabs-nav{margin:0}.ant-pro-page-container-ghost .ant-pro-page-container-warp{background-color:transparent}.ant-pro-page-container-ghost .ant-pro-page-container-children-content{margin-top:0}.ant-pro-page-container-main .ant-pro-page-container-detail{display:flex}.ant-pro-page-container-main .ant-pro-page-container-row{display:flex;width:100%}.ant-pro-page-container-main .ant-pro-page-container-title-content{margin-bottom:16px}.ant-pro-page-container-main .ant-pro-page-container-content,.ant-pro-page-container-main .ant-pro-page-container-title{flex:auto;width:100%}.ant-pro-page-container-main .ant-pro-page-container-extraContent,.ant-pro-page-container-main .ant-pro-page-container-main{flex:0 1 auto}.ant-pro-page-container-main .ant-pro-page-container-main{width:100%}.ant-pro-page-container-main .ant-pro-page-container-title{margin-bottom:16px}.ant-pro-page-container-main .ant-pro-page-container-logo{margin-bottom:16px}.ant-pro-page-container-main .ant-pro-page-container-extraContent{min-width:242px;margin-left:88px;text-align:right}@media screen and (max-width:1200px){.ant-pro-page-container-main .ant-pro-page-container-extraContent{margin-left:44px}}@media screen and (max-width:992px){.ant-pro-page-container-main .ant-pro-page-container-extraContent{margin-left:20px}}@media screen and (max-width:768px){.ant-pro-page-container-main .ant-pro-page-container-row{display:block}.ant-pro-page-container-main .ant-pro-page-container-action,.ant-pro-page-container-main .ant-pro-page-container-extraContent{margin-left:0;text-align:left}}@media screen and (max-width:576px){.ant-pro-page-container-detail{display:block}.ant-pro-page-container-extraContent{margin-left:0}}.ant-pro-grid-content{width:100%}.ant-pro-grid-content.wide{max-width:1200px;margin:0 auto}.ant-pro-footer-bar{position:fixed;right:0;bottom:0;z-index:99;display:flex;align-items:center;width:100%;padding:0 24px;line-height:44px;background:#fff;border-top:1px solid #f0f0f0;box-shadow:0 -6px 16px -8px rgba(0,0,0,.08),0 -9px 28px 0 rgba(0,0,0,.05),0 -12px 48px 16px rgba(0,0,0,.03);transition:width .3s cubic-bezier(.645,.045,.355,1)}.ant-pro-footer-bar-left{flex:1 1}.ant-pro-footer-bar-right>*{margin-right:8px}.ant-pro-footer-bar-right>:last-child{margin:0}.ant-layout{display:flex;flex:auto;flex-direction:column;min-height:0;background:#f0f2f5}.ant-layout,.ant-layout *{box-sizing:border-box}.ant-layout.ant-layout-has-sider{flex-direction:row}.ant-layout.ant-layout-has-sider>.ant-layout,.ant-layout.ant-layout-has-sider>.ant-layout-content{width:0}.ant-layout-footer,.ant-layout-header{flex:0 0 auto}.ant-layout-header{height:64px;padding:0 50px;color:rgba(0,10,36,.85);line-height:64px;background:#001529}.ant-layout-footer{padding:24px 50px;color:rgba(0,10,36,.85);font-size:14px;background:#f0f2f5}.ant-layout-content{flex:auto;min-height:0}.ant-layout-sider{position:relative;min-width:0;background:#001529;transition:all .2s}.ant-layout-sider-children{height:100%;margin-top:-.1px;padding-top:.1px}.ant-layout-sider-children .ant-menu.ant-menu-inline-collapsed{width:auto}.ant-layout-sider-has-trigger{padding-bottom:48px}.ant-layout-sider-right{order:1}.ant-layout-sider-trigger{position:fixed;bottom:0;z-index:1;height:48px;color:#fff;line-height:48px;text-align:center;background:#002140;cursor:pointer;transition:all .2s}.ant-layout-sider-zero-width>*{overflow:hidden}.ant-layout-sider-zero-width-trigger{position:absolute;top:64px;right:-36px;z-index:1;width:36px;height:42px;color:#fff;font-size:18px;line-height:42px;text-align:center;background:#001529;border-radius:0 4px 4px 0;cursor:pointer;transition:background .3s ease}.ant-layout-sider-zero-width-trigger:after{position:absolute;top:0;right:0;bottom:0;left:0;background:transparent;transition:all .3s;content:""}.ant-layout-sider-zero-width-trigger:hover:after{background:hsla(0,0%,100%,.1)}.ant-layout-sider-zero-width-trigger-right{left:-36px;border-radius:4px 0 0 4px}.ant-layout-sider-light{background:#fff}.ant-layout-sider-light .ant-layout-sider-trigger{color:rgba(0,10,36,.85);background:#fff}.ant-layout-sider-light .ant-layout-sider-zero-width-trigger{color:rgba(0,10,36,.85);background:#fff}.ant-layout-rtl{direction:rtl}.ant-pro-basicLayout{display:flex;flex-direction:column;width:100%;min-height:100%}.ant-pro-basicLayout .ant-layout-header.ant-pro-fixed-header{position:fixed;top:0}.ant-pro-basicLayout .ant-layout-header.ant-pro-header-light{background:#fff}.ant-pro-basicLayout-content{position:relative;margin:24px}.ant-pro-basicLayout-content .ant-pro-page-container{margin:-24px -24px 0}.ant-pro-basicLayout-content-disable-margin{margin:0}.ant-pro-basicLayout-content-disable-margin .ant-pro-page-container{margin:0}.ant-pro-basicLayout-content>.ant-layout{max-height:100%}.ant-pro-basicLayout .ant-pro-basicLayout-is-children.ant-pro-basicLayout-fix-siderbar{height:100vh;overflow:hidden;transform:rotate(0)}.ant-pro-basicLayout .ant-pro-basicLayout-has-header .tech-page-container{height:calc(100vh - 48px)}.ant-pro-basicLayout .ant-pro-basicLayout-has-header .ant-pro-basicLayout-is-children.ant-pro-basicLayout-has-header .tech-page-container{height:calc(100vh - 96px)}.ant-pro-basicLayout .ant-pro-basicLayout-has-header .ant-pro-basicLayout-is-children.ant-pro-basicLayout-has-header .ant-pro-basicLayout-is-children{min-height:calc(100vh - 48px)}.ant-pro-basicLayout .ant-pro-basicLayout-has-header .ant-pro-basicLayout-is-children.ant-pro-basicLayout-has-header .ant-pro-basicLayout-is-children.ant-pro-basicLayout-fix-siderbar{height:calc(100vh - 48px)}.ant-pro-fixed-header{z-index:9;width:100%}.ant-pro-fixed-header-action{transition:width .3s cubic-bezier(.645,.045,.355,1)}.ant-pro-header-realDark{box-shadow:0 2px 8px 0 rgba(0,0,0,.65)}.ant-pro-global-header{position:relative;display:flex;align-items:center;height:100%;padding:0 16px;background:#fff;box-shadow:0 1px 4px rgba(0,21,41,.08)}.ant-pro-global-header>*{height:100%}.ant-pro-global-header-collapsed-button{display:flex;align-items:center;margin-left:16px;font-size:20px}.ant-pro-global-header-layout-mix{background-color:#001529}.ant-pro-global-header-layout-mix .ant-pro-global-header-logo h1{color:#fff}.ant-pro-global-header-layout-mix .anticon{color:#fff}.ant-pro-global-header-logo{position:relative;overflow:hidden}.ant-pro-global-header-logo a{display:flex;align-items:center;height:100%}.ant-pro-global-header-logo a img{height:28px}.ant-pro-global-header-logo a h1{height:32px;margin:0 0 0 12px;color:#296df3;font-weight:600;font-size:18px;line-height:32px}.ant-pro-global-header-logo-rtl a h1{margin:0 12px 0 0}.ant-pro-global-header-menu .anticon{margin-right:8px}.ant-pro-global-header-menu .ant-dropdown-menu-item{min-width:160px}.ant-pro-global-header .dark{height:48px}.ant-pro-global-header .dark .action{color:hsla(0,0%,100%,.85)}.ant-pro-global-header .dark .action>i{color:hsla(0,0%,100%,.85)}.ant-pro-global-header .dark .action.opened,.ant-pro-global-header .dark .action:hover{background:#296df3}.ant-pro-global-header .dark .action .ant-badge{color:hsla(0,0%,100%,.85)}.ant-pro-sider{position:relative;background-color:#001529;border-right:0}.ant-pro-sider .ant-menu{background:transparent}.ant-pro-sider.ant-layout-sider-light .ant-menu-item a{color:rgba(0,10,36,.85)}.ant-pro-sider.ant-layout-sider-light .ant-menu-item-selected a,.ant-pro-sider.ant-layout-sider-light .ant-menu-item a:hover{color:#296df3}.ant-pro-sider-logo{position:relative;display:flex;align-items:center;padding:16px;cursor:pointer;transition:padding .3s cubic-bezier(.645,.045,.355,1)}.ant-pro-sider-logo>a{display:flex;align-items:center;justify-content:center;min-height:32px}.ant-pro-sider-logo img{display:inline-block;height:32px;vertical-align:middle}.ant-pro-sider-logo h1{display:inline-block;height:32px;margin:0 0 0 12px;color:#fff;font-weight:600;font-size:18px;line-height:32px;vertical-align:middle;animation:pro-layout-title-hide .3s}.ant-pro-sider-extra{margin-bottom:16px;padding:0 16px}.ant-pro-sider-extra-no-logo{margin-top:16px}.ant-pro-sider-menu{position:relative;z-index:10;min-height:100%;box-shadow:2px 0 6px rgba(0,21,41,.35)}.ant-pro-sider .ant-layout-sider-children{display:flex;flex-direction:column;height:100%}.ant-pro-sider .ant-layout-sider-children ::-webkit-scrollbar{width:6px;height:6px}.ant-pro-sider .ant-layout-sider-children ::-webkit-scrollbar-track{background:hsla(0,0%,100%,.15);border-radius:3px;box-shadow:inset 0 0 5px rgba(37,37,37,.05)}.ant-pro-sider .ant-layout-sider-children ::-webkit-scrollbar-thumb{background:hsla(0,0%,100%,.2);border-radius:3px;box-shadow:inset 0 0 5px hsla(0,0%,100%,.05)}.ant-pro-sider.ant-layout-sider-collapsed .ant-menu-inline-collapsed{width:48px}.ant-pro-sider.ant-layout-sider-collapsed .ant-pro-sider-logo{padding:16px 8px}.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed{position:fixed;top:0;left:0;z-index:100;height:100%;overflow:auto;overflow-x:hidden;box-shadow:2px 0 8px 0 rgba(29,35,41,.05)}.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed>.ant-menu-root :not(.ant-pro-sider-link-menu){height:calc(100vh - 48px);overflow-y:auto}.ant-pro-sider-light{background-color:#fff;box-shadow:2px 0 8px 0 rgba(29,35,41,.05)}.ant-pro-sider-light .ant-layout-sider-children ::-webkit-scrollbar-track{background:rgba(0,0,0,.06);border-radius:3px;box-shadow:inset 0 0 5px rgba(0,21,41,.05)}.ant-pro-sider-light .ant-layout-sider-children ::-webkit-scrollbar-thumb{background:rgba(0,0,0,.12);border-radius:3px;box-shadow:inset 0 0 5px rgba(0,21,41,.05)}.ant-pro-sider-light .ant-pro-sider-logo h1{color:#296df3}.ant-pro-sider-light .ant-menu-light{border-right-color:transparent}.ant-pro-sider-light .ant-pro-sider-collapsed-button{border-top:1px solid #f0f0f0}.ant-pro-sider-icon{width:14px;vertical-align:baseline}.ant-pro-sider-links{width:100%}.ant-pro-sider-links ul.ant-menu-root{height:auto}.ant-pro-sider-collapsed-button{border-top:1px solid rgba(0,0,0,.25)}.ant-pro-sider-collapsed-button .anticon{font-size:16px}.ant-pro-sider .top-nav-menu li.ant-menu-item{height:100%;line-height:1}.ant-pro-sider .drawer .drawer-content{background:#001529}@keyframes pro-layout-title-hide{0%{display:none;opacity:0}80%{display:none;opacity:0}to{display:unset;opacity:1}}.ant-skeleton{display:table;width:100%}.ant-skeleton-header{display:table-cell;padding-right:16px;vertical-align:top}.ant-skeleton-header .ant-skeleton-avatar{display:inline-block;vertical-align:top;background:hsla(0,0%,74.5%,.2);width:32px;height:32px;line-height:32px}.ant-skeleton-header .ant-skeleton-avatar.ant-skeleton-avatar-circle{border-radius:50%}.ant-skeleton-header .ant-skeleton-avatar-lg{width:40px;height:40px;line-height:40px}.ant-skeleton-header .ant-skeleton-avatar-lg.ant-skeleton-avatar-circle{border-radius:50%}.ant-skeleton-header .ant-skeleton-avatar-sm{width:24px;height:24px;line-height:24px}.ant-skeleton-header .ant-skeleton-avatar-sm.ant-skeleton-avatar-circle{border-radius:50%}.ant-skeleton-content{display:table-cell;width:100%;vertical-align:top}.ant-skeleton-content .ant-skeleton-title{width:100%;height:16px;background:hsla(0,0%,74.5%,.2);border-radius:4px}.ant-skeleton-content .ant-skeleton-title+.ant-skeleton-paragraph{margin-top:24px}.ant-skeleton-content .ant-skeleton-paragraph{padding:0}.ant-skeleton-content .ant-skeleton-paragraph>li{width:100%;height:16px;list-style:none;background:hsla(0,0%,74.5%,.2);border-radius:4px}.ant-skeleton-content .ant-skeleton-paragraph>li:last-child:not(:first-child):not(:nth-child(2)){width:61%}.ant-skeleton-content .ant-skeleton-paragraph>li+li{margin-top:16px}.ant-skeleton-with-avatar .ant-skeleton-content .ant-skeleton-title{margin-top:12px}.ant-skeleton-with-avatar .ant-skeleton-content .ant-skeleton-title+.ant-skeleton-paragraph{margin-top:28px}.ant-skeleton-round .ant-skeleton-content .ant-skeleton-paragraph>li,.ant-skeleton-round .ant-skeleton-content .ant-skeleton-title{border-radius:100px}.ant-skeleton-active .ant-skeleton-avatar,.ant-skeleton-active .ant-skeleton-button,.ant-skeleton-active .ant-skeleton-image,.ant-skeleton-active .ant-skeleton-input,.ant-skeleton-active .ant-skeleton-paragraph>li,.ant-skeleton-active .ant-skeleton-title{position:relative;z-index:0;overflow:hidden;background:transparent}.ant-skeleton-active .ant-skeleton-avatar:after,.ant-skeleton-active .ant-skeleton-button:after,.ant-skeleton-active .ant-skeleton-image:after,.ant-skeleton-active .ant-skeleton-input:after,.ant-skeleton-active .ant-skeleton-paragraph>li:after,.ant-skeleton-active .ant-skeleton-title:after{position:absolute;top:0;right:-150%;bottom:0;left:-150%;background:linear-gradient(90deg,hsla(0,0%,74.5%,.2) 25%,hsla(0,0%,50.6%,.24) 37%,hsla(0,0%,74.5%,.2) 63%);animation:ant-skeleton-loading 1.4s ease infinite;content:""}.ant-skeleton.ant-skeleton-block{width:100%}.ant-skeleton.ant-skeleton-block .ant-skeleton-button{width:100%}.ant-skeleton.ant-skeleton-block .ant-skeleton-input{width:100%}.ant-skeleton-element{display:inline-block;width:auto}.ant-skeleton-element .ant-skeleton-button{display:inline-block;vertical-align:top;background:hsla(0,0%,74.5%,.2);border-radius:4px;width:64px;min-width:64px;height:32px;line-height:32px}.ant-skeleton-element .ant-skeleton-button.ant-skeleton-button-square{width:32px;min-width:32px}.ant-skeleton-element .ant-skeleton-button.ant-skeleton-button-circle{width:32px;min-width:32px;border-radius:50%}.ant-skeleton-element .ant-skeleton-button.ant-skeleton-button-round{border-radius:32px}.ant-skeleton-element .ant-skeleton-button-lg{width:80px;min-width:80px;height:40px;line-height:40px}.ant-skeleton-element .ant-skeleton-button-lg.ant-skeleton-button-square{width:40px;min-width:40px}.ant-skeleton-element .ant-skeleton-button-lg.ant-skeleton-button-circle{width:40px;min-width:40px;border-radius:50%}.ant-skeleton-element .ant-skeleton-button-lg.ant-skeleton-button-round{border-radius:40px}.ant-skeleton-element .ant-skeleton-button-sm{width:48px;min-width:48px;height:24px;line-height:24px}.ant-skeleton-element .ant-skeleton-button-sm.ant-skeleton-button-square{width:24px;min-width:24px}.ant-skeleton-element .ant-skeleton-button-sm.ant-skeleton-button-circle{width:24px;min-width:24px;border-radius:50%}.ant-skeleton-element .ant-skeleton-button-sm.ant-skeleton-button-round{border-radius:24px}.ant-skeleton-element .ant-skeleton-avatar{display:inline-block;vertical-align:top;background:hsla(0,0%,74.5%,.2);width:32px;height:32px;line-height:32px}.ant-skeleton-element .ant-skeleton-avatar.ant-skeleton-avatar-circle{border-radius:50%}.ant-skeleton-element .ant-skeleton-avatar-lg{width:40px;height:40px;line-height:40px}.ant-skeleton-element .ant-skeleton-avatar-lg.ant-skeleton-avatar-circle{border-radius:50%}.ant-skeleton-element .ant-skeleton-avatar-sm{width:24px;height:24px;line-height:24px}.ant-skeleton-element .ant-skeleton-avatar-sm.ant-skeleton-avatar-circle{border-radius:50%}.ant-skeleton-element .ant-skeleton-input{display:inline-block;vertical-align:top;background:hsla(0,0%,74.5%,.2);width:160px;min-width:160px;height:32px;line-height:32px}.ant-skeleton-element .ant-skeleton-input-lg{width:200px;min-width:200px;height:40px;line-height:40px}.ant-skeleton-element .ant-skeleton-input-sm{width:120px;min-width:120px;height:24px;line-height:24px}.ant-skeleton-element .ant-skeleton-image{display:flex;align-items:center;justify-content:center;vertical-align:top;background:hsla(0,0%,74.5%,.2);width:96px;height:96px;line-height:96px}.ant-skeleton-element .ant-skeleton-image.ant-skeleton-image-circle{border-radius:50%}.ant-skeleton-element .ant-skeleton-image-path{fill:#bfbfbf}.ant-skeleton-element .ant-skeleton-image-svg{width:48px;height:48px;line-height:48px;max-width:192px;max-height:192px}.ant-skeleton-element .ant-skeleton-image-svg.ant-skeleton-image-circle{border-radius:50%}@keyframes ant-skeleton-loading{0%{transform:translateX(-37.5%)}to{transform:translateX(37.5%)}}.ant-skeleton-rtl{direction:rtl}.ant-skeleton-rtl .ant-skeleton-header{padding-right:0;padding-left:16px}.ant-skeleton-rtl.ant-skeleton.ant-skeleton-active .ant-skeleton-content .ant-skeleton-paragraph>li,.ant-skeleton-rtl.ant-skeleton.ant-skeleton-active .ant-skeleton-content .ant-skeleton-title{animation-name:ant-skeleton-loading-rtl}.ant-skeleton-rtl.ant-skeleton.ant-skeleton-active .ant-skeleton-avatar{animation-name:ant-skeleton-loading-rtl}@keyframes ant-skeleton-loading-rtl{0%{background-position:0 50%}to{background-position:100% 50%}}.ant-pro-top-nav-header{position:relative;width:100%;height:100%;box-shadow:0 1px 4px 0 rgba(0,21,41,.12);transition:background .3s,width .2s}.ant-pro-top-nav-header .ant-menu{background:transparent}.ant-pro-top-nav-header.light{background-color:#fff}.ant-pro-top-nav-header.light .ant-pro-top-nav-header-logo h1{color:rgba(0,10,36,.85)}.ant-pro-top-nav-header.light .anticon{color:inherit}.ant-pro-top-nav-header-main{display:flex;height:100%;padding-left:16px}.ant-pro-top-nav-header-main-left{display:flex;min-width:192px}.ant-pro-top-nav-header .anticon{color:#fff}.ant-pro-top-nav-header-logo{position:relative;min-width:165px;height:100%;overflow:hidden}.ant-pro-top-nav-header-logo a>svg,.ant-pro-top-nav-header-logo img{display:inline-block;height:32px;vertical-align:middle}.ant-pro-top-nav-header-logo h1{display:inline-block;margin:0 0 0 12px;color:#fff;font-size:16px;vertical-align:top}.ant-pro-top-nav-header-menu{min-width:0}.ant-pro-top-nav-header-menu .ant-menu.ant-menu-horizontal{height:100%;border:none}.ant-pro-global-footer{margin:48px 0 24px;padding:0 16px;text-align:center}.ant-pro-global-footer-links{margin-bottom:8px}.ant-pro-global-footer-links a{color:rgba(0,10,36,.65);transition:all .3s}.ant-pro-global-footer-links a:not(:last-child){margin-right:40px}.ant-pro-global-footer-links a:hover{color:rgba(0,10,36,.85)}.ant-pro-global-footer-copyright{color:rgba(0,10,36,.65);font-size:14px}.ant-drawer{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;pointer-events:none}.ant-drawer-inline{position:absolute}.ant-drawer-mask{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1000;background:rgba(0,0,0,.45);pointer-events:auto}.ant-drawer-content-wrapper{position:absolute;z-index:1000;transition:all .3s}.ant-drawer-content-wrapper-hidden{display:none}.ant-drawer-left>.ant-drawer-content-wrapper{top:0;bottom:0;left:0;box-shadow:6px 0 16px -8px rgba(0,0,0,.08),9px 0 28px 0 rgba(0,0,0,.05),12px 0 48px 16px rgba(0,0,0,.03)}.ant-drawer-right>.ant-drawer-content-wrapper{top:0;right:0;bottom:0;box-shadow:-6px 0 16px -8px rgba(0,0,0,.08),-9px 0 28px 0 rgba(0,0,0,.05),-12px 0 48px 16px rgba(0,0,0,.03)}.ant-drawer-top>.ant-drawer-content-wrapper{top:0;right:0;left:0;box-shadow:0 6px 16px -8px rgba(0,0,0,.08),0 9px 28px 0 rgba(0,0,0,.05),0 12px 48px 16px rgba(0,0,0,.03)}.ant-drawer-bottom>.ant-drawer-content-wrapper{right:0;bottom:0;left:0;box-shadow:0 -6px 16px -8px rgba(0,0,0,.08),0 -9px 28px 0 rgba(0,0,0,.05),0 -12px 48px 16px rgba(0,0,0,.03)}.ant-drawer-content{width:100%;height:100%;overflow:auto;background:#fff;pointer-events:auto}.ant-drawer-wrapper-body{display:flex;flex-direction:column;width:100%;height:100%}.ant-drawer-header{display:flex;flex:0 1;align-items:center;padding:16px 24px;font-size:16px;line-height:22px;border-bottom:1px solid #f0f0f0}.ant-drawer-header-title{display:flex;flex:1 1;align-items:center;min-width:0;min-height:0}.ant-drawer-extra{flex:none}.ant-drawer-close{display:inline-block;margin-right:12px;color:rgba(0,10,36,.65);font-weight:700;font-size:16px;font-style:normal;line-height:1;text-align:center;text-transform:none;text-decoration:none;background:transparent;border:0;outline:0;cursor:pointer;transition:color .3s;text-rendering:auto}.ant-drawer-close:focus,.ant-drawer-close:hover{color:rgba(0,0,0,.75);text-decoration:none}.ant-drawer-title{flex:1 1;margin:0;color:rgba(0,10,36,.85);font-weight:500;font-size:16px;line-height:22px}.ant-drawer-body{flex:1 1;min-width:0;min-height:0;padding:24px;overflow:auto}.ant-drawer-footer{flex-shrink:0;padding:10px 16px;border-top:1px solid #f0f0f0}.panel-motion-appear-start,.panel-motion-enter-start,.panel-motion-leave-start{transition:none}.panel-motion-appear-active,.panel-motion-enter-active,.panel-motion-leave-active{transition:all .3s}.ant-drawer-mask-motion-appear-active,.ant-drawer-mask-motion-enter-active,.ant-drawer-mask-motion-leave-active{transition:all .3s}.ant-drawer-mask-motion-appear,.ant-drawer-mask-motion-enter{opacity:0}.ant-drawer-mask-motion-appear-active,.ant-drawer-mask-motion-enter-active{opacity:1}.ant-drawer-mask-motion-leave{opacity:1}.ant-drawer-mask-motion-leave-active{opacity:0}.ant-drawer-panel-motion-left-appear-start,.ant-drawer-panel-motion-left-enter-start,.ant-drawer-panel-motion-left-leave-start{transition:none}.ant-drawer-panel-motion-left-appear-active,.ant-drawer-panel-motion-left-enter-active,.ant-drawer-panel-motion-left-leave-active{transition:all .3s}.ant-drawer-panel-motion-left-appear-start,.ant-drawer-panel-motion-left-enter-start{transform:translateX(-100%)!important}.ant-drawer-panel-motion-left-appear-active,.ant-drawer-panel-motion-left-enter-active{transform:translateX(0)}.ant-drawer-panel-motion-left-leave{transform:translateX(0)}.ant-drawer-panel-motion-left-leave-active{transform:translateX(-100%)}.ant-drawer-panel-motion-right-appear-start,.ant-drawer-panel-motion-right-enter-start,.ant-drawer-panel-motion-right-leave-start{transition:none}.ant-drawer-panel-motion-right-appear-active,.ant-drawer-panel-motion-right-enter-active,.ant-drawer-panel-motion-right-leave-active{transition:all .3s}.ant-drawer-panel-motion-right-appear-start,.ant-drawer-panel-motion-right-enter-start{transform:translateX(100%)!important}.ant-drawer-panel-motion-right-appear-active,.ant-drawer-panel-motion-right-enter-active{transform:translateX(0)}.ant-drawer-panel-motion-right-leave{transform:translateX(0)}.ant-drawer-panel-motion-right-leave-active{transform:translateX(100%)}.ant-drawer-panel-motion-top-appear-start,.ant-drawer-panel-motion-top-enter-start,.ant-drawer-panel-motion-top-leave-start{transition:none}.ant-drawer-panel-motion-top-appear-active,.ant-drawer-panel-motion-top-enter-active,.ant-drawer-panel-motion-top-leave-active{transition:all .3s}.ant-drawer-panel-motion-top-appear-start,.ant-drawer-panel-motion-top-enter-start{transform:translateY(-100%)!important}.ant-drawer-panel-motion-top-appear-active,.ant-drawer-panel-motion-top-enter-active{transform:translateY(0)}.ant-drawer-panel-motion-top-leave{transform:translateY(0)}.ant-drawer-panel-motion-top-leave-active{transform:translateY(-100%)}.ant-drawer-panel-motion-bottom-appear-start,.ant-drawer-panel-motion-bottom-enter-start,.ant-drawer-panel-motion-bottom-leave-start{transition:none}.ant-drawer-panel-motion-bottom-appear-active,.ant-drawer-panel-motion-bottom-enter-active,.ant-drawer-panel-motion-bottom-leave-active{transition:all .3s}.ant-drawer-panel-motion-bottom-appear-start,.ant-drawer-panel-motion-bottom-enter-start{transform:translateY(100%)!important}.ant-drawer-panel-motion-bottom-appear-active,.ant-drawer-panel-motion-bottom-enter-active{transform:translateY(0)}.ant-drawer-panel-motion-bottom-leave{transform:translateY(0)}.ant-drawer-panel-motion-bottom-leave-active{transform:translateY(100%)}.ant-drawer-rtl{direction:rtl}.ant-drawer-rtl .ant-drawer-close{margin-right:0;margin-left:12px}.leftAvatar___jXS-t{display:flex;align-items:center;justify-content:center;width:40px;height:40px;margin-right:6px;color:var(--chat-blue);font-size:40px;background-color:#fff;border-radius:50%}.message___ov1VS .domainName___2DDh-{margin-bottom:2px;margin-left:4px;color:var(--text-color);font-weight:500}.message___ov1VS .messageContent___5HLSN{display:flex;align-items:flex-start}.message___ov1VS .messageContent___5HLSN .messageBody___3Dtin{width:100%}.message___ov1VS .messageContent___5HLSN .messageBody___3Dtin .messageTopBar___9O3GQ{max-width:90%;margin:0 16px;padding:12px 0 8px;overflow:hidden;color:var(--text-color-third);font-size:13px;white-space:nowrap;text-overflow:ellipsis;background-color:#fff}.message___ov1VS .messageContent___5HLSN .avatar___1wuzv{margin-right:4px}.message___ov1VS .messageContent___5HLSN .bubble___2rE8_{box-sizing:border-box;min-width:1px;max-width:100%;padding:8px 16px 10px;background:hsla(0,0%,100%,.8);border:1px solid transparent;border-radius:12px;box-shadow:0 2px 4px rgba(0,0,0,.14),0 0 2px rgba(0,0,0,.12)}.message___ov1VS .messageContent___5HLSN .bubble___2rE8_ .text___2A2KV{line-height:1.5;white-space:pre-wrap;overflow-wrap:break-word;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.message___ov1VS .messageContent___5HLSN .bubble___2rE8_ .textMsg___1Cagn{padding:12px 0 5px}.message___ov1VS .messageContent___5HLSN .bubble___2rE8_ .topBar___3SUj7{display:flex;align-items:center;max-width:100%;padding:4px 0 8px;overflow-x:auto;color:var(--text-color);font-weight:500;font-size:14px;white-space:nowrap;border-bottom:1px solid rgba(0,0,0,.03)}.message___ov1VS .messageContent___5HLSN .bubble___2rE8_ .topBar___3SUj7 .messageTitleWrapper___2nkrf{display:flex;align-items:center}.message___ov1VS .messageContent___5HLSN .bubble___2rE8_ .topBar___3SUj7 .messageTitle___nEuXN{display:flex;align-items:center;color:var(--text-color);font-weight:500;font-size:14px;white-space:nowrap}.message___ov1VS.right___3ioPO .messageContent___5HLSN{flex-direction:row-reverse}.message___ov1VS.right___3ioPO .messageContent___5HLSN .bubble___2rE8_{float:right;box-sizing:border-box;padding:8px 16px;color:#fff;font-size:16px;background:linear-gradient(81.62deg,#2870ea 8.72%,var(--chat-blue) 85.01%);border:1px solid transparent;box-shadow:0 2px 4px rgba(0,0,0,.14),0 0 2px rgba(0,0,0,.12)}.message___ov1VS.right___3ioPO .messageContent___5HLSN .bubble___2rE8_ .text___2A2KV::selection{background:#1ba1f7}.textBubble___ihT3i{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.listenerSex___37uVn{padding-bottom:24px}.listenerArea___3pK5q{padding-top:24px;padding-bottom:12px}.typing___1luaU{width:100%;padding:0 5px}.typing___1luaU .ant-spin-dot{width:100%}.messageEntityName___258Wt{cursor:pointer}.messageEntityName___258Wt:hover{color:var(--primary-color)}.messageAvatar___1Ywwf{margin-right:8px}.dataHolder___u5qE_{position:relative}.subTitle___ck_64{margin-left:20px;color:var(--text-color-third);font-weight:400;font-size:12px}.subTitle___ck_64 .subTitleValue___k_e_P{margin-left:6px;color:var(--text-color);font-size:13px}.avatarPopover___3r5u1 .ant-popover-inner-content{padding:3px 4px!important}.moreOption___1NGcC{display:flex;align-items:center;margin-top:10px;color:var(--text-color-fourth);font-size:12px}.moreOption___1NGcC .selectOthers___2xwh0{color:var(--text-color);cursor:pointer}.moreOption___1NGcC .selectOthers___2xwh0:hover{color:var(--primary-color)}.moreOption___1NGcC .indicators___1jqCq{display:flex;align-items:center;margin-left:12px;grid-column-gap:12px;-webkit-column-gap:12px;column-gap:12px}.moreOption___1NGcC .indicators___1jqCq .indicator___YCPxh{cursor:pointer}.moreOption___1NGcC .indicators___1jqCq .indicator___YCPxh:hover{color:var(--primary-color)}.contentName___211iT{max-width:350px;white-space:nowrap;text-overflow:ellipsis}.aggregatorIndicator___2E_41{color:var(--text-color);font-weight:500;font-size:20px}.entityId___1lmAV{display:flex;align-items:center;margin-left:12px;grid-column-gap:4px;-webkit-column-gap:4px;column-gap:4px}.entityId___1lmAV .idTitle___1jx5q{color:var(--text-color-fourth);font-size:12px}.entityId___1lmAV .idValue___bpiF6{color:var(--text-color-fourth);font-size:13px;cursor:pointer}.entityId___1lmAV .idValue___bpiF6:hover{color:var(--primary-color)}.typingBubble___Q0Uqn{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.quote___3zRsl{margin-bottom:4px;padding:0 4px 0 6px;color:var(--border-color-base);font-size:13px;border-left:4px solid var(--border-color-base);border-top-left-radius:2px;border-bottom-left-radius:2px}.filterSection___22RNx{display:flex;align-items:center;color:var(--text-color-secondary);font-weight:400;font-size:13px}.filterSection___22RNx .filterItem___2-VW0{padding:2px 12px;color:var(--text-color-secondary);background-color:#edf2f2;border-radius:13px}.noPermissionTip___3KH3I{display:flex;align-items:center}.tip___CcPGG{margin-left:6px;color:var(--text-color-third)}.infoBar___2hqGy{display:flex;flex-wrap:wrap;align-items:center;margin-top:20px;grid-column-gap:20px;-webkit-column-gap:20px;column-gap:20px}.mainEntityInfo___7_pqq{display:flex;flex-wrap:wrap;align-items:center;font-size:13px;grid-column-gap:20px;-webkit-column-gap:20px;column-gap:20px}.mainEntityInfo___7_pqq .infoItem___2NwSz{display:flex;align-items:center}.mainEntityInfo___7_pqq .infoItem___2NwSz .infoName___3W7On{color:var(--text-color-fourth)}.mainEntityInfo___7_pqq .infoItem___2NwSz .infoValue___3egki{color:var(--text-color-secondary)}.textWrapper___H89lc{display:flex;align-items:center}.textWrapper___H89lc.rightTextWrapper___yPncY{justify-content:flex-end}.textWrapper___H89lc .rightAvatar___E5la8{margin-left:6px}.chat___2o_TX{height:calc(100vh - 48px)!important;overflow:hidden;background:linear-gradient(180deg,rgba(23,74,228,0) 29.44%,rgba(23,74,228,.06)),linear-gradient(90deg,#f3f3f7,#f3f3f7 20%,#ebf0f9 60%,#f3f3f7 80%,#f3f3f7)}.chat___2o_TX .chatSection___3V3NJ{display:flex;width:100vw!important;height:calc(100vh - 48px)!important;overflow:hidden}.chat___2o_TX .chatApp___16BaS{display:flex;flex-direction:column;width:calc(100vw - 225px);height:calc(100vh - 48px);padding-left:20px;color:rgba(0,0,0,.87)}.chat___2o_TX .chatApp___16BaS .emptyHolder___563Et{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.chat___2o_TX .chatApp___16BaS .navBar___1-YkL{position:relative;z-index:10;display:flex;align-items:center;height:40px;padding:0 10px;background:rgb(243 243 243);border-bottom:1px solid #e4e4e4}.chat___2o_TX .chatApp___16BaS .navBar___1-YkL .conversationNameWrapper___367aO{display:flex;align-items:center}.chat___2o_TX .chatApp___16BaS .navBar___1-YkL .conversationNameWrapper___367aO .conversationName___2BsWh{padding:4px 12px;color:var(--text-color-third)!important;font-size:14px!important;border-radius:4px;cursor:pointer}.chat___2o_TX .chatApp___16BaS .navBar___1-YkL .conversationNameWrapper___367aO .conversationName___2BsWh .editIcon___2Od_L{margin-left:10px;color:var(--text-color-fourth);font-size:14px}.chat___2o_TX .chatApp___16BaS .navBar___1-YkL .conversationNameWrapper___367aO .conversationName___2BsWh:hover{background-color:rgba(0,0,0,.03)}.chat___2o_TX .chatApp___16BaS .navBar___1-YkL .conversationNameWrapper___367aO .divider___n3Yfc{width:1px;height:16px;margin-right:4px;margin-left:12px;background-color:var(--text-color-fourth)}.chat___2o_TX .chatApp___16BaS .navBar___1-YkL .conversationInput___2iw0p{width:300px;color:var(--text-color-third)!important;font-size:14px!important;cursor:default!important}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk{display:flex;flex:1 1;height:100%}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi{display:flex;flex-direction:column;width:100%}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy{position:relative;display:flex;flex:1 1;flex-direction:column;min-height:0;overflow-x:hidden;overflow-y:scroll}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS{display:flex;flex-direction:column;padding:20px 20px 90px 4px;grid-row-gap:10px;row-gap:10px}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf{display:flex;flex-direction:column;grid-row-gap:10px;row-gap:10px}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-table-row{background-color:#fff}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-table-tbody>tr>td{border-bottom:1px solid #f0f0f0;transition:background .2s,border-color .2s}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ss-chat-table-even-row{background-color:#fbfbfb}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-table-wrapper .ant-table-pagination{display:flex;flex-wrap:wrap;justify-content:center;margin:16px 0;grid-row-gap:8px;row-gap:8px}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination .ant-pagination-next,.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination .ant-pagination-prev{display:inline-block;min-width:32px;height:32px;color:rgba(0,0,0,.88);line-height:32px;text-align:center;vertical-align:middle;list-style:none;border-radius:6px;cursor:pointer;transition:all .2s}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination .ant-pagination-next .ant-pagination-item-link,.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination .ant-pagination-prev .ant-pagination-item-link{display:block;width:100%;height:100%;padding:0;font-size:12px;text-align:center;background-color:transparent;border:1px solid transparent;border-radius:6px;outline:none;transition:border .2s}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination-jump-next .ant-pagination-item-link,.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination-jump-prev .ant-pagination-item-link{display:inline-block;min-width:32px;height:32px;color:rgba(0,0,0,.25);line-height:32px;text-align:center;vertical-align:middle;list-style:none;border-radius:6px;cursor:pointer;transition:all .2s}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination-options{display:inline-block;margin-left:16px;vertical-align:middle}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination .ant-pagination-item{display:inline-block;min-width:32px;height:32px;line-height:30px;text-align:center;vertical-align:middle;list-style:none;background-color:transparent;border:1px solid transparent;border-radius:6px;outline:0;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-margin-end:8px;margin-inline-end:8px}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination .ant-pagination-item-active{font-weight:600;background-color:#fff;border-color:var(--primary-color)}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS .messageItem___rC6Pf .ant-pagination{box-sizing:border-box;margin:0;padding:0;color:#606266;font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum","tnum"}.chat___2o_TX .chatApp___16BaS .chatBody___3Qpmk .chatContent___1jNIi .messageContainer___3pMiy .messageList___2A2BS.miniProgramLoading___1Rlat{position:absolute;bottom:10000px;width:100%}.chat___2o_TX.mobile___1qe49{height:100%!important}.chat___2o_TX.mobile___1qe49 .chatSection___3V3NJ{width:100%!important;height:100%!important}.chat___2o_TX.mobile___1qe49 .conversation___2jDz6{height:100%!important}.chat___2o_TX.mobile___1qe49 .chatApp___16BaS{width:calc(100% - 225px)!important;height:100%!important;margin-top:0!important}.mobile___1qe49 .messageList___2A2BS{padding:20px 12px!important}.keyword___1PW1c{color:var(--primary-color)}.messageItem___rC6Pf{margin-top:12px}.messageTime___gu9g5{display:flex;align-items:center;justify-content:center;margin-top:20px;color:#999}.modules___1xbPz{display:flex;align-items:center;height:40px;padding:8px 12px;overflow:hidden;background:#f3f3f3;border-top:1px solid #e4e4e4}.modules___1xbPz .moduleType___3WYlk{width:80px;margin-right:12px}.modules___1xbPz .moduleType___3WYlk .ant-select-selection-item{font-size:13px!important}.modules___1xbPz .moduleType___3WYlk .ant-select-selection-item,.modules___1xbPz .moduleType___3WYlk .ant-select-single:not(.ant-select-customize-input) .ant-select-selector:after{line-height:28px!important}.modules___1xbPz .moduleType___3WYlk .moduleSelect___1DUPs{box-sizing:border-box;width:100%;height:100%;color:rgba(0,0,0,.87);word-break:break-all;border:0;border-radius:20px}.modules___1xbPz .moduleType___3WYlk .moduleSelect___1DUPs .ant-select-selector{height:30px!important;border:1px solid var(--primary-color)!important;border-radius:20px!important}.modules___1xbPz .moduleType___3WYlk .moduleSelect___1DUPs .ant-select-arrow{margin-top:-4px!important}.modules___1xbPz .example___qyX62{margin-right:4px;color:var(--text-color-secondary);font-size:13px}.modules___1xbPz button[ant-click-animating-without-extra-node]:after{border:0;opacity:0;animation:0 1 ease 0 normal none}.modules___1xbPz .iconBtn{color:rgba(0,0,0,.4)!important;background:transparent!important;border:0!important;box-shadow:none!important}.modules___1xbPz .iconBtn .scrollerControlIcon{font-size:12px}.modules___1xbPz .iconBtn:hover{background:rgba(0,0,0,.05)!important}.modules___1xbPz .modulesInner___P640o{display:flex;flex:1 1;overflow-x:scroll;overflow-y:hidden;scroll-behavior:smooth}.modules___1xbPz .modulesInner___P640o::-webkit-scrollbar{display:none}.modules___1xbPz .modulesInner___P640o .moduleItem___2feFt{position:relative;display:flex;align-items:center;margin-left:8px;padding:4px 11px;color:var(--text-color);font-weight:500;font-size:14px;line-height:1.43;white-space:nowrap;background:#fff;border:1px solid #fff;border-radius:20px;cursor:pointer;transition:.15s ease-in-out}.modules___1xbPz .modulesInner___P640o .moduleItem___2feFt:hover{background:rgba(0,0,0,.05);background-clip:padding-box;border-color:rgba(0,0,0,.05)}.modules___1xbPz .modulesInner___P640o .moduleItem___2feFt:first-child{margin-left:0!important}.modules___1xbPz .modulesInner___P640o .moduleItem___2feFt.activeModuleItem___1SjFq{color:var(--primary-color)!important;border-color:var(--primary-color)!important}.modules___1xbPz .modulesInner___P640o .moduleItem___2feFt.cmdItem___3JNP5{font-weight:400;font-size:13px}.optGroupBar___1SdJW{display:flex;align-items:center;justify-content:space-between}.optGroupBar___1SdJW.recentSearchBar___2_mds{padding-top:2px;padding-bottom:5px}.optGroupBar___1SdJW .optGroupTitle___37RjX{color:#333;font-weight:500;font-size:14px}.optGroupBar___1SdJW .recentSearch___22cDn{color:#999;font-weight:400}.optGroupBar___1SdJW .clearSearch___39Pk0{color:#666;font-size:14px;cursor:pointer}.recentSearchOption___56Zak{padding-left:12px!important}.recentSearchOption___56Zak .optionItem___22ifI{display:flex;align-items:center;justify-content:space-between;width:483px}.recentSearchOption___56Zak .optionItem___22ifI .removeRecentMsg___yYKh3{display:none;cursor:pointer}.recentSearchOption___56Zak:hover .removeRecentMsg___yYKh3{display:block}.addConversation___1YYx4{display:flex;align-items:center;margin-left:12px;color:var(--text-color-third);grid-column-gap:4px;-webkit-column-gap:4px;column-gap:4px;cursor:pointer}.addConversation___1YYx4:hover{color:var(--primary-color)}.loadingWords___26Axn{padding:40px 1px}.associateWordsOption___10StO{display:flex;align-items:center;grid-column-gap:10px;-webkit-column-gap:10px;column-gap:10px}.associateWordsOption___10StO .optionContent___1Pc9x{display:flex;align-items:center;min-width:450px;grid-column-gap:10px;-webkit-column-gap:10px;column-gap:10px}.associateWordsOption___10StO .indicatorItem___2Lzo1{min-width:180px}.associateWordsOption___10StO .indicatorItem___2Lzo1 .indicatorLabel___1bkQZ{color:var(--text-color-fourth);font-size:12px}.associateWordsOption___10StO .indicatorItem___2Lzo1 .indicatorValue___2pnTF{margin-left:4px;font-size:13px}.autoCompleteDropdown___wKtOT{width:650px!important;min-width:650px!important;border-radius:10px}.autoCompleteDropdown___wKtOT .ant-select-item{min-height:36px!important;line-height:26px!important}.autoCompleteDropdown___wKtOT .ant-select-item:not(:first-child):hover{background:#f5f5f5!important}.recommendItemTitle___2SKwT{margin-right:14px;padding:4px 12px;background-color:var(--deep-background);border-radius:2px}.refeshQuestions___JlEIo{cursor:pointer}.refeshQuestions___JlEIo .reloadIcon___1X8ml{margin-right:4px}.recommendQuestions___gp_hT{display:flex;align-items:center;justify-content:center;width:54px;height:100%;color:var(--text-color-fourth);font-size:18px;background:hsla(0,0%,100%,.2);cursor:pointer}.recommendQuestions___gp_hT:hover{background:hsla(0,0%,100%,.1)}.currentTool___1xNWw{position:relative;display:flex;align-items:center;justify-content:center;padding:0 24px 0 2px;color:var(--chat-blue);font-weight:500;font-size:16px;background:hsla(0,0%,100%,.2)}.currentTool___1xNWw .removeTool___2WRZr{position:absolute;top:14px;right:6px;color:var(--text-color-fifth);font-size:14px;cursor:pointer}.currentTool___1xNWw .removeTool___2WRZr:hover{color:var(--chat-blue)}.associateOption___3ZTe2{display:flex;align-items:center}.associateOptionAvatar___gUvQm{width:32px;margin-right:10px}.optionContent___1Pc9x{min-width:330px}.optionIndicator___2oWOU{min-width:120px;margin-left:4px;color:var(--text-color-fourth);font-size:12px}.messageLoading___Jehct{margin-top:30px;padding:0 20px}.ss-chat-recommend-options .ant-table-thead .ant-table-cell{padding:8px!important}.ss-chat-recommend-options .ant-table-tbody .ant-table-cell{padding:8px!important;border-bottom:1px solid #f0f0f0}.context___1OCN5{display:flex;flex-direction:column;padding:20px 10px 0;border-top:1px solid #ccc}.context___1OCN5 .title___10GWP{margin-bottom:22px;color:var(--text-color);font-size:16px;line-height:24px}.context___1OCN5 .desc___2-XNh{max-height:350px;margin-top:10px;margin-bottom:10px;overflow-y:auto;color:var(--text-color-third);font-size:13px;line-height:22px}.context___1OCN5 .field___3ejkW{display:flex;flex-wrap:wrap;align-items:center;margin-bottom:10px}.context___1OCN5 .field___3ejkW.columnLayout___2QKpP{flex-direction:column}.context___1OCN5 .field___3ejkW .avatar___1OcVc{margin-right:8px}.context___1OCN5 .filterSection___8VuXR{margin-bottom:12px}.context___1OCN5 .fieldName___dMy48{margin-right:6px;color:var(--text-color);font-weight:500}.context___1OCN5 .fieldValue___1y7ju{max-width:150px;overflow:hidden;color:var(--text-color);white-space:nowrap;text-overflow:ellipsis}.context___1OCN5 .filterValues___R7F2_{display:flex;flex-wrap:wrap;margin-top:10px;font-size:13px;grid-column-gap:4px;-webkit-column-gap:4px;column-gap:4px;grid-row-gap:4px;row-gap:4px}.context___1OCN5 .filterValues___R7F2_ .filterItem___3xOt7{padding:2px 12px;color:var(--text-color-secondary);background-color:var(--body-background);border-radius:13px}.introduction___Vdv6R{display:flex;flex-direction:column;padding:0 10px 4px}.introduction___Vdv6R .title___3aeP6{margin-bottom:22px;color:var(--text-color);font-size:16px;line-height:24px}.introduction___Vdv6R .desc___dHm5v{max-height:350px;margin-top:10px;margin-bottom:10px;overflow-y:auto;color:var(--text-color-third);font-size:13px;line-height:22px}.introduction___Vdv6R .field___2Vyao{display:flex;flex-wrap:wrap;align-items:center;margin-bottom:10px}.introduction___Vdv6R .field___2Vyao.columnLayout___NXrLE{flex-direction:column}.introduction___Vdv6R .field___2Vyao .avatar___1s50O{margin-right:8px}.introduction___Vdv6R .fieldName___2gYEr{margin-right:6px;color:var(--text-color);font-weight:500}.introduction___Vdv6R .fieldValue___3xcNc{color:var(--text-color)}.introduction___Vdv6R .fieldValue___3xcNc.switchField___3C4t3{cursor:pointer}.introduction___Vdv6R .fieldValue___3xcNc.dimensionFieldValue___39Yua{max-width:90px}.introduction___Vdv6R .fieldValue___3xcNc.mainNameFieldValue___OkzeS{max-width:90px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.rightSection___wiZOa{width:225px;height:calc(100vh - 48px);margin-right:12px;padding-bottom:10px;overflow-y:auto}.rightSection___wiZOa .entityInfo___8Dh7w{margin-top:20px}.rightSection___wiZOa .entityInfo___8Dh7w .topInfo___Wm-Z0{margin-bottom:20px;color:var(--text-color-third);font-weight:500;font-size:14px}.domains___2sNnl{margin-top:20px;padding-top:20px;border-top:1px solid #ccc}.domains___2sNnl .titleBar___18_Sr{display:flex;align-items:center;grid-column-gap:4px;-webkit-column-gap:4px;column-gap:4px;margin-bottom:12px}.domains___2sNnl .titleBar___18_Sr .title___vvDMG{padding-left:10px;color:var(--text-color);font-size:16px;line-height:24px}.domains___2sNnl .titleBar___18_Sr .subTitle___3Gezp{font-size:13px;color:var(--text-color-third)}.domains___2sNnl .domainList___2Fuun{display:flex;flex-direction:column}.domains___2sNnl .domainList___2Fuun .domainItem___-Hg_Y{display:flex;align-items:center;padding:4px 10px;font-size:14px;cursor:pointer}.domains___2sNnl .domainList___2Fuun .domainItem___-Hg_Y .loadingIcon___w5OHT{margin-right:6px;color:var(--text-color-fifth);font-size:12px}.domains___2sNnl .domainList___2Fuun .domainItem___-Hg_Y .arrowIcon___1yO5n{margin-right:6px;color:var(--text-color-fifth);font-size:12px}.domains___2sNnl .domainList___2Fuun .domainItem___-Hg_Y .domainIcon___3OrVz{margin-right:6px;color:var(--blue)}.domains___2sNnl .domainList___2Fuun .domainItem___-Hg_Y .domainName___3FZaC{width:150px;overflow:hidden;color:var(--text-color-secondary);white-space:nowrap;text-overflow:ellipsis}.domains___2sNnl .domainList___2Fuun .domainItem___-Hg_Y:hover{background-color:var(--link-hover-bg-color)}.domains___2sNnl .domainList___2Fuun .domainItem___-Hg_Y.activeDomainItem___2i6vy{background-color:var(--link-hover-bg-color)}.conversationHistory___2WtWO{position:absolute;top:0;left:0;z-index:10;display:flex;flex-direction:column;width:100%;height:calc(100vh - 78px);overflow:hidden;background:#f3f3f7;border-right:1px solid var(--border-color-base)}.conversationHistory___2WtWO .header___1iZH9{display:flex;align-items:center;justify-content:space-between;height:50px;padding:0 16px;border-bottom:1px solid #e8e8e8}.conversationHistory___2WtWO .header___1iZH9 .headerTitle___1Yrqd{color:var(--text-color);font-weight:500;font-size:16px}.conversationHistory___2WtWO .header___1iZH9 .headerClose___2UOzu{color:var(--text-color-third);font-size:16px;cursor:pointer}.conversationHistory___2WtWO .header___1iZH9 .headerClose___2UOzu:hover{color:var(--chat-blue)}.conversationHistory___2WtWO .conversationContent___vJ9FX{flex:1 1;overflow:auto}.conversationHistory___2WtWO .conversationContent___vJ9FX .conversationItem___dWcaS{display:flex;flex-direction:column;align-items:flex-start;padding:8px 16px;border-bottom:1px solid var(--border-color-base-bg-5);cursor:pointer;grid-row-gap:2px;row-gap:2px}.conversationHistory___2WtWO .conversationContent___vJ9FX .conversationItem___dWcaS:hover{background:var(--light-blue-background)}.conversationHistory___2WtWO .conversationContent___vJ9FX .conversationItem___dWcaS .conversationName___3nzQA{width:170px;overflow:hidden;color:var(--text-color);font-size:14px;white-space:nowrap;text-overflow:ellipsis}.conversationHistory___2WtWO .conversationContent___vJ9FX .conversationItem___dWcaS .conversationTime___e9w2j{color:var(--text-color-third);font-size:13px}.ant-modal{color:rgba(0,10,36,.85)}.ant-modal-title{color:rgba(0,10,36,.85)}.ant-modal-content{border-radius:4px}.ant-modal-close{color:rgba(0,10,36,.65)}.ant-modal-header{color:rgba(0,10,36,.85);border-radius:4px 4px 0 0}.ant-modal-footer{border-radius:0 0 4px 4px}.ant-modal-confirm-body .ant-modal-confirm-title{color:rgba(0,10,36,.85)}.ant-modal-confirm-body .ant-modal-confirm-content{color:rgba(0,10,36,.85)}.ant-modal-confirm-error .ant-modal-confirm-body>.anticon{color:#ef4872}.ant-modal-confirm-confirm .ant-modal-confirm-body>.anticon,.ant-modal-confirm-warning .ant-modal-confirm-body>.anticon{color:#ffb924}.ant-modal-confirm-info .ant-modal-confirm-body>.anticon{color:#296df3}.ant-modal-confirm-success .ant-modal-confirm-body>.anticon{color:#26c992}.ant-input-affix-wrapper{position:relative;display:inline-block;width:100%;min-width:0;padding:4px 11px;color:rgba(0,10,36,.85);font-size:14px;line-height:1.5715;background-color:#fff;background-image:none;border:1px solid #d9d9d9;border-radius:4px;transition:all .3s;display:inline-flex}.ant-input-affix-wrapper::-webkit-input-placeholder{color:#bfbfbf;-webkit-user-select:none;user-select:none}.ant-input-affix-wrapper:-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-affix-wrapper::-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-affix-wrapper::placeholder{color:#bfbfbf;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-input-affix-wrapper:-ms-input-placeholder{text-overflow:ellipsis}.ant-input-affix-wrapper:placeholder-shown{text-overflow:ellipsis}.ant-input-affix-wrapper:hover{border-color:#4e86f5;border-right-width:1px}.ant-input-rtl .ant-input-affix-wrapper:hover{border-right-width:0;border-left-width:1px!important}.ant-input-affix-wrapper-focused,.ant-input-affix-wrapper:focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-input-rtl .ant-input-affix-wrapper-focused,.ant-input-rtl .ant-input-affix-wrapper:focus{border-right-width:0;border-left-width:1px!important}.ant-input-affix-wrapper-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-affix-wrapper-disabled:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input-affix-wrapper[disabled]{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-affix-wrapper[disabled]:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input-affix-wrapper-borderless,.ant-input-affix-wrapper-borderless-disabled,.ant-input-affix-wrapper-borderless-focused,.ant-input-affix-wrapper-borderless:focus,.ant-input-affix-wrapper-borderless:hover,.ant-input-affix-wrapper-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-input-affix-wrapper{max-width:100%;height:auto;min-height:32px;line-height:1.5715;vertical-align:bottom;transition:all .3s,height 0s}.ant-input-affix-wrapper-lg{padding:6.5px 11px;font-size:16px}.ant-input-affix-wrapper-sm{padding:0 7px}.ant-input-affix-wrapper-rtl{direction:rtl}.ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover{border-color:#4e86f5;border-right-width:1px;z-index:1}.ant-input-rtl .ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover{border-right-width:0;border-left-width:1px!important}.ant-input-search-with-button .ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover{z-index:0}.ant-input-affix-wrapper-focused,.ant-input-affix-wrapper:focus{z-index:1}.ant-input-affix-wrapper-disabled .ant-input[disabled]{background:hsla(0,0%,100%,0)}.ant-input-affix-wrapper>.ant-input{font-size:inherit;border:none;outline:none}.ant-input-affix-wrapper>.ant-input:focus{box-shadow:none!important}.ant-input-affix-wrapper>.ant-input:not(textarea){padding:0}.ant-input-affix-wrapper:before{display:inline-block;width:0;visibility:hidden;content:"\a0"}.ant-input-prefix,.ant-input-suffix{display:flex;flex:none;align-items:center}.ant-input-prefix>:not(:last-child),.ant-input-suffix>:not(:last-child){margin-right:8px}.ant-input-show-count-suffix{color:rgba(0,10,36,.65)}.ant-input-show-count-has-suffix{margin-right:2px}.ant-input-prefix{margin-right:4px}.ant-input-suffix{margin-left:4px}.ant-input-clear-icon,.anticon.ant-input-clear-icon{margin:0;color:rgba(0,0,0,.25);font-size:12px;vertical-align:-1px;cursor:pointer;transition:color .3s}.ant-input-clear-icon:hover,.anticon.ant-input-clear-icon:hover{color:rgba(0,10,36,.65)}.ant-input-clear-icon:active,.anticon.ant-input-clear-icon:active{color:rgba(0,10,36,.85)}.ant-input-clear-icon-hidden,.anticon.ant-input-clear-icon-hidden{visibility:hidden}.ant-input-clear-icon-has-suffix,.anticon.ant-input-clear-icon-has-suffix{margin:0 4px}.ant-input-affix-wrapper.ant-input-affix-wrapper-textarea-with-clear-btn{padding:0}.ant-input-affix-wrapper.ant-input-affix-wrapper-textarea-with-clear-btn .ant-input-clear-icon{position:absolute;top:8px;right:8px;z-index:1}.ant-input-status-error:not(.ant-input-disabled):not(.ant-input-borderless).ant-input,.ant-input-status-error:not(.ant-input-disabled):not(.ant-input-borderless).ant-input:hover{background:#fff;border-color:#ef4872}.ant-input-status-error:not(.ant-input-disabled):not(.ant-input-borderless).ant-input-focused,.ant-input-status-error:not(.ant-input-disabled):not(.ant-input-borderless).ant-input:focus{border-color:#fc7492;box-shadow:0 0 0 2px rgba(239,72,114,.2);border-right-width:1px;outline:0}.ant-input-status-error .ant-input-prefix{color:#ef4872}.ant-input-status-warning:not(.ant-input-disabled):not(.ant-input-borderless).ant-input,.ant-input-status-warning:not(.ant-input-disabled):not(.ant-input-borderless).ant-input:hover{background:#fff;border-color:#ffb924}.ant-input-status-warning:not(.ant-input-disabled):not(.ant-input-borderless).ant-input-focused,.ant-input-status-warning:not(.ant-input-disabled):not(.ant-input-borderless).ant-input:focus{border-color:#ffcc4d;box-shadow:0 0 0 2px rgba(255,185,36,.2);border-right-width:1px;outline:0}.ant-input-status-warning .ant-input-prefix{color:#ffb924}.ant-input-affix-wrapper-status-error:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper,.ant-input-affix-wrapper-status-error:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper:hover{background:#fff;border-color:#ef4872}.ant-input-affix-wrapper-status-error:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper-focused,.ant-input-affix-wrapper-status-error:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper:focus{border-color:#fc7492;box-shadow:0 0 0 2px rgba(239,72,114,.2);border-right-width:1px;outline:0}.ant-input-affix-wrapper-status-error .ant-input-prefix{color:#ef4872}.ant-input-affix-wrapper-status-warning:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper,.ant-input-affix-wrapper-status-warning:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper:hover{background:#fff;border-color:#ffb924}.ant-input-affix-wrapper-status-warning:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper-focused,.ant-input-affix-wrapper-status-warning:not(.ant-input-affix-wrapper-disabled):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper:focus{border-color:#ffcc4d;box-shadow:0 0 0 2px rgba(255,185,36,.2);border-right-width:1px;outline:0}.ant-input-affix-wrapper-status-warning .ant-input-prefix{color:#ffb924}.ant-input-textarea-status-error.ant-input-textarea-has-feedback .ant-input,.ant-input-textarea-status-success.ant-input-textarea-has-feedback .ant-input,.ant-input-textarea-status-validating.ant-input-textarea-has-feedback .ant-input,.ant-input-textarea-status-warning.ant-input-textarea-has-feedback .ant-input{padding-right:24px}.ant-input-group-wrapper-status-error .ant-input-group-addon{color:#ef4872;border-color:#ef4872}.ant-input-group-wrapper-status-warning .ant-input-group-addon{color:#ffb924;border-color:#ffb924}.ant-input{box-sizing:border-box;margin:0;font-variant:tabular-nums;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:inline-block;width:100%;min-width:0;padding:4px 11px;color:rgba(0,10,36,.85);font-size:14px;line-height:1.5715;background-color:#fff;background-image:none;border:1px solid #d9d9d9;border-radius:4px;transition:all .3s}.ant-input::-webkit-input-placeholder{color:#bfbfbf;-webkit-user-select:none;user-select:none}.ant-input:-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input::-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input::placeholder{color:#bfbfbf;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-input:-ms-input-placeholder{text-overflow:ellipsis}.ant-input:placeholder-shown{text-overflow:ellipsis}.ant-input:hover{border-color:#4e86f5;border-right-width:1px}.ant-input-rtl .ant-input:hover{border-right-width:0;border-left-width:1px!important}.ant-input-focused,.ant-input:focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-input-rtl .ant-input-focused,.ant-input-rtl .ant-input:focus{border-right-width:0;border-left-width:1px!important}.ant-input-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-disabled:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input[disabled]{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input[disabled]:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input-borderless,.ant-input-borderless-disabled,.ant-input-borderless-focused,.ant-input-borderless:focus,.ant-input-borderless:hover,.ant-input-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-input{max-width:100%;height:auto;min-height:32px;line-height:1.5715;vertical-align:bottom;transition:all .3s,height 0s}.ant-input-lg{padding:6.5px 11px;font-size:16px}.ant-input-sm{padding:0 7px}.ant-input-rtl{direction:rtl}.ant-input-group{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:table;width:100%;border-collapse:separate;border-spacing:0}.ant-input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.ant-input-group>[class*=col-]{padding-right:8px}.ant-input-group>[class*=col-]:last-child{padding-right:0}.ant-input-group-addon,.ant-input-group-wrap,.ant-input-group>.ant-input{display:table-cell}.ant-input-group-addon:not(:first-child):not(:last-child),.ant-input-group-wrap:not(:first-child):not(:last-child),.ant-input-group>.ant-input:not(:first-child):not(:last-child){border-radius:0}.ant-input-group-addon,.ant-input-group-wrap{width:1px;white-space:nowrap;vertical-align:middle}.ant-input-group-wrap>*{display:block!important}.ant-input-group .ant-input{float:left;width:100%;margin-bottom:0;text-align:inherit}.ant-input-group .ant-input:focus{z-index:1;border-right-width:1px}.ant-input-group .ant-input:hover{z-index:1;border-right-width:1px}.ant-input-search-with-button .ant-input-group .ant-input:hover{z-index:0}.ant-input-group-addon{position:relative;padding:0 11px;color:rgba(0,10,36,.85);font-weight:400;font-size:14px;text-align:center;background-color:#fafafa;border:1px solid #d9d9d9;border-radius:4px;transition:all .3s}.ant-input-group-addon .ant-select{margin:-5px -11px}.ant-input-group-addon .ant-select.ant-select-single:not(.ant-select-customize-input) .ant-select-selector{background-color:inherit;border:1px solid transparent;box-shadow:none}.ant-input-group-addon .ant-select-focused .ant-select-selector,.ant-input-group-addon .ant-select-open .ant-select-selector{color:#296df3}.ant-input-group-addon .ant-cascader-picker{margin:-9px -12px;background-color:transparent}.ant-input-group-addon .ant-cascader-picker .ant-cascader-input{text-align:left;border:0;box-shadow:none}.ant-input-group-addon:first-child,.ant-input-group>.ant-input:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-group-addon:first-child .ant-select .ant-select-selector,.ant-input-group>.ant-input:first-child .ant-select .ant-select-selector{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-group>.ant-input-affix-wrapper:not(:first-child) .ant-input{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-group>.ant-input-affix-wrapper:not(:last-child) .ant-input{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-group-addon:first-child{border-right:0}.ant-input-group-addon:last-child{border-left:0}.ant-input-group-addon:last-child,.ant-input-group>.ant-input:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-group-addon:last-child .ant-select .ant-select-selector,.ant-input-group>.ant-input:last-child .ant-select .ant-select-selector{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-group-lg .ant-input,.ant-input-group-lg>.ant-input-group-addon{padding:6.5px 11px;font-size:16px}.ant-input-group-sm .ant-input,.ant-input-group-sm>.ant-input-group-addon{padding:0 7px}.ant-input-group-lg .ant-select-single .ant-select-selector{height:40px}.ant-input-group-sm .ant-select-single .ant-select-selector{height:24px}.ant-input-group .ant-input-affix-wrapper:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-search .ant-input-group .ant-input-affix-wrapper:not(:last-child){border-top-left-radius:4px;border-bottom-left-radius:4px}.ant-input-group .ant-input-affix-wrapper:not(:first-child),.ant-input-search .ant-input-group .ant-input-affix-wrapper:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-group.ant-input-group-compact{display:block}.ant-input-group.ant-input-group-compact:before{display:table;content:""}.ant-input-group.ant-input-group-compact:after{display:table;clear:both;content:""}.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child){border-right-width:1px}.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child):hover,.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child):hover,.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child):hover{z-index:1}.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child):focus,.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child):focus,.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child):focus{z-index:1}.ant-input-group.ant-input-group-compact>*{display:inline-block;float:none;vertical-align:top;border-radius:0}.ant-input-group.ant-input-group-compact>.ant-input-affix-wrapper,.ant-input-group.ant-input-group-compact>.ant-input-number-affix-wrapper,.ant-input-group.ant-input-group-compact>.ant-picker-range{display:inline-flex}.ant-input-group.ant-input-group-compact>:not(:last-child){margin-right:-1px;border-right-width:1px}.ant-input-group.ant-input-group-compact .ant-input{float:none}.ant-input-group.ant-input-group-compact>.ant-cascader-picker .ant-input,.ant-input-group.ant-input-group-compact>.ant-input-group-wrapper .ant-input,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input,.ant-input-group.ant-input-group-compact>.ant-select>.ant-select-selector{border-right-width:1px;border-radius:0}.ant-input-group.ant-input-group-compact>.ant-cascader-picker .ant-input:hover,.ant-input-group.ant-input-group-compact>.ant-input-group-wrapper .ant-input:hover,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input:hover,.ant-input-group.ant-input-group-compact>.ant-select>.ant-select-selector:hover{z-index:1}.ant-input-group.ant-input-group-compact>.ant-cascader-picker .ant-input:focus,.ant-input-group.ant-input-group-compact>.ant-input-group-wrapper .ant-input:focus,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input:focus,.ant-input-group.ant-input-group-compact>.ant-select>.ant-select-selector:focus{z-index:1}.ant-input-group.ant-input-group-compact>.ant-select-focused{z-index:1}.ant-input-group.ant-input-group-compact>.ant-select>.ant-select-arrow{z-index:1}.ant-input-group.ant-input-group-compact>.ant-cascader-picker:first-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete:first-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-select:first-child>.ant-select-selector,.ant-input-group.ant-input-group-compact>:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}.ant-input-group.ant-input-group-compact>.ant-cascader-picker-focused:last-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-cascader-picker:last-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-select:last-child>.ant-select-selector,.ant-input-group.ant-input-group-compact>:last-child{border-right-width:1px;border-top-right-radius:4px;border-bottom-right-radius:4px}.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input{vertical-align:top}.ant-input-group.ant-input-group-compact .ant-input-group-wrapper+.ant-input-group-wrapper{margin-left:-1px}.ant-input-group.ant-input-group-compact .ant-input-group-wrapper+.ant-input-group-wrapper .ant-input-affix-wrapper{border-radius:0}.ant-input-group.ant-input-group-compact .ant-input-group-wrapper:not(:last-child).ant-input-search>.ant-input-group>.ant-input-group-addon>.ant-input-search-button{border-radius:0}.ant-input-group.ant-input-group-compact .ant-input-group-wrapper:not(:last-child).ant-input-search>.ant-input-group>.ant-input{border-radius:4px 0 0 4px}.ant-input-group-rtl .ant-input-group-addon:first-child,.ant-input-group>.ant-input-rtl:first-child{border-radius:0 4px 4px 0}.ant-input-group-rtl .ant-input-group-addon:first-child{border-right:1px solid #d9d9d9;border-left:0}.ant-input-group-rtl .ant-input-group-addon:last-child{border-right:0;border-left:1px solid #d9d9d9;border-radius:4px 0 0 4px}.ant-input-group-rtl.ant-input-group-addon:last-child,.ant-input-group-rtl.ant-input-group>.ant-input:last-child{border-radius:4px 0 0 4px}.ant-input-group-rtl.ant-input-group .ant-input-affix-wrapper:not(:first-child){border-radius:4px 0 0 4px}.ant-input-group-rtl.ant-input-group .ant-input-affix-wrapper:not(:last-child){border-radius:0 4px 4px 0}.ant-input-group-rtl.ant-input-group.ant-input-group-compact>:not(:last-child){margin-right:0;margin-left:-1px;border-left-width:1px}.ant-input-group-rtl.ant-input-group.ant-input-group-compact>.ant-cascader-picker:first-child .ant-input,.ant-input-group-rtl.ant-input-group.ant-input-group-compact>.ant-select-auto-complete:first-child .ant-input,.ant-input-group-rtl.ant-input-group.ant-input-group-compact>.ant-select:first-child>.ant-select-selector,.ant-input-group-rtl.ant-input-group.ant-input-group-compact>:first-child{border-radius:0 4px 4px 0}.ant-input-group-rtl.ant-input-group.ant-input-group-compact>.ant-cascader-picker-focused:last-child .ant-input,.ant-input-group-rtl.ant-input-group.ant-input-group-compact>.ant-cascader-picker:last-child .ant-input,.ant-input-group-rtl.ant-input-group.ant-input-group-compact>.ant-select-auto-complete:last-child .ant-input,.ant-input-group-rtl.ant-input-group.ant-input-group-compact>.ant-select:last-child>.ant-select-selector,.ant-input-group-rtl.ant-input-group.ant-input-group-compact>:last-child{border-left-width:1px;border-radius:4px 0 0 4px}.ant-input-group.ant-input-group-compact .ant-input-group-wrapper-rtl+.ant-input-group-wrapper-rtl{margin-right:-1px;margin-left:0}.ant-input-group.ant-input-group-compact .ant-input-group-wrapper-rtl:not(:last-child).ant-input-search>.ant-input-group>.ant-input{border-radius:0 4px 4px 0}.ant-input-group-wrapper{display:inline-block;width:100%;text-align:start;vertical-align:top}.ant-input-password-icon.anticon{color:rgba(0,10,36,.65);cursor:pointer;transition:all .3s}.ant-input-password-icon.anticon:hover{color:rgba(0,0,0,.85)}.ant-input[type=color]{height:32px}.ant-input[type=color].ant-input-lg{height:40px}.ant-input[type=color].ant-input-sm{height:24px;padding-top:3px;padding-bottom:3px}.ant-input-textarea-show-count>.ant-input{height:100%}.ant-input-textarea-show-count:after{float:right;color:rgba(0,10,36,.65);white-space:nowrap;content:attr(data-count);pointer-events:none}.ant-input-textarea-show-count.ant-input-textarea-in-form-item:after{margin-bottom:-22px}.ant-input-textarea-suffix{position:absolute;top:0;right:11px;bottom:0;z-index:1;display:inline-flex;align-items:center;margin:auto}.ant-input-compact-item:not(.ant-input-compact-last-item):not(.ant-input-compact-item-rtl){margin-right:-1px}.ant-input-compact-item:not(.ant-input-compact-last-item).ant-input-compact-item-rtl{margin-left:-1px}.ant-input-compact-item:active,.ant-input-compact-item:focus,.ant-input-compact-item:hover{z-index:2}.ant-input-compact-item[disabled]{z-index:0}.ant-input-compact-item:not(.ant-input-compact-first-item):not(.ant-input-compact-last-item).ant-input{border-radius:0}.ant-input-compact-item.ant-input.ant-input-compact-first-item:not(.ant-input-compact-last-item):not(.ant-input-compact-item-rtl){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-compact-item.ant-input.ant-input-compact-last-item:not(.ant-input-compact-first-item):not(.ant-input-compact-item-rtl){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-compact-item.ant-input.ant-input-compact-item-rtl.ant-input-compact-first-item:not(.ant-input-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-compact-item.ant-input.ant-input-compact-item-rtl.ant-input-compact-last-item:not(.ant-input-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-search .ant-input:focus,.ant-input-search .ant-input:hover{border-color:#4e86f5}.ant-input-search .ant-input:focus+.ant-input-group-addon .ant-input-search-button:not(.ant-btn-primary),.ant-input-search .ant-input:hover+.ant-input-group-addon .ant-input-search-button:not(.ant-btn-primary){border-left-color:#4e86f5}.ant-input-search .ant-input-affix-wrapper{border-radius:0}.ant-input-search .ant-input-lg{line-height:1.5713}.ant-input-search>.ant-input-group>.ant-input-group-addon:last-child{left:-1px;padding:0;border:0}.ant-input-search>.ant-input-group>.ant-input-group-addon:last-child .ant-input-search-button{padding-top:0;padding-bottom:0;border-radius:0 4px 4px 0}.ant-input-search>.ant-input-group>.ant-input-group-addon:last-child .ant-input-search-button:not(.ant-btn-primary){color:rgba(0,10,36,.65)}.ant-input-search>.ant-input-group>.ant-input-group-addon:last-child .ant-input-search-button:not(.ant-btn-primary).ant-btn-loading:before{top:0;right:0;bottom:0;left:0}.ant-input-search-button{height:32px}.ant-input-search-button:focus,.ant-input-search-button:hover{z-index:1}.ant-input-search-large .ant-input-search-button{height:40px}.ant-input-search-small .ant-input-search-button{height:24px}.ant-input-search.ant-input-compact-item:not(.ant-input-compact-item-rtl):not(.ant-input-compact-last-item) .ant-input-group-addon .ant-input-search-button{margin-right:-1px;border-radius:0}.ant-input-search.ant-input-compact-item:not(.ant-input-compact-first-item) .ant-input,.ant-input-search.ant-input-compact-item:not(.ant-input-compact-first-item) .ant-input-affix-wrapper{border-radius:0}.ant-input-search.ant-input-compact-item .ant-input-affix-wrapper:active,.ant-input-search.ant-input-compact-item .ant-input-affix-wrapper:focus,.ant-input-search.ant-input-compact-item .ant-input-affix-wrapper:hover,.ant-input-search.ant-input-compact-item>.ant-input-group-addon .ant-input-search-button:active,.ant-input-search.ant-input-compact-item>.ant-input-group-addon .ant-input-search-button:focus,.ant-input-search.ant-input-compact-item>.ant-input-group-addon .ant-input-search-button:hover,.ant-input-search.ant-input-compact-item>.ant-input:active,.ant-input-search.ant-input-compact-item>.ant-input:focus,.ant-input-search.ant-input-compact-item>.ant-input:hover{z-index:2}.ant-input-search.ant-input-compact-item>.ant-input-affix-wrapper-focused{z-index:2}.ant-input-search.ant-input-compact-item-rtl:not(.ant-input-compact-last-item) .ant-input-group-addon:last-child .ant-input-search-button{margin-left:-1px;border-radius:0}.ant-input-group-wrapper-rtl{direction:rtl}.ant-input-group-rtl{direction:rtl}.ant-input-affix-wrapper.ant-input-affix-wrapper-rtl>input.ant-input{border:none;outline:none}.ant-input-affix-wrapper-rtl .ant-input-prefix{margin:0 0 0 4px}.ant-input-affix-wrapper-rtl .ant-input-suffix{margin:0 4px 0 0}.ant-input-textarea-rtl{direction:rtl}.ant-input-textarea-rtl.ant-input-textarea-show-count:after{text-align:left}.ant-input-affix-wrapper-rtl .ant-input-clear-icon-has-suffix{margin-right:0;margin-left:4px}.ant-input-affix-wrapper-rtl .ant-input-clear-icon{right:auto;left:8px}.ant-input-search-rtl{direction:rtl}.ant-input-search-rtl .ant-input:focus+.ant-input-group-addon .ant-input-search-button:not(.ant-btn-primary),.ant-input-search-rtl .ant-input:hover+.ant-input-group-addon .ant-input-search-button:not(.ant-btn-primary){border-left-color:#d9d9d9}.ant-input-search-rtl .ant-input:focus+.ant-input-group-addon .ant-input-search-button:not(.ant-btn-primary):hover,.ant-input-search-rtl .ant-input:hover+.ant-input-group-addon .ant-input-search-button:not(.ant-btn-primary):hover{border-left-color:#4e86f5}.ant-input-search-rtl>.ant-input-group>.ant-input-affix-wrapper-focused,.ant-input-search-rtl>.ant-input-group>.ant-input-affix-wrapper:hover{border-right-color:#4e86f5}.ant-input-search-rtl>.ant-input-group>.ant-input-group-addon:last-child{right:-1px;left:auto}.ant-input-search-rtl>.ant-input-group>.ant-input-group-addon:last-child .ant-input-search-button{border-radius:4px 0 0 4px}@media (-ms-high-contrast:none),screen and (-ms-high-contrast:active){.ant-input{height:32px}.ant-input-lg{height:40px}.ant-input-sm{height:24px}.ant-input-affix-wrapper>input.ant-input{height:auto}}.ant-form-item .ant-input-number+.ant-form-text{margin-left:8px}.ant-form-inline{display:flex;flex-wrap:wrap}.ant-form-inline .ant-form-item{flex:none;flex-wrap:nowrap;margin-right:16px;margin-bottom:0}.ant-form-inline .ant-form-item-with-help{margin-bottom:24px}.ant-form-inline .ant-form-item>.ant-form-item-control,.ant-form-inline .ant-form-item>.ant-form-item-label{display:inline-block;vertical-align:top}.ant-form-inline .ant-form-item>.ant-form-item-label{flex:none}.ant-form-inline .ant-form-item .ant-form-text{display:inline-block}.ant-form-inline .ant-form-item .ant-form-item-has-feedback{display:inline-block}.ant-form-horizontal .ant-form-item-label{flex-grow:0}.ant-form-horizontal .ant-form-item-control{flex:1 1;min-width:0}.ant-form-horizontal .ant-form-item-label[class$="-24"]+.ant-form-item-control,.ant-form-horizontal .ant-form-item-label[class*="-24 "]+.ant-form-item-control{min-width:unset}.ant-form-vertical .ant-form-item-row{flex-direction:column}.ant-form-vertical .ant-form-item-label>label{height:auto}.ant-form-vertical .ant-form-item .ant-form-item-control{width:100%}.ant-col-24.ant-form-item-label,.ant-col-xl-24.ant-form-item-label,.ant-form-vertical .ant-form-item-label{padding:0 0 8px;line-height:1.5715;white-space:normal;text-align:left}.ant-col-24.ant-form-item-label>label,.ant-col-xl-24.ant-form-item-label>label,.ant-form-vertical .ant-form-item-label>label{margin:0}.ant-col-24.ant-form-item-label>label:after,.ant-col-xl-24.ant-form-item-label>label:after,.ant-form-vertical .ant-form-item-label>label:after{display:none}.ant-form-rtl.ant-col-24.ant-form-item-label,.ant-form-rtl.ant-col-xl-24.ant-form-item-label,.ant-form-rtl.ant-form-vertical .ant-form-item-label{text-align:right}@media (max-width:575px){.ant-form-item .ant-form-item-label{padding:0 0 8px;line-height:1.5715;white-space:normal;text-align:left}.ant-form-item .ant-form-item-label>label{margin:0}.ant-form-item .ant-form-item-label>label:after{display:none}.ant-form-rtl.ant-form-item .ant-form-item-label{text-align:right}.ant-form .ant-form-item{flex-wrap:wrap}.ant-form .ant-form-item .ant-form-item-control,.ant-form .ant-form-item .ant-form-item-label{flex:0 0 100%;max-width:100%}.ant-col-xs-24.ant-form-item-label{padding:0 0 8px;line-height:1.5715;white-space:normal;text-align:left}.ant-col-xs-24.ant-form-item-label>label{margin:0}.ant-col-xs-24.ant-form-item-label>label:after{display:none}.ant-form-rtl.ant-col-xs-24.ant-form-item-label{text-align:right}}@media (max-width:767px){.ant-col-sm-24.ant-form-item-label{padding:0 0 8px;line-height:1.5715;white-space:normal;text-align:left}.ant-col-sm-24.ant-form-item-label>label{margin:0}.ant-col-sm-24.ant-form-item-label>label:after{display:none}.ant-form-rtl.ant-col-sm-24.ant-form-item-label{text-align:right}}@media (max-width:991px){.ant-col-md-24.ant-form-item-label{padding:0 0 8px;line-height:1.5715;white-space:normal;text-align:left}.ant-col-md-24.ant-form-item-label>label{margin:0}.ant-col-md-24.ant-form-item-label>label:after{display:none}.ant-form-rtl.ant-col-md-24.ant-form-item-label{text-align:right}}@media (max-width:1199px){.ant-col-lg-24.ant-form-item-label{padding:0 0 8px;line-height:1.5715;white-space:normal;text-align:left}.ant-col-lg-24.ant-form-item-label>label{margin:0}.ant-col-lg-24.ant-form-item-label>label:after{display:none}.ant-form-rtl.ant-col-lg-24.ant-form-item-label{text-align:right}}@media (max-width:1599px){.ant-col-xl-24.ant-form-item-label{padding:0 0 8px;line-height:1.5715;white-space:normal;text-align:left}.ant-col-xl-24.ant-form-item-label>label{margin:0}.ant-col-xl-24.ant-form-item-label>label:after{display:none}.ant-form-rtl.ant-col-xl-24.ant-form-item-label{text-align:right}}.ant-form-item-explain-error{color:#ef4872}.ant-form-item-explain-warning{color:#ffb924}.ant-form-item-has-feedback .ant-switch{margin:2px 0 4px}.ant-form-item-has-warning .ant-form-item-split{color:#ffb924}.ant-form-item-has-error .ant-form-item-split{color:#ef4872}.ant-form{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum"}.ant-form legend{display:block;width:100%;margin-bottom:20px;padding:0;color:rgba(0,10,36,.65);font-size:16px;line-height:inherit;border:0;border-bottom:1px solid #d9d9d9}.ant-form label{font-size:14px}.ant-form input[type=search]{box-sizing:border-box}.ant-form input[type=checkbox],.ant-form input[type=radio]{line-height:normal}.ant-form input[type=file]{display:block}.ant-form input[type=range]{display:block;width:100%}.ant-form select[multiple],.ant-form select[size]{height:auto}.ant-form input[type=checkbox]:focus,.ant-form input[type=file]:focus,.ant-form input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.ant-form output{display:block;padding-top:15px;color:rgba(0,10,36,.85);font-size:14px;line-height:1.5715}.ant-form .ant-form-text{display:inline-block;padding-right:8px}.ant-form-small .ant-form-item-label>label{height:24px}.ant-form-small .ant-form-item-control-input{min-height:24px}.ant-form-large .ant-form-item-label>label{height:40px}.ant-form-large .ant-form-item-control-input{min-height:40px}.ant-form-item{box-sizing:border-box;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";margin:0 0 24px;vertical-align:top}.ant-form-item-with-help{transition:none}.ant-form-item-hidden,.ant-form-item-hidden.ant-row{display:none}.ant-form-item-label{display:inline-block;flex-grow:0;overflow:hidden;white-space:nowrap;text-align:right;vertical-align:middle}.ant-form-item-label-left{text-align:left}.ant-form-item-label-wrap{overflow:unset;line-height:1.3215em;white-space:unset}.ant-form-item-label>label{position:relative;display:inline-flex;align-items:center;max-width:100%;height:32px;color:rgba(0,10,36,.85);font-size:14px}.ant-form-item-label>label>.anticon{font-size:14px;vertical-align:top}.ant-form-item-label>label.ant-form-item-required:not(.ant-form-item-required-mark-optional):before{display:inline-block;margin-right:4px;color:#ef4872;font-size:14px;font-family:SimSun,sans-serif;line-height:1;content:"*"}.ant-form-hide-required-mark .ant-form-item-label>label.ant-form-item-required:not(.ant-form-item-required-mark-optional):before{display:none}.ant-form-item-label>label .ant-form-item-optional{display:inline-block;margin-left:4px;color:rgba(0,10,36,.65)}.ant-form-hide-required-mark .ant-form-item-label>label .ant-form-item-optional{display:none}.ant-form-item-label>label .ant-form-item-tooltip{color:rgba(0,10,36,.65);cursor:help;-webkit-writing-mode:horizontal-tb;-ms-writing-mode:lr-tb;writing-mode:horizontal-tb;-webkit-margin-start:4px;margin-inline-start:4px}.ant-form-item-label>label:after{content:":";position:relative;top:-.5px;margin:0 8px 0 2px}.ant-form-item-label>label.ant-form-item-no-colon:after{content:" "}.ant-form-item-control{display:flex;flex-direction:column;flex-grow:1}.ant-form-item-control:first-child:not([class^=ant-col-]):not([class*=" ant-col-"]){width:100%}.ant-form-item-control-input{position:relative;display:flex;align-items:center;min-height:32px}.ant-form-item-control-input-content{flex:auto;max-width:100%}.ant-form-item-explain,.ant-form-item-extra{clear:both;color:rgba(0,10,36,.65);font-size:14px;line-height:1.5715;transition:color .3s cubic-bezier(.215,.61,.355,1);padding-top:0}.ant-form-item-explain-connected{width:100%}.ant-form-item-extra{min-height:24px}.ant-form-item-with-help .ant-form-item-explain{height:auto;opacity:1}.ant-form-item-feedback-icon{font-size:14px;text-align:center;visibility:visible;animation:zoomIn .3s cubic-bezier(.12,.4,.29,1.46);pointer-events:none}.ant-form-item-feedback-icon-success{color:#26c992}.ant-form-item-feedback-icon-error{color:#ef4872}.ant-form-item-feedback-icon-warning{color:#ffb924}.ant-form-item-feedback-icon-validating{color:#296df3}.ant-show-help{transition:opacity .3s cubic-bezier(.645,.045,.355,1)}.ant-show-help-appear,.ant-show-help-enter{opacity:0}.ant-show-help-appear-active,.ant-show-help-enter-active{opacity:1}.ant-show-help-leave{opacity:1}.ant-show-help-leave-active{opacity:0}.ant-show-help-item{overflow:hidden;transition:height .3s cubic-bezier(.645,.045,.355,1),opacity .3s cubic-bezier(.645,.045,.355,1),transform .3s cubic-bezier(.645,.045,.355,1)!important}.ant-show-help-item-appear,.ant-show-help-item-enter{transform:translateY(-5px);opacity:0}.ant-show-help-item-appear-active,.ant-show-help-item-enter-active{transform:translateY(0);opacity:1}.ant-show-help-item-leave{transition:height .2s cubic-bezier(.645,.045,.355,1),opacity .2s cubic-bezier(.645,.045,.355,1),transform .2s cubic-bezier(.645,.045,.355,1)!important}.ant-show-help-item-leave-active{transform:translateY(-5px)}@keyframes diffZoomIn1{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes diffZoomIn2{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes diffZoomIn3{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}.ant-form-rtl{direction:rtl}.ant-form-rtl .ant-form-item-label{text-align:left}.ant-form-rtl .ant-form-item-label>label.ant-form-item-required:before{margin-right:0;margin-left:4px}.ant-form-rtl .ant-form-item-label>label:after{margin:0 2px 0 8px}.ant-form-rtl .ant-form-item-label>label .ant-form-item-optional{margin-right:4px;margin-left:0}.ant-col-rtl .ant-form-item-control:first-child{width:100%}.ant-form-rtl .ant-form-item-has-feedback .ant-input{padding-right:11px;padding-left:24px}.ant-form-rtl .ant-form-item-has-feedback .ant-input-affix-wrapper .ant-input-suffix{padding-right:11px;padding-left:18px}.ant-form-rtl .ant-form-item-has-feedback .ant-input-affix-wrapper .ant-input{padding:0}.ant-form-rtl .ant-form-item-has-feedback .ant-input-number-affix-wrapper .ant-input-number{padding:0}.ant-form-rtl .ant-form-item-has-feedback .ant-input-search:not(.ant-input-search-enter-button) .ant-input-suffix{right:auto;left:28px}.ant-form-rtl .ant-form-item-has-feedback .ant-input-number{padding-left:18px}.ant-form-rtl .ant-form-item-has-feedback :not(.ant-input-group-addon)>.ant-select .ant-select-arrow,.ant-form-rtl .ant-form-item-has-feedback :not(.ant-input-group-addon)>.ant-select .ant-select-clear,.ant-form-rtl .ant-form-item-has-feedback :not(.ant-input-number-group-addon)>.ant-select .ant-select-arrow,.ant-form-rtl .ant-form-item-has-feedback :not(.ant-input-number-group-addon)>.ant-select .ant-select-clear,.ant-form-rtl .ant-form-item-has-feedback>.ant-select .ant-select-arrow,.ant-form-rtl .ant-form-item-has-feedback>.ant-select .ant-select-clear{right:auto;left:32px}.ant-form-rtl .ant-form-item-has-feedback :not(.ant-input-group-addon)>.ant-select .ant-select-selection-selected-value,.ant-form-rtl .ant-form-item-has-feedback :not(.ant-input-number-group-addon)>.ant-select .ant-select-selection-selected-value,.ant-form-rtl .ant-form-item-has-feedback>.ant-select .ant-select-selection-selected-value{padding-right:0;padding-left:42px}.ant-form-rtl .ant-form-item-has-feedback .ant-cascader-picker-arrow{margin-right:0;margin-left:19px}.ant-form-rtl .ant-form-item-has-feedback .ant-cascader-picker-clear{right:auto;left:32px}.ant-form-rtl .ant-form-item-has-feedback .ant-picker{padding-right:11px;padding-left:29.2px}.ant-form-rtl .ant-form-item-has-feedback .ant-picker-large{padding-right:11px;padding-left:29.2px}.ant-form-rtl .ant-form-item-has-feedback .ant-picker-small{padding-right:7px;padding-left:25.2px}.ant-form-rtl .ant-form-item-has-feedback.ant-form-item-has-error .ant-form-item-children-icon,.ant-form-rtl .ant-form-item-has-feedback.ant-form-item-has-success .ant-form-item-children-icon,.ant-form-rtl .ant-form-item-has-feedback.ant-form-item-has-warning .ant-form-item-children-icon,.ant-form-rtl .ant-form-item-has-feedback.ant-form-item-is-validating .ant-form-item-children-icon{right:auto;left:0}.ant-form-rtl.ant-form-inline .ant-form-item{margin-right:0;margin-left:16px}.ant-row{display:flex;flex-flow:row wrap;min-width:0}.ant-row:after,.ant-row:before{display:flex}.ant-row-no-wrap{flex-wrap:nowrap}.ant-row-start{justify-content:flex-start}.ant-row-center{justify-content:center}.ant-row-end{justify-content:flex-end}.ant-row-space-between{justify-content:space-between}.ant-row-space-around{justify-content:space-around}.ant-row-space-evenly{justify-content:space-evenly}.ant-row-top{align-items:flex-start}.ant-row-middle{align-items:center}.ant-row-bottom{align-items:flex-end}.ant-col{position:relative;max-width:100%;min-height:1px}.ant-col-24{display:block;flex:0 0 100%;max-width:100%}.ant-col-push-24{left:100%}.ant-col-pull-24{right:100%}.ant-col-offset-24{margin-left:100%}.ant-col-order-24{order:24}.ant-col-23{display:block;flex:0 0 95.83333333%;max-width:95.83333333%}.ant-col-push-23{left:95.83333333%}.ant-col-pull-23{right:95.83333333%}.ant-col-offset-23{margin-left:95.83333333%}.ant-col-order-23{order:23}.ant-col-22{display:block;flex:0 0 91.66666667%;max-width:91.66666667%}.ant-col-push-22{left:91.66666667%}.ant-col-pull-22{right:91.66666667%}.ant-col-offset-22{margin-left:91.66666667%}.ant-col-order-22{order:22}.ant-col-21{display:block;flex:0 0 87.5%;max-width:87.5%}.ant-col-push-21{left:87.5%}.ant-col-pull-21{right:87.5%}.ant-col-offset-21{margin-left:87.5%}.ant-col-order-21{order:21}.ant-col-20{display:block;flex:0 0 83.33333333%;max-width:83.33333333%}.ant-col-push-20{left:83.33333333%}.ant-col-pull-20{right:83.33333333%}.ant-col-offset-20{margin-left:83.33333333%}.ant-col-order-20{order:20}.ant-col-19{display:block;flex:0 0 79.16666667%;max-width:79.16666667%}.ant-col-push-19{left:79.16666667%}.ant-col-pull-19{right:79.16666667%}.ant-col-offset-19{margin-left:79.16666667%}.ant-col-order-19{order:19}.ant-col-18{display:block;flex:0 0 75%;max-width:75%}.ant-col-push-18{left:75%}.ant-col-pull-18{right:75%}.ant-col-offset-18{margin-left:75%}.ant-col-order-18{order:18}.ant-col-17{display:block;flex:0 0 70.83333333%;max-width:70.83333333%}.ant-col-push-17{left:70.83333333%}.ant-col-pull-17{right:70.83333333%}.ant-col-offset-17{margin-left:70.83333333%}.ant-col-order-17{order:17}.ant-col-16{display:block;flex:0 0 66.66666667%;max-width:66.66666667%}.ant-col-push-16{left:66.66666667%}.ant-col-pull-16{right:66.66666667%}.ant-col-offset-16{margin-left:66.66666667%}.ant-col-order-16{order:16}.ant-col-15{display:block;flex:0 0 62.5%;max-width:62.5%}.ant-col-push-15{left:62.5%}.ant-col-pull-15{right:62.5%}.ant-col-offset-15{margin-left:62.5%}.ant-col-order-15{order:15}.ant-col-14{display:block;flex:0 0 58.33333333%;max-width:58.33333333%}.ant-col-push-14{left:58.33333333%}.ant-col-pull-14{right:58.33333333%}.ant-col-offset-14{margin-left:58.33333333%}.ant-col-order-14{order:14}.ant-col-13{display:block;flex:0 0 54.16666667%;max-width:54.16666667%}.ant-col-push-13{left:54.16666667%}.ant-col-pull-13{right:54.16666667%}.ant-col-offset-13{margin-left:54.16666667%}.ant-col-order-13{order:13}.ant-col-12{display:block;flex:0 0 50%;max-width:50%}.ant-col-push-12{left:50%}.ant-col-pull-12{right:50%}.ant-col-offset-12{margin-left:50%}.ant-col-order-12{order:12}.ant-col-11{display:block;flex:0 0 45.83333333%;max-width:45.83333333%}.ant-col-push-11{left:45.83333333%}.ant-col-pull-11{right:45.83333333%}.ant-col-offset-11{margin-left:45.83333333%}.ant-col-order-11{order:11}.ant-col-10{display:block;flex:0 0 41.66666667%;max-width:41.66666667%}.ant-col-push-10{left:41.66666667%}.ant-col-pull-10{right:41.66666667%}.ant-col-offset-10{margin-left:41.66666667%}.ant-col-order-10{order:10}.ant-col-9{display:block;flex:0 0 37.5%;max-width:37.5%}.ant-col-push-9{left:37.5%}.ant-col-pull-9{right:37.5%}.ant-col-offset-9{margin-left:37.5%}.ant-col-order-9{order:9}.ant-col-8{display:block;flex:0 0 33.33333333%;max-width:33.33333333%}.ant-col-push-8{left:33.33333333%}.ant-col-pull-8{right:33.33333333%}.ant-col-offset-8{margin-left:33.33333333%}.ant-col-order-8{order:8}.ant-col-7{display:block;flex:0 0 29.16666667%;max-width:29.16666667%}.ant-col-push-7{left:29.16666667%}.ant-col-pull-7{right:29.16666667%}.ant-col-offset-7{margin-left:29.16666667%}.ant-col-order-7{order:7}.ant-col-6{display:block;flex:0 0 25%;max-width:25%}.ant-col-push-6{left:25%}.ant-col-pull-6{right:25%}.ant-col-offset-6{margin-left:25%}.ant-col-order-6{order:6}.ant-col-5{display:block;flex:0 0 20.83333333%;max-width:20.83333333%}.ant-col-push-5{left:20.83333333%}.ant-col-pull-5{right:20.83333333%}.ant-col-offset-5{margin-left:20.83333333%}.ant-col-order-5{order:5}.ant-col-4{display:block;flex:0 0 16.66666667%;max-width:16.66666667%}.ant-col-push-4{left:16.66666667%}.ant-col-pull-4{right:16.66666667%}.ant-col-offset-4{margin-left:16.66666667%}.ant-col-order-4{order:4}.ant-col-3{display:block;flex:0 0 12.5%;max-width:12.5%}.ant-col-push-3{left:12.5%}.ant-col-pull-3{right:12.5%}.ant-col-offset-3{margin-left:12.5%}.ant-col-order-3{order:3}.ant-col-2{display:block;flex:0 0 8.33333333%;max-width:8.33333333%}.ant-col-push-2{left:8.33333333%}.ant-col-pull-2{right:8.33333333%}.ant-col-offset-2{margin-left:8.33333333%}.ant-col-order-2{order:2}.ant-col-1{display:block;flex:0 0 4.16666667%;max-width:4.16666667%}.ant-col-push-1{left:4.16666667%}.ant-col-pull-1{right:4.16666667%}.ant-col-offset-1{margin-left:4.16666667%}.ant-col-order-1{order:1}.ant-col-0{display:none}.ant-col-offset-0{margin-left:0}.ant-col-order-0{order:0}.ant-col-offset-0.ant-col-rtl{margin-right:0}.ant-col-push-1.ant-col-rtl{right:4.16666667%;left:auto}.ant-col-pull-1.ant-col-rtl{right:auto;left:4.16666667%}.ant-col-offset-1.ant-col-rtl{margin-right:4.16666667%;margin-left:0}.ant-col-push-2.ant-col-rtl{right:8.33333333%;left:auto}.ant-col-pull-2.ant-col-rtl{right:auto;left:8.33333333%}.ant-col-offset-2.ant-col-rtl{margin-right:8.33333333%;margin-left:0}.ant-col-push-3.ant-col-rtl{right:12.5%;left:auto}.ant-col-pull-3.ant-col-rtl{right:auto;left:12.5%}.ant-col-offset-3.ant-col-rtl{margin-right:12.5%;margin-left:0}.ant-col-push-4.ant-col-rtl{right:16.66666667%;left:auto}.ant-col-pull-4.ant-col-rtl{right:auto;left:16.66666667%}.ant-col-offset-4.ant-col-rtl{margin-right:16.66666667%;margin-left:0}.ant-col-push-5.ant-col-rtl{right:20.83333333%;left:auto}.ant-col-pull-5.ant-col-rtl{right:auto;left:20.83333333%}.ant-col-offset-5.ant-col-rtl{margin-right:20.83333333%;margin-left:0}.ant-col-push-6.ant-col-rtl{right:25%;left:auto}.ant-col-pull-6.ant-col-rtl{right:auto;left:25%}.ant-col-offset-6.ant-col-rtl{margin-right:25%;margin-left:0}.ant-col-push-7.ant-col-rtl{right:29.16666667%;left:auto}.ant-col-pull-7.ant-col-rtl{right:auto;left:29.16666667%}.ant-col-offset-7.ant-col-rtl{margin-right:29.16666667%;margin-left:0}.ant-col-push-8.ant-col-rtl{right:33.33333333%;left:auto}.ant-col-pull-8.ant-col-rtl{right:auto;left:33.33333333%}.ant-col-offset-8.ant-col-rtl{margin-right:33.33333333%;margin-left:0}.ant-col-push-9.ant-col-rtl{right:37.5%;left:auto}.ant-col-pull-9.ant-col-rtl{right:auto;left:37.5%}.ant-col-offset-9.ant-col-rtl{margin-right:37.5%;margin-left:0}.ant-col-push-10.ant-col-rtl{right:41.66666667%;left:auto}.ant-col-pull-10.ant-col-rtl{right:auto;left:41.66666667%}.ant-col-offset-10.ant-col-rtl{margin-right:41.66666667%;margin-left:0}.ant-col-push-11.ant-col-rtl{right:45.83333333%;left:auto}.ant-col-pull-11.ant-col-rtl{right:auto;left:45.83333333%}.ant-col-offset-11.ant-col-rtl{margin-right:45.83333333%;margin-left:0}.ant-col-push-12.ant-col-rtl{right:50%;left:auto}.ant-col-pull-12.ant-col-rtl{right:auto;left:50%}.ant-col-offset-12.ant-col-rtl{margin-right:50%;margin-left:0}.ant-col-push-13.ant-col-rtl{right:54.16666667%;left:auto}.ant-col-pull-13.ant-col-rtl{right:auto;left:54.16666667%}.ant-col-offset-13.ant-col-rtl{margin-right:54.16666667%;margin-left:0}.ant-col-push-14.ant-col-rtl{right:58.33333333%;left:auto}.ant-col-pull-14.ant-col-rtl{right:auto;left:58.33333333%}.ant-col-offset-14.ant-col-rtl{margin-right:58.33333333%;margin-left:0}.ant-col-push-15.ant-col-rtl{right:62.5%;left:auto}.ant-col-pull-15.ant-col-rtl{right:auto;left:62.5%}.ant-col-offset-15.ant-col-rtl{margin-right:62.5%;margin-left:0}.ant-col-push-16.ant-col-rtl{right:66.66666667%;left:auto}.ant-col-pull-16.ant-col-rtl{right:auto;left:66.66666667%}.ant-col-offset-16.ant-col-rtl{margin-right:66.66666667%;margin-left:0}.ant-col-push-17.ant-col-rtl{right:70.83333333%;left:auto}.ant-col-pull-17.ant-col-rtl{right:auto;left:70.83333333%}.ant-col-offset-17.ant-col-rtl{margin-right:70.83333333%;margin-left:0}.ant-col-push-18.ant-col-rtl{right:75%;left:auto}.ant-col-pull-18.ant-col-rtl{right:auto;left:75%}.ant-col-offset-18.ant-col-rtl{margin-right:75%;margin-left:0}.ant-col-push-19.ant-col-rtl{right:79.16666667%;left:auto}.ant-col-pull-19.ant-col-rtl{right:auto;left:79.16666667%}.ant-col-offset-19.ant-col-rtl{margin-right:79.16666667%;margin-left:0}.ant-col-push-20.ant-col-rtl{right:83.33333333%;left:auto}.ant-col-pull-20.ant-col-rtl{right:auto;left:83.33333333%}.ant-col-offset-20.ant-col-rtl{margin-right:83.33333333%;margin-left:0}.ant-col-push-21.ant-col-rtl{right:87.5%;left:auto}.ant-col-pull-21.ant-col-rtl{right:auto;left:87.5%}.ant-col-offset-21.ant-col-rtl{margin-right:87.5%;margin-left:0}.ant-col-push-22.ant-col-rtl{right:91.66666667%;left:auto}.ant-col-pull-22.ant-col-rtl{right:auto;left:91.66666667%}.ant-col-offset-22.ant-col-rtl{margin-right:91.66666667%;margin-left:0}.ant-col-push-23.ant-col-rtl{right:95.83333333%;left:auto}.ant-col-pull-23.ant-col-rtl{right:auto;left:95.83333333%}.ant-col-offset-23.ant-col-rtl{margin-right:95.83333333%;margin-left:0}.ant-col-push-24.ant-col-rtl{right:100%;left:auto}.ant-col-pull-24.ant-col-rtl{right:auto;left:100%}.ant-col-offset-24.ant-col-rtl{margin-right:100%;margin-left:0}.ant-col-xs-24{display:block;flex:0 0 100%;max-width:100%}.ant-col-xs-push-24{left:100%}.ant-col-xs-pull-24{right:100%}.ant-col-xs-offset-24{margin-left:100%}.ant-col-xs-order-24{order:24}.ant-col-xs-23{display:block;flex:0 0 95.83333333%;max-width:95.83333333%}.ant-col-xs-push-23{left:95.83333333%}.ant-col-xs-pull-23{right:95.83333333%}.ant-col-xs-offset-23{margin-left:95.83333333%}.ant-col-xs-order-23{order:23}.ant-col-xs-22{display:block;flex:0 0 91.66666667%;max-width:91.66666667%}.ant-col-xs-push-22{left:91.66666667%}.ant-col-xs-pull-22{right:91.66666667%}.ant-col-xs-offset-22{margin-left:91.66666667%}.ant-col-xs-order-22{order:22}.ant-col-xs-21{display:block;flex:0 0 87.5%;max-width:87.5%}.ant-col-xs-push-21{left:87.5%}.ant-col-xs-pull-21{right:87.5%}.ant-col-xs-offset-21{margin-left:87.5%}.ant-col-xs-order-21{order:21}.ant-col-xs-20{display:block;flex:0 0 83.33333333%;max-width:83.33333333%}.ant-col-xs-push-20{left:83.33333333%}.ant-col-xs-pull-20{right:83.33333333%}.ant-col-xs-offset-20{margin-left:83.33333333%}.ant-col-xs-order-20{order:20}.ant-col-xs-19{display:block;flex:0 0 79.16666667%;max-width:79.16666667%}.ant-col-xs-push-19{left:79.16666667%}.ant-col-xs-pull-19{right:79.16666667%}.ant-col-xs-offset-19{margin-left:79.16666667%}.ant-col-xs-order-19{order:19}.ant-col-xs-18{display:block;flex:0 0 75%;max-width:75%}.ant-col-xs-push-18{left:75%}.ant-col-xs-pull-18{right:75%}.ant-col-xs-offset-18{margin-left:75%}.ant-col-xs-order-18{order:18}.ant-col-xs-17{display:block;flex:0 0 70.83333333%;max-width:70.83333333%}.ant-col-xs-push-17{left:70.83333333%}.ant-col-xs-pull-17{right:70.83333333%}.ant-col-xs-offset-17{margin-left:70.83333333%}.ant-col-xs-order-17{order:17}.ant-col-xs-16{display:block;flex:0 0 66.66666667%;max-width:66.66666667%}.ant-col-xs-push-16{left:66.66666667%}.ant-col-xs-pull-16{right:66.66666667%}.ant-col-xs-offset-16{margin-left:66.66666667%}.ant-col-xs-order-16{order:16}.ant-col-xs-15{display:block;flex:0 0 62.5%;max-width:62.5%}.ant-col-xs-push-15{left:62.5%}.ant-col-xs-pull-15{right:62.5%}.ant-col-xs-offset-15{margin-left:62.5%}.ant-col-xs-order-15{order:15}.ant-col-xs-14{display:block;flex:0 0 58.33333333%;max-width:58.33333333%}.ant-col-xs-push-14{left:58.33333333%}.ant-col-xs-pull-14{right:58.33333333%}.ant-col-xs-offset-14{margin-left:58.33333333%}.ant-col-xs-order-14{order:14}.ant-col-xs-13{display:block;flex:0 0 54.16666667%;max-width:54.16666667%}.ant-col-xs-push-13{left:54.16666667%}.ant-col-xs-pull-13{right:54.16666667%}.ant-col-xs-offset-13{margin-left:54.16666667%}.ant-col-xs-order-13{order:13}.ant-col-xs-12{display:block;flex:0 0 50%;max-width:50%}.ant-col-xs-push-12{left:50%}.ant-col-xs-pull-12{right:50%}.ant-col-xs-offset-12{margin-left:50%}.ant-col-xs-order-12{order:12}.ant-col-xs-11{display:block;flex:0 0 45.83333333%;max-width:45.83333333%}.ant-col-xs-push-11{left:45.83333333%}.ant-col-xs-pull-11{right:45.83333333%}.ant-col-xs-offset-11{margin-left:45.83333333%}.ant-col-xs-order-11{order:11}.ant-col-xs-10{display:block;flex:0 0 41.66666667%;max-width:41.66666667%}.ant-col-xs-push-10{left:41.66666667%}.ant-col-xs-pull-10{right:41.66666667%}.ant-col-xs-offset-10{margin-left:41.66666667%}.ant-col-xs-order-10{order:10}.ant-col-xs-9{display:block;flex:0 0 37.5%;max-width:37.5%}.ant-col-xs-push-9{left:37.5%}.ant-col-xs-pull-9{right:37.5%}.ant-col-xs-offset-9{margin-left:37.5%}.ant-col-xs-order-9{order:9}.ant-col-xs-8{display:block;flex:0 0 33.33333333%;max-width:33.33333333%}.ant-col-xs-push-8{left:33.33333333%}.ant-col-xs-pull-8{right:33.33333333%}.ant-col-xs-offset-8{margin-left:33.33333333%}.ant-col-xs-order-8{order:8}.ant-col-xs-7{display:block;flex:0 0 29.16666667%;max-width:29.16666667%}.ant-col-xs-push-7{left:29.16666667%}.ant-col-xs-pull-7{right:29.16666667%}.ant-col-xs-offset-7{margin-left:29.16666667%}.ant-col-xs-order-7{order:7}.ant-col-xs-6{display:block;flex:0 0 25%;max-width:25%}.ant-col-xs-push-6{left:25%}.ant-col-xs-pull-6{right:25%}.ant-col-xs-offset-6{margin-left:25%}.ant-col-xs-order-6{order:6}.ant-col-xs-5{display:block;flex:0 0 20.83333333%;max-width:20.83333333%}.ant-col-xs-push-5{left:20.83333333%}.ant-col-xs-pull-5{right:20.83333333%}.ant-col-xs-offset-5{margin-left:20.83333333%}.ant-col-xs-order-5{order:5}.ant-col-xs-4{display:block;flex:0 0 16.66666667%;max-width:16.66666667%}.ant-col-xs-push-4{left:16.66666667%}.ant-col-xs-pull-4{right:16.66666667%}.ant-col-xs-offset-4{margin-left:16.66666667%}.ant-col-xs-order-4{order:4}.ant-col-xs-3{display:block;flex:0 0 12.5%;max-width:12.5%}.ant-col-xs-push-3{left:12.5%}.ant-col-xs-pull-3{right:12.5%}.ant-col-xs-offset-3{margin-left:12.5%}.ant-col-xs-order-3{order:3}.ant-col-xs-2{display:block;flex:0 0 8.33333333%;max-width:8.33333333%}.ant-col-xs-push-2{left:8.33333333%}.ant-col-xs-pull-2{right:8.33333333%}.ant-col-xs-offset-2{margin-left:8.33333333%}.ant-col-xs-order-2{order:2}.ant-col-xs-1{display:block;flex:0 0 4.16666667%;max-width:4.16666667%}.ant-col-xs-push-1{left:4.16666667%}.ant-col-xs-pull-1{right:4.16666667%}.ant-col-xs-offset-1{margin-left:4.16666667%}.ant-col-xs-order-1{order:1}.ant-col-xs-0{display:none}.ant-col-push-0{left:auto}.ant-col-pull-0{right:auto}.ant-col-xs-push-0{left:auto}.ant-col-xs-pull-0{right:auto}.ant-col-xs-offset-0{margin-left:0}.ant-col-xs-order-0{order:0}.ant-col-push-0.ant-col-rtl{right:auto}.ant-col-pull-0.ant-col-rtl{left:auto}.ant-col-xs-push-0.ant-col-rtl{right:auto}.ant-col-xs-pull-0.ant-col-rtl{left:auto}.ant-col-xs-offset-0.ant-col-rtl{margin-right:0}.ant-col-xs-push-1.ant-col-rtl{right:4.16666667%;left:auto}.ant-col-xs-pull-1.ant-col-rtl{right:auto;left:4.16666667%}.ant-col-xs-offset-1.ant-col-rtl{margin-right:4.16666667%;margin-left:0}.ant-col-xs-push-2.ant-col-rtl{right:8.33333333%;left:auto}.ant-col-xs-pull-2.ant-col-rtl{right:auto;left:8.33333333%}.ant-col-xs-offset-2.ant-col-rtl{margin-right:8.33333333%;margin-left:0}.ant-col-xs-push-3.ant-col-rtl{right:12.5%;left:auto}.ant-col-xs-pull-3.ant-col-rtl{right:auto;left:12.5%}.ant-col-xs-offset-3.ant-col-rtl{margin-right:12.5%;margin-left:0}.ant-col-xs-push-4.ant-col-rtl{right:16.66666667%;left:auto}.ant-col-xs-pull-4.ant-col-rtl{right:auto;left:16.66666667%}.ant-col-xs-offset-4.ant-col-rtl{margin-right:16.66666667%;margin-left:0}.ant-col-xs-push-5.ant-col-rtl{right:20.83333333%;left:auto}.ant-col-xs-pull-5.ant-col-rtl{right:auto;left:20.83333333%}.ant-col-xs-offset-5.ant-col-rtl{margin-right:20.83333333%;margin-left:0}.ant-col-xs-push-6.ant-col-rtl{right:25%;left:auto}.ant-col-xs-pull-6.ant-col-rtl{right:auto;left:25%}.ant-col-xs-offset-6.ant-col-rtl{margin-right:25%;margin-left:0}.ant-col-xs-push-7.ant-col-rtl{right:29.16666667%;left:auto}.ant-col-xs-pull-7.ant-col-rtl{right:auto;left:29.16666667%}.ant-col-xs-offset-7.ant-col-rtl{margin-right:29.16666667%;margin-left:0}.ant-col-xs-push-8.ant-col-rtl{right:33.33333333%;left:auto}.ant-col-xs-pull-8.ant-col-rtl{right:auto;left:33.33333333%}.ant-col-xs-offset-8.ant-col-rtl{margin-right:33.33333333%;margin-left:0}.ant-col-xs-push-9.ant-col-rtl{right:37.5%;left:auto}.ant-col-xs-pull-9.ant-col-rtl{right:auto;left:37.5%}.ant-col-xs-offset-9.ant-col-rtl{margin-right:37.5%;margin-left:0}.ant-col-xs-push-10.ant-col-rtl{right:41.66666667%;left:auto}.ant-col-xs-pull-10.ant-col-rtl{right:auto;left:41.66666667%}.ant-col-xs-offset-10.ant-col-rtl{margin-right:41.66666667%;margin-left:0}.ant-col-xs-push-11.ant-col-rtl{right:45.83333333%;left:auto}.ant-col-xs-pull-11.ant-col-rtl{right:auto;left:45.83333333%}.ant-col-xs-offset-11.ant-col-rtl{margin-right:45.83333333%;margin-left:0}.ant-col-xs-push-12.ant-col-rtl{right:50%;left:auto}.ant-col-xs-pull-12.ant-col-rtl{right:auto;left:50%}.ant-col-xs-offset-12.ant-col-rtl{margin-right:50%;margin-left:0}.ant-col-xs-push-13.ant-col-rtl{right:54.16666667%;left:auto}.ant-col-xs-pull-13.ant-col-rtl{right:auto;left:54.16666667%}.ant-col-xs-offset-13.ant-col-rtl{margin-right:54.16666667%;margin-left:0}.ant-col-xs-push-14.ant-col-rtl{right:58.33333333%;left:auto}.ant-col-xs-pull-14.ant-col-rtl{right:auto;left:58.33333333%}.ant-col-xs-offset-14.ant-col-rtl{margin-right:58.33333333%;margin-left:0}.ant-col-xs-push-15.ant-col-rtl{right:62.5%;left:auto}.ant-col-xs-pull-15.ant-col-rtl{right:auto;left:62.5%}.ant-col-xs-offset-15.ant-col-rtl{margin-right:62.5%;margin-left:0}.ant-col-xs-push-16.ant-col-rtl{right:66.66666667%;left:auto}.ant-col-xs-pull-16.ant-col-rtl{right:auto;left:66.66666667%}.ant-col-xs-offset-16.ant-col-rtl{margin-right:66.66666667%;margin-left:0}.ant-col-xs-push-17.ant-col-rtl{right:70.83333333%;left:auto}.ant-col-xs-pull-17.ant-col-rtl{right:auto;left:70.83333333%}.ant-col-xs-offset-17.ant-col-rtl{margin-right:70.83333333%;margin-left:0}.ant-col-xs-push-18.ant-col-rtl{right:75%;left:auto}.ant-col-xs-pull-18.ant-col-rtl{right:auto;left:75%}.ant-col-xs-offset-18.ant-col-rtl{margin-right:75%;margin-left:0}.ant-col-xs-push-19.ant-col-rtl{right:79.16666667%;left:auto}.ant-col-xs-pull-19.ant-col-rtl{right:auto;left:79.16666667%}.ant-col-xs-offset-19.ant-col-rtl{margin-right:79.16666667%;margin-left:0}.ant-col-xs-push-20.ant-col-rtl{right:83.33333333%;left:auto}.ant-col-xs-pull-20.ant-col-rtl{right:auto;left:83.33333333%}.ant-col-xs-offset-20.ant-col-rtl{margin-right:83.33333333%;margin-left:0}.ant-col-xs-push-21.ant-col-rtl{right:87.5%;left:auto}.ant-col-xs-pull-21.ant-col-rtl{right:auto;left:87.5%}.ant-col-xs-offset-21.ant-col-rtl{margin-right:87.5%;margin-left:0}.ant-col-xs-push-22.ant-col-rtl{right:91.66666667%;left:auto}.ant-col-xs-pull-22.ant-col-rtl{right:auto;left:91.66666667%}.ant-col-xs-offset-22.ant-col-rtl{margin-right:91.66666667%;margin-left:0}.ant-col-xs-push-23.ant-col-rtl{right:95.83333333%;left:auto}.ant-col-xs-pull-23.ant-col-rtl{right:auto;left:95.83333333%}.ant-col-xs-offset-23.ant-col-rtl{margin-right:95.83333333%;margin-left:0}.ant-col-xs-push-24.ant-col-rtl{right:100%;left:auto}.ant-col-xs-pull-24.ant-col-rtl{right:auto;left:100%}.ant-col-xs-offset-24.ant-col-rtl{margin-right:100%;margin-left:0}@media (min-width:576px){.ant-col-sm-24{display:block;flex:0 0 100%;max-width:100%}.ant-col-sm-push-24{left:100%}.ant-col-sm-pull-24{right:100%}.ant-col-sm-offset-24{margin-left:100%}.ant-col-sm-order-24{order:24}.ant-col-sm-23{display:block;flex:0 0 95.83333333%;max-width:95.83333333%}.ant-col-sm-push-23{left:95.83333333%}.ant-col-sm-pull-23{right:95.83333333%}.ant-col-sm-offset-23{margin-left:95.83333333%}.ant-col-sm-order-23{order:23}.ant-col-sm-22{display:block;flex:0 0 91.66666667%;max-width:91.66666667%}.ant-col-sm-push-22{left:91.66666667%}.ant-col-sm-pull-22{right:91.66666667%}.ant-col-sm-offset-22{margin-left:91.66666667%}.ant-col-sm-order-22{order:22}.ant-col-sm-21{display:block;flex:0 0 87.5%;max-width:87.5%}.ant-col-sm-push-21{left:87.5%}.ant-col-sm-pull-21{right:87.5%}.ant-col-sm-offset-21{margin-left:87.5%}.ant-col-sm-order-21{order:21}.ant-col-sm-20{display:block;flex:0 0 83.33333333%;max-width:83.33333333%}.ant-col-sm-push-20{left:83.33333333%}.ant-col-sm-pull-20{right:83.33333333%}.ant-col-sm-offset-20{margin-left:83.33333333%}.ant-col-sm-order-20{order:20}.ant-col-sm-19{display:block;flex:0 0 79.16666667%;max-width:79.16666667%}.ant-col-sm-push-19{left:79.16666667%}.ant-col-sm-pull-19{right:79.16666667%}.ant-col-sm-offset-19{margin-left:79.16666667%}.ant-col-sm-order-19{order:19}.ant-col-sm-18{display:block;flex:0 0 75%;max-width:75%}.ant-col-sm-push-18{left:75%}.ant-col-sm-pull-18{right:75%}.ant-col-sm-offset-18{margin-left:75%}.ant-col-sm-order-18{order:18}.ant-col-sm-17{display:block;flex:0 0 70.83333333%;max-width:70.83333333%}.ant-col-sm-push-17{left:70.83333333%}.ant-col-sm-pull-17{right:70.83333333%}.ant-col-sm-offset-17{margin-left:70.83333333%}.ant-col-sm-order-17{order:17}.ant-col-sm-16{display:block;flex:0 0 66.66666667%;max-width:66.66666667%}.ant-col-sm-push-16{left:66.66666667%}.ant-col-sm-pull-16{right:66.66666667%}.ant-col-sm-offset-16{margin-left:66.66666667%}.ant-col-sm-order-16{order:16}.ant-col-sm-15{display:block;flex:0 0 62.5%;max-width:62.5%}.ant-col-sm-push-15{left:62.5%}.ant-col-sm-pull-15{right:62.5%}.ant-col-sm-offset-15{margin-left:62.5%}.ant-col-sm-order-15{order:15}.ant-col-sm-14{display:block;flex:0 0 58.33333333%;max-width:58.33333333%}.ant-col-sm-push-14{left:58.33333333%}.ant-col-sm-pull-14{right:58.33333333%}.ant-col-sm-offset-14{margin-left:58.33333333%}.ant-col-sm-order-14{order:14}.ant-col-sm-13{display:block;flex:0 0 54.16666667%;max-width:54.16666667%}.ant-col-sm-push-13{left:54.16666667%}.ant-col-sm-pull-13{right:54.16666667%}.ant-col-sm-offset-13{margin-left:54.16666667%}.ant-col-sm-order-13{order:13}.ant-col-sm-12{display:block;flex:0 0 50%;max-width:50%}.ant-col-sm-push-12{left:50%}.ant-col-sm-pull-12{right:50%}.ant-col-sm-offset-12{margin-left:50%}.ant-col-sm-order-12{order:12}.ant-col-sm-11{display:block;flex:0 0 45.83333333%;max-width:45.83333333%}.ant-col-sm-push-11{left:45.83333333%}.ant-col-sm-pull-11{right:45.83333333%}.ant-col-sm-offset-11{margin-left:45.83333333%}.ant-col-sm-order-11{order:11}.ant-col-sm-10{display:block;flex:0 0 41.66666667%;max-width:41.66666667%}.ant-col-sm-push-10{left:41.66666667%}.ant-col-sm-pull-10{right:41.66666667%}.ant-col-sm-offset-10{margin-left:41.66666667%}.ant-col-sm-order-10{order:10}.ant-col-sm-9{display:block;flex:0 0 37.5%;max-width:37.5%}.ant-col-sm-push-9{left:37.5%}.ant-col-sm-pull-9{right:37.5%}.ant-col-sm-offset-9{margin-left:37.5%}.ant-col-sm-order-9{order:9}.ant-col-sm-8{display:block;flex:0 0 33.33333333%;max-width:33.33333333%}.ant-col-sm-push-8{left:33.33333333%}.ant-col-sm-pull-8{right:33.33333333%}.ant-col-sm-offset-8{margin-left:33.33333333%}.ant-col-sm-order-8{order:8}.ant-col-sm-7{display:block;flex:0 0 29.16666667%;max-width:29.16666667%}.ant-col-sm-push-7{left:29.16666667%}.ant-col-sm-pull-7{right:29.16666667%}.ant-col-sm-offset-7{margin-left:29.16666667%}.ant-col-sm-order-7{order:7}.ant-col-sm-6{display:block;flex:0 0 25%;max-width:25%}.ant-col-sm-push-6{left:25%}.ant-col-sm-pull-6{right:25%}.ant-col-sm-offset-6{margin-left:25%}.ant-col-sm-order-6{order:6}.ant-col-sm-5{display:block;flex:0 0 20.83333333%;max-width:20.83333333%}.ant-col-sm-push-5{left:20.83333333%}.ant-col-sm-pull-5{right:20.83333333%}.ant-col-sm-offset-5{margin-left:20.83333333%}.ant-col-sm-order-5{order:5}.ant-col-sm-4{display:block;flex:0 0 16.66666667%;max-width:16.66666667%}.ant-col-sm-push-4{left:16.66666667%}.ant-col-sm-pull-4{right:16.66666667%}.ant-col-sm-offset-4{margin-left:16.66666667%}.ant-col-sm-order-4{order:4}.ant-col-sm-3{display:block;flex:0 0 12.5%;max-width:12.5%}.ant-col-sm-push-3{left:12.5%}.ant-col-sm-pull-3{right:12.5%}.ant-col-sm-offset-3{margin-left:12.5%}.ant-col-sm-order-3{order:3}.ant-col-sm-2{display:block;flex:0 0 8.33333333%;max-width:8.33333333%}.ant-col-sm-push-2{left:8.33333333%}.ant-col-sm-pull-2{right:8.33333333%}.ant-col-sm-offset-2{margin-left:8.33333333%}.ant-col-sm-order-2{order:2}.ant-col-sm-1{display:block;flex:0 0 4.16666667%;max-width:4.16666667%}.ant-col-sm-push-1{left:4.16666667%}.ant-col-sm-pull-1{right:4.16666667%}.ant-col-sm-offset-1{margin-left:4.16666667%}.ant-col-sm-order-1{order:1}.ant-col-sm-0{display:none}.ant-col-push-0{left:auto}.ant-col-pull-0{right:auto}.ant-col-sm-push-0{left:auto}.ant-col-sm-pull-0{right:auto}.ant-col-sm-offset-0{margin-left:0}.ant-col-sm-order-0{order:0}.ant-col-push-0.ant-col-rtl{right:auto}.ant-col-pull-0.ant-col-rtl{left:auto}.ant-col-sm-push-0.ant-col-rtl{right:auto}.ant-col-sm-pull-0.ant-col-rtl{left:auto}.ant-col-sm-offset-0.ant-col-rtl{margin-right:0}.ant-col-sm-push-1.ant-col-rtl{right:4.16666667%;left:auto}.ant-col-sm-pull-1.ant-col-rtl{right:auto;left:4.16666667%}.ant-col-sm-offset-1.ant-col-rtl{margin-right:4.16666667%;margin-left:0}.ant-col-sm-push-2.ant-col-rtl{right:8.33333333%;left:auto}.ant-col-sm-pull-2.ant-col-rtl{right:auto;left:8.33333333%}.ant-col-sm-offset-2.ant-col-rtl{margin-right:8.33333333%;margin-left:0}.ant-col-sm-push-3.ant-col-rtl{right:12.5%;left:auto}.ant-col-sm-pull-3.ant-col-rtl{right:auto;left:12.5%}.ant-col-sm-offset-3.ant-col-rtl{margin-right:12.5%;margin-left:0}.ant-col-sm-push-4.ant-col-rtl{right:16.66666667%;left:auto}.ant-col-sm-pull-4.ant-col-rtl{right:auto;left:16.66666667%}.ant-col-sm-offset-4.ant-col-rtl{margin-right:16.66666667%;margin-left:0}.ant-col-sm-push-5.ant-col-rtl{right:20.83333333%;left:auto}.ant-col-sm-pull-5.ant-col-rtl{right:auto;left:20.83333333%}.ant-col-sm-offset-5.ant-col-rtl{margin-right:20.83333333%;margin-left:0}.ant-col-sm-push-6.ant-col-rtl{right:25%;left:auto}.ant-col-sm-pull-6.ant-col-rtl{right:auto;left:25%}.ant-col-sm-offset-6.ant-col-rtl{margin-right:25%;margin-left:0}.ant-col-sm-push-7.ant-col-rtl{right:29.16666667%;left:auto}.ant-col-sm-pull-7.ant-col-rtl{right:auto;left:29.16666667%}.ant-col-sm-offset-7.ant-col-rtl{margin-right:29.16666667%;margin-left:0}.ant-col-sm-push-8.ant-col-rtl{right:33.33333333%;left:auto}.ant-col-sm-pull-8.ant-col-rtl{right:auto;left:33.33333333%}.ant-col-sm-offset-8.ant-col-rtl{margin-right:33.33333333%;margin-left:0}.ant-col-sm-push-9.ant-col-rtl{right:37.5%;left:auto}.ant-col-sm-pull-9.ant-col-rtl{right:auto;left:37.5%}.ant-col-sm-offset-9.ant-col-rtl{margin-right:37.5%;margin-left:0}.ant-col-sm-push-10.ant-col-rtl{right:41.66666667%;left:auto}.ant-col-sm-pull-10.ant-col-rtl{right:auto;left:41.66666667%}.ant-col-sm-offset-10.ant-col-rtl{margin-right:41.66666667%;margin-left:0}.ant-col-sm-push-11.ant-col-rtl{right:45.83333333%;left:auto}.ant-col-sm-pull-11.ant-col-rtl{right:auto;left:45.83333333%}.ant-col-sm-offset-11.ant-col-rtl{margin-right:45.83333333%;margin-left:0}.ant-col-sm-push-12.ant-col-rtl{right:50%;left:auto}.ant-col-sm-pull-12.ant-col-rtl{right:auto;left:50%}.ant-col-sm-offset-12.ant-col-rtl{margin-right:50%;margin-left:0}.ant-col-sm-push-13.ant-col-rtl{right:54.16666667%;left:auto}.ant-col-sm-pull-13.ant-col-rtl{right:auto;left:54.16666667%}.ant-col-sm-offset-13.ant-col-rtl{margin-right:54.16666667%;margin-left:0}.ant-col-sm-push-14.ant-col-rtl{right:58.33333333%;left:auto}.ant-col-sm-pull-14.ant-col-rtl{right:auto;left:58.33333333%}.ant-col-sm-offset-14.ant-col-rtl{margin-right:58.33333333%;margin-left:0}.ant-col-sm-push-15.ant-col-rtl{right:62.5%;left:auto}.ant-col-sm-pull-15.ant-col-rtl{right:auto;left:62.5%}.ant-col-sm-offset-15.ant-col-rtl{margin-right:62.5%;margin-left:0}.ant-col-sm-push-16.ant-col-rtl{right:66.66666667%;left:auto}.ant-col-sm-pull-16.ant-col-rtl{right:auto;left:66.66666667%}.ant-col-sm-offset-16.ant-col-rtl{margin-right:66.66666667%;margin-left:0}.ant-col-sm-push-17.ant-col-rtl{right:70.83333333%;left:auto}.ant-col-sm-pull-17.ant-col-rtl{right:auto;left:70.83333333%}.ant-col-sm-offset-17.ant-col-rtl{margin-right:70.83333333%;margin-left:0}.ant-col-sm-push-18.ant-col-rtl{right:75%;left:auto}.ant-col-sm-pull-18.ant-col-rtl{right:auto;left:75%}.ant-col-sm-offset-18.ant-col-rtl{margin-right:75%;margin-left:0}.ant-col-sm-push-19.ant-col-rtl{right:79.16666667%;left:auto}.ant-col-sm-pull-19.ant-col-rtl{right:auto;left:79.16666667%}.ant-col-sm-offset-19.ant-col-rtl{margin-right:79.16666667%;margin-left:0}.ant-col-sm-push-20.ant-col-rtl{right:83.33333333%;left:auto}.ant-col-sm-pull-20.ant-col-rtl{right:auto;left:83.33333333%}.ant-col-sm-offset-20.ant-col-rtl{margin-right:83.33333333%;margin-left:0}.ant-col-sm-push-21.ant-col-rtl{right:87.5%;left:auto}.ant-col-sm-pull-21.ant-col-rtl{right:auto;left:87.5%}.ant-col-sm-offset-21.ant-col-rtl{margin-right:87.5%;margin-left:0}.ant-col-sm-push-22.ant-col-rtl{right:91.66666667%;left:auto}.ant-col-sm-pull-22.ant-col-rtl{right:auto;left:91.66666667%}.ant-col-sm-offset-22.ant-col-rtl{margin-right:91.66666667%;margin-left:0}.ant-col-sm-push-23.ant-col-rtl{right:95.83333333%;left:auto}.ant-col-sm-pull-23.ant-col-rtl{right:auto;left:95.83333333%}.ant-col-sm-offset-23.ant-col-rtl{margin-right:95.83333333%;margin-left:0}.ant-col-sm-push-24.ant-col-rtl{right:100%;left:auto}.ant-col-sm-pull-24.ant-col-rtl{right:auto;left:100%}.ant-col-sm-offset-24.ant-col-rtl{margin-right:100%;margin-left:0}}@media (min-width:768px){.ant-col-md-24{display:block;flex:0 0 100%;max-width:100%}.ant-col-md-push-24{left:100%}.ant-col-md-pull-24{right:100%}.ant-col-md-offset-24{margin-left:100%}.ant-col-md-order-24{order:24}.ant-col-md-23{display:block;flex:0 0 95.83333333%;max-width:95.83333333%}.ant-col-md-push-23{left:95.83333333%}.ant-col-md-pull-23{right:95.83333333%}.ant-col-md-offset-23{margin-left:95.83333333%}.ant-col-md-order-23{order:23}.ant-col-md-22{display:block;flex:0 0 91.66666667%;max-width:91.66666667%}.ant-col-md-push-22{left:91.66666667%}.ant-col-md-pull-22{right:91.66666667%}.ant-col-md-offset-22{margin-left:91.66666667%}.ant-col-md-order-22{order:22}.ant-col-md-21{display:block;flex:0 0 87.5%;max-width:87.5%}.ant-col-md-push-21{left:87.5%}.ant-col-md-pull-21{right:87.5%}.ant-col-md-offset-21{margin-left:87.5%}.ant-col-md-order-21{order:21}.ant-col-md-20{display:block;flex:0 0 83.33333333%;max-width:83.33333333%}.ant-col-md-push-20{left:83.33333333%}.ant-col-md-pull-20{right:83.33333333%}.ant-col-md-offset-20{margin-left:83.33333333%}.ant-col-md-order-20{order:20}.ant-col-md-19{display:block;flex:0 0 79.16666667%;max-width:79.16666667%}.ant-col-md-push-19{left:79.16666667%}.ant-col-md-pull-19{right:79.16666667%}.ant-col-md-offset-19{margin-left:79.16666667%}.ant-col-md-order-19{order:19}.ant-col-md-18{display:block;flex:0 0 75%;max-width:75%}.ant-col-md-push-18{left:75%}.ant-col-md-pull-18{right:75%}.ant-col-md-offset-18{margin-left:75%}.ant-col-md-order-18{order:18}.ant-col-md-17{display:block;flex:0 0 70.83333333%;max-width:70.83333333%}.ant-col-md-push-17{left:70.83333333%}.ant-col-md-pull-17{right:70.83333333%}.ant-col-md-offset-17{margin-left:70.83333333%}.ant-col-md-order-17{order:17}.ant-col-md-16{display:block;flex:0 0 66.66666667%;max-width:66.66666667%}.ant-col-md-push-16{left:66.66666667%}.ant-col-md-pull-16{right:66.66666667%}.ant-col-md-offset-16{margin-left:66.66666667%}.ant-col-md-order-16{order:16}.ant-col-md-15{display:block;flex:0 0 62.5%;max-width:62.5%}.ant-col-md-push-15{left:62.5%}.ant-col-md-pull-15{right:62.5%}.ant-col-md-offset-15{margin-left:62.5%}.ant-col-md-order-15{order:15}.ant-col-md-14{display:block;flex:0 0 58.33333333%;max-width:58.33333333%}.ant-col-md-push-14{left:58.33333333%}.ant-col-md-pull-14{right:58.33333333%}.ant-col-md-offset-14{margin-left:58.33333333%}.ant-col-md-order-14{order:14}.ant-col-md-13{display:block;flex:0 0 54.16666667%;max-width:54.16666667%}.ant-col-md-push-13{left:54.16666667%}.ant-col-md-pull-13{right:54.16666667%}.ant-col-md-offset-13{margin-left:54.16666667%}.ant-col-md-order-13{order:13}.ant-col-md-12{display:block;flex:0 0 50%;max-width:50%}.ant-col-md-push-12{left:50%}.ant-col-md-pull-12{right:50%}.ant-col-md-offset-12{margin-left:50%}.ant-col-md-order-12{order:12}.ant-col-md-11{display:block;flex:0 0 45.83333333%;max-width:45.83333333%}.ant-col-md-push-11{left:45.83333333%}.ant-col-md-pull-11{right:45.83333333%}.ant-col-md-offset-11{margin-left:45.83333333%}.ant-col-md-order-11{order:11}.ant-col-md-10{display:block;flex:0 0 41.66666667%;max-width:41.66666667%}.ant-col-md-push-10{left:41.66666667%}.ant-col-md-pull-10{right:41.66666667%}.ant-col-md-offset-10{margin-left:41.66666667%}.ant-col-md-order-10{order:10}.ant-col-md-9{display:block;flex:0 0 37.5%;max-width:37.5%}.ant-col-md-push-9{left:37.5%}.ant-col-md-pull-9{right:37.5%}.ant-col-md-offset-9{margin-left:37.5%}.ant-col-md-order-9{order:9}.ant-col-md-8{display:block;flex:0 0 33.33333333%;max-width:33.33333333%}.ant-col-md-push-8{left:33.33333333%}.ant-col-md-pull-8{right:33.33333333%}.ant-col-md-offset-8{margin-left:33.33333333%}.ant-col-md-order-8{order:8}.ant-col-md-7{display:block;flex:0 0 29.16666667%;max-width:29.16666667%}.ant-col-md-push-7{left:29.16666667%}.ant-col-md-pull-7{right:29.16666667%}.ant-col-md-offset-7{margin-left:29.16666667%}.ant-col-md-order-7{order:7}.ant-col-md-6{display:block;flex:0 0 25%;max-width:25%}.ant-col-md-push-6{left:25%}.ant-col-md-pull-6{right:25%}.ant-col-md-offset-6{margin-left:25%}.ant-col-md-order-6{order:6}.ant-col-md-5{display:block;flex:0 0 20.83333333%;max-width:20.83333333%}.ant-col-md-push-5{left:20.83333333%}.ant-col-md-pull-5{right:20.83333333%}.ant-col-md-offset-5{margin-left:20.83333333%}.ant-col-md-order-5{order:5}.ant-col-md-4{display:block;flex:0 0 16.66666667%;max-width:16.66666667%}.ant-col-md-push-4{left:16.66666667%}.ant-col-md-pull-4{right:16.66666667%}.ant-col-md-offset-4{margin-left:16.66666667%}.ant-col-md-order-4{order:4}.ant-col-md-3{display:block;flex:0 0 12.5%;max-width:12.5%}.ant-col-md-push-3{left:12.5%}.ant-col-md-pull-3{right:12.5%}.ant-col-md-offset-3{margin-left:12.5%}.ant-col-md-order-3{order:3}.ant-col-md-2{display:block;flex:0 0 8.33333333%;max-width:8.33333333%}.ant-col-md-push-2{left:8.33333333%}.ant-col-md-pull-2{right:8.33333333%}.ant-col-md-offset-2{margin-left:8.33333333%}.ant-col-md-order-2{order:2}.ant-col-md-1{display:block;flex:0 0 4.16666667%;max-width:4.16666667%}.ant-col-md-push-1{left:4.16666667%}.ant-col-md-pull-1{right:4.16666667%}.ant-col-md-offset-1{margin-left:4.16666667%}.ant-col-md-order-1{order:1}.ant-col-md-0{display:none}.ant-col-push-0{left:auto}.ant-col-pull-0{right:auto}.ant-col-md-push-0{left:auto}.ant-col-md-pull-0{right:auto}.ant-col-md-offset-0{margin-left:0}.ant-col-md-order-0{order:0}.ant-col-push-0.ant-col-rtl{right:auto}.ant-col-pull-0.ant-col-rtl{left:auto}.ant-col-md-push-0.ant-col-rtl{right:auto}.ant-col-md-pull-0.ant-col-rtl{left:auto}.ant-col-md-offset-0.ant-col-rtl{margin-right:0}.ant-col-md-push-1.ant-col-rtl{right:4.16666667%;left:auto}.ant-col-md-pull-1.ant-col-rtl{right:auto;left:4.16666667%}.ant-col-md-offset-1.ant-col-rtl{margin-right:4.16666667%;margin-left:0}.ant-col-md-push-2.ant-col-rtl{right:8.33333333%;left:auto}.ant-col-md-pull-2.ant-col-rtl{right:auto;left:8.33333333%}.ant-col-md-offset-2.ant-col-rtl{margin-right:8.33333333%;margin-left:0}.ant-col-md-push-3.ant-col-rtl{right:12.5%;left:auto}.ant-col-md-pull-3.ant-col-rtl{right:auto;left:12.5%}.ant-col-md-offset-3.ant-col-rtl{margin-right:12.5%;margin-left:0}.ant-col-md-push-4.ant-col-rtl{right:16.66666667%;left:auto}.ant-col-md-pull-4.ant-col-rtl{right:auto;left:16.66666667%}.ant-col-md-offset-4.ant-col-rtl{margin-right:16.66666667%;margin-left:0}.ant-col-md-push-5.ant-col-rtl{right:20.83333333%;left:auto}.ant-col-md-pull-5.ant-col-rtl{right:auto;left:20.83333333%}.ant-col-md-offset-5.ant-col-rtl{margin-right:20.83333333%;margin-left:0}.ant-col-md-push-6.ant-col-rtl{right:25%;left:auto}.ant-col-md-pull-6.ant-col-rtl{right:auto;left:25%}.ant-col-md-offset-6.ant-col-rtl{margin-right:25%;margin-left:0}.ant-col-md-push-7.ant-col-rtl{right:29.16666667%;left:auto}.ant-col-md-pull-7.ant-col-rtl{right:auto;left:29.16666667%}.ant-col-md-offset-7.ant-col-rtl{margin-right:29.16666667%;margin-left:0}.ant-col-md-push-8.ant-col-rtl{right:33.33333333%;left:auto}.ant-col-md-pull-8.ant-col-rtl{right:auto;left:33.33333333%}.ant-col-md-offset-8.ant-col-rtl{margin-right:33.33333333%;margin-left:0}.ant-col-md-push-9.ant-col-rtl{right:37.5%;left:auto}.ant-col-md-pull-9.ant-col-rtl{right:auto;left:37.5%}.ant-col-md-offset-9.ant-col-rtl{margin-right:37.5%;margin-left:0}.ant-col-md-push-10.ant-col-rtl{right:41.66666667%;left:auto}.ant-col-md-pull-10.ant-col-rtl{right:auto;left:41.66666667%}.ant-col-md-offset-10.ant-col-rtl{margin-right:41.66666667%;margin-left:0}.ant-col-md-push-11.ant-col-rtl{right:45.83333333%;left:auto}.ant-col-md-pull-11.ant-col-rtl{right:auto;left:45.83333333%}.ant-col-md-offset-11.ant-col-rtl{margin-right:45.83333333%;margin-left:0}.ant-col-md-push-12.ant-col-rtl{right:50%;left:auto}.ant-col-md-pull-12.ant-col-rtl{right:auto;left:50%}.ant-col-md-offset-12.ant-col-rtl{margin-right:50%;margin-left:0}.ant-col-md-push-13.ant-col-rtl{right:54.16666667%;left:auto}.ant-col-md-pull-13.ant-col-rtl{right:auto;left:54.16666667%}.ant-col-md-offset-13.ant-col-rtl{margin-right:54.16666667%;margin-left:0}.ant-col-md-push-14.ant-col-rtl{right:58.33333333%;left:auto}.ant-col-md-pull-14.ant-col-rtl{right:auto;left:58.33333333%}.ant-col-md-offset-14.ant-col-rtl{margin-right:58.33333333%;margin-left:0}.ant-col-md-push-15.ant-col-rtl{right:62.5%;left:auto}.ant-col-md-pull-15.ant-col-rtl{right:auto;left:62.5%}.ant-col-md-offset-15.ant-col-rtl{margin-right:62.5%;margin-left:0}.ant-col-md-push-16.ant-col-rtl{right:66.66666667%;left:auto}.ant-col-md-pull-16.ant-col-rtl{right:auto;left:66.66666667%}.ant-col-md-offset-16.ant-col-rtl{margin-right:66.66666667%;margin-left:0}.ant-col-md-push-17.ant-col-rtl{right:70.83333333%;left:auto}.ant-col-md-pull-17.ant-col-rtl{right:auto;left:70.83333333%}.ant-col-md-offset-17.ant-col-rtl{margin-right:70.83333333%;margin-left:0}.ant-col-md-push-18.ant-col-rtl{right:75%;left:auto}.ant-col-md-pull-18.ant-col-rtl{right:auto;left:75%}.ant-col-md-offset-18.ant-col-rtl{margin-right:75%;margin-left:0}.ant-col-md-push-19.ant-col-rtl{right:79.16666667%;left:auto}.ant-col-md-pull-19.ant-col-rtl{right:auto;left:79.16666667%}.ant-col-md-offset-19.ant-col-rtl{margin-right:79.16666667%;margin-left:0}.ant-col-md-push-20.ant-col-rtl{right:83.33333333%;left:auto}.ant-col-md-pull-20.ant-col-rtl{right:auto;left:83.33333333%}.ant-col-md-offset-20.ant-col-rtl{margin-right:83.33333333%;margin-left:0}.ant-col-md-push-21.ant-col-rtl{right:87.5%;left:auto}.ant-col-md-pull-21.ant-col-rtl{right:auto;left:87.5%}.ant-col-md-offset-21.ant-col-rtl{margin-right:87.5%;margin-left:0}.ant-col-md-push-22.ant-col-rtl{right:91.66666667%;left:auto}.ant-col-md-pull-22.ant-col-rtl{right:auto;left:91.66666667%}.ant-col-md-offset-22.ant-col-rtl{margin-right:91.66666667%;margin-left:0}.ant-col-md-push-23.ant-col-rtl{right:95.83333333%;left:auto}.ant-col-md-pull-23.ant-col-rtl{right:auto;left:95.83333333%}.ant-col-md-offset-23.ant-col-rtl{margin-right:95.83333333%;margin-left:0}.ant-col-md-push-24.ant-col-rtl{right:100%;left:auto}.ant-col-md-pull-24.ant-col-rtl{right:auto;left:100%}.ant-col-md-offset-24.ant-col-rtl{margin-right:100%;margin-left:0}}@media (min-width:992px){.ant-col-lg-24{display:block;flex:0 0 100%;max-width:100%}.ant-col-lg-push-24{left:100%}.ant-col-lg-pull-24{right:100%}.ant-col-lg-offset-24{margin-left:100%}.ant-col-lg-order-24{order:24}.ant-col-lg-23{display:block;flex:0 0 95.83333333%;max-width:95.83333333%}.ant-col-lg-push-23{left:95.83333333%}.ant-col-lg-pull-23{right:95.83333333%}.ant-col-lg-offset-23{margin-left:95.83333333%}.ant-col-lg-order-23{order:23}.ant-col-lg-22{display:block;flex:0 0 91.66666667%;max-width:91.66666667%}.ant-col-lg-push-22{left:91.66666667%}.ant-col-lg-pull-22{right:91.66666667%}.ant-col-lg-offset-22{margin-left:91.66666667%}.ant-col-lg-order-22{order:22}.ant-col-lg-21{display:block;flex:0 0 87.5%;max-width:87.5%}.ant-col-lg-push-21{left:87.5%}.ant-col-lg-pull-21{right:87.5%}.ant-col-lg-offset-21{margin-left:87.5%}.ant-col-lg-order-21{order:21}.ant-col-lg-20{display:block;flex:0 0 83.33333333%;max-width:83.33333333%}.ant-col-lg-push-20{left:83.33333333%}.ant-col-lg-pull-20{right:83.33333333%}.ant-col-lg-offset-20{margin-left:83.33333333%}.ant-col-lg-order-20{order:20}.ant-col-lg-19{display:block;flex:0 0 79.16666667%;max-width:79.16666667%}.ant-col-lg-push-19{left:79.16666667%}.ant-col-lg-pull-19{right:79.16666667%}.ant-col-lg-offset-19{margin-left:79.16666667%}.ant-col-lg-order-19{order:19}.ant-col-lg-18{display:block;flex:0 0 75%;max-width:75%}.ant-col-lg-push-18{left:75%}.ant-col-lg-pull-18{right:75%}.ant-col-lg-offset-18{margin-left:75%}.ant-col-lg-order-18{order:18}.ant-col-lg-17{display:block;flex:0 0 70.83333333%;max-width:70.83333333%}.ant-col-lg-push-17{left:70.83333333%}.ant-col-lg-pull-17{right:70.83333333%}.ant-col-lg-offset-17{margin-left:70.83333333%}.ant-col-lg-order-17{order:17}.ant-col-lg-16{display:block;flex:0 0 66.66666667%;max-width:66.66666667%}.ant-col-lg-push-16{left:66.66666667%}.ant-col-lg-pull-16{right:66.66666667%}.ant-col-lg-offset-16{margin-left:66.66666667%}.ant-col-lg-order-16{order:16}.ant-col-lg-15{display:block;flex:0 0 62.5%;max-width:62.5%}.ant-col-lg-push-15{left:62.5%}.ant-col-lg-pull-15{right:62.5%}.ant-col-lg-offset-15{margin-left:62.5%}.ant-col-lg-order-15{order:15}.ant-col-lg-14{display:block;flex:0 0 58.33333333%;max-width:58.33333333%}.ant-col-lg-push-14{left:58.33333333%}.ant-col-lg-pull-14{right:58.33333333%}.ant-col-lg-offset-14{margin-left:58.33333333%}.ant-col-lg-order-14{order:14}.ant-col-lg-13{display:block;flex:0 0 54.16666667%;max-width:54.16666667%}.ant-col-lg-push-13{left:54.16666667%}.ant-col-lg-pull-13{right:54.16666667%}.ant-col-lg-offset-13{margin-left:54.16666667%}.ant-col-lg-order-13{order:13}.ant-col-lg-12{display:block;flex:0 0 50%;max-width:50%}.ant-col-lg-push-12{left:50%}.ant-col-lg-pull-12{right:50%}.ant-col-lg-offset-12{margin-left:50%}.ant-col-lg-order-12{order:12}.ant-col-lg-11{display:block;flex:0 0 45.83333333%;max-width:45.83333333%}.ant-col-lg-push-11{left:45.83333333%}.ant-col-lg-pull-11{right:45.83333333%}.ant-col-lg-offset-11{margin-left:45.83333333%}.ant-col-lg-order-11{order:11}.ant-col-lg-10{display:block;flex:0 0 41.66666667%;max-width:41.66666667%}.ant-col-lg-push-10{left:41.66666667%}.ant-col-lg-pull-10{right:41.66666667%}.ant-col-lg-offset-10{margin-left:41.66666667%}.ant-col-lg-order-10{order:10}.ant-col-lg-9{display:block;flex:0 0 37.5%;max-width:37.5%}.ant-col-lg-push-9{left:37.5%}.ant-col-lg-pull-9{right:37.5%}.ant-col-lg-offset-9{margin-left:37.5%}.ant-col-lg-order-9{order:9}.ant-col-lg-8{display:block;flex:0 0 33.33333333%;max-width:33.33333333%}.ant-col-lg-push-8{left:33.33333333%}.ant-col-lg-pull-8{right:33.33333333%}.ant-col-lg-offset-8{margin-left:33.33333333%}.ant-col-lg-order-8{order:8}.ant-col-lg-7{display:block;flex:0 0 29.16666667%;max-width:29.16666667%}.ant-col-lg-push-7{left:29.16666667%}.ant-col-lg-pull-7{right:29.16666667%}.ant-col-lg-offset-7{margin-left:29.16666667%}.ant-col-lg-order-7{order:7}.ant-col-lg-6{display:block;flex:0 0 25%;max-width:25%}.ant-col-lg-push-6{left:25%}.ant-col-lg-pull-6{right:25%}.ant-col-lg-offset-6{margin-left:25%}.ant-col-lg-order-6{order:6}.ant-col-lg-5{display:block;flex:0 0 20.83333333%;max-width:20.83333333%}.ant-col-lg-push-5{left:20.83333333%}.ant-col-lg-pull-5{right:20.83333333%}.ant-col-lg-offset-5{margin-left:20.83333333%}.ant-col-lg-order-5{order:5}.ant-col-lg-4{display:block;flex:0 0 16.66666667%;max-width:16.66666667%}.ant-col-lg-push-4{left:16.66666667%}.ant-col-lg-pull-4{right:16.66666667%}.ant-col-lg-offset-4{margin-left:16.66666667%}.ant-col-lg-order-4{order:4}.ant-col-lg-3{display:block;flex:0 0 12.5%;max-width:12.5%}.ant-col-lg-push-3{left:12.5%}.ant-col-lg-pull-3{right:12.5%}.ant-col-lg-offset-3{margin-left:12.5%}.ant-col-lg-order-3{order:3}.ant-col-lg-2{display:block;flex:0 0 8.33333333%;max-width:8.33333333%}.ant-col-lg-push-2{left:8.33333333%}.ant-col-lg-pull-2{right:8.33333333%}.ant-col-lg-offset-2{margin-left:8.33333333%}.ant-col-lg-order-2{order:2}.ant-col-lg-1{display:block;flex:0 0 4.16666667%;max-width:4.16666667%}.ant-col-lg-push-1{left:4.16666667%}.ant-col-lg-pull-1{right:4.16666667%}.ant-col-lg-offset-1{margin-left:4.16666667%}.ant-col-lg-order-1{order:1}.ant-col-lg-0{display:none}.ant-col-push-0{left:auto}.ant-col-pull-0{right:auto}.ant-col-lg-push-0{left:auto}.ant-col-lg-pull-0{right:auto}.ant-col-lg-offset-0{margin-left:0}.ant-col-lg-order-0{order:0}.ant-col-push-0.ant-col-rtl{right:auto}.ant-col-pull-0.ant-col-rtl{left:auto}.ant-col-lg-push-0.ant-col-rtl{right:auto}.ant-col-lg-pull-0.ant-col-rtl{left:auto}.ant-col-lg-offset-0.ant-col-rtl{margin-right:0}.ant-col-lg-push-1.ant-col-rtl{right:4.16666667%;left:auto}.ant-col-lg-pull-1.ant-col-rtl{right:auto;left:4.16666667%}.ant-col-lg-offset-1.ant-col-rtl{margin-right:4.16666667%;margin-left:0}.ant-col-lg-push-2.ant-col-rtl{right:8.33333333%;left:auto}.ant-col-lg-pull-2.ant-col-rtl{right:auto;left:8.33333333%}.ant-col-lg-offset-2.ant-col-rtl{margin-right:8.33333333%;margin-left:0}.ant-col-lg-push-3.ant-col-rtl{right:12.5%;left:auto}.ant-col-lg-pull-3.ant-col-rtl{right:auto;left:12.5%}.ant-col-lg-offset-3.ant-col-rtl{margin-right:12.5%;margin-left:0}.ant-col-lg-push-4.ant-col-rtl{right:16.66666667%;left:auto}.ant-col-lg-pull-4.ant-col-rtl{right:auto;left:16.66666667%}.ant-col-lg-offset-4.ant-col-rtl{margin-right:16.66666667%;margin-left:0}.ant-col-lg-push-5.ant-col-rtl{right:20.83333333%;left:auto}.ant-col-lg-pull-5.ant-col-rtl{right:auto;left:20.83333333%}.ant-col-lg-offset-5.ant-col-rtl{margin-right:20.83333333%;margin-left:0}.ant-col-lg-push-6.ant-col-rtl{right:25%;left:auto}.ant-col-lg-pull-6.ant-col-rtl{right:auto;left:25%}.ant-col-lg-offset-6.ant-col-rtl{margin-right:25%;margin-left:0}.ant-col-lg-push-7.ant-col-rtl{right:29.16666667%;left:auto}.ant-col-lg-pull-7.ant-col-rtl{right:auto;left:29.16666667%}.ant-col-lg-offset-7.ant-col-rtl{margin-right:29.16666667%;margin-left:0}.ant-col-lg-push-8.ant-col-rtl{right:33.33333333%;left:auto}.ant-col-lg-pull-8.ant-col-rtl{right:auto;left:33.33333333%}.ant-col-lg-offset-8.ant-col-rtl{margin-right:33.33333333%;margin-left:0}.ant-col-lg-push-9.ant-col-rtl{right:37.5%;left:auto}.ant-col-lg-pull-9.ant-col-rtl{right:auto;left:37.5%}.ant-col-lg-offset-9.ant-col-rtl{margin-right:37.5%;margin-left:0}.ant-col-lg-push-10.ant-col-rtl{right:41.66666667%;left:auto}.ant-col-lg-pull-10.ant-col-rtl{right:auto;left:41.66666667%}.ant-col-lg-offset-10.ant-col-rtl{margin-right:41.66666667%;margin-left:0}.ant-col-lg-push-11.ant-col-rtl{right:45.83333333%;left:auto}.ant-col-lg-pull-11.ant-col-rtl{right:auto;left:45.83333333%}.ant-col-lg-offset-11.ant-col-rtl{margin-right:45.83333333%;margin-left:0}.ant-col-lg-push-12.ant-col-rtl{right:50%;left:auto}.ant-col-lg-pull-12.ant-col-rtl{right:auto;left:50%}.ant-col-lg-offset-12.ant-col-rtl{margin-right:50%;margin-left:0}.ant-col-lg-push-13.ant-col-rtl{right:54.16666667%;left:auto}.ant-col-lg-pull-13.ant-col-rtl{right:auto;left:54.16666667%}.ant-col-lg-offset-13.ant-col-rtl{margin-right:54.16666667%;margin-left:0}.ant-col-lg-push-14.ant-col-rtl{right:58.33333333%;left:auto}.ant-col-lg-pull-14.ant-col-rtl{right:auto;left:58.33333333%}.ant-col-lg-offset-14.ant-col-rtl{margin-right:58.33333333%;margin-left:0}.ant-col-lg-push-15.ant-col-rtl{right:62.5%;left:auto}.ant-col-lg-pull-15.ant-col-rtl{right:auto;left:62.5%}.ant-col-lg-offset-15.ant-col-rtl{margin-right:62.5%;margin-left:0}.ant-col-lg-push-16.ant-col-rtl{right:66.66666667%;left:auto}.ant-col-lg-pull-16.ant-col-rtl{right:auto;left:66.66666667%}.ant-col-lg-offset-16.ant-col-rtl{margin-right:66.66666667%;margin-left:0}.ant-col-lg-push-17.ant-col-rtl{right:70.83333333%;left:auto}.ant-col-lg-pull-17.ant-col-rtl{right:auto;left:70.83333333%}.ant-col-lg-offset-17.ant-col-rtl{margin-right:70.83333333%;margin-left:0}.ant-col-lg-push-18.ant-col-rtl{right:75%;left:auto}.ant-col-lg-pull-18.ant-col-rtl{right:auto;left:75%}.ant-col-lg-offset-18.ant-col-rtl{margin-right:75%;margin-left:0}.ant-col-lg-push-19.ant-col-rtl{right:79.16666667%;left:auto}.ant-col-lg-pull-19.ant-col-rtl{right:auto;left:79.16666667%}.ant-col-lg-offset-19.ant-col-rtl{margin-right:79.16666667%;margin-left:0}.ant-col-lg-push-20.ant-col-rtl{right:83.33333333%;left:auto}.ant-col-lg-pull-20.ant-col-rtl{right:auto;left:83.33333333%}.ant-col-lg-offset-20.ant-col-rtl{margin-right:83.33333333%;margin-left:0}.ant-col-lg-push-21.ant-col-rtl{right:87.5%;left:auto}.ant-col-lg-pull-21.ant-col-rtl{right:auto;left:87.5%}.ant-col-lg-offset-21.ant-col-rtl{margin-right:87.5%;margin-left:0}.ant-col-lg-push-22.ant-col-rtl{right:91.66666667%;left:auto}.ant-col-lg-pull-22.ant-col-rtl{right:auto;left:91.66666667%}.ant-col-lg-offset-22.ant-col-rtl{margin-right:91.66666667%;margin-left:0}.ant-col-lg-push-23.ant-col-rtl{right:95.83333333%;left:auto}.ant-col-lg-pull-23.ant-col-rtl{right:auto;left:95.83333333%}.ant-col-lg-offset-23.ant-col-rtl{margin-right:95.83333333%;margin-left:0}.ant-col-lg-push-24.ant-col-rtl{right:100%;left:auto}.ant-col-lg-pull-24.ant-col-rtl{right:auto;left:100%}.ant-col-lg-offset-24.ant-col-rtl{margin-right:100%;margin-left:0}}@media (min-width:1200px){.ant-col-xl-24{display:block;flex:0 0 100%;max-width:100%}.ant-col-xl-push-24{left:100%}.ant-col-xl-pull-24{right:100%}.ant-col-xl-offset-24{margin-left:100%}.ant-col-xl-order-24{order:24}.ant-col-xl-23{display:block;flex:0 0 95.83333333%;max-width:95.83333333%}.ant-col-xl-push-23{left:95.83333333%}.ant-col-xl-pull-23{right:95.83333333%}.ant-col-xl-offset-23{margin-left:95.83333333%}.ant-col-xl-order-23{order:23}.ant-col-xl-22{display:block;flex:0 0 91.66666667%;max-width:91.66666667%}.ant-col-xl-push-22{left:91.66666667%}.ant-col-xl-pull-22{right:91.66666667%}.ant-col-xl-offset-22{margin-left:91.66666667%}.ant-col-xl-order-22{order:22}.ant-col-xl-21{display:block;flex:0 0 87.5%;max-width:87.5%}.ant-col-xl-push-21{left:87.5%}.ant-col-xl-pull-21{right:87.5%}.ant-col-xl-offset-21{margin-left:87.5%}.ant-col-xl-order-21{order:21}.ant-col-xl-20{display:block;flex:0 0 83.33333333%;max-width:83.33333333%}.ant-col-xl-push-20{left:83.33333333%}.ant-col-xl-pull-20{right:83.33333333%}.ant-col-xl-offset-20{margin-left:83.33333333%}.ant-col-xl-order-20{order:20}.ant-col-xl-19{display:block;flex:0 0 79.16666667%;max-width:79.16666667%}.ant-col-xl-push-19{left:79.16666667%}.ant-col-xl-pull-19{right:79.16666667%}.ant-col-xl-offset-19{margin-left:79.16666667%}.ant-col-xl-order-19{order:19}.ant-col-xl-18{display:block;flex:0 0 75%;max-width:75%}.ant-col-xl-push-18{left:75%}.ant-col-xl-pull-18{right:75%}.ant-col-xl-offset-18{margin-left:75%}.ant-col-xl-order-18{order:18}.ant-col-xl-17{display:block;flex:0 0 70.83333333%;max-width:70.83333333%}.ant-col-xl-push-17{left:70.83333333%}.ant-col-xl-pull-17{right:70.83333333%}.ant-col-xl-offset-17{margin-left:70.83333333%}.ant-col-xl-order-17{order:17}.ant-col-xl-16{display:block;flex:0 0 66.66666667%;max-width:66.66666667%}.ant-col-xl-push-16{left:66.66666667%}.ant-col-xl-pull-16{right:66.66666667%}.ant-col-xl-offset-16{margin-left:66.66666667%}.ant-col-xl-order-16{order:16}.ant-col-xl-15{display:block;flex:0 0 62.5%;max-width:62.5%}.ant-col-xl-push-15{left:62.5%}.ant-col-xl-pull-15{right:62.5%}.ant-col-xl-offset-15{margin-left:62.5%}.ant-col-xl-order-15{order:15}.ant-col-xl-14{display:block;flex:0 0 58.33333333%;max-width:58.33333333%}.ant-col-xl-push-14{left:58.33333333%}.ant-col-xl-pull-14{right:58.33333333%}.ant-col-xl-offset-14{margin-left:58.33333333%}.ant-col-xl-order-14{order:14}.ant-col-xl-13{display:block;flex:0 0 54.16666667%;max-width:54.16666667%}.ant-col-xl-push-13{left:54.16666667%}.ant-col-xl-pull-13{right:54.16666667%}.ant-col-xl-offset-13{margin-left:54.16666667%}.ant-col-xl-order-13{order:13}.ant-col-xl-12{display:block;flex:0 0 50%;max-width:50%}.ant-col-xl-push-12{left:50%}.ant-col-xl-pull-12{right:50%}.ant-col-xl-offset-12{margin-left:50%}.ant-col-xl-order-12{order:12}.ant-col-xl-11{display:block;flex:0 0 45.83333333%;max-width:45.83333333%}.ant-col-xl-push-11{left:45.83333333%}.ant-col-xl-pull-11{right:45.83333333%}.ant-col-xl-offset-11{margin-left:45.83333333%}.ant-col-xl-order-11{order:11}.ant-col-xl-10{display:block;flex:0 0 41.66666667%;max-width:41.66666667%}.ant-col-xl-push-10{left:41.66666667%}.ant-col-xl-pull-10{right:41.66666667%}.ant-col-xl-offset-10{margin-left:41.66666667%}.ant-col-xl-order-10{order:10}.ant-col-xl-9{display:block;flex:0 0 37.5%;max-width:37.5%}.ant-col-xl-push-9{left:37.5%}.ant-col-xl-pull-9{right:37.5%}.ant-col-xl-offset-9{margin-left:37.5%}.ant-col-xl-order-9{order:9}.ant-col-xl-8{display:block;flex:0 0 33.33333333%;max-width:33.33333333%}.ant-col-xl-push-8{left:33.33333333%}.ant-col-xl-pull-8{right:33.33333333%}.ant-col-xl-offset-8{margin-left:33.33333333%}.ant-col-xl-order-8{order:8}.ant-col-xl-7{display:block;flex:0 0 29.16666667%;max-width:29.16666667%}.ant-col-xl-push-7{left:29.16666667%}.ant-col-xl-pull-7{right:29.16666667%}.ant-col-xl-offset-7{margin-left:29.16666667%}.ant-col-xl-order-7{order:7}.ant-col-xl-6{display:block;flex:0 0 25%;max-width:25%}.ant-col-xl-push-6{left:25%}.ant-col-xl-pull-6{right:25%}.ant-col-xl-offset-6{margin-left:25%}.ant-col-xl-order-6{order:6}.ant-col-xl-5{display:block;flex:0 0 20.83333333%;max-width:20.83333333%}.ant-col-xl-push-5{left:20.83333333%}.ant-col-xl-pull-5{right:20.83333333%}.ant-col-xl-offset-5{margin-left:20.83333333%}.ant-col-xl-order-5{order:5}.ant-col-xl-4{display:block;flex:0 0 16.66666667%;max-width:16.66666667%}.ant-col-xl-push-4{left:16.66666667%}.ant-col-xl-pull-4{right:16.66666667%}.ant-col-xl-offset-4{margin-left:16.66666667%}.ant-col-xl-order-4{order:4}.ant-col-xl-3{display:block;flex:0 0 12.5%;max-width:12.5%}.ant-col-xl-push-3{left:12.5%}.ant-col-xl-pull-3{right:12.5%}.ant-col-xl-offset-3{margin-left:12.5%}.ant-col-xl-order-3{order:3}.ant-col-xl-2{display:block;flex:0 0 8.33333333%;max-width:8.33333333%}.ant-col-xl-push-2{left:8.33333333%}.ant-col-xl-pull-2{right:8.33333333%}.ant-col-xl-offset-2{margin-left:8.33333333%}.ant-col-xl-order-2{order:2}.ant-col-xl-1{display:block;flex:0 0 4.16666667%;max-width:4.16666667%}.ant-col-xl-push-1{left:4.16666667%}.ant-col-xl-pull-1{right:4.16666667%}.ant-col-xl-offset-1{margin-left:4.16666667%}.ant-col-xl-order-1{order:1}.ant-col-xl-0{display:none}.ant-col-push-0{left:auto}.ant-col-pull-0{right:auto}.ant-col-xl-push-0{left:auto}.ant-col-xl-pull-0{right:auto}.ant-col-xl-offset-0{margin-left:0}.ant-col-xl-order-0{order:0}.ant-col-push-0.ant-col-rtl{right:auto}.ant-col-pull-0.ant-col-rtl{left:auto}.ant-col-xl-push-0.ant-col-rtl{right:auto}.ant-col-xl-pull-0.ant-col-rtl{left:auto}.ant-col-xl-offset-0.ant-col-rtl{margin-right:0}.ant-col-xl-push-1.ant-col-rtl{right:4.16666667%;left:auto}.ant-col-xl-pull-1.ant-col-rtl{right:auto;left:4.16666667%}.ant-col-xl-offset-1.ant-col-rtl{margin-right:4.16666667%;margin-left:0}.ant-col-xl-push-2.ant-col-rtl{right:8.33333333%;left:auto}.ant-col-xl-pull-2.ant-col-rtl{right:auto;left:8.33333333%}.ant-col-xl-offset-2.ant-col-rtl{margin-right:8.33333333%;margin-left:0}.ant-col-xl-push-3.ant-col-rtl{right:12.5%;left:auto}.ant-col-xl-pull-3.ant-col-rtl{right:auto;left:12.5%}.ant-col-xl-offset-3.ant-col-rtl{margin-right:12.5%;margin-left:0}.ant-col-xl-push-4.ant-col-rtl{right:16.66666667%;left:auto}.ant-col-xl-pull-4.ant-col-rtl{right:auto;left:16.66666667%}.ant-col-xl-offset-4.ant-col-rtl{margin-right:16.66666667%;margin-left:0}.ant-col-xl-push-5.ant-col-rtl{right:20.83333333%;left:auto}.ant-col-xl-pull-5.ant-col-rtl{right:auto;left:20.83333333%}.ant-col-xl-offset-5.ant-col-rtl{margin-right:20.83333333%;margin-left:0}.ant-col-xl-push-6.ant-col-rtl{right:25%;left:auto}.ant-col-xl-pull-6.ant-col-rtl{right:auto;left:25%}.ant-col-xl-offset-6.ant-col-rtl{margin-right:25%;margin-left:0}.ant-col-xl-push-7.ant-col-rtl{right:29.16666667%;left:auto}.ant-col-xl-pull-7.ant-col-rtl{right:auto;left:29.16666667%}.ant-col-xl-offset-7.ant-col-rtl{margin-right:29.16666667%;margin-left:0}.ant-col-xl-push-8.ant-col-rtl{right:33.33333333%;left:auto}.ant-col-xl-pull-8.ant-col-rtl{right:auto;left:33.33333333%}.ant-col-xl-offset-8.ant-col-rtl{margin-right:33.33333333%;margin-left:0}.ant-col-xl-push-9.ant-col-rtl{right:37.5%;left:auto}.ant-col-xl-pull-9.ant-col-rtl{right:auto;left:37.5%}.ant-col-xl-offset-9.ant-col-rtl{margin-right:37.5%;margin-left:0}.ant-col-xl-push-10.ant-col-rtl{right:41.66666667%;left:auto}.ant-col-xl-pull-10.ant-col-rtl{right:auto;left:41.66666667%}.ant-col-xl-offset-10.ant-col-rtl{margin-right:41.66666667%;margin-left:0}.ant-col-xl-push-11.ant-col-rtl{right:45.83333333%;left:auto}.ant-col-xl-pull-11.ant-col-rtl{right:auto;left:45.83333333%}.ant-col-xl-offset-11.ant-col-rtl{margin-right:45.83333333%;margin-left:0}.ant-col-xl-push-12.ant-col-rtl{right:50%;left:auto}.ant-col-xl-pull-12.ant-col-rtl{right:auto;left:50%}.ant-col-xl-offset-12.ant-col-rtl{margin-right:50%;margin-left:0}.ant-col-xl-push-13.ant-col-rtl{right:54.16666667%;left:auto}.ant-col-xl-pull-13.ant-col-rtl{right:auto;left:54.16666667%}.ant-col-xl-offset-13.ant-col-rtl{margin-right:54.16666667%;margin-left:0}.ant-col-xl-push-14.ant-col-rtl{right:58.33333333%;left:auto}.ant-col-xl-pull-14.ant-col-rtl{right:auto;left:58.33333333%}.ant-col-xl-offset-14.ant-col-rtl{margin-right:58.33333333%;margin-left:0}.ant-col-xl-push-15.ant-col-rtl{right:62.5%;left:auto}.ant-col-xl-pull-15.ant-col-rtl{right:auto;left:62.5%}.ant-col-xl-offset-15.ant-col-rtl{margin-right:62.5%;margin-left:0}.ant-col-xl-push-16.ant-col-rtl{right:66.66666667%;left:auto}.ant-col-xl-pull-16.ant-col-rtl{right:auto;left:66.66666667%}.ant-col-xl-offset-16.ant-col-rtl{margin-right:66.66666667%;margin-left:0}.ant-col-xl-push-17.ant-col-rtl{right:70.83333333%;left:auto}.ant-col-xl-pull-17.ant-col-rtl{right:auto;left:70.83333333%}.ant-col-xl-offset-17.ant-col-rtl{margin-right:70.83333333%;margin-left:0}.ant-col-xl-push-18.ant-col-rtl{right:75%;left:auto}.ant-col-xl-pull-18.ant-col-rtl{right:auto;left:75%}.ant-col-xl-offset-18.ant-col-rtl{margin-right:75%;margin-left:0}.ant-col-xl-push-19.ant-col-rtl{right:79.16666667%;left:auto}.ant-col-xl-pull-19.ant-col-rtl{right:auto;left:79.16666667%}.ant-col-xl-offset-19.ant-col-rtl{margin-right:79.16666667%;margin-left:0}.ant-col-xl-push-20.ant-col-rtl{right:83.33333333%;left:auto}.ant-col-xl-pull-20.ant-col-rtl{right:auto;left:83.33333333%}.ant-col-xl-offset-20.ant-col-rtl{margin-right:83.33333333%;margin-left:0}.ant-col-xl-push-21.ant-col-rtl{right:87.5%;left:auto}.ant-col-xl-pull-21.ant-col-rtl{right:auto;left:87.5%}.ant-col-xl-offset-21.ant-col-rtl{margin-right:87.5%;margin-left:0}.ant-col-xl-push-22.ant-col-rtl{right:91.66666667%;left:auto}.ant-col-xl-pull-22.ant-col-rtl{right:auto;left:91.66666667%}.ant-col-xl-offset-22.ant-col-rtl{margin-right:91.66666667%;margin-left:0}.ant-col-xl-push-23.ant-col-rtl{right:95.83333333%;left:auto}.ant-col-xl-pull-23.ant-col-rtl{right:auto;left:95.83333333%}.ant-col-xl-offset-23.ant-col-rtl{margin-right:95.83333333%;margin-left:0}.ant-col-xl-push-24.ant-col-rtl{right:100%;left:auto}.ant-col-xl-pull-24.ant-col-rtl{right:auto;left:100%}.ant-col-xl-offset-24.ant-col-rtl{margin-right:100%;margin-left:0}}@media (min-width:1600px){.ant-col-xxl-24{display:block;flex:0 0 100%;max-width:100%}.ant-col-xxl-push-24{left:100%}.ant-col-xxl-pull-24{right:100%}.ant-col-xxl-offset-24{margin-left:100%}.ant-col-xxl-order-24{order:24}.ant-col-xxl-23{display:block;flex:0 0 95.83333333%;max-width:95.83333333%}.ant-col-xxl-push-23{left:95.83333333%}.ant-col-xxl-pull-23{right:95.83333333%}.ant-col-xxl-offset-23{margin-left:95.83333333%}.ant-col-xxl-order-23{order:23}.ant-col-xxl-22{display:block;flex:0 0 91.66666667%;max-width:91.66666667%}.ant-col-xxl-push-22{left:91.66666667%}.ant-col-xxl-pull-22{right:91.66666667%}.ant-col-xxl-offset-22{margin-left:91.66666667%}.ant-col-xxl-order-22{order:22}.ant-col-xxl-21{display:block;flex:0 0 87.5%;max-width:87.5%}.ant-col-xxl-push-21{left:87.5%}.ant-col-xxl-pull-21{right:87.5%}.ant-col-xxl-offset-21{margin-left:87.5%}.ant-col-xxl-order-21{order:21}.ant-col-xxl-20{display:block;flex:0 0 83.33333333%;max-width:83.33333333%}.ant-col-xxl-push-20{left:83.33333333%}.ant-col-xxl-pull-20{right:83.33333333%}.ant-col-xxl-offset-20{margin-left:83.33333333%}.ant-col-xxl-order-20{order:20}.ant-col-xxl-19{display:block;flex:0 0 79.16666667%;max-width:79.16666667%}.ant-col-xxl-push-19{left:79.16666667%}.ant-col-xxl-pull-19{right:79.16666667%}.ant-col-xxl-offset-19{margin-left:79.16666667%}.ant-col-xxl-order-19{order:19}.ant-col-xxl-18{display:block;flex:0 0 75%;max-width:75%}.ant-col-xxl-push-18{left:75%}.ant-col-xxl-pull-18{right:75%}.ant-col-xxl-offset-18{margin-left:75%}.ant-col-xxl-order-18{order:18}.ant-col-xxl-17{display:block;flex:0 0 70.83333333%;max-width:70.83333333%}.ant-col-xxl-push-17{left:70.83333333%}.ant-col-xxl-pull-17{right:70.83333333%}.ant-col-xxl-offset-17{margin-left:70.83333333%}.ant-col-xxl-order-17{order:17}.ant-col-xxl-16{display:block;flex:0 0 66.66666667%;max-width:66.66666667%}.ant-col-xxl-push-16{left:66.66666667%}.ant-col-xxl-pull-16{right:66.66666667%}.ant-col-xxl-offset-16{margin-left:66.66666667%}.ant-col-xxl-order-16{order:16}.ant-col-xxl-15{display:block;flex:0 0 62.5%;max-width:62.5%}.ant-col-xxl-push-15{left:62.5%}.ant-col-xxl-pull-15{right:62.5%}.ant-col-xxl-offset-15{margin-left:62.5%}.ant-col-xxl-order-15{order:15}.ant-col-xxl-14{display:block;flex:0 0 58.33333333%;max-width:58.33333333%}.ant-col-xxl-push-14{left:58.33333333%}.ant-col-xxl-pull-14{right:58.33333333%}.ant-col-xxl-offset-14{margin-left:58.33333333%}.ant-col-xxl-order-14{order:14}.ant-col-xxl-13{display:block;flex:0 0 54.16666667%;max-width:54.16666667%}.ant-col-xxl-push-13{left:54.16666667%}.ant-col-xxl-pull-13{right:54.16666667%}.ant-col-xxl-offset-13{margin-left:54.16666667%}.ant-col-xxl-order-13{order:13}.ant-col-xxl-12{display:block;flex:0 0 50%;max-width:50%}.ant-col-xxl-push-12{left:50%}.ant-col-xxl-pull-12{right:50%}.ant-col-xxl-offset-12{margin-left:50%}.ant-col-xxl-order-12{order:12}.ant-col-xxl-11{display:block;flex:0 0 45.83333333%;max-width:45.83333333%}.ant-col-xxl-push-11{left:45.83333333%}.ant-col-xxl-pull-11{right:45.83333333%}.ant-col-xxl-offset-11{margin-left:45.83333333%}.ant-col-xxl-order-11{order:11}.ant-col-xxl-10{display:block;flex:0 0 41.66666667%;max-width:41.66666667%}.ant-col-xxl-push-10{left:41.66666667%}.ant-col-xxl-pull-10{right:41.66666667%}.ant-col-xxl-offset-10{margin-left:41.66666667%}.ant-col-xxl-order-10{order:10}.ant-col-xxl-9{display:block;flex:0 0 37.5%;max-width:37.5%}.ant-col-xxl-push-9{left:37.5%}.ant-col-xxl-pull-9{right:37.5%}.ant-col-xxl-offset-9{margin-left:37.5%}.ant-col-xxl-order-9{order:9}.ant-col-xxl-8{display:block;flex:0 0 33.33333333%;max-width:33.33333333%}.ant-col-xxl-push-8{left:33.33333333%}.ant-col-xxl-pull-8{right:33.33333333%}.ant-col-xxl-offset-8{margin-left:33.33333333%}.ant-col-xxl-order-8{order:8}.ant-col-xxl-7{display:block;flex:0 0 29.16666667%;max-width:29.16666667%}.ant-col-xxl-push-7{left:29.16666667%}.ant-col-xxl-pull-7{right:29.16666667%}.ant-col-xxl-offset-7{margin-left:29.16666667%}.ant-col-xxl-order-7{order:7}.ant-col-xxl-6{display:block;flex:0 0 25%;max-width:25%}.ant-col-xxl-push-6{left:25%}.ant-col-xxl-pull-6{right:25%}.ant-col-xxl-offset-6{margin-left:25%}.ant-col-xxl-order-6{order:6}.ant-col-xxl-5{display:block;flex:0 0 20.83333333%;max-width:20.83333333%}.ant-col-xxl-push-5{left:20.83333333%}.ant-col-xxl-pull-5{right:20.83333333%}.ant-col-xxl-offset-5{margin-left:20.83333333%}.ant-col-xxl-order-5{order:5}.ant-col-xxl-4{display:block;flex:0 0 16.66666667%;max-width:16.66666667%}.ant-col-xxl-push-4{left:16.66666667%}.ant-col-xxl-pull-4{right:16.66666667%}.ant-col-xxl-offset-4{margin-left:16.66666667%}.ant-col-xxl-order-4{order:4}.ant-col-xxl-3{display:block;flex:0 0 12.5%;max-width:12.5%}.ant-col-xxl-push-3{left:12.5%}.ant-col-xxl-pull-3{right:12.5%}.ant-col-xxl-offset-3{margin-left:12.5%}.ant-col-xxl-order-3{order:3}.ant-col-xxl-2{display:block;flex:0 0 8.33333333%;max-width:8.33333333%}.ant-col-xxl-push-2{left:8.33333333%}.ant-col-xxl-pull-2{right:8.33333333%}.ant-col-xxl-offset-2{margin-left:8.33333333%}.ant-col-xxl-order-2{order:2}.ant-col-xxl-1{display:block;flex:0 0 4.16666667%;max-width:4.16666667%}.ant-col-xxl-push-1{left:4.16666667%}.ant-col-xxl-pull-1{right:4.16666667%}.ant-col-xxl-offset-1{margin-left:4.16666667%}.ant-col-xxl-order-1{order:1}.ant-col-xxl-0{display:none}.ant-col-push-0{left:auto}.ant-col-pull-0{right:auto}.ant-col-xxl-push-0{left:auto}.ant-col-xxl-pull-0{right:auto}.ant-col-xxl-offset-0{margin-left:0}.ant-col-xxl-order-0{order:0}.ant-col-push-0.ant-col-rtl{right:auto}.ant-col-pull-0.ant-col-rtl{left:auto}.ant-col-xxl-push-0.ant-col-rtl{right:auto}.ant-col-xxl-pull-0.ant-col-rtl{left:auto}.ant-col-xxl-offset-0.ant-col-rtl{margin-right:0}.ant-col-xxl-push-1.ant-col-rtl{right:4.16666667%;left:auto}.ant-col-xxl-pull-1.ant-col-rtl{right:auto;left:4.16666667%}.ant-col-xxl-offset-1.ant-col-rtl{margin-right:4.16666667%;margin-left:0}.ant-col-xxl-push-2.ant-col-rtl{right:8.33333333%;left:auto}.ant-col-xxl-pull-2.ant-col-rtl{right:auto;left:8.33333333%}.ant-col-xxl-offset-2.ant-col-rtl{margin-right:8.33333333%;margin-left:0}.ant-col-xxl-push-3.ant-col-rtl{right:12.5%;left:auto}.ant-col-xxl-pull-3.ant-col-rtl{right:auto;left:12.5%}.ant-col-xxl-offset-3.ant-col-rtl{margin-right:12.5%;margin-left:0}.ant-col-xxl-push-4.ant-col-rtl{right:16.66666667%;left:auto}.ant-col-xxl-pull-4.ant-col-rtl{right:auto;left:16.66666667%}.ant-col-xxl-offset-4.ant-col-rtl{margin-right:16.66666667%;margin-left:0}.ant-col-xxl-push-5.ant-col-rtl{right:20.83333333%;left:auto}.ant-col-xxl-pull-5.ant-col-rtl{right:auto;left:20.83333333%}.ant-col-xxl-offset-5.ant-col-rtl{margin-right:20.83333333%;margin-left:0}.ant-col-xxl-push-6.ant-col-rtl{right:25%;left:auto}.ant-col-xxl-pull-6.ant-col-rtl{right:auto;left:25%}.ant-col-xxl-offset-6.ant-col-rtl{margin-right:25%;margin-left:0}.ant-col-xxl-push-7.ant-col-rtl{right:29.16666667%;left:auto}.ant-col-xxl-pull-7.ant-col-rtl{right:auto;left:29.16666667%}.ant-col-xxl-offset-7.ant-col-rtl{margin-right:29.16666667%;margin-left:0}.ant-col-xxl-push-8.ant-col-rtl{right:33.33333333%;left:auto}.ant-col-xxl-pull-8.ant-col-rtl{right:auto;left:33.33333333%}.ant-col-xxl-offset-8.ant-col-rtl{margin-right:33.33333333%;margin-left:0}.ant-col-xxl-push-9.ant-col-rtl{right:37.5%;left:auto}.ant-col-xxl-pull-9.ant-col-rtl{right:auto;left:37.5%}.ant-col-xxl-offset-9.ant-col-rtl{margin-right:37.5%;margin-left:0}.ant-col-xxl-push-10.ant-col-rtl{right:41.66666667%;left:auto}.ant-col-xxl-pull-10.ant-col-rtl{right:auto;left:41.66666667%}.ant-col-xxl-offset-10.ant-col-rtl{margin-right:41.66666667%;margin-left:0}.ant-col-xxl-push-11.ant-col-rtl{right:45.83333333%;left:auto}.ant-col-xxl-pull-11.ant-col-rtl{right:auto;left:45.83333333%}.ant-col-xxl-offset-11.ant-col-rtl{margin-right:45.83333333%;margin-left:0}.ant-col-xxl-push-12.ant-col-rtl{right:50%;left:auto}.ant-col-xxl-pull-12.ant-col-rtl{right:auto;left:50%}.ant-col-xxl-offset-12.ant-col-rtl{margin-right:50%;margin-left:0}.ant-col-xxl-push-13.ant-col-rtl{right:54.16666667%;left:auto}.ant-col-xxl-pull-13.ant-col-rtl{right:auto;left:54.16666667%}.ant-col-xxl-offset-13.ant-col-rtl{margin-right:54.16666667%;margin-left:0}.ant-col-xxl-push-14.ant-col-rtl{right:58.33333333%;left:auto}.ant-col-xxl-pull-14.ant-col-rtl{right:auto;left:58.33333333%}.ant-col-xxl-offset-14.ant-col-rtl{margin-right:58.33333333%;margin-left:0}.ant-col-xxl-push-15.ant-col-rtl{right:62.5%;left:auto}.ant-col-xxl-pull-15.ant-col-rtl{right:auto;left:62.5%}.ant-col-xxl-offset-15.ant-col-rtl{margin-right:62.5%;margin-left:0}.ant-col-xxl-push-16.ant-col-rtl{right:66.66666667%;left:auto}.ant-col-xxl-pull-16.ant-col-rtl{right:auto;left:66.66666667%}.ant-col-xxl-offset-16.ant-col-rtl{margin-right:66.66666667%;margin-left:0}.ant-col-xxl-push-17.ant-col-rtl{right:70.83333333%;left:auto}.ant-col-xxl-pull-17.ant-col-rtl{right:auto;left:70.83333333%}.ant-col-xxl-offset-17.ant-col-rtl{margin-right:70.83333333%;margin-left:0}.ant-col-xxl-push-18.ant-col-rtl{right:75%;left:auto}.ant-col-xxl-pull-18.ant-col-rtl{right:auto;left:75%}.ant-col-xxl-offset-18.ant-col-rtl{margin-right:75%;margin-left:0}.ant-col-xxl-push-19.ant-col-rtl{right:79.16666667%;left:auto}.ant-col-xxl-pull-19.ant-col-rtl{right:auto;left:79.16666667%}.ant-col-xxl-offset-19.ant-col-rtl{margin-right:79.16666667%;margin-left:0}.ant-col-xxl-push-20.ant-col-rtl{right:83.33333333%;left:auto}.ant-col-xxl-pull-20.ant-col-rtl{right:auto;left:83.33333333%}.ant-col-xxl-offset-20.ant-col-rtl{margin-right:83.33333333%;margin-left:0}.ant-col-xxl-push-21.ant-col-rtl{right:87.5%;left:auto}.ant-col-xxl-pull-21.ant-col-rtl{right:auto;left:87.5%}.ant-col-xxl-offset-21.ant-col-rtl{margin-right:87.5%;margin-left:0}.ant-col-xxl-push-22.ant-col-rtl{right:91.66666667%;left:auto}.ant-col-xxl-pull-22.ant-col-rtl{right:auto;left:91.66666667%}.ant-col-xxl-offset-22.ant-col-rtl{margin-right:91.66666667%;margin-left:0}.ant-col-xxl-push-23.ant-col-rtl{right:95.83333333%;left:auto}.ant-col-xxl-pull-23.ant-col-rtl{right:auto;left:95.83333333%}.ant-col-xxl-offset-23.ant-col-rtl{margin-right:95.83333333%;margin-left:0}.ant-col-xxl-push-24.ant-col-rtl{right:100%;left:auto}.ant-col-xxl-pull-24.ant-col-rtl{right:auto;left:100%}.ant-col-xxl-offset-24.ant-col-rtl{margin-right:100%;margin-left:0}}.ant-row-rtl{direction:rtl}.conversation___TJbiP{position:relative;margin-top:30px;padding:0 10px}.conversation___TJbiP .conversationSection___HsioJ{width:100%;height:100%}.conversation___TJbiP .conversationSection___HsioJ .sectionTitle___2tcoL{margin-bottom:12px;color:var(--text-color);font-size:16px;line-height:24px}.conversation___TJbiP .conversationSection___HsioJ .conversationList___1JJCj .conversationItem___3rc1d{cursor:pointer}.conversation___TJbiP .conversationSection___HsioJ .conversationList___1JJCj .conversationItem___3rc1d .conversationItemContent___1Yy3m{display:flex;align-items:center;padding:10px 0;color:var(--text-color-third)}.conversation___TJbiP .conversationSection___HsioJ .conversationList___1JJCj .conversationItem___3rc1d .conversationItemContent___1Yy3m .conversationIcon___31q0k{margin-right:10px;color:var(--text-color-fourth);font-size:20px}.conversation___TJbiP .conversationSection___HsioJ .conversationList___1JJCj .conversationItem___3rc1d .conversationItemContent___1Yy3m .conversationContent___3cv34{width:160px;overflow:hidden;color:var(--text-color-third);white-space:nowrap;text-overflow:ellipsis}.conversation___TJbiP .conversationSection___HsioJ .conversationList___1JJCj .conversationItem___3rc1d.activeConversationItem___7NFEq .conversationContent___3cv34,.conversation___TJbiP .conversationSection___HsioJ .conversationList___1JJCj .conversationItem___3rc1d:hover .conversationContent___3cv34{color:var(--chat-blue)}.ant-select-auto-complete{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum"}.ant-select-auto-complete .ant-select-clear{right:13px}.ant-select-single .ant-select-selector{display:flex}.ant-select-single .ant-select-selector .ant-select-selection-search{position:absolute;top:0;right:11px;bottom:0;left:11px}.ant-select-single .ant-select-selector .ant-select-selection-search-input{width:100%}.ant-select-single .ant-select-selector .ant-select-selection-item,.ant-select-single .ant-select-selector .ant-select-selection-placeholder{padding:0;line-height:30px;transition:all .3s,visibility 0s}.ant-select-single .ant-select-selector .ant-select-selection-item{position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-select-single .ant-select-selector .ant-select-selection-placeholder{transition:none;pointer-events:none}.ant-select-single .ant-select-selector .ant-select-selection-item:after,.ant-select-single .ant-select-selector .ant-select-selection-placeholder:after,.ant-select-single .ant-select-selector:after{display:inline-block;width:0;visibility:hidden;content:"\a0"}.ant-select-single.ant-select-show-arrow .ant-select-selection-search{right:25px}.ant-select-single.ant-select-show-arrow .ant-select-selection-item,.ant-select-single.ant-select-show-arrow .ant-select-selection-placeholder{padding-right:18px}.ant-select-single.ant-select-open .ant-select-selection-item{color:#bfbfbf}.ant-select-single:not(.ant-select-customize-input) .ant-select-selector{width:100%;height:32px;padding:0 11px}.ant-select-single:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-search-input{height:30px}.ant-select-single:not(.ant-select-customize-input) .ant-select-selector:after{line-height:30px}.ant-select-single.ant-select-customize-input .ant-select-selector:after{display:none}.ant-select-single.ant-select-customize-input .ant-select-selector .ant-select-selection-search{position:static;width:100%}.ant-select-single.ant-select-customize-input .ant-select-selector .ant-select-selection-placeholder{position:absolute;right:0;left:0;padding:0 11px}.ant-select-single.ant-select-customize-input .ant-select-selector .ant-select-selection-placeholder:after{display:none}.ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector{height:40px}.ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-item,.ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-placeholder,.ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector:after{line-height:38px}.ant-select-single.ant-select-lg:not(.ant-select-customize-input):not(.ant-select-customize-input) .ant-select-selection-search-input{height:38px}.ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector{height:24px}.ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-item,.ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-placeholder,.ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector:after{line-height:22px}.ant-select-single.ant-select-sm:not(.ant-select-customize-input):not(.ant-select-customize-input) .ant-select-selection-search-input{height:22px}.ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selection-search{right:7px;left:7px}.ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector{padding:0 7px}.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-search{right:28px}.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-item,.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-placeholder{padding-right:21px}.ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector{padding:0 11px}.ant-select-selection-overflow{position:relative;display:flex;flex:auto;flex-wrap:wrap;max-width:100%}.ant-select-selection-overflow-item{flex:none;align-self:center;max-width:100%}.ant-select-multiple .ant-select-selector{display:flex;flex-wrap:wrap;align-items:center;padding:1px 4px}.ant-select-show-search.ant-select-multiple .ant-select-selector{cursor:text}.ant-select-disabled.ant-select-multiple .ant-select-selector{background:#f5f5f5;cursor:not-allowed}.ant-select-multiple .ant-select-selector:after{display:inline-block;width:0;margin:2px 0;line-height:24px;visibility:hidden;content:"\a0"}.ant-select-multiple.ant-select-allow-clear .ant-select-selector,.ant-select-multiple.ant-select-show-arrow .ant-select-selector{padding-right:24px}.ant-select-multiple .ant-select-selection-item{position:relative;display:flex;flex:none;box-sizing:border-box;max-width:100%;height:24px;margin-top:2px;margin-bottom:2px;line-height:22px;background:#f5f5f5;border:1px solid #f0f0f0;border-radius:4px;cursor:default;transition:font-size .3s,line-height .3s,height .3s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-margin-end:4px;margin-inline-end:4px;-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:4px;padding-inline-end:4px}.ant-select-disabled.ant-select-multiple .ant-select-selection-item{color:#bfbfbf;border-color:#d9d9d9;cursor:not-allowed}.ant-select-multiple .ant-select-selection-item-content{display:inline-block;margin-right:4px;overflow:hidden;white-space:pre;text-overflow:ellipsis}.ant-select-multiple .ant-select-selection-item-remove{color:inherit;font-style:normal;line-height:0;text-align:center;text-transform:none;vertical-align:-.125em;text-rendering:optimizelegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;color:rgba(0,10,36,.65);font-weight:700;font-size:10px;line-height:inherit;cursor:pointer}.ant-select-multiple .ant-select-selection-item-remove>*{line-height:1}.ant-select-multiple .ant-select-selection-item-remove svg{display:inline-block}.ant-select-multiple .ant-select-selection-item-remove:before{display:none}.ant-select-multiple .ant-select-selection-item-remove .ant-select-multiple .ant-select-selection-item-remove-icon{display:block}.ant-select-multiple .ant-select-selection-item-remove>.anticon{vertical-align:middle}.ant-select-multiple .ant-select-selection-item-remove:hover{color:rgba(0,0,0,.75)}.ant-select-multiple .ant-select-selection-overflow-item+.ant-select-selection-overflow-item .ant-select-selection-search{-webkit-margin-start:0;margin-inline-start:0}.ant-select-multiple .ant-select-selection-search{position:relative;max-width:100%;-webkit-margin-start:7px;margin-inline-start:7px}.ant-select-multiple .ant-select-selection-search-input,.ant-select-multiple .ant-select-selection-search-mirror{height:24px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";line-height:24px;transition:all .3s}.ant-select-multiple .ant-select-selection-search-input{width:100%;min-width:4.1px}.ant-select-multiple .ant-select-selection-search-mirror{position:absolute;top:0;left:0;z-index:999;white-space:pre;visibility:hidden}.ant-select-multiple .ant-select-selection-placeholder{position:absolute;top:50%;right:11px;left:11px;transform:translateY(-50%);transition:all .3s}.ant-select-multiple.ant-select-lg .ant-select-selector:after{line-height:32px}.ant-select-multiple.ant-select-lg .ant-select-selection-item{line-height:30px}.ant-select-multiple.ant-select-lg .ant-select-selection-search{height:32px;line-height:32px}.ant-select-multiple.ant-select-lg .ant-select-selection-search-input,.ant-select-multiple.ant-select-lg .ant-select-selection-search-mirror{height:32px;line-height:30px}.ant-select-multiple.ant-select-sm .ant-select-selector:after{line-height:16px}.ant-select-multiple.ant-select-sm .ant-select-selection-item{height:16px;line-height:14px}.ant-select-multiple.ant-select-sm .ant-select-selection-search{height:16px;line-height:16px}.ant-select-multiple.ant-select-sm .ant-select-selection-search-input,.ant-select-multiple.ant-select-sm .ant-select-selection-search-mirror{height:16px;line-height:14px}.ant-select-multiple.ant-select-sm .ant-select-selection-placeholder{left:7px}.ant-select-multiple.ant-select-sm .ant-select-selection-search{-webkit-margin-start:3px;margin-inline-start:3px}.ant-select-multiple.ant-select-lg .ant-select-selection-item{height:32px;line-height:32px}.ant-select-disabled .ant-select-selection-item-remove{display:none}.ant-select-status-error.ant-select:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer) .ant-select-selector{background-color:#fff;border-color:#ef4872!important}.ant-select-status-error.ant-select:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer).ant-select-focused .ant-select-selector,.ant-select-status-error.ant-select:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer).ant-select-open .ant-select-selector{border-color:#fc7492;box-shadow:0 0 0 2px rgba(239,72,114,.2);border-right-width:1px;outline:0}.ant-select-status-warning.ant-select:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer) .ant-select-selector{background-color:#fff;border-color:#ffb924!important}.ant-select-status-warning.ant-select:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer).ant-select-focused .ant-select-selector,.ant-select-status-warning.ant-select:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer).ant-select-open .ant-select-selector{border-color:#ffcc4d;box-shadow:0 0 0 2px rgba(255,185,36,.2);border-right-width:1px;outline:0}.ant-select-status-error.ant-select-has-feedback .ant-select-clear,.ant-select-status-success.ant-select-has-feedback .ant-select-clear,.ant-select-status-validating.ant-select-has-feedback .ant-select-clear,.ant-select-status-warning.ant-select-has-feedback .ant-select-clear{right:32px}.ant-select-status-error.ant-select-has-feedback .ant-select-selection-selected-value,.ant-select-status-success.ant-select-has-feedback .ant-select-selection-selected-value,.ant-select-status-validating.ant-select-has-feedback .ant-select-selection-selected-value,.ant-select-status-warning.ant-select-has-feedback .ant-select-selection-selected-value{padding-right:42px}.ant-select{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:inline-block;cursor:pointer}.ant-select:not(.ant-select-customize-input) .ant-select-selector{position:relative;background-color:#fff;border:1px solid #d9d9d9;border-radius:4px;transition:all .3s cubic-bezier(.645,.045,.355,1)}.ant-select:not(.ant-select-customize-input) .ant-select-selector input{cursor:pointer}.ant-select-show-search.ant-select:not(.ant-select-customize-input) .ant-select-selector{cursor:text}.ant-select-show-search.ant-select:not(.ant-select-customize-input) .ant-select-selector input{cursor:auto}.ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) .ant-select-selector{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-select-disabled.ant-select:not(.ant-select-customize-input) .ant-select-selector{color:rgba(0,0,0,.25);background:#f5f5f5;cursor:not-allowed}.ant-select-multiple.ant-select-disabled.ant-select:not(.ant-select-customize-input) .ant-select-selector{background:#f5f5f5}.ant-select-disabled.ant-select:not(.ant-select-customize-input) .ant-select-selector input{cursor:not-allowed}.ant-select:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-search-input{margin:0;padding:0;background:transparent;border:none;outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.ant-select:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-search-input::-webkit-search-cancel-button{display:none;-webkit-appearance:none}.ant-select:not(.ant-select-disabled):hover .ant-select-selector{border-color:#4e86f5;border-right-width:1px}.ant-select-selection-item{flex:1 1;overflow:hidden;font-weight:400;white-space:nowrap;text-overflow:ellipsis}@media (-ms-high-contrast:none){.ant-select-selection-item,.ant-select-selection-item ::-ms-backdrop{flex:auto}}.ant-select-selection-placeholder{flex:1 1;overflow:hidden;color:#bfbfbf;white-space:nowrap;text-overflow:ellipsis;pointer-events:none}@media (-ms-high-contrast:none){.ant-select-selection-placeholder,.ant-select-selection-placeholder ::-ms-backdrop{flex:auto}}.ant-select-arrow{display:inline-block;color:inherit;font-style:normal;line-height:0;text-transform:none;vertical-align:-.125em;text-rendering:optimizelegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;position:absolute;top:50%;right:11px;display:flex;align-items:center;height:12px;margin-top:-6px;color:rgba(0,0,0,.25);font-size:12px;line-height:1;text-align:center;pointer-events:none}.ant-select-arrow>*{line-height:1}.ant-select-arrow svg{display:inline-block}.ant-select-arrow:before{display:none}.ant-select-arrow .ant-select-arrow-icon{display:block}.ant-select-arrow .anticon{vertical-align:top;transition:transform .3s}.ant-select-arrow .anticon>svg{vertical-align:top}.ant-select-arrow .anticon:not(.ant-select-suffix){pointer-events:auto}.ant-select-disabled .ant-select-arrow{cursor:not-allowed}.ant-select-arrow>:not(:last-child){-webkit-margin-end:8px;margin-inline-end:8px}.ant-select-clear{position:absolute;top:50%;right:11px;z-index:1;display:inline-block;width:12px;height:12px;margin-top:-6px;color:rgba(0,0,0,.25);font-size:12px;font-style:normal;line-height:1;text-align:center;text-transform:none;background:#fff;cursor:pointer;opacity:0;transition:color .3s ease,opacity .15s ease;text-rendering:auto}.ant-select-clear:before{display:block}.ant-select-clear:hover{color:rgba(0,10,36,.65)}.ant-select:hover .ant-select-clear{opacity:1}.ant-select-dropdown{margin:0;color:rgba(0,10,36,.85);font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum",;position:absolute;top:-9999px;left:-9999px;z-index:1050;box-sizing:border-box;padding:4px 0;overflow:hidden;font-size:14px;font-variant:normal;background-color:#fff;border-radius:4px;outline:none;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}.ant-select-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-select-dropdown-placement-bottomLeft,.ant-select-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-select-dropdown-placement-bottomLeft{animation-name:antSlideUpIn}.ant-select-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-select-dropdown-placement-topLeft,.ant-select-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-select-dropdown-placement-topLeft{animation-name:antSlideDownIn}.ant-select-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-select-dropdown-placement-bottomLeft{animation-name:antSlideUpOut}.ant-select-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-select-dropdown-placement-topLeft{animation-name:antSlideDownOut}.ant-select-dropdown-hidden{display:none}.ant-select-dropdown-empty{color:rgba(0,0,0,.25)}.ant-select-item-empty{position:relative;display:block;min-height:32px;padding:5px 12px;color:rgba(0,10,36,.85);font-weight:400;font-size:14px;line-height:22px;color:rgba(0,0,0,.25)}.ant-select-item{position:relative;display:block;min-height:32px;padding:5px 12px;color:rgba(0,10,36,.85);font-weight:400;font-size:14px;line-height:22px;cursor:pointer;transition:background .3s ease}.ant-select-item-group{color:rgba(0,10,36,.65);font-size:12px;cursor:default}.ant-select-item-option{display:flex}.ant-select-item-option-content{flex:auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-select-item-option-state{flex:none}.ant-select-item-option-active:not(.ant-select-item-option-disabled){background-color:#f5f5f5}.ant-select-item-option-selected:not(.ant-select-item-option-disabled){color:rgba(0,10,36,.85);font-weight:600;background-color:#e3ecfd}.ant-select-item-option-selected:not(.ant-select-item-option-disabled) .ant-select-item-option-state{color:#296df3}.ant-select-item-option-disabled{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-select-item-option-disabled.ant-select-item-option-selected{background-color:#f5f5f5}.ant-select-item-option-grouped{padding-left:24px}.ant-select-lg{font-size:16px}.ant-select-borderless .ant-select-selector{background-color:transparent!important;border-color:transparent!important;box-shadow:none!important}.ant-select.ant-select-in-form-item{width:100%}.ant-select-compact-item:not(.ant-select-compact-last-item){margin-right:-1px}.ant-select-compact-item:not(.ant-select-compact-last-item).ant-select-compact-item-rtl{margin-right:0;margin-left:-1px}.ant-select-compact-item:active>*,.ant-select-compact-item:focus>*,.ant-select-compact-item:hover>*{z-index:2}.ant-select-compact-item.ant-select-focused>*{z-index:2}.ant-select-compact-item[disabled]>*{z-index:0}.ant-select-compact-item:not(.ant-select-compact-first-item):not(.ant-select-compact-last-item).ant-select>.ant-select-selector{border-radius:0}.ant-select-compact-item.ant-select-compact-first-item.ant-select:not(.ant-select-compact-last-item):not(.ant-select-compact-item-rtl)>.ant-select-selector{border-top-right-radius:0;border-bottom-right-radius:0}.ant-select-compact-item.ant-select-compact-last-item.ant-select:not(.ant-select-compact-first-item):not(.ant-select-compact-item-rtl)>.ant-select-selector{border-top-left-radius:0;border-bottom-left-radius:0}.ant-select-compact-item.ant-select.ant-select-compact-first-item.ant-select-compact-item-rtl:not(.ant-select-compact-last-item)>.ant-select-selector{border-top-left-radius:0;border-bottom-left-radius:0}.ant-select-compact-item.ant-select.ant-select-compact-last-item.ant-select-compact-item-rtl:not(.ant-select-compact-first-item)>.ant-select-selector{border-top-right-radius:0;border-bottom-right-radius:0}.ant-select-rtl{direction:rtl}.ant-select-rtl .ant-select-arrow{right:auto;left:11px}.ant-select-rtl .ant-select-clear{right:auto;left:11px}.ant-select-dropdown-rtl{direction:rtl}.ant-select-dropdown-rtl .ant-select-item-option-grouped{padding-right:24px;padding-left:12px}.ant-select-rtl.ant-select-multiple.ant-select-allow-clear .ant-select-selector,.ant-select-rtl.ant-select-multiple.ant-select-show-arrow .ant-select-selector{padding-right:4px;padding-left:24px}.ant-select-rtl.ant-select-multiple .ant-select-selection-item{text-align:right}.ant-select-rtl.ant-select-multiple .ant-select-selection-item-content{margin-right:0;margin-left:4px;text-align:right}.ant-select-rtl.ant-select-multiple .ant-select-selection-search-mirror{right:0;left:auto}.ant-select-rtl.ant-select-multiple .ant-select-selection-placeholder{right:11px;left:auto}.ant-select-rtl.ant-select-multiple.ant-select-sm .ant-select-selection-placeholder{right:7px}.ant-select-rtl.ant-select-single .ant-select-selector .ant-select-selection-item,.ant-select-rtl.ant-select-single .ant-select-selector .ant-select-selection-placeholder{right:0;left:9px;text-align:right}.ant-select-rtl.ant-select-single.ant-select-show-arrow .ant-select-selection-search{right:11px;left:25px}.ant-select-rtl.ant-select-single.ant-select-show-arrow .ant-select-selection-item,.ant-select-rtl.ant-select-single.ant-select-show-arrow .ant-select-selection-placeholder{padding-right:0;padding-left:18px}.ant-select-rtl.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-search{right:6px}.ant-select-rtl.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-item,.ant-select-rtl.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-placeholder{padding-right:0;padding-left:21px}.ant-empty{margin:0 8px;font-size:14px;line-height:1.5715;text-align:center}.ant-empty-image{height:100px;margin-bottom:8px}.ant-empty-image img{height:100%}.ant-empty-image svg{height:100%;margin:auto}.ant-empty-footer{margin-top:16px}.ant-empty-normal{margin:32px 0;color:rgba(0,0,0,.25)}.ant-empty-normal .ant-empty-image{height:40px}.ant-empty-small{margin:8px 0;color:rgba(0,0,0,.25)}.ant-empty-small .ant-empty-image{height:35px}.ant-empty-img-default-ellipse{fill:#f5f5f5;fill-opacity:.8}.ant-empty-img-default-path-1{fill:#aeb8c2}.ant-empty-img-default-path-2{fill:url(#linearGradient-1)}.ant-empty-img-default-path-3{fill:#f5f5f7}.ant-empty-img-default-path-4{fill:#dce0e6}.ant-empty-img-default-path-5{fill:#dce0e6}.ant-empty-img-default-g{fill:#fff}.ant-empty-img-simple-ellipse{fill:#f5f5f5}.ant-empty-img-simple-g{stroke:#d9d9d9}.ant-empty-img-simple-path{fill:#fafafa}.ant-empty-rtl{direction:rtl}.ant-tag{box-sizing:border-box;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-block;height:auto;margin:0 8px 0 0;padding:0 7px;font-size:12px;line-height:20px;white-space:nowrap;background:#fafafa;border:1px solid #d9d9d9;border-radius:4px;opacity:1;transition:all .3s}.ant-tag,.ant-tag a,.ant-tag a:hover{color:rgba(0,10,36,.85)}.ant-tag>a:first-child:last-child{display:inline-block;margin:0 -8px;padding:0 8px}.ant-tag-close-icon{margin-left:3px;color:rgba(0,10,36,.65);font-size:10px;cursor:pointer;transition:all .3s}.ant-tag-close-icon:hover{color:rgba(0,10,36,.85)}.ant-tag-has-color{border-color:transparent}.ant-tag-has-color,.ant-tag-has-color .anticon-close,.ant-tag-has-color .anticon-close:hover,.ant-tag-has-color a,.ant-tag-has-color a:hover{color:#fff}.ant-tag-checkable{background-color:transparent;border-color:transparent;cursor:pointer}.ant-tag-checkable:not(.ant-tag-checkable-checked):hover{color:#296df3}.ant-tag-checkable-checked,.ant-tag-checkable:active{color:#fff}.ant-tag-checkable-checked{background-color:#296df3}.ant-tag-checkable:active{background-color:#0d57e8}.ant-tag-hidden{display:none}.ant-tag-pink{color:#c41d7f;background:#fff0f6;border-color:#ffadd2}.ant-tag-pink-inverse{color:#fff;background:#eb2f96;border-color:#eb2f96}.ant-tag-magenta{color:#c41d7f;background:#fff0f6;border-color:#ffadd2}.ant-tag-magenta-inverse{color:#fff;background:#eb2f96;border-color:#eb2f96}.ant-tag-red{color:#cf1322;background:#fff1f0;border-color:#ffa39e}.ant-tag-red-inverse{color:#fff;background:#f5222d;border-color:#f5222d}.ant-tag-volcano{color:#d4380d;background:#fff2e8;border-color:#ffbb96}.ant-tag-volcano-inverse{color:#fff;background:#fa541c;border-color:#fa541c}.ant-tag-orange{color:#d46b08;background:#fff7e6;border-color:#ffd591}.ant-tag-orange-inverse{color:#fff;background:#fa8c16;border-color:#fa8c16}.ant-tag-yellow{color:#d4b106;background:#feffe6;border-color:#fffb8f}.ant-tag-yellow-inverse{color:#fff;background:#fadb14;border-color:#fadb14}.ant-tag-gold{color:#d99414;background:#fffdf0;border-color:#ffea9e}.ant-tag-gold-inverse{color:#fff;background:#ffb924;border-color:#ffb924}.ant-tag-cyan{color:#08979c;background:#e6fffb;border-color:#87e8de}.ant-tag-cyan-inverse{color:#fff;background:#13c2c2;border-color:#13c2c2}.ant-tag-lime{color:#7cb305;background:#fcffe6;border-color:#eaff8f}.ant-tag-lime-inverse{color:#fff;background:#a0d911;border-color:#a0d911}.ant-tag-green{color:#17a379;background:#f0fff7;border-color:#a1f0cd}.ant-tag-green-inverse{color:#fff;background:#26c992;border-color:#26c992}.ant-tag-blue{color:#184ecc;background:#f0f7ff;border-color:#a6ccff}.ant-tag-blue-inverse{color:#fff;background:#296df3;border-color:#296df3}.ant-tag-geekblue{color:#1d39c4;background:#f0f5ff;border-color:#adc6ff}.ant-tag-geekblue-inverse{color:#fff;background:#2f54eb;border-color:#2f54eb}.ant-tag-purple{color:#531dab;background:#f9f0ff;border-color:#d3adf7}.ant-tag-purple-inverse{color:#fff;background:#722ed1;border-color:#722ed1}.ant-tag-success{color:#26c992;background:#f0fff7;border-color:#a1f0cd}.ant-tag-processing{color:#296df3;background:#f0f7ff;border-color:#a6ccff}.ant-tag-error{color:#ef4872;background:#fff0f1;border-color:#ffc7cf}.ant-tag-warning{color:#ffb924;background:#fffdf0;border-color:#ffea9e}.ant-tag>.anticon+span,.ant-tag>span+.anticon{margin-left:7px}.ant-tag.ant-tag-rtl{margin-right:0;margin-left:8px;direction:rtl;text-align:right}.ant-tag-rtl .ant-tag-close-icon{margin-right:3px;margin-left:0}.ant-tag-rtl.ant-tag>.anticon+span,.ant-tag-rtl.ant-tag>span+.anticon{margin-right:7px;margin-left:0}.chatFooter___3U7Ja{position:relative;z-index:10;display:flex;flex-direction:column;margin-top:6px;margin-right:20px;margin-bottom:40px}.chatFooter___3U7Ja .composer___nXwyD{display:flex;height:46px}.chatFooter___3U7Ja .composer___nXwyD .collapseBtn___3ROh9{height:46px;margin:0 10px;color:var(--text-color-third);font-size:20px;line-height:46px;cursor:pointer}.chatFooter___3U7Ja .composer___nXwyD .collapseBtn___3ROh9:hover{color:var(--chat-blue)}.chatFooter___3U7Ja .composer___nXwyD .addConversation___2gYpO{height:46px;margin:0 20px 0 10px;color:var(--text-color-fourth);font-size:26px;line-height:54px;cursor:pointer}.chatFooter___3U7Ja .composer___nXwyD .addConversation___2gYpO:hover{color:var(--chat-blue)}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj{flex:1 1}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj .composerInput___27grD{width:100%;height:100%}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj .composerInput___27grD .ant-select-selector{box-sizing:border-box;height:100%;overflow:hidden;color:rgba(0,0,0,.87);font-size:16px;word-break:break-all;background:#fff;border:0;border-radius:24px;box-shadow:0 -.5px 0 rgba(0,0,0,.07),0 0 18px rgba(0,0,0,.1);transition:border-color .15s ease-in-out;resize:none}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj .composerInput___27grD .ant-select-selector .ant-select-selection-search-input{height:100%!important;padding:0 20px}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj .composerInput___27grD .ant-select-selector .ant-select-selection-search{right:0!important;left:0!important}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj .composerInput___27grD .ant-select-selector .ant-select-selection-placeholder{padding-left:10px!important;line-height:45px}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj .composerInput___27grD .ant-select-clear{right:auto;left:500px;width:16px;height:16px;margin-top:-8px;font-size:16px}.chatFooter___3U7Ja .composer___nXwyD .composerInputWrapper___33XEj .ant-select-focused .ant-select-selector{box-shadow:0 0 3px #4a72f5!important}.chatFooter___3U7Ja .sendBtn___1mSEb{position:absolute;top:50%;right:6px;display:flex;align-items:center;justify-content:center;width:30px;height:30px;color:#fff;font-size:20px;background-color:#b8b8bf;border:unset;border-radius:50%;transform:translateY(-50%);transition:background-color .3s ease 0s}.chatFooter___3U7Ja .sendBtn___1mSEb.sendBtnActive___2tnLt{background-color:var(--chat-blue)}.chatFooter___3U7Ja.mobile___1ObPp{height:40px;margin:12px 12px 20px}.chatFooter___3U7Ja.mobile___1ObPp .addConversation___2gYpO{height:40px;margin:0 12px 0 4px}.chatFooter___3U7Ja.mobile___1ObPp .composer___nXwyD{height:40px}.chatFooter___3U7Ja.mobile___1ObPp .composer___nXwyD .ant-select-selector{font-size:14px!important}.chatFooter___3U7Ja.mobile___1ObPp .composer___nXwyD .ant-select-selection-placeholder{line-height:39px!important}.searchOption___3IfcA{padding:6px 20px;color:#212121;font-size:16px}.mobile___1ObPp .searchOption___3IfcA{min-height:26px;padding:2px 12px;font-size:14px}.domain___3oxKe{margin-top:2px;color:var(--text-color-fourth);font-size:13px;line-height:12px}.autoCompleteDropdown___1y8g6{left:20px!important;width:-webkit-fit-content!important;width:-moz-fit-content!important;width:fit-content!important;min-width:100px!important;border-radius:6px}.autoCompleteDropdown___1y8g6.domainOptions___3lo34{width:150px!important}.autoCompleteDropdown___1y8g6.domainOptions___3lo34 .searchOption___3IfcA{padding:0 10px;color:var(--text-color-secondary);font-size:14px}.autoCompleteDropdown___1y8g6.domainOptions___3lo34 .ant-select-item{height:30px!important;line-height:30px!important}.semanticType___2NkK7{margin-right:10px}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;font-size:14px}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}:root:root{--primary:180deg 4%;--wy-color:#c20c0c;--detail-width:1300px;--primary-1:#fff0f0;--primary-2:#ffc7c7;--primary-3:#ff9ea1;--primary-4:#ff757e;--primary-5:#ff4d5e;--primary-6:#ff2441;--primary-7:#d91434;--primary-8:rgba(255,36,66,0.1);--info-color:#ff2442;--newrank-color:#ff7800;--warning-color:#faad14;--normal-color:#d9d9d9;--white:#fff;--white-30:hsla(0,0%,100%,0.3);--black:#000;--disabled-color:#afb6b6;--disabled-bg:#eceeee;--border-color-base:#e1e6e6;--chat-border-color-base:#d5d7db;--light-blue-background:rgba(58,100,255,0.1);--link-color:#3a64ff;--link-hover-color:#638aff;--link-active-color:#2748d9;--link-bg-color:rgba(58,100,255,0.1);--text-accent-color:#3a64ff;--primary-green:#31c462;--link-hover-bg-color:rgba(58,100,255,0.06);--success-2:rgba(82,196,26,0.2);--success-pink:#ff8193;--disabled-bg-3:hsla(180,6%,93%,0.3);--tooltip-bg:#fff;--record-btn:#00b354;--record-btn-bg:rgba(0,179,84,0.1);--record-btn-bg-3:rgba(0,179,84,0.3);--border-color-base-bg-5:hsla(180,9%,89%,0.5);--user-gao-color:#fcad36;--user-hao-color:#ec6f6f;--user-all-color:#252526;--nr-menu-highlight-color:#ff2442;--nr-menu-icon-hover-color:#ff2442;--nr-sider-background:#fff;--nr-menu-bg:#fff;--nr-sider-fixed-zindex:12;--nr-header-fixed-zindex:11;--newrank-color-bg:rgba(255,120,0,0.1);--newrank-color-bg-3:rgba(255,120,0,0.3);--warning-05:rgba(250,173,20,0.05);--bridge-account-color:#ff2442;--bridge-agency-color:#3a64ff;--bridge-free-color:#ff7800;--bridge-medium-color:#00b354}.ss-chat-dimension,.ss-chat-metric{position:relative}.ss-chat-dimension:after,.ss-chat-metric:after{position:absolute;right:.5px;bottom:-2px;left:.5px;height:2px;margin:0 1px;content:""}.ss-chat-dimension:after{background:var(--chat-blue)}.ss-chat-metric:after{background:var(--primary-green)}.ss-chat-table-row{cursor:pointer}.ss-chat-even-row{background-color:#fbfbfb}.ss-chat-no-border-table .ant-table-cell{border:none!important}.ss-chat-no-border-table .ant-table-tbody>tr.ant-table-row:hover>td{background-color:#efefef!important}.ss-chat-bar{height:270px;margin-top:16px}.ss-chat-table{margin-top:20px;margin-bottom:20px}.ss-chat-table-photo{display:flex;align-items:center;justify-content:center}.ss-chat-table table{width:100%}.ss-chat-table-even-row{background-color:#fbfbfb}.ss-chat-table .ant-table-container table>thead>tr:first-child th:first-child{border-top-left-radius:12px!important;border-bottom-left-radius:12px!important}.ss-chat-table .ant-table-container table>thead>tr:first-child th:last-child{border-top-right-radius:12px!important;border-bottom-right-radius:12px!important}.ss-chat-table .ant-table-tbody>tr.ant-table-row:hover>td{background-color:#fafafa!important}.ss-chat-table .ant-table-cell{text-align:center!important}.ss-chat-table .ant-table-thead .ant-table-cell{padding-top:10px;padding-bottom:10px;color:#666;font-size:13px;background:#f0f2f5}.ss-chat-table .ant-table-thead .ant-table-cell:before{display:none}.ss-chat-table .ss-chat-table-formatted-value{font-weight:500;font-size:16px}.ss-chat-table .ant-table-thead .ant-table-cell{padding-top:8.5px;padding-bottom:8.5px;color:#737b7b;font-weight:500;font-size:14px;background-color:#edf2f2}.ss-chat-table .ant-table-tbody .ant-table-cell{padding:15px 0;color:#333;font-size:14px}.ss-chat-message-domain-name{color:var(--text-color);margin-bottom:2px;margin-left:4px;font-weight:500}.ss-chat-message-content{display:flex;align-items:flex-start}.ss-chat-message-body{width:100%}.ss-chat-message-bubble{box-sizing:border-box;min-width:1px;max-width:100%;padding:8px 16px 10px;background:hsla(0,0%,100%,.8);border:1px solid transparent;border-radius:12px;box-shadow:0 2px 4px rgba(0,0,0,.14),0 0 2px rgba(0,0,0,.12)}.ss-chat-message-top-bar{position:relative;max-width:100%;padding:4px 0 8px;color:var(--text-color-third);font-size:13px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;border-bottom:1px solid rgba(0,0,0,.03)}.ss-chat-message-filter-section{display:flex;align-items:center;color:var(--text-color-secondary);font-weight:400;font-size:13px}.ss-chat-message-filter-values{display:flex;align-items:center;grid-column-gap:6px;-webkit-column-gap:6px;column-gap:6px}.ss-chat-message-filter-item{padding:2px 12px;color:var(--text-color-secondary);background-color:#edf2f2;border-radius:13px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ss-chat-message-tip{margin-left:6px;color:var(--text-color-third)}.ss-chat-message-info-bar{display:flex;align-items:center;grid-row-gap:12px;row-gap:12px;flex-wrap:wrap;margin-top:20px;grid-column-gap:20px;-webkit-column-gap:20px;column-gap:20px;color:var(--text-color-secondary);background:rgba(133,156,241,.1);padding:4px 12px;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;border-radius:8px}.ss-chat-message-main-entity-info{display:flex;flex-wrap:wrap;align-items:center;font-size:13px;grid-column-gap:20px;-webkit-column-gap:20px;column-gap:20px;grid-row-gap:10px;row-gap:10px}.ss-chat-message-info-item{display:flex;align-items:center}.ss-chat-message-info-name{color:var(--text-color-third)}.ss-chat-message-info-value{color:var(--text-color)}.ss-chat-metric-card{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:150px;grid-row-gap:4px;row-gap:4px}.ss-chat-metric-card-indicator{display:flex;flex-direction:column;align-items:flex-start;justify-content:center}.ss-chat-metric-card-date-range{color:var(--text-color-fourth);font-size:14px}.ss-chat-metric-card-indicator-value{color:var(--text-color);font-weight:600;font-size:30px}.ss-chat-metric-card-indicator-name{color:var(--text-color-fourth);font-size:14px}.ss-chat-metric-trend{display:flex;flex-direction:column;align-items:center;justify-content:center;margin-top:16px;width:100%;grid-row-gap:4px;row-gap:4px}.ss-chat-metric-trend-indicator{display:flex;flex-direction:column;align-items:flex-start;justify-content:center}.ss-chat-metric-trend-date-range{color:var(--text-color-fourth);font-size:14px}.ss-chat-metric-trend-indicator-value{color:var(--text-color);font-weight:600;font-size:30px}.ss-chat-metric-trend-indicator-name{color:var(--text-color-fourth);font-size:14px}.ss-chat-metric-trend-flow-trend-chart{height:270px}.ss-chat-metric-trend-charts{display:flex;flex-direction:column;width:100%;grid-row-gap:16px;row-gap:16px}.ss-chat-metric-trend-metric-fields{display:flex;flex-wrap:wrap;align-items:center;grid-row-gap:12px;row-gap:12px}.ss-chat-metric-trend-metric-field{display:inline-block;box-sizing:border-box;height:auto;margin:0 8px 0 0;padding:1px 8px;color:var(--text-color-third);font-variant:tabular-nums;line-height:20px;white-space:nowrap;list-style:none;border-color:transparent;border-radius:2px;cursor:pointer;opacity:1;transition:all .3s;font-feature-settings:"tnum","tnum","tnum"}.ss-chat-metric-trend-metric-field:hover{color:var(--chat-blue)}.ss-chat-metric-trend-metric-field-active{color:#fff!important;background-color:var(--chat-blue)}.ss-chat-metric-trend-metric-field-single{padding-left:0;font-weight:500;cursor:default;color:var(--text-color-secondary)}.ss-chat-metric-trend-metric-field-single:hover{color:var(--text-color-secondary)}.ss-chat-metric-trend-date-options{display:flex;align-items:center;grid-column-gap:20px;-webkit-column-gap:20px;column-gap:20px;font-size:14px}.ss-chat-metric-trend-date-option{position:relative;color:var(--text-color-secondary);cursor:pointer}.ss-chat-metric-trend-date-option:hover{color:var(--chat-blue)}.ss-chat-metric-trend-date-option-active{color:var(--chat-blue)}.ss-chat-metric-trend-date-option-mobile{font-size:12px}.ss-chat-metric-trend-active-identifier{position:absolute;bottom:-6px;width:100%;height:4px;background-color:var(--chat-blue);border-radius:4px 4px 0 0}.ss-chat-metric-trend-date-option-divider{width:1px;height:16px;background-color:var(--text-color-fifth)}.ss-chat-apply-auth{font-size:14px;color:var(--text-color)}.ss-chat-apply-auth-apply{color:var(--chat-blue);cursor:pointer}.ss-chat-no-permission-chart{position:relative;width:100%;height:300px}.ss-chat-no-permission-chart-holder{width:100%;height:300px}.ss-chat-no-permission-chart-bar-chart-holder{margin-top:20px}.ss-chat-no-permission-chart-no-permission{position:absolute;top:50%;left:50%;padding:4px 12px;transform:translate(-50%,-50%)}.semantic-info-popover-cls{max-width:300px}.semantic-info-popover-cls-spin-box{text-align:center;padding-top:10px}.semantic-info-popover-cls .ant-popover-title{padding:5px 8px 4px}.semantic-info-popover-cls .ant-popover-inner-content{min-height:60px;min-width:185px}.ss-chat-semantic-detail-info-bar{display:flex;flex-wrap:wrap;align-items:center;margin:20px 0;grid-column-gap:20px;-webkit-column-gap:20px;column-gap:20px}.ss-chat-semantic-detail-description{font-size:13px;color:var(--text-color-fourth)}.ss-chat-semantic-detail-main-entity-info{display:flex;flex-wrap:wrap;align-items:center;font-size:13px;grid-column-gap:20px;-webkit-column-gap:20px;column-gap:20px}.ss-chat-semantic-detail-info-item{display:flex;align-items:center}.ss-chat-semantic-detail-info-name{color:var(--text-color-fourth)}.ss-chat-semantic-detail-info-value{color:var(--text-color-secondary)}.ss-chat-semantic-detail-title{font-size:16px;margin-left:15px;line-height:30px}.ss-chat-semantic-detail-title:before{display:block;position:absolute;content:"";left:0;top:6px;height:15px;width:3px;font-size:0;background:#0e73ff;border-radius:2px;border:1px solid #0e73ff}.ss-chat-semantic-detail-label{font-size:14px;color:var(--text-color-fourth)}.ss-chat-semantic-detail-section-item{cursor:pointer}.ss-chat-semantic-detail-section-item:hover{color:var(--chat-blue)}.ss-chat-semantic-detail-reload{display:flex;align-items:center;color:var(--text-color-fourth);font-size:12px;grid-column-gap:4px;-webkit-column-gap:4px;column-gap:4px;cursor:pointer;position:relative;top:3px}.ss-chat-semantic-detail-reload:hover{color:var(--chat-blue)}.ss-chat-semantic-detail-reload-icon{font-size:10px;position:relative}.ss-chat-semantic-detail-header{font-size:14px;color:var(--text-color-fourth);margin-bottom:5px}.ss-chat-semantic-detail-more{cursor:pointer;font-size:12px}.ss-chat-semantic-detail-more:hover{color:var(--chat-blue)}.ss-chat-semantic-detail-recommend-questions-content{height:300px;overflow:auto}.ss-chat-semantic-detail-question{cursor:pointer;color:rgba(0,0,0,.87)}.ss-chat-semantic-detail-question:hover{color:var(--chat-blue)}.ss-chat-semantic-detail-content-col{min-width:300px;overflow-y:hidden;height:32px;overflow-x:scroll}.ss-chat-semantic-detail-content-col-box{width:-webkit-max-content;width:-moz-max-content;width:max-content}.ss-chat-item{display:flex}.ss-chat-item-avatar{display:flex;align-items:center;justify-content:center;font-size:40px;width:40px;height:40px;margin-right:6px;border-radius:50%;color:var(--chat-blue);background-color:#fff}.ss-chat-item-content{width:calc(100% - 50px)}.ss-chat-item-metric-info-list{margin-top:30px;display:flex;flex-direction:column;grid-row-gap:30px;row-gap:30px}.ss-chat-item-typing{width:100%;padding:0 5px}.ss-chat-item-typing .ant-spin-dot{width:100%!important;height:100%!important}.ss-chat-item-typing-bubble{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;padding:8px 16px!important}.ss-chat-item-text-bubble{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.ss-chat-item-text{line-height:1.5;white-space:pre-wrap;overflow-wrap:break-word;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ss-chat-tools{display:flex;align-items:center;margin-top:12px;grid-column-gap:6px;-webkit-column-gap:6px;column-gap:6px}.ss-chat-tools-feedback{display:flex;align-items:center;margin-left:4px;color:var(--text-color-third);grid-column-gap:6px;-webkit-column-gap:6px;column-gap:6px}.ss-chat-tools-like{margin-right:4px}.ss-chat-tools-mobile-tools{display:flex;flex-direction:column;margin-top:12px;grid-row-gap:10px;row-gap:10px}.ss-chat-tools-tools{margin-top:0}.ss-chat-tools-feedback{margin-left:2px}.ss-chat-suggestion{margin-top:30px}.ss-chat-suggestion .ss-chat-suggestion-mobile{margin-top:12px;font-size:13px}.ss-chat-suggestion-tip{margin-bottom:12px}.ss-chat-suggestion-content-section{display:flex;align-items:center;margin-bottom:10px;grid-row-gap:12px;row-gap:12px}.ss-chat-suggestion-title{color:var(--text-color-fourth)}.ss-chat-suggestion-section-items{display:flex;flex-wrap:wrap;align-items:center}.ss-chat-suggestion-section-item-selectable{cursor:pointer}.ss-chat-suggestion-section-item-selectable:hover{color:var(--chat-blue)}.ss-chat-suggestion-reload{display:flex;align-items:center;margin-right:14px;margin-left:20px;color:var(--text-color-fourth);font-size:12px;grid-column-gap:4px;-webkit-column-gap:4px;column-gap:4px;cursor:pointer}.ss-chat-suggestion-reload:hover{color:var(--chat-blue)}.ss-chat-suggestion-reload-icon{font-size:10px}.ant-tree.ant-tree-directory .ant-tree-treenode{position:relative}.ant-tree.ant-tree-directory .ant-tree-treenode:before{position:absolute;top:0;right:0;bottom:4px;left:0;transition:background-color .3s;content:"";pointer-events:none}.ant-tree.ant-tree-directory .ant-tree-treenode:hover:before{background:#f5f5f5}.ant-tree.ant-tree-directory .ant-tree-treenode>*{z-index:1}.ant-tree.ant-tree-directory .ant-tree-treenode .ant-tree-switcher{transition:color .3s}.ant-tree.ant-tree-directory .ant-tree-treenode .ant-tree-node-content-wrapper{border-radius:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-tree.ant-tree-directory .ant-tree-treenode .ant-tree-node-content-wrapper:hover{background:transparent}.ant-tree.ant-tree-directory .ant-tree-treenode .ant-tree-node-content-wrapper.ant-tree-node-selected{color:#fff;background:transparent}.ant-tree.ant-tree-directory .ant-tree-treenode-selected:before,.ant-tree.ant-tree-directory .ant-tree-treenode-selected:hover:before{background:#296df3}.ant-tree.ant-tree-directory .ant-tree-treenode-selected .ant-tree-switcher{color:#fff}.ant-tree.ant-tree-directory .ant-tree-treenode-selected .ant-tree-node-content-wrapper{color:#fff;background:transparent}.ant-tree-checkbox{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;top:.2em;line-height:1;white-space:nowrap;outline:none;cursor:pointer}.ant-tree-checkbox-input:focus+.ant-tree-checkbox-inner,.ant-tree-checkbox-wrapper:hover .ant-tree-checkbox-inner,.ant-tree-checkbox:hover .ant-tree-checkbox-inner{border-color:#296df3}.ant-tree-checkbox-checked:after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #296df3;border-radius:2px;visibility:hidden;animation:antCheckboxEffect .36s ease-in-out;animation-fill-mode:backwards;content:""}.ant-tree-checkbox-wrapper:hover .ant-tree-checkbox:after,.ant-tree-checkbox:hover:after{visibility:visible}.ant-tree-checkbox-inner{position:relative;top:0;left:0;display:block;width:16px;height:16px;direction:ltr;background-color:#fff;border:1px solid #d9d9d9;border-radius:2px;border-collapse:separate;transition:all .3s}.ant-tree-checkbox-inner:after{position:absolute;top:50%;left:21.5%;display:table;width:5.71428571px;height:9.14285714px;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(0) translate(-50%,-50%);opacity:0;transition:all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;content:" "}.ant-tree-checkbox-input{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;width:100%;height:100%;cursor:pointer;opacity:0}.ant-tree-checkbox-checked .ant-tree-checkbox-inner:after{position:absolute;display:table;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(1) translate(-50%,-50%);opacity:1;transition:all .2s cubic-bezier(.12,.4,.29,1.46) .1s;content:" "}.ant-tree-checkbox-checked .ant-tree-checkbox-inner{background-color:#296df3;border-color:#296df3}.ant-tree-checkbox-disabled{cursor:not-allowed}.ant-tree-checkbox-disabled.ant-tree-checkbox-checked .ant-tree-checkbox-inner:after{border-color:rgba(0,0,0,.25);animation-name:none}.ant-tree-checkbox-disabled .ant-tree-checkbox-input{cursor:not-allowed;pointer-events:none}.ant-tree-checkbox-disabled .ant-tree-checkbox-inner{background-color:#f5f5f5;border-color:#d9d9d9!important}.ant-tree-checkbox-disabled .ant-tree-checkbox-inner:after{border-color:#f5f5f5;border-collapse:separate;animation-name:none}.ant-tree-checkbox-disabled+span{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-tree-checkbox-disabled:hover:after,.ant-tree-checkbox-wrapper:hover .ant-tree-checkbox-disabled:after{visibility:hidden}.ant-tree-checkbox-wrapper{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-flex;align-items:baseline;line-height:unset;cursor:pointer}.ant-tree-checkbox-wrapper:after{display:inline-block;width:0;overflow:hidden;content:"\a0"}.ant-tree-checkbox-wrapper.ant-tree-checkbox-wrapper-disabled{cursor:not-allowed}.ant-tree-checkbox-wrapper+.ant-tree-checkbox-wrapper{margin-left:8px}.ant-tree-checkbox-wrapper.ant-tree-checkbox-wrapper-in-form-item input[type=checkbox]{width:14px;height:14px}.ant-tree-checkbox+span{padding-right:8px;padding-left:8px}.ant-tree-checkbox-group{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-block}.ant-tree-checkbox-group-item{margin-right:8px}.ant-tree-checkbox-group-item:last-child{margin-right:0}.ant-tree-checkbox-group-item+.ant-tree-checkbox-group-item{margin-left:0}.ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner{background-color:#fff;border-color:#d9d9d9}.ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner:after{top:50%;left:50%;width:8px;height:8px;background-color:#296df3;border:0;transform:translate(-50%,-50%) scale(1);opacity:1;content:" "}.ant-tree-checkbox-indeterminate.ant-tree-checkbox-disabled .ant-tree-checkbox-inner:after{background-color:rgba(0,0,0,.25);border-color:rgba(0,0,0,.25)}.ant-tree{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";background:#fff;border-radius:4px;transition:background-color .3s}.ant-tree-focused:not(:hover):not(.ant-tree-active-focused){background:#e3ecfd}.ant-tree-list-holder-inner{align-items:flex-start}.ant-tree.ant-tree-block-node .ant-tree-list-holder-inner{align-items:stretch}.ant-tree.ant-tree-block-node .ant-tree-list-holder-inner .ant-tree-node-content-wrapper{flex:auto}.ant-tree.ant-tree-block-node .ant-tree-list-holder-inner .ant-tree-treenode.dragging{position:relative}.ant-tree.ant-tree-block-node .ant-tree-list-holder-inner .ant-tree-treenode.dragging:after{position:absolute;top:0;right:0;bottom:4px;left:0;border:1px solid #296df3;opacity:0;animation:ant-tree-node-fx-do-not-use .3s;animation-play-state:running;animation-fill-mode:forwards;content:"";pointer-events:none}.ant-tree .ant-tree-treenode{display:flex;align-items:flex-start;padding:0 0 4px;outline:none}.ant-tree .ant-tree-treenode-disabled .ant-tree-node-content-wrapper{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-tree .ant-tree-treenode-disabled .ant-tree-node-content-wrapper:hover{background:transparent}.ant-tree .ant-tree-treenode-active .ant-tree-node-content-wrapper{background:#f5f5f5}.ant-tree .ant-tree-treenode:not(.ant-tree .ant-tree-treenode-disabled).filter-node .ant-tree-title{color:inherit;font-weight:500}.ant-tree .ant-tree-treenode-draggable .ant-tree-draggable-icon{width:24px;line-height:24px;text-align:center;visibility:visible;opacity:.2;transition:opacity .3s}.ant-tree-treenode:hover .ant-tree .ant-tree-treenode-draggable .ant-tree-draggable-icon{opacity:.45}.ant-tree .ant-tree-treenode-draggable.ant-tree-treenode-disabled .ant-tree-draggable-icon{visibility:hidden}.ant-tree-indent{align-self:stretch;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-tree-indent-unit{display:inline-block;width:24px}.ant-tree-draggable-icon{visibility:hidden}.ant-tree-switcher{position:relative;flex:none;align-self:stretch;width:24px;margin:0;line-height:24px;text-align:center;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-tree-switcher .ant-select-tree-switcher-icon,.ant-tree-switcher .ant-tree-switcher-icon{display:inline-block;font-size:10px;vertical-align:baseline}.ant-tree-switcher .ant-select-tree-switcher-icon svg,.ant-tree-switcher .ant-tree-switcher-icon svg{transition:transform .3s}.ant-tree-switcher-noop{cursor:default}.ant-tree-switcher_close .ant-tree-switcher-icon svg{transform:rotate(-90deg)}.ant-tree-switcher-loading-icon{color:#296df3}.ant-tree-switcher-leaf-line{position:relative;z-index:1;display:inline-block;width:100%;height:100%}.ant-tree-switcher-leaf-line:before{position:absolute;top:0;right:12px;bottom:-4px;margin-left:-1px;border-right:1px solid #d9d9d9;content:" "}.ant-tree-switcher-leaf-line:after{position:absolute;width:10px;height:14px;border-bottom:1px solid #d9d9d9;content:" "}.ant-tree-checkbox{top:auto;margin:4px 8px 0 0}.ant-tree .ant-tree-node-content-wrapper{position:relative;z-index:auto;min-height:24px;margin:0;padding:0 4px;color:inherit;line-height:24px;background:transparent;border-radius:4px;cursor:pointer;transition:all .3s,border 0s,line-height 0s,box-shadow 0s}.ant-tree .ant-tree-node-content-wrapper:hover{background-color:#f5f5f5}.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{background-color:#bed2fb}.ant-tree .ant-tree-node-content-wrapper .ant-tree-iconEle{display:inline-block;width:24px;height:24px;line-height:24px;text-align:center;vertical-align:top}.ant-tree .ant-tree-node-content-wrapper .ant-tree-iconEle:empty{display:none}.ant-tree-unselectable .ant-tree-node-content-wrapper:hover{background-color:transparent}.ant-tree-node-content-wrapper{line-height:24px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-tree-node-content-wrapper .ant-tree-drop-indicator{position:absolute;z-index:1;height:2px;background-color:#296df3;border-radius:1px;pointer-events:none}.ant-tree-node-content-wrapper .ant-tree-drop-indicator:after{position:absolute;top:-3px;left:-6px;width:8px;height:8px;background-color:transparent;border:2px solid #296df3;border-radius:50%;content:""}.ant-tree .ant-tree-treenode.drop-container>[draggable]{box-shadow:0 0 0 2px #296df3}.ant-tree-show-line .ant-tree-indent-unit{position:relative;height:100%}.ant-tree-show-line .ant-tree-indent-unit:before{position:absolute;top:0;right:12px;bottom:-4px;border-right:1px solid #d9d9d9;content:""}.ant-tree-show-line .ant-tree-indent-unit-end:before{display:none}.ant-tree-show-line .ant-tree-switcher{background:#fff}.ant-tree-show-line .ant-tree-switcher-line-icon{vertical-align:-.15em}.ant-tree .ant-tree-treenode-leaf-last .ant-tree-switcher-leaf-line:before{top:auto!important;bottom:auto!important;height:14px!important}.ant-tree-rtl{direction:rtl}.ant-tree-rtl .ant-tree-node-content-wrapper[draggable=true] .ant-tree-drop-indicator:after{right:-6px;left:unset}.ant-tree .ant-tree-treenode-rtl{direction:rtl}.ant-tree-rtl .ant-tree-switcher_close .ant-tree-switcher-icon svg{transform:rotate(90deg)}.ant-tree-rtl.ant-tree-show-line .ant-tree-indent-unit:before{right:auto;left:-13px;border-right:none;border-left:1px solid #d9d9d9}.ant-tree-rtl .ant-tree-checkbox{margin:4px 0 0 8px}.ant-tree-select-dropdown-rtl .ant-select-tree-checkbox{margin:4px 0 0 8px}.ant-popconfirm{z-index:1060}.ant-switch{margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:inline-block;box-sizing:border-box;min-width:44px;height:22px;line-height:22px;vertical-align:middle;background-color:rgba(0,0,0,.25);border:0;border-radius:100px;cursor:pointer;transition:all .2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-switch:focus{outline:0;box-shadow:0 0 0 2px rgba(0,0,0,.1)}.ant-switch-checked:focus{box-shadow:0 0 0 2px #e3ecfd}.ant-switch:focus:hover{box-shadow:none}.ant-switch-checked{background-color:#296df3}.ant-switch-disabled,.ant-switch-loading{cursor:not-allowed;opacity:.4}.ant-switch-disabled *,.ant-switch-loading *{box-shadow:none;cursor:not-allowed}.ant-switch-inner{display:block;margin:0 7px 0 25px;color:#fff;font-size:12px;transition:margin .2s}.ant-switch-checked .ant-switch-inner{margin:0 25px 0 7px}.ant-switch-handle{position:absolute;top:2px;left:2px;width:18px;height:18px;transition:all .2s ease-in-out}.ant-switch-handle:before{position:absolute;top:0;right:0;bottom:0;left:0;background-color:#fff;border-radius:9px;box-shadow:0 2px 4px 0 rgba(0,35,11,.2);transition:all .2s ease-in-out;content:""}.ant-switch-checked .ant-switch-handle{left:calc(100% - 20px)}.ant-switch:not(.ant-switch-disabled):active .ant-switch-handle:before{right:-30%;left:0}.ant-switch:not(.ant-switch-disabled):active.ant-switch-checked .ant-switch-handle:before{right:0;left:-30%}.ant-switch-loading-icon.anticon{position:relative;top:2px;color:rgba(0,0,0,.65);vertical-align:top}.ant-switch-checked .ant-switch-loading-icon{color:#296df3}.ant-switch-small{min-width:28px;height:16px;line-height:16px}.ant-switch-small .ant-switch-inner{margin:0 5px 0 18px;font-size:12px}.ant-switch-small .ant-switch-handle{width:12px;height:12px}.ant-switch-small .ant-switch-loading-icon{top:1.5px;font-size:9px}.ant-switch-small.ant-switch-checked .ant-switch-inner{margin:0 18px 0 5px}.ant-switch-small.ant-switch-checked .ant-switch-handle{left:calc(100% - 14px)}.ant-switch-rtl{direction:rtl}.ant-switch-rtl .ant-switch-inner{margin:0 25px 0 7px}.ant-switch-rtl .ant-switch-handle{right:2px;left:auto}.ant-switch-rtl:not(.ant-switch-rtl-disabled):active .ant-switch-handle:before{right:0;left:-30%}.ant-switch-rtl:not(.ant-switch-rtl-disabled):active.ant-switch-checked .ant-switch-handle:before{right:-30%;left:0}.ant-switch-rtl.ant-switch-checked .ant-switch-inner{margin:0 7px 0 25px}.ant-switch-rtl.ant-switch-checked .ant-switch-handle{right:calc(100% - 20px)}.ant-switch-rtl.ant-switch-small.ant-switch-checked .ant-switch-handle{right:calc(100% - 14px)}.projectBody___1O75d{display:flex;flex-direction:row;background-color:#fff;height:calc(100vh - 48px)}.projectBody___1O75d .projectManger___2moa9{width:100%;min-height:calc(100vh - 48px);background:#f8f9fb;position:relative}.projectBody___1O75d .projectManger___2moa9 .collapseLeftBtn___271Yq{position:absolute;top:calc(50% + 45px);left:0;z-index:100;display:flex;align-items:center;height:70px;color:#fff;font-size:12px;background-color:rgba(40,46,54,.2);border-radius:0 24px 24px 0;cursor:pointer;transition:all .3s ease}.projectBody___1O75d .projectManger___2moa9 .title___LuK7d{margin-bottom:0;padding:20px;font-size:20px;line-height:34px;border-bottom:1px solid #d9d9d9}.projectBody___1O75d .projectManger___2moa9 .tab___DxzVP{padding:0 20px;line-height:28px}.projectBody___1O75d .projectManger___2moa9 .mainTip___1uvL1{padding:20px}.projectBody___1O75d .projectManger___2moa9 .ant-card-body{padding:0!important}.projectBody___1O75d .projectManger___2moa9 .ant-tabs-content-holder{overflow:scroll;height:calc(100vh - 192px)}.projectBody___1O75d .projectManger___2moa9 .resource___3CU5R{display:flex}.projectBody___1O75d .projectManger___2moa9 .resource___3CU5R .tree___2sPCD{flex:1 1}.projectBody___1O75d .projectManger___2moa9 .resource___3CU5R .tree___2sPCD .headOperation___35Wj2 .btn___2RLpC{margin-right:18px}.projectBody___1O75d .projectManger___2moa9 .resource___3CU5R .tree___2sPCD .resourceSearch___3I419{margin:10px 0}.projectBody___1O75d .projectManger___2moa9 .resource___3CU5R .view___1TePK{width:480px;padding-left:20px}.projectBody___1O75d .projectManger___2moa9 .resource___3CU5R .selectTypesBtn___24cg5{margin-right:8px}.projectList___3ra_d{display:flex;flex-direction:column;width:400px;overflow:hidden}.projectList___3ra_d .addBtn___8opNc{cursor:pointer;width:100%;font-size:18px;margin-top:18px}.projectList___3ra_d .addBtn___8opNc:hover{color:#296df3}.projectList___3ra_d .treeTitle___2YiW-{margin-bottom:0;padding:20px;line-height:34px;text-align:right;background:#fff;border-bottom:1px solid #d9d9d9}.projectList___3ra_d .treeTitle___2YiW- .title___LuK7d{float:left}.projectList___3ra_d .search___lSpVC{width:calc(100% - 20px);margin:10px}.projectList___3ra_d .tree___2sPCD{flex:1 1;padding:10px}.projectList___3ra_d .tree___2sPCD .projectItem___2-Mu_{display:flex;width:100%;cursor:auto}.projectList___3ra_d .tree___2sPCD .projectItem___2-Mu_ .title___LuK7d{flex:1 1;cursor:pointer}.projectList___3ra_d .tree___2sPCD .projectItem___2-Mu_ .operation___1tdgy .icon___1rxv-{margin-left:6px;cursor:pointer}.user___w0WDu{display:grid}.search___lSpVC{width:50%;margin-bottom:20px}.paramsName___2MM76{margin-right:10px}.deleteBtn___1it0i{margin-left:5px}.authBtn___L5Y_I{cursor:pointer}.selectedResource___3RJBb{font-size:12px;color:#a9a9a9;margin-top:4px}.switch___1jFlm{display:flex;justify-content:flex-start}.switch___1jFlm .switchUser___38oOw{width:200px;margin-left:33px}.switch___1jFlm .switchUser___38oOw .ant-select{width:100%!important}.dimensionIntentionForm___FyYSx{margin-bottom:-24px!important;margin-top:10px;margin-left:26px}.classTable____ikBn .ant-pro-table-search-query-filter{padding-left:0!important}.classTable____ikBn .ant-table-tbody>tr.ant-table-row-selected>td{background:none}.classTableSelectColumnAlignLeft___sqT0O .ant-table-selection-column{text-align:left}.permissionDrawer___D8WZs .ant-drawer-body{background:#f8f9fb}.domainSelector___NAmEr{display:flex;width:-webkit-max-content;width:-moz-max-content;width:max-content;padding:0 11px;cursor:pointer;position:relative;border-radius:4px;transition:all .3s cubic-bezier(.645,.045,.355,1);color:rgba(0,10,36,.8509803921568627)}.domainSelector___NAmEr .downIcon___1oUlL{margin-left:10px;font-size:14px}.domainSelector___NAmEr:hover{color:#296df3}.overviewExtraContainer___2blJS{display:flex;font-size:14px}.overviewExtraContainer___2blJS .extraWrapper___1WW79{display:flex;width:100%}.overviewExtraContainer___2blJS .extraWrapper___1WW79 .extraStatistic___2jUk3{display:inline-flex;color:rgba(42,46,54,.65);box-sizing:border-box;margin:0;padding:0;font-size:14px;line-height:1.57142857;list-style:none}.overviewExtraContainer___2blJS .extraWrapper___1WW79 .extraStatistic___2jUk3 .extraTitle___3z5J2{font-size:12px;-webkit-margin-end:6px;margin-inline-end:6px;-webkit-margin-after:0;margin-block-end:0;margin-bottom:4px;color:rgba(42,46,54,.45)}.overviewExtraContainer___2blJS .extraWrapper___1WW79 .extraStatistic___2jUk3 .extraValue___2Ir7u{font-size:12px;color:rgba(42,46,54,.65);display:inline-block;direction:ltr}.infoTagList___2JA93 .siteTagPlus___1xPLu{background:#fff;border-style:dashed}.infoTagList___2JA93 .editTag___3QSGZ{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.infoTagList___2JA93 .tagInput___3FcCc{width:78px;margin-right:8px;vertical-align:top}.infoTagList___2JA93 [data-theme=dark] .siteTagPlus___1xPLu{background:transparent;border-style:dashed}.ant-input-number-affix-wrapper{display:inline-block;width:100%;min-width:0;color:rgba(0,10,36,.85);font-size:14px;line-height:1.5715;background-color:#fff;background-image:none;border:1px solid #d9d9d9;border-radius:4px;transition:all .3s;position:relative;display:inline-flex;width:90px;padding:0;-webkit-padding-start:11px;padding-inline-start:11px}.ant-input-number-affix-wrapper::-webkit-input-placeholder{color:#bfbfbf;-webkit-user-select:none;user-select:none}.ant-input-number-affix-wrapper:-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-number-affix-wrapper::-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-number-affix-wrapper::placeholder{color:#bfbfbf;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-input-number-affix-wrapper:-ms-input-placeholder{text-overflow:ellipsis}.ant-input-number-affix-wrapper:placeholder-shown{text-overflow:ellipsis}.ant-input-number-affix-wrapper:hover{border-color:#4e86f5;border-right-width:1px}.ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper:focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-input-number-affix-wrapper-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number-affix-wrapper-disabled:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input-number-affix-wrapper[disabled]{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number-affix-wrapper[disabled]:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input-number-affix-wrapper-borderless,.ant-input-number-affix-wrapper-borderless-disabled,.ant-input-number-affix-wrapper-borderless-focused,.ant-input-number-affix-wrapper-borderless:focus,.ant-input-number-affix-wrapper-borderless:hover,.ant-input-number-affix-wrapper-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-input-number-affix-wrapper{max-width:100%;height:auto;min-height:32px;line-height:1.5715;vertical-align:bottom;transition:all .3s,height 0s}.ant-input-number-affix-wrapper-lg{padding:6.5px 11px;font-size:16px}.ant-input-number-affix-wrapper-sm{padding:0 7px}.ant-input-number-affix-wrapper:not(.ant-input-number-affix-wrapper-disabled):hover{border-color:#4e86f5;border-right-width:1px;z-index:1}.ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper:focus{z-index:1}.ant-input-number-affix-wrapper-disabled .ant-input-number[disabled]{background:transparent}.ant-input-number-affix-wrapper>div.ant-input-number{width:100%;border:none;outline:none}.ant-input-number-affix-wrapper>div.ant-input-number.ant-input-number-focused{box-shadow:none!important}.ant-input-number-affix-wrapper input.ant-input-number-input{padding:0}.ant-input-number-affix-wrapper:before{display:inline-block;width:0;visibility:hidden;content:"\a0"}.ant-input-number-affix-wrapper .ant-input-number-handler-wrap{z-index:2}.ant-input-number-prefix,.ant-input-number-suffix{display:flex;flex:none;align-items:center;pointer-events:none}.ant-input-number-prefix{-webkit-margin-end:4px;margin-inline-end:4px}.ant-input-number-suffix{position:absolute;top:0;right:0;z-index:1;height:100%;margin-right:11px;margin-left:4px}.ant-input-number-group-wrapper .ant-input-number-affix-wrapper{width:100%}.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number,.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:hover{background:#fff;border-color:#ef4872}.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number-focused,.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:focus{border-color:#fc7492;box-shadow:0 0 0 2px rgba(239,72,114,.2);border-right-width:1px;outline:0}.ant-input-number-status-error .ant-input-number-prefix{color:#ef4872}.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number,.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:hover{background:#fff;border-color:#ffb924}.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number-focused,.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:focus{border-color:#ffcc4d;box-shadow:0 0 0 2px rgba(255,185,36,.2);border-right-width:1px;outline:0}.ant-input-number-status-warning .ant-input-number-prefix{color:#ffb924}.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper,.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:hover{background:#fff;border-color:#ef4872}.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:focus{border-color:#fc7492;box-shadow:0 0 0 2px rgba(239,72,114,.2);border-right-width:1px;outline:0}.ant-input-number-affix-wrapper-status-error .ant-input-number-prefix{color:#ef4872}.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper,.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:hover{background:#fff;border-color:#ffb924}.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:focus{border-color:#ffcc4d;box-shadow:0 0 0 2px rgba(255,185,36,.2);border-right-width:1px;outline:0}.ant-input-number-affix-wrapper-status-warning .ant-input-number-prefix{color:#ffb924}.ant-input-number-group-wrapper-status-error .ant-input-number-group-addon{color:#ef4872;border-color:#ef4872}.ant-input-number-group-wrapper-status-warning .ant-input-number-group-addon{color:#ffb924;border-color:#ffb924}.ant-input-number{box-sizing:border-box;font-variant:tabular-nums;list-style:none;font-feature-settings:"tnum","tnum";position:relative;width:100%;min-width:0;color:rgba(0,10,36,.85);font-size:14px;line-height:1.5715;background-color:#fff;background-image:none;transition:all .3s;display:inline-block;width:90px;margin:0;padding:0;border:1px solid #d9d9d9;border-radius:4px}.ant-input-number::-webkit-input-placeholder{color:#bfbfbf;-webkit-user-select:none;user-select:none}.ant-input-number:-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-number::-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-number::placeholder{color:#bfbfbf;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-input-number:-ms-input-placeholder{text-overflow:ellipsis}.ant-input-number:placeholder-shown{text-overflow:ellipsis}.ant-input-number-focused,.ant-input-number:focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-input-number[disabled]{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number[disabled]:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input-number-borderless,.ant-input-number-borderless-disabled,.ant-input-number-borderless-focused,.ant-input-number-borderless:focus,.ant-input-number-borderless:hover,.ant-input-number-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-input-number{max-width:100%;height:auto;min-height:32px;line-height:1.5715;vertical-align:bottom;transition:all .3s,height 0s}.ant-input-number-lg{padding:6.5px 11px}.ant-input-number-sm{padding:0 7px}.ant-input-number-group{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:table;width:100%;border-collapse:separate;border-spacing:0}.ant-input-number-group[class*=col-]{float:none;padding-right:0;padding-left:0}.ant-input-number-group>[class*=col-]{padding-right:8px}.ant-input-number-group>[class*=col-]:last-child{padding-right:0}.ant-input-number-group-addon,.ant-input-number-group-wrap,.ant-input-number-group>.ant-input-number{display:table-cell}.ant-input-number-group-addon:not(:first-child):not(:last-child),.ant-input-number-group-wrap:not(:first-child):not(:last-child),.ant-input-number-group>.ant-input-number:not(:first-child):not(:last-child){border-radius:0}.ant-input-number-group-addon,.ant-input-number-group-wrap{width:1px;white-space:nowrap;vertical-align:middle}.ant-input-number-group-wrap>*{display:block!important}.ant-input-number-group .ant-input-number{float:left;width:100%;margin-bottom:0;text-align:inherit}.ant-input-number-group .ant-input-number:focus{z-index:1;border-right-width:1px}.ant-input-number-group .ant-input-number:hover{z-index:1;border-right-width:1px}.ant-input-search-with-button .ant-input-number-group .ant-input-number:hover{z-index:0}.ant-input-number-group-addon{position:relative;padding:0 11px;color:rgba(0,10,36,.85);font-weight:400;font-size:14px;text-align:center;background-color:#fafafa;border:1px solid #d9d9d9;border-radius:4px;transition:all .3s}.ant-input-number-group-addon .ant-select{margin:-5px -11px}.ant-input-number-group-addon .ant-select.ant-select-single:not(.ant-select-customize-input) .ant-select-selector{background-color:inherit;border:1px solid transparent;box-shadow:none}.ant-input-number-group-addon .ant-select-focused .ant-select-selector,.ant-input-number-group-addon .ant-select-open .ant-select-selector{color:#296df3}.ant-input-number-group-addon .ant-cascader-picker{margin:-9px -12px;background-color:transparent}.ant-input-number-group-addon .ant-cascader-picker .ant-cascader-input{text-align:left;border:0;box-shadow:none}.ant-input-number-group-addon:first-child,.ant-input-number-group>.ant-input-number:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-group-addon:first-child .ant-select .ant-select-selector,.ant-input-number-group>.ant-input-number:first-child .ant-select .ant-select-selector{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-group>.ant-input-number-affix-wrapper:not(:first-child) .ant-input-number{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group>.ant-input-number-affix-wrapper:not(:last-child) .ant-input-number{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-group-addon:first-child{border-right:0}.ant-input-number-group-addon:last-child{border-left:0}.ant-input-number-group-addon:last-child,.ant-input-number-group>.ant-input-number:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group-addon:last-child .ant-select .ant-select-selector,.ant-input-number-group>.ant-input-number:last-child .ant-select .ant-select-selector{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group-lg .ant-input-number,.ant-input-number-group-lg>.ant-input-number-group-addon{padding:6.5px 11px;font-size:16px}.ant-input-number-group-sm .ant-input-number,.ant-input-number-group-sm>.ant-input-number-group-addon{padding:0 7px}.ant-input-number-group-lg .ant-select-single .ant-select-selector{height:40px}.ant-input-number-group-sm .ant-select-single .ant-select-selector{height:24px}.ant-input-number-group .ant-input-number-affix-wrapper:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-search .ant-input-number-group .ant-input-number-affix-wrapper:not(:last-child){border-top-left-radius:4px;border-bottom-left-radius:4px}.ant-input-number-group .ant-input-number-affix-wrapper:not(:first-child),.ant-input-search .ant-input-number-group .ant-input-number-affix-wrapper:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group.ant-input-number-group-compact{display:block}.ant-input-number-group.ant-input-number-group-compact:before{display:table;content:""}.ant-input-number-group.ant-input-number-group-compact:after{display:table;clear:both;content:""}.ant-input-number-group.ant-input-number-group-compact-addon:not(:first-child):not(:last-child),.ant-input-number-group.ant-input-number-group-compact-wrap:not(:first-child):not(:last-child),.ant-input-number-group.ant-input-number-group-compact>.ant-input-number:not(:first-child):not(:last-child){border-right-width:1px}.ant-input-number-group.ant-input-number-group-compact-addon:not(:first-child):not(:last-child):hover,.ant-input-number-group.ant-input-number-group-compact-wrap:not(:first-child):not(:last-child):hover,.ant-input-number-group.ant-input-number-group-compact>.ant-input-number:not(:first-child):not(:last-child):hover{z-index:1}.ant-input-number-group.ant-input-number-group-compact-addon:not(:first-child):not(:last-child):focus,.ant-input-number-group.ant-input-number-group-compact-wrap:not(:first-child):not(:last-child):focus,.ant-input-number-group.ant-input-number-group-compact>.ant-input-number:not(:first-child):not(:last-child):focus{z-index:1}.ant-input-number-group.ant-input-number-group-compact>*{display:inline-block;float:none;vertical-align:top;border-radius:0}.ant-input-number-group.ant-input-number-group-compact>.ant-input-number-affix-wrapper,.ant-input-number-group.ant-input-number-group-compact>.ant-input-number-number-affix-wrapper,.ant-input-number-group.ant-input-number-group-compact>.ant-picker-range{display:inline-flex}.ant-input-number-group.ant-input-number-group-compact>:not(:last-child){margin-right:-1px;border-right-width:1px}.ant-input-number-group.ant-input-number-group-compact .ant-input-number{float:none}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-input-group-wrapper .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-selector{border-right-width:1px;border-radius:0}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker .ant-input:hover,.ant-input-number-group.ant-input-number-group-compact>.ant-input-group-wrapper .ant-input:hover,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input:hover,.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-selector:hover{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker .ant-input:focus,.ant-input-number-group.ant-input-number-group-compact>.ant-input-group-wrapper .ant-input:focus,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input:focus,.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-selector:focus{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-select-focused{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-arrow{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker:first-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete:first-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select:first-child>.ant-select-selector,.ant-input-number-group.ant-input-number-group-compact>:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker-focused:last-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker:last-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select:last-child>.ant-select-selector,.ant-input-number-group.ant-input-number-group-compact>:last-child{border-right-width:1px;border-top-right-radius:4px;border-bottom-right-radius:4px}.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input{vertical-align:top}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper+.ant-input-group-wrapper{margin-left:-1px}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper+.ant-input-group-wrapper .ant-input-affix-wrapper{border-radius:0}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper:not(:last-child).ant-input-search>.ant-input-group>.ant-input-group-addon>.ant-input-search-button{border-radius:0}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper:not(:last-child).ant-input-search>.ant-input-group>.ant-input{border-radius:4px 0 0 4px}.ant-input-number-group>.ant-input-number-rtl:first-child{border-radius:0 4px 4px 0}.ant-input-number-group>.ant-input-number-rtl:last-child{border-radius:4px 0 0 4px}.ant-input-number-group-rtl .ant-input-number-group-addon:first-child{border-right:1px solid #d9d9d9;border-left:0;border-radius:0 4px 4px 0}.ant-input-number-group-rtl .ant-input-number-group-addon:last-child{border-right:0;border-left:1px solid #d9d9d9;border-radius:4px 0 0 4px}.ant-input-number-group-wrapper{display:inline-block;text-align:start;vertical-align:top}.ant-input-number-handler{position:relative;display:block;width:100%;height:50%;overflow:hidden;color:rgba(0,10,36,.65);font-weight:700;line-height:0;text-align:center;border-left:1px solid #d9d9d9;transition:all .1s linear}.ant-input-number-handler:active{background:#f4f4f4}.ant-input-number-handler:hover .ant-input-number-handler-down-inner,.ant-input-number-handler:hover .ant-input-number-handler-up-inner{color:#4e86f5}.ant-input-number-handler-down-inner,.ant-input-number-handler-up-inner{display:inline-block;color:inherit;font-style:normal;line-height:0;text-align:center;text-transform:none;vertical-align:-.125em;text-rendering:optimizelegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;position:absolute;right:4px;width:12px;height:12px;color:rgba(0,10,36,.65);line-height:12px;transition:all .1s linear;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-input-number-handler-down-inner>*,.ant-input-number-handler-up-inner>*{line-height:1}.ant-input-number-handler-down-inner svg,.ant-input-number-handler-up-inner svg{display:inline-block}.ant-input-number-handler-down-inner:before,.ant-input-number-handler-up-inner:before{display:none}.ant-input-number-handler-down-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-down-inner .ant-input-number-handler-up-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-up-inner-icon{display:block}.ant-input-number:hover{border-color:#4e86f5;border-right-width:1px}.ant-input-number:hover+.ant-form-item-children-icon{opacity:0;transition:opacity .24s linear .24s}.ant-input-number-focused{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-input-number-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number-disabled:hover{border-color:#d9d9d9;border-right-width:1px}.ant-input-number-disabled .ant-input-number-input{cursor:not-allowed}.ant-input-number-disabled .ant-input-number-handler-wrap{display:none}.ant-input-number-readonly .ant-input-number-handler-wrap{display:none}.ant-input-number-input{width:100%;height:30px;padding:0 11px;text-align:left;background-color:transparent;border:0;border-radius:4px;outline:0;transition:all .3s linear;-webkit-appearance:textfield!important;-moz-appearance:textfield!important;appearance:textfield!important}.ant-input-number-input::-webkit-input-placeholder{color:#bfbfbf;-webkit-user-select:none;user-select:none}.ant-input-number-input:-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-number-input::-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-input-number-input::placeholder{color:#bfbfbf;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-input-number-input:-ms-input-placeholder{text-overflow:ellipsis}.ant-input-number-input:placeholder-shown{text-overflow:ellipsis}.ant-input-number-input[type=number]::-webkit-inner-spin-button,.ant-input-number-input[type=number]::-webkit-outer-spin-button{margin:0;-webkit-appearance:none;appearance:none}.ant-input-number-lg{padding:0;font-size:16px}.ant-input-number-lg input{height:38px}.ant-input-number-sm{padding:0}.ant-input-number-sm input{height:22px;padding:0 7px}.ant-input-number-handler-wrap{position:absolute;top:0;right:0;width:22px;height:100%;background:#fff;border-radius:0 4px 4px 0;opacity:0;transition:opacity .24s linear .1s}.ant-input-number-handler-wrap .ant-input-number-handler .ant-input-number-handler-down-inner,.ant-input-number-handler-wrap .ant-input-number-handler .ant-input-number-handler-up-inner{display:flex;align-items:center;justify-content:center;min-width:auto;margin-right:0;font-size:7px}.ant-input-number-borderless .ant-input-number-handler-wrap{border-left-width:0}.ant-input-number-handler-wrap:hover .ant-input-number-handler{height:40%}.ant-input-number-focused .ant-input-number-handler-wrap,.ant-input-number:hover .ant-input-number-handler-wrap{opacity:1}.ant-input-number-handler-up{border-top-right-radius:4px;cursor:pointer}.ant-input-number-handler-up-inner{top:50%;margin-top:-5px;text-align:center}.ant-input-number-handler-up:hover{height:60%!important}.ant-input-number-handler-down{top:0;border-top:1px solid #d9d9d9;border-bottom-right-radius:4px;cursor:pointer}.ant-input-number-handler-down-inner{top:50%;text-align:center;transform:translateY(-50%)}.ant-input-number-handler-down:hover{height:60%!important}.ant-input-number-borderless .ant-input-number-handler-down{border-top-width:0}.ant-input-number-focused:not(.ant-input-number-borderless) .ant-input-number-handler-down,.ant-input-number:hover:not(.ant-input-number-borderless) .ant-input-number-handler-down{border-top:1px solid #d9d9d9}.ant-input-number-handler-down-disabled,.ant-input-number-handler-up-disabled{cursor:not-allowed}.ant-input-number-handler-down-disabled:hover .ant-input-number-handler-down-inner,.ant-input-number-handler-up-disabled:hover .ant-input-number-handler-up-inner{color:rgba(0,0,0,.25)}.ant-input-number-borderless{box-shadow:none}.ant-input-number-out-of-range input{color:#ef4872}.ant-input-number-compact-item:not(.ant-input-number-compact-last-item):not(.ant-input-number-compact-item-rtl){margin-right:-1px}.ant-input-number-compact-item:not(.ant-input-number-compact-last-item).ant-input-number-compact-item-rtl{margin-left:-1px}.ant-input-number-compact-item:active,.ant-input-number-compact-item:focus,.ant-input-number-compact-item:hover{z-index:2}.ant-input-number-compact-item.ant-input-number-focused{z-index:2}.ant-input-number-compact-item[disabled]{z-index:0}.ant-input-number-compact-item:not(.ant-input-number-compact-first-item):not(.ant-input-number-compact-last-item).ant-input-number{border-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-first-item:not(.ant-input-number-compact-last-item):not(.ant-input-number-compact-item-rtl){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-last-item:not(.ant-input-number-compact-first-item):not(.ant-input-number-compact-item-rtl){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-item-rtl.ant-input-number-compact-first-item:not(.ant-input-number-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-item-rtl.ant-input-number-compact-last-item:not(.ant-input-number-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-rtl{direction:rtl}.ant-input-number-rtl .ant-input-number-handler{border-right:1px solid #d9d9d9;border-left:0}.ant-input-number-rtl .ant-input-number-handler-wrap{right:auto;left:0}.ant-input-number-rtl.ant-input-number-borderless .ant-input-number-handler-wrap{border-right-width:0}.ant-input-number-rtl .ant-input-number-handler-up{border-top-right-radius:0}.ant-input-number-rtl .ant-input-number-handler-down{border-bottom-right-radius:0}.ant-input-number-rtl .ant-input-number-input{direction:ltr;text-align:right}.ant-transfer-customize-list .ant-transfer-list{flex:1 1 50%;width:auto;height:auto;min-height:200px}.ant-transfer-customize-list .ant-table-wrapper .ant-table-small{border:0;border-radius:0}.ant-transfer-customize-list .ant-table-wrapper .ant-table-small .ant-table-selection-column{width:40px;min-width:40px}.ant-transfer-customize-list .ant-table-wrapper .ant-table-small>.ant-table-content>.ant-table-body>table>.ant-table-thead>tr>th{background:#fafafa}.ant-transfer-customize-list .ant-table-wrapper .ant-table-small>.ant-table-content .ant-table-row:last-child td{border-bottom:1px solid #f0f0f0}.ant-transfer-customize-list .ant-table-wrapper .ant-table-small .ant-table-body{margin:0}.ant-transfer-customize-list .ant-table-wrapper .ant-table-pagination.ant-pagination{margin:16px 0 4px}.ant-transfer-customize-list .ant-input[disabled]{background-color:transparent}.ant-transfer-status-error .ant-transfer-list{border-color:#ef4872}.ant-transfer-status-error .ant-transfer-list-search:not([disabled]){border-color:#d9d9d9}.ant-transfer-status-error .ant-transfer-list-search:not([disabled]):hover{border-color:#4e86f5;border-right-width:1px}.ant-transfer-status-error .ant-transfer-list-search:not([disabled]):focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-transfer-status-warning .ant-transfer-list{border-color:#ffb924}.ant-transfer-status-warning .ant-transfer-list-search:not([disabled]){border-color:#d9d9d9}.ant-transfer-status-warning .ant-transfer-list-search:not([disabled]):hover{border-color:#4e86f5;border-right-width:1px}.ant-transfer-status-warning .ant-transfer-list-search:not([disabled]):focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-transfer{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:flex;align-items:stretch}.ant-transfer-disabled .ant-transfer-list{background:#f5f5f5}.ant-transfer-list{display:flex;flex-direction:column;width:180px;height:200px;border:1px solid #d9d9d9;border-radius:4px}.ant-transfer-list-with-pagination{width:250px;height:auto}.ant-transfer-list-search .anticon-search{color:rgba(0,0,0,.25)}.ant-transfer-list-header{display:flex;flex:none;align-items:center;height:40px;padding:8px 12px 9px;color:rgba(0,10,36,.85);background:#fff;border-bottom:1px solid #f0f0f0;border-radius:4px 4px 0 0}.ant-transfer-list-header>:not(:last-child){margin-right:4px}.ant-transfer-list-header>*{flex:none}.ant-transfer-list-header-title{flex:auto;overflow:hidden;white-space:nowrap;text-align:right;text-overflow:ellipsis}.ant-transfer-list-header-dropdown{font-size:10px;transform:translateY(10%);cursor:pointer}.ant-transfer-list-header-dropdown[disabled]{cursor:not-allowed}.ant-transfer-list-body{display:flex;flex:auto;flex-direction:column;overflow:hidden;font-size:14px}.ant-transfer-list-body-search-wrapper{position:relative;flex:none;padding:12px}.ant-transfer-list-content{flex:auto;margin:0;padding:0;overflow:auto;list-style:none}.ant-transfer-list-content-item{display:flex;align-items:center;min-height:32px;padding:6px 12px;line-height:20px;transition:all .3s}.ant-transfer-list-content-item>:not(:last-child){margin-right:8px}.ant-transfer-list-content-item>*{flex:none}.ant-transfer-list-content-item-text{flex:auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-transfer-list-content-item-remove{position:relative;color:#d9d9d9;cursor:pointer;transition:all .3s}.ant-transfer-list-content-item-remove:hover{color:#5493ff}.ant-transfer-list-content-item-remove:after{position:absolute;top:-6px;right:-50%;bottom:-6px;left:-50%;content:""}.ant-transfer-list-content-item:not(.ant-transfer-list-content-item-disabled):hover{background-color:#f5f5f5;cursor:pointer}.ant-transfer-list-content-item:not(.ant-transfer-list-content-item-disabled).ant-transfer-list-content-item-checked:hover{background-color:#d9e6fc}.ant-transfer-list-content-show-remove .ant-transfer-list-content-item:not(.ant-transfer-list-content-item-disabled):hover{background:transparent;cursor:default}.ant-transfer-list-content-item-checked{background-color:#e3ecfd}.ant-transfer-list-content-item-disabled{color:rgba(0,10,36,.25);cursor:not-allowed}.ant-transfer-list-pagination{padding:8px 0;text-align:right;border-top:1px solid #f0f0f0}.ant-transfer-list-body-not-found{flex:none;width:100%;margin:auto 0;color:rgba(0,0,0,.25);text-align:center}.ant-transfer-list-footer{border-top:1px solid #f0f0f0}.ant-transfer-operation{display:flex;flex:none;flex-direction:column;align-self:center;margin:0 8px;vertical-align:middle}.ant-transfer-operation .ant-btn{display:block}.ant-transfer-operation .ant-btn:first-child{margin-bottom:4px}.ant-transfer-operation .ant-btn .anticon{font-size:12px}.ant-transfer .ant-empty-image{max-height:-2px}.ant-transfer-rtl{direction:rtl}.ant-transfer-rtl .ant-transfer-list-search{padding-right:8px;padding-left:24px}.ant-transfer-rtl .ant-transfer-list-search-action{right:auto;left:12px}.ant-transfer-rtl .ant-transfer-list-header>:not(:last-child){margin-right:0;margin-left:4px}.ant-transfer-rtl .ant-transfer-list-header{right:0;left:auto}.ant-transfer-rtl .ant-transfer-list-header-title{text-align:left}.ant-transfer-rtl .ant-transfer-list-content-item>:not(:last-child){margin-right:0;margin-left:8px}.ant-transfer-rtl .ant-transfer-list-pagination{text-align:left}.ant-transfer-rtl .ant-transfer-list-footer{right:0;left:auto}.ant-checkbox{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;top:.2em;line-height:1;white-space:nowrap;outline:none;cursor:pointer}.ant-checkbox-input:focus+.ant-checkbox-inner,.ant-checkbox-wrapper:hover .ant-checkbox-inner,.ant-checkbox:hover .ant-checkbox-inner{border-color:#296df3}.ant-checkbox-checked:after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #296df3;border-radius:2px;visibility:hidden;animation:antCheckboxEffect .36s ease-in-out;animation-fill-mode:backwards;content:""}.ant-checkbox-wrapper:hover .ant-checkbox:after,.ant-checkbox:hover:after{visibility:visible}.ant-checkbox-inner{position:relative;top:0;left:0;display:block;width:16px;height:16px;direction:ltr;background-color:#fff;border:1px solid #d9d9d9;border-radius:2px;border-collapse:separate;transition:all .3s}.ant-checkbox-inner:after{position:absolute;top:50%;left:21.5%;display:table;width:5.71428571px;height:9.14285714px;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(0) translate(-50%,-50%);opacity:0;transition:all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;content:" "}.ant-checkbox-input{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;width:100%;height:100%;cursor:pointer;opacity:0}.ant-checkbox-checked .ant-checkbox-inner:after{position:absolute;display:table;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(1) translate(-50%,-50%);opacity:1;transition:all .2s cubic-bezier(.12,.4,.29,1.46) .1s;content:" "}.ant-checkbox-checked .ant-checkbox-inner{background-color:#296df3;border-color:#296df3}.ant-checkbox-disabled{cursor:not-allowed}.ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner:after{border-color:rgba(0,0,0,.25);animation-name:none}.ant-checkbox-disabled .ant-checkbox-input{cursor:not-allowed;pointer-events:none}.ant-checkbox-disabled .ant-checkbox-inner{background-color:#f5f5f5;border-color:#d9d9d9!important}.ant-checkbox-disabled .ant-checkbox-inner:after{border-color:#f5f5f5;border-collapse:separate;animation-name:none}.ant-checkbox-disabled+span{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-checkbox-disabled:hover:after,.ant-checkbox-wrapper:hover .ant-checkbox-disabled:after{visibility:hidden}.ant-checkbox-wrapper{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-flex;align-items:baseline;line-height:unset;cursor:pointer}.ant-checkbox-wrapper:after{display:inline-block;width:0;overflow:hidden;content:"\a0"}.ant-checkbox-wrapper.ant-checkbox-wrapper-disabled{cursor:not-allowed}.ant-checkbox-wrapper+.ant-checkbox-wrapper{margin-left:8px}.ant-checkbox-wrapper.ant-checkbox-wrapper-in-form-item input[type=checkbox]{width:14px;height:14px}.ant-checkbox+span{padding-right:8px;padding-left:8px}.ant-checkbox-group{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-block}.ant-checkbox-group-item{margin-right:8px}.ant-checkbox-group-item:last-child{margin-right:0}.ant-checkbox-group-item+.ant-checkbox-group-item{margin-left:0}.ant-checkbox-indeterminate .ant-checkbox-inner{background-color:#fff;border-color:#d9d9d9}.ant-checkbox-indeterminate .ant-checkbox-inner:after{top:50%;left:50%;width:8px;height:8px;background-color:#296df3;border:0;transform:translate(-50%,-50%) scale(1);opacity:1;content:" "}.ant-checkbox-indeterminate.ant-checkbox-disabled .ant-checkbox-inner:after{background-color:rgba(0,0,0,.25);border-color:rgba(0,0,0,.25)}.ant-checkbox-rtl{direction:rtl}.ant-checkbox-group-rtl .ant-checkbox-group-item{margin-right:0;margin-left:8px}.ant-checkbox-group-rtl .ant-checkbox-group-item:last-child{margin-left:0!important}.ant-checkbox-group-rtl .ant-checkbox-group-item+.ant-checkbox-group-item{margin-left:8px}.ant-pagination{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum"}.ant-pagination ol,.ant-pagination ul{margin:0;padding:0;list-style:none}.ant-pagination:after{display:block;clear:both;height:0;overflow:hidden;visibility:hidden;content:" "}.ant-pagination-total-text{display:inline-block;height:32px;margin-right:8px;line-height:30px;vertical-align:middle}.ant-pagination-item{display:inline-block;min-width:32px;height:32px;margin-right:8px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";line-height:30px;text-align:center;vertical-align:middle;list-style:none;background-color:#fff;border:1px solid #d9d9d9;border-radius:4px;outline:0;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-pagination-item a{display:block;padding:0 6px;color:rgba(0,10,36,.85);transition:none}.ant-pagination-item a:hover{text-decoration:none}.ant-pagination-item:hover{border-color:#296df3;transition:all .3s}.ant-pagination-item:hover a{color:#296df3}.ant-pagination-item:focus-visible{border-color:#296df3;transition:all .3s}.ant-pagination-item:focus-visible a{color:#296df3}.ant-pagination-item-active{font-weight:500;background:#fff;border-color:#296df3}.ant-pagination-item-active a{color:#296df3}.ant-pagination-item-active:hover{border-color:#4e86f5}.ant-pagination-item-active:focus-visible{border-color:#4e86f5}.ant-pagination-item-active:hover a{color:#4e86f5}.ant-pagination-item-active:focus-visible a{color:#4e86f5}.ant-pagination-jump-next,.ant-pagination-jump-prev{outline:0}.ant-pagination-jump-next .ant-pagination-item-container,.ant-pagination-jump-prev .ant-pagination-item-container{position:relative}.ant-pagination-jump-next .ant-pagination-item-container .ant-pagination-item-link-icon,.ant-pagination-jump-prev .ant-pagination-item-container .ant-pagination-item-link-icon{color:#296df3;font-size:12px;letter-spacing:-1px;opacity:0;transition:all .2s}.ant-pagination-jump-next .ant-pagination-item-container .ant-pagination-item-link-icon-svg,.ant-pagination-jump-prev .ant-pagination-item-container .ant-pagination-item-link-icon-svg{top:0;right:0;bottom:0;left:0;margin:auto}.ant-pagination-jump-next .ant-pagination-item-container .ant-pagination-item-ellipsis,.ant-pagination-jump-prev .ant-pagination-item-container .ant-pagination-item-ellipsis{position:absolute;top:0;right:0;bottom:0;left:0;display:block;margin:auto;color:rgba(0,0,0,.25);font-family:Arial,Helvetica,sans-serif;letter-spacing:2px;text-align:center;text-indent:.13em;opacity:1;transition:all .2s}.ant-pagination-jump-next:hover .ant-pagination-item-link-icon,.ant-pagination-jump-prev:hover .ant-pagination-item-link-icon{opacity:1}.ant-pagination-jump-next:hover .ant-pagination-item-ellipsis,.ant-pagination-jump-prev:hover .ant-pagination-item-ellipsis{opacity:0}.ant-pagination-jump-next:focus-visible .ant-pagination-item-link-icon,.ant-pagination-jump-prev:focus-visible .ant-pagination-item-link-icon{opacity:1}.ant-pagination-jump-next:focus-visible .ant-pagination-item-ellipsis,.ant-pagination-jump-prev:focus-visible .ant-pagination-item-ellipsis{opacity:0}.ant-pagination-jump-next,.ant-pagination-jump-prev,.ant-pagination-prev{margin-right:8px}.ant-pagination-jump-next,.ant-pagination-jump-prev,.ant-pagination-next,.ant-pagination-prev{display:inline-block;min-width:32px;height:32px;color:rgba(0,10,36,.85);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";line-height:32px;text-align:center;vertical-align:middle;list-style:none;border-radius:4px;cursor:pointer;transition:all .3s}.ant-pagination-next,.ant-pagination-prev{font-family:Arial,Helvetica,sans-serif;outline:0}.ant-pagination-next button,.ant-pagination-prev button{color:rgba(0,10,36,.85);cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-pagination-next:hover button,.ant-pagination-prev:hover button{border-color:#4e86f5}.ant-pagination-next .ant-pagination-item-link,.ant-pagination-prev .ant-pagination-item-link{display:block;width:100%;height:100%;padding:0;font-size:12px;text-align:center;background-color:#fff;border:1px solid #d9d9d9;border-radius:4px;outline:none;transition:all .3s}.ant-pagination-next:focus-visible .ant-pagination-item-link,.ant-pagination-prev:focus-visible .ant-pagination-item-link{color:#296df3;border-color:#296df3}.ant-pagination-next:hover .ant-pagination-item-link,.ant-pagination-prev:hover .ant-pagination-item-link{color:#296df3;border-color:#296df3}.ant-pagination-disabled,.ant-pagination-disabled:hover{cursor:not-allowed}.ant-pagination-disabled .ant-pagination-item-link,.ant-pagination-disabled:hover .ant-pagination-item-link{color:rgba(0,0,0,.25);border-color:#d9d9d9;cursor:not-allowed}.ant-pagination-disabled:focus-visible{cursor:not-allowed}.ant-pagination-disabled:focus-visible .ant-pagination-item-link{color:rgba(0,0,0,.25);border-color:#d9d9d9;cursor:not-allowed}.ant-pagination-slash{margin:0 10px 0 5px}.ant-pagination-options{display:inline-block;margin-left:16px;vertical-align:middle}@media (-ms-high-contrast:none){.ant-pagination-options,.ant-pagination-options ::-ms-backdrop{vertical-align:top}}.ant-pagination-options-size-changer.ant-select{display:inline-block;width:auto}.ant-pagination-options-quick-jumper{display:inline-block;height:32px;margin-left:8px;line-height:32px;vertical-align:top}.ant-pagination-options-quick-jumper input{position:relative;display:inline-block;width:100%;min-width:0;padding:4px 11px;color:rgba(0,10,36,.85);font-size:14px;line-height:1.5715;background-color:#fff;background-image:none;border:1px solid #d9d9d9;border-radius:4px;transition:all .3s;width:50px;height:32px;margin:0 8px}.ant-pagination-options-quick-jumper input::-webkit-input-placeholder{color:#bfbfbf;-webkit-user-select:none;user-select:none}.ant-pagination-options-quick-jumper input:-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-pagination-options-quick-jumper input::-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-pagination-options-quick-jumper input::placeholder{color:#bfbfbf;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-pagination-options-quick-jumper input:-ms-input-placeholder{text-overflow:ellipsis}.ant-pagination-options-quick-jumper input:placeholder-shown{text-overflow:ellipsis}.ant-pagination-options-quick-jumper input:hover{border-color:#4e86f5;border-right-width:1px}.ant-pagination-options-quick-jumper input-focused,.ant-pagination-options-quick-jumper input:focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-pagination-options-quick-jumper input-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-pagination-options-quick-jumper input-disabled:hover{border-color:#d9d9d9;border-right-width:1px}.ant-pagination-options-quick-jumper input[disabled]{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-pagination-options-quick-jumper input[disabled]:hover{border-color:#d9d9d9;border-right-width:1px}.ant-pagination-options-quick-jumper input-borderless,.ant-pagination-options-quick-jumper input-borderless-disabled,.ant-pagination-options-quick-jumper input-borderless-focused,.ant-pagination-options-quick-jumper input-borderless:focus,.ant-pagination-options-quick-jumper input-borderless:hover,.ant-pagination-options-quick-jumper input-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-pagination-options-quick-jumper input{max-width:100%;height:auto;min-height:32px;line-height:1.5715;vertical-align:bottom;transition:all .3s,height 0s}.ant-pagination-options-quick-jumper input-lg{padding:6.5px 11px;font-size:16px}.ant-pagination-options-quick-jumper input-sm{padding:0 7px}.ant-pagination-simple .ant-pagination-next,.ant-pagination-simple .ant-pagination-prev{height:24px;line-height:24px;vertical-align:top}.ant-pagination-simple .ant-pagination-next .ant-pagination-item-link,.ant-pagination-simple .ant-pagination-prev .ant-pagination-item-link{height:24px;background-color:transparent;border:0}.ant-pagination-simple .ant-pagination-next .ant-pagination-item-link:after,.ant-pagination-simple .ant-pagination-prev .ant-pagination-item-link:after{height:24px;line-height:24px}.ant-pagination-simple .ant-pagination-simple-pager{display:inline-block;height:24px;margin-right:8px}.ant-pagination-simple .ant-pagination-simple-pager input{box-sizing:border-box;height:100%;margin-right:8px;padding:0 6px;text-align:center;background-color:#fff;border:1px solid #d9d9d9;border-radius:4px;outline:none;transition:border-color .3s}.ant-pagination-simple .ant-pagination-simple-pager input:hover{border-color:#296df3}.ant-pagination-simple .ant-pagination-simple-pager input:focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2)}.ant-pagination-simple .ant-pagination-simple-pager input[disabled]{color:rgba(0,0,0,.25);background:#f5f5f5;border-color:#d9d9d9;cursor:not-allowed}.ant-pagination.ant-pagination-mini .ant-pagination-simple-pager,.ant-pagination.ant-pagination-mini .ant-pagination-total-text{height:24px;line-height:24px}.ant-pagination.ant-pagination-mini .ant-pagination-item{min-width:24px;height:24px;margin:0;line-height:22px}.ant-pagination.ant-pagination-mini .ant-pagination-item:not(.ant-pagination-item-active){background:transparent;border-color:transparent}.ant-pagination.ant-pagination-mini .ant-pagination-next,.ant-pagination.ant-pagination-mini .ant-pagination-prev{min-width:24px;height:24px;margin:0;line-height:24px}.ant-pagination.ant-pagination-mini .ant-pagination-next .ant-pagination-item-link,.ant-pagination.ant-pagination-mini .ant-pagination-prev .ant-pagination-item-link{background:transparent;border-color:transparent}.ant-pagination.ant-pagination-mini .ant-pagination-next .ant-pagination-item-link:after,.ant-pagination.ant-pagination-mini .ant-pagination-prev .ant-pagination-item-link:after{height:24px;line-height:24px}.ant-pagination.ant-pagination-mini .ant-pagination-jump-next,.ant-pagination.ant-pagination-mini .ant-pagination-jump-prev{height:24px;margin-right:0;line-height:24px}.ant-pagination.ant-pagination-mini .ant-pagination-options{margin-left:2px}.ant-pagination.ant-pagination-mini .ant-pagination-options-size-changer{top:0}.ant-pagination.ant-pagination-mini .ant-pagination-options-quick-jumper{height:24px;line-height:24px}.ant-pagination.ant-pagination-mini .ant-pagination-options-quick-jumper input{padding:0 7px;width:44px;height:24px}.ant-pagination.ant-pagination-disabled{cursor:not-allowed}.ant-pagination.ant-pagination-disabled .ant-pagination-item{background:#f5f5f5;border-color:#d9d9d9;cursor:not-allowed}.ant-pagination.ant-pagination-disabled .ant-pagination-item a{color:rgba(0,0,0,.25);background:transparent;border:none;cursor:not-allowed}.ant-pagination.ant-pagination-disabled .ant-pagination-item-active{background:#e6e6e6}.ant-pagination.ant-pagination-disabled .ant-pagination-item-active a{color:rgba(0,0,0,.25)}.ant-pagination.ant-pagination-disabled .ant-pagination-item-link{color:rgba(0,0,0,.25);background:#f5f5f5;border-color:#d9d9d9;cursor:not-allowed}.ant-pagination-simple.ant-pagination.ant-pagination-disabled .ant-pagination-item-link{background:transparent}.ant-pagination.ant-pagination-disabled .ant-pagination-item-link-icon{opacity:0}.ant-pagination.ant-pagination-disabled .ant-pagination-item-ellipsis{opacity:1}.ant-pagination.ant-pagination-disabled .ant-pagination-simple-pager{color:rgba(0,0,0,.25)}@media only screen and (max-width:992px){.ant-pagination-item-after-jump-prev,.ant-pagination-item-before-jump-next{display:none}}@media only screen and (max-width:576px){.ant-pagination-options{display:none}}.ant-pagination-rtl .ant-pagination-total-text{margin-right:0;margin-left:8px}.ant-pagination-rtl .ant-pagination-item,.ant-pagination-rtl .ant-pagination-jump-next,.ant-pagination-rtl .ant-pagination-jump-prev,.ant-pagination-rtl .ant-pagination-prev{margin-right:0;margin-left:8px}.ant-pagination-rtl .ant-pagination-slash{margin:0 5px 0 10px}.ant-pagination-rtl .ant-pagination-options{margin-right:16px;margin-left:0}.ant-pagination-rtl .ant-pagination-options .ant-pagination-options-size-changer.ant-select{margin-right:0;margin-left:8px}.ant-pagination-rtl .ant-pagination-options .ant-pagination-options-quick-jumper{margin-left:0}.ant-pagination-rtl.ant-pagination-simple .ant-pagination-simple-pager{margin-right:0;margin-left:8px}.ant-pagination-rtl.ant-pagination-simple .ant-pagination-simple-pager input{margin-right:0;margin-left:8px}.ant-pagination-rtl.ant-pagination.mini .ant-pagination-options{margin-right:2px;margin-left:0}.ant-table.ant-table-middle{font-size:14px}.ant-table.ant-table-middle .ant-table-footer,.ant-table.ant-table-middle .ant-table-tbody>tr>td,.ant-table.ant-table-middle .ant-table-thead>tr>th,.ant-table.ant-table-middle .ant-table-title,.ant-table.ant-table-middle tfoot>tr>td,.ant-table.ant-table-middle tfoot>tr>th{padding:12px 8px}.ant-table.ant-table-middle .ant-table-filter-trigger{margin-right:-4px}.ant-table.ant-table-middle .ant-table-expanded-row-fixed{margin:-12px -8px}.ant-table.ant-table-middle .ant-table-tbody .ant-table-wrapper:only-child .ant-table{margin:-12px -8px -12px 40px}.ant-table.ant-table-middle .ant-table-selection-column{-webkit-padding-start:2px;padding-inline-start:2px}.ant-table.ant-table-small{font-size:14px}.ant-table.ant-table-small .ant-table-footer,.ant-table.ant-table-small .ant-table-tbody>tr>td,.ant-table.ant-table-small .ant-table-thead>tr>th,.ant-table.ant-table-small .ant-table-title,.ant-table.ant-table-small tfoot>tr>td,.ant-table.ant-table-small tfoot>tr>th{padding:8px}.ant-table.ant-table-small .ant-table-filter-trigger{margin-right:-4px}.ant-table.ant-table-small .ant-table-expanded-row-fixed{margin:-8px}.ant-table.ant-table-small .ant-table-tbody .ant-table-wrapper:only-child .ant-table{margin:-8px -8px -8px 40px}.ant-table.ant-table-small .ant-table-selection-column{-webkit-padding-start:2px;padding-inline-start:2px}.ant-table.ant-table-bordered>.ant-table-title{border:1px solid #f0f0f0;border-bottom:0}.ant-table.ant-table-bordered>.ant-table-container{border-left:1px solid #f0f0f0}.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>tbody>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>tfoot>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>tfoot>tr>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>thead>tr>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>tbody>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>tfoot>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>tfoot>tr>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>thead>tr>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>tbody>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>tfoot>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>tfoot>tr>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>thead>tr>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>tbody>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>tfoot>tr>td,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>tfoot>tr>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>thead>tr>th{border-right:1px solid #f0f0f0}.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>thead>tr:not(:last-child)>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>thead>tr:not(:last-child)>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>thead>tr:not(:last-child)>th,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>thead>tr:not(:last-child)>th{border-bottom:1px solid #f0f0f0}.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>thead>tr>th:before,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>thead>tr>th:before,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>thead>tr>th:before,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>thead>tr>th:before{background-color:transparent!important}.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>tbody>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>tfoot>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>thead>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>tbody>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>tfoot>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>thead>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>tbody>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>tfoot>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>thead>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>tbody>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>tfoot>tr>.ant-table-cell-fix-right-first:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>thead>tr>.ant-table-cell-fix-right-first:after{border-right:1px solid #f0f0f0}.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>tbody>tr>td>.ant-table-expanded-row-fixed,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>tbody>tr>td>.ant-table-expanded-row-fixed,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>tbody>tr>td>.ant-table-expanded-row-fixed,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>tbody>tr>td>.ant-table-expanded-row-fixed{margin:-16px -17px}.ant-table.ant-table-bordered>.ant-table-container>.ant-table-body>table>tbody>tr>td>.ant-table-expanded-row-fixed:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>tbody>tr>td>.ant-table-expanded-row-fixed:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table>tbody>tr>td>.ant-table-expanded-row-fixed:after,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-summary>table>tbody>tr>td>.ant-table-expanded-row-fixed:after{position:absolute;top:0;right:1px;bottom:0;border-right:1px solid #f0f0f0;content:""}.ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table,.ant-table.ant-table-bordered>.ant-table-container>.ant-table-header>table{border-top:1px solid #f0f0f0}.ant-table.ant-table-bordered.ant-table-scroll-horizontal>.ant-table-container>.ant-table-body>table>tbody>tr.ant-table-expanded-row>td,.ant-table.ant-table-bordered.ant-table-scroll-horizontal>.ant-table-container>.ant-table-body>table>tbody>tr.ant-table-placeholder>td{border-right:0}.ant-table.ant-table-bordered.ant-table-middle>.ant-table-container>.ant-table-body>table>tbody>tr>td>.ant-table-expanded-row-fixed,.ant-table.ant-table-bordered.ant-table-middle>.ant-table-container>.ant-table-content>table>tbody>tr>td>.ant-table-expanded-row-fixed{margin:-12px -9px}.ant-table.ant-table-bordered.ant-table-small>.ant-table-container>.ant-table-body>table>tbody>tr>td>.ant-table-expanded-row-fixed,.ant-table.ant-table-bordered.ant-table-small>.ant-table-container>.ant-table-content>table>tbody>tr>td>.ant-table-expanded-row-fixed{margin:-8px -9px}.ant-table.ant-table-bordered>.ant-table-footer{border:1px solid #f0f0f0;border-top:0}.ant-table-cell .ant-table-container:first-child{border-top:0}.ant-table-cell-scrollbar:not([rowspan]){box-shadow:0 1px 0 1px #fafafa}.ant-table-wrapper{clear:both;max-width:100%}.ant-table-wrapper:before{display:table;content:""}.ant-table-wrapper:after{display:table;clear:both;content:""}.ant-table{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;font-size:14px;background:#fff;border-radius:4px}.ant-table table{width:100%;text-align:left;border-radius:4px 4px 0 0;border-collapse:separate;border-spacing:0}.ant-table-tbody>tr>td,.ant-table-thead>tr>th,.ant-table tfoot>tr>td,.ant-table tfoot>tr>th{position:relative;padding:16px;overflow-wrap:break-word}.ant-table-cell-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;word-break:keep-all}.ant-table-cell-ellipsis.ant-table-cell-fix-left-last,.ant-table-cell-ellipsis.ant-table-cell-fix-right-first{overflow:visible}.ant-table-cell-ellipsis.ant-table-cell-fix-left-last .ant-table-cell-content,.ant-table-cell-ellipsis.ant-table-cell-fix-right-first .ant-table-cell-content{display:block;overflow:hidden;text-overflow:ellipsis}.ant-table-cell-ellipsis .ant-table-column-title{overflow:hidden;text-overflow:ellipsis;word-break:keep-all}.ant-table-title{padding:16px}.ant-table-footer{padding:16px;color:rgba(0,10,36,.85);background:#fafafa}.ant-table-thead>tr>th{position:relative;color:rgba(0,10,36,.85);font-weight:500;text-align:left;background:#fafafa;border-bottom:1px solid #f0f0f0;transition:background .3s ease}.ant-table-thead>tr>th[colspan]:not([colspan="1"]){text-align:center}.ant-table-thead>tr>th:not(:last-child):not(.ant-table-selection-column):not(.ant-table-row-expand-icon-cell):not([colspan]):before{position:absolute;top:50%;right:0;width:1px;height:1.6em;background-color:rgba(0,0,0,.06);transform:translateY(-50%);transition:background-color .3s;content:""}.ant-table-thead>tr:not(:last-child)>th[colspan]{border-bottom:0}.ant-table-tbody>tr>td{border-bottom:1px solid #f0f0f0;transition:background .3s}.ant-table-tbody>tr>td>.ant-table-expanded-row-fixed>.ant-table-wrapper:only-child .ant-table,.ant-table-tbody>tr>td>.ant-table-wrapper:only-child .ant-table{margin:-16px -16px -16px 32px}.ant-table-tbody>tr>td>.ant-table-expanded-row-fixed>.ant-table-wrapper:only-child .ant-table-tbody>tr:last-child>td,.ant-table-tbody>tr>td>.ant-table-wrapper:only-child .ant-table-tbody>tr:last-child>td{border-bottom:0}.ant-table-tbody>tr>td>.ant-table-expanded-row-fixed>.ant-table-wrapper:only-child .ant-table-tbody>tr:last-child>td:first-child,.ant-table-tbody>tr>td>.ant-table-expanded-row-fixed>.ant-table-wrapper:only-child .ant-table-tbody>tr:last-child>td:last-child,.ant-table-tbody>tr>td>.ant-table-wrapper:only-child .ant-table-tbody>tr:last-child>td:first-child,.ant-table-tbody>tr>td>.ant-table-wrapper:only-child .ant-table-tbody>tr:last-child>td:last-child{border-radius:0}.ant-table-tbody>tr.ant-table-row:hover>td,.ant-table-tbody>tr>td.ant-table-cell-row-hover{background:#fafafa}.ant-table-tbody>tr.ant-table-row-selected>td{background:#e3ecfd;border-color:rgba(0,0,0,.03)}.ant-table-tbody>tr.ant-table-row-selected:hover>td{background:#d9e6fc}.ant-table-summary{position:relative;z-index:2;background:#fff}div.ant-table-summary{box-shadow:0 -1px 0 #f0f0f0}.ant-table-summary>tr>td,.ant-table-summary>tr>th{border-bottom:1px solid #f0f0f0}.ant-table-pagination.ant-pagination{margin:16px 0}.ant-table-pagination{display:flex;flex-wrap:wrap;grid-row-gap:8px;row-gap:8px}.ant-table-pagination>*{flex:none}.ant-table-pagination-left{justify-content:flex-start}.ant-table-pagination-center{justify-content:center}.ant-table-pagination-right{justify-content:flex-end}.ant-table-thead th.ant-table-column-has-sorters{outline:none;cursor:pointer;transition:all .3s}.ant-table-thead th.ant-table-column-has-sorters:hover{background:rgba(0,0,0,.04)}.ant-table-thead th.ant-table-column-has-sorters:hover:before{background-color:transparent!important}.ant-table-thead th.ant-table-column-has-sorters:focus-visible{color:#296df3}.ant-table-thead th.ant-table-column-has-sorters.ant-table-cell-fix-left:hover,.ant-table-thead th.ant-table-column-has-sorters.ant-table-cell-fix-right:hover{background:#f5f5f5}.ant-table-thead th.ant-table-column-sort{background:#f5f5f5}.ant-table-thead th.ant-table-column-sort:before{background-color:transparent!important}td.ant-table-column-sort{background:#fafafa}.ant-table-column-title{position:relative;z-index:1;flex:1 1}.ant-table-column-sorters{display:flex;flex:auto;align-items:center;justify-content:space-between}.ant-table-column-sorters:after{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;content:""}.ant-table-column-sorter{margin-left:4px;color:#bfbfbf;font-size:0;transition:color .3s}.ant-table-column-sorter-inner{display:inline-flex;flex-direction:column;align-items:center}.ant-table-column-sorter-down,.ant-table-column-sorter-up{font-size:11px}.ant-table-column-sorter-down.active,.ant-table-column-sorter-up.active{color:#296df3}.ant-table-column-sorter-up+.ant-table-column-sorter-down{margin-top:-.3em}.ant-table-column-sorters:hover .ant-table-column-sorter{color:#a6a6a6}.ant-table-filter-column{display:flex;justify-content:space-between}.ant-table-filter-trigger{position:relative;display:flex;align-items:center;margin:-4px -8px -4px 4px;padding:0 4px;color:#bfbfbf;font-size:12px;border-radius:4px;cursor:pointer;transition:all .3s}.ant-table-filter-trigger:hover{color:rgba(0,10,36,.65);background:rgba(0,0,0,.04)}.ant-table-filter-trigger.active{color:#296df3}.ant-table-filter-dropdown{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";min-width:120px;background-color:#fff;border-radius:4px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05)}.ant-table-filter-dropdown .ant-dropdown-menu{max-height:264px;overflow-x:hidden;border:0;box-shadow:none}.ant-table-filter-dropdown .ant-dropdown-menu:empty:after{display:block;padding:8px 0;color:rgba(0,0,0,.25);font-size:12px;text-align:center;content:"Not Found"}.ant-table-filter-dropdown-tree{padding:8px 8px 0}.ant-table-filter-dropdown-tree .ant-tree-treenode .ant-tree-node-content-wrapper:hover{background-color:#f5f5f5}.ant-table-filter-dropdown-tree .ant-tree-treenode-checkbox-checked .ant-tree-node-content-wrapper,.ant-table-filter-dropdown-tree .ant-tree-treenode-checkbox-checked .ant-tree-node-content-wrapper:hover{background-color:#bed2fb}.ant-table-filter-dropdown-search{padding:8px;border-bottom:1px solid #f0f0f0}.ant-table-filter-dropdown-search-input input{min-width:140px}.ant-table-filter-dropdown-search-input .anticon{color:rgba(0,0,0,.25)}.ant-table-filter-dropdown-checkall{width:100%;margin-bottom:4px;margin-left:4px}.ant-table-filter-dropdown-submenu>ul{max-height:calc(100vh - 130px);overflow-x:hidden;overflow-y:auto}.ant-table-filter-dropdown-submenu .ant-checkbox-wrapper+span,.ant-table-filter-dropdown .ant-checkbox-wrapper+span{padding-left:8px}.ant-table-filter-dropdown-btns{display:flex;justify-content:space-between;padding:7px 8px;overflow:hidden;background-color:inherit;border-top:1px solid #f0f0f0}.ant-table-selection-col{width:32px}.ant-table-bordered .ant-table-selection-col{width:50px}table tr td.ant-table-selection-column,table tr th.ant-table-selection-column{padding-right:8px;padding-left:8px;text-align:center}table tr td.ant-table-selection-column .ant-radio-wrapper,table tr th.ant-table-selection-column .ant-radio-wrapper{margin-right:0}table tr th.ant-table-selection-column.ant-table-cell-fix-left{z-index:3}table tr th.ant-table-selection-column:after{background-color:transparent!important}.ant-table-selection{position:relative;display:inline-flex;flex-direction:column}.ant-table-selection-extra{position:absolute;top:0;z-index:1;cursor:pointer;transition:all .3s;-webkit-margin-start:100%;margin-inline-start:100%;-webkit-padding-start:4px;padding-inline-start:4px}.ant-table-selection-extra .anticon{color:#bfbfbf;font-size:10px}.ant-table-selection-extra .anticon:hover{color:#a6a6a6}.ant-table-expand-icon-col{width:48px}.ant-table-row-expand-icon-cell{text-align:center}.ant-table-row-expand-icon-cell .ant-table-row-expand-icon{display:inline-flex;float:none;vertical-align:sub}.ant-table-row-indent{float:left;height:1px}.ant-table-row-expand-icon{color:#296df3;outline:none;cursor:pointer;transition:color .3s;position:relative;float:left;box-sizing:border-box;width:17px;height:17px;padding:0;color:inherit;line-height:17px;background:#fff;border:1px solid #f0f0f0;border-radius:4px;transform:scale(.94117647);transition:all .3s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-table-row-expand-icon:focus-visible,.ant-table-row-expand-icon:hover{color:#5493ff}.ant-table-row-expand-icon:active{color:#184ecc}.ant-table-row-expand-icon:active,.ant-table-row-expand-icon:focus,.ant-table-row-expand-icon:hover{border-color:currentcolor}.ant-table-row-expand-icon:after,.ant-table-row-expand-icon:before{position:absolute;background:currentcolor;transition:transform .3s ease-out;content:""}.ant-table-row-expand-icon:before{top:7px;right:3px;left:3px;height:1px}.ant-table-row-expand-icon:after{top:3px;bottom:3px;left:7px;width:1px;transform:rotate(90deg)}.ant-table-row-expand-icon-collapsed:before{transform:rotate(-180deg)}.ant-table-row-expand-icon-collapsed:after{transform:rotate(0deg)}.ant-table-row-expand-icon-spaced{background:transparent;border:0;visibility:hidden}.ant-table-row-expand-icon-spaced:after,.ant-table-row-expand-icon-spaced:before{display:none;content:none}.ant-table-row-indent+.ant-table-row-expand-icon{margin-top:2.5005px;margin-right:8px}tr.ant-table-expanded-row:hover>td,tr.ant-table-expanded-row>td{background:#fbfbfb}tr.ant-table-expanded-row .ant-descriptions-view{display:flex}tr.ant-table-expanded-row .ant-descriptions-view table{flex:auto;width:auto}.ant-table .ant-table-expanded-row-fixed{position:relative;margin:-16px;padding:16px}.ant-table-tbody>tr.ant-table-placeholder{text-align:center}.ant-table-empty .ant-table-tbody>tr.ant-table-placeholder{color:rgba(0,0,0,.25)}.ant-table-tbody>tr.ant-table-placeholder:hover>td{background:#fff}.ant-table-cell-fix-left,.ant-table-cell-fix-right{position:-webkit-sticky!important;position:sticky!important;z-index:2;background:#fff}.ant-table-cell-fix-left-first:after,.ant-table-cell-fix-left-last:after{position:absolute;top:0;right:0;bottom:-1px;width:30px;transform:translateX(100%);transition:box-shadow .3s;content:"";pointer-events:none}.ant-table-cell-fix-left-all:after{display:none}.ant-table-cell-fix-right-first:after,.ant-table-cell-fix-right-last:after{position:absolute;top:0;bottom:-1px;left:0;width:30px;transform:translateX(-100%);transition:box-shadow .3s;content:"";pointer-events:none}.ant-table .ant-table-container:after,.ant-table .ant-table-container:before{position:absolute;top:0;bottom:0;z-index:4;width:30px;transition:box-shadow .3s;content:"";pointer-events:none}.ant-table .ant-table-container:before{left:0}.ant-table .ant-table-container:after{right:0}.ant-table-ping-left:not(.ant-table-has-fix-left)>.ant-table-container{position:relative}.ant-table-ping-left:not(.ant-table-has-fix-left)>.ant-table-container:before{box-shadow:inset 10px 0 8px -8px rgba(0,0,0,.15)}.ant-table-ping-left .ant-table-cell-fix-left-first:after,.ant-table-ping-left .ant-table-cell-fix-left-last:after{box-shadow:inset 10px 0 8px -8px rgba(0,0,0,.15)}.ant-table-ping-left .ant-table-cell-fix-left-last:before{background-color:transparent!important}.ant-table-ping-right:not(.ant-table-has-fix-right)>.ant-table-container{position:relative}.ant-table-ping-right:not(.ant-table-has-fix-right)>.ant-table-container:after{box-shadow:inset -10px 0 8px -8px rgba(0,0,0,.15)}.ant-table-ping-right .ant-table-cell-fix-right-first:after,.ant-table-ping-right .ant-table-cell-fix-right-last:after{box-shadow:inset -10px 0 8px -8px rgba(0,0,0,.15)}.ant-table-sticky-holder{position:-webkit-sticky;position:sticky;z-index:3;background:#fff}.ant-table-sticky-scroll{position:-webkit-sticky;position:sticky;bottom:0;z-index:3;display:flex;align-items:center;background:#fff;border-top:1px solid #f0f0f0;opacity:.6}.ant-table-sticky-scroll:hover{transform-origin:center bottom}.ant-table-sticky-scroll-bar{height:8px;background-color:rgba(0,0,0,.35);border-radius:4px}.ant-table-sticky-scroll-bar:hover{background-color:rgba(0,0,0,.8)}.ant-table-sticky-scroll-bar-active{background-color:rgba(0,0,0,.8)}@media (-ms-high-contrast:none){.ant-table-ping-left .ant-table-cell-fix-left-last:after{box-shadow:none!important}.ant-table-ping-right .ant-table-cell-fix-right-first:after{box-shadow:none!important}}.ant-table-title{border-radius:4px 4px 0 0}.ant-table-title+.ant-table-container{border-top-left-radius:0;border-top-right-radius:0}.ant-table-title+.ant-table-container table{border-radius:0}.ant-table-title+.ant-table-container table>thead>tr:first-child th:first-child{border-radius:0}.ant-table-title+.ant-table-container table>thead>tr:first-child th:last-child{border-radius:0}.ant-table-container{border-top-left-radius:4px;border-top-right-radius:4px}.ant-table-container table>thead>tr:first-child th:first-child{border-top-left-radius:4px}.ant-table-container table>thead>tr:first-child th:last-child{border-top-right-radius:4px}.ant-table-footer{border-radius:0 0 4px 4px}.ant-table-wrapper-rtl{direction:rtl}.ant-table-rtl{direction:rtl}.ant-table-wrapper-rtl .ant-table table{text-align:right}.ant-table-wrapper-rtl .ant-table-thead>tr>th[colspan]:not([colspan="1"]){text-align:center}.ant-table-wrapper-rtl .ant-table-thead>tr>th:not(:last-child):not(.ant-table-selection-column):not(.ant-table-row-expand-icon-cell):not([colspan]):before{right:auto;left:0}.ant-table-wrapper-rtl .ant-table-thead>tr>th{text-align:right}.ant-table-tbody>tr .ant-table-wrapper:only-child .ant-table.ant-table-rtl{margin:-16px 33px -16px -16px}.ant-table-wrapper.ant-table-wrapper-rtl .ant-table-pagination-left{justify-content:flex-end}.ant-table-wrapper.ant-table-wrapper-rtl .ant-table-pagination-right{justify-content:flex-start}.ant-table-wrapper-rtl .ant-table-column-sorter{margin-right:4px;margin-left:0}.ant-table-wrapper-rtl .ant-table-filter-column-title{padding:16px 16px 16px 2.3em}.ant-table-rtl .ant-table-thead tr th.ant-table-column-has-sorters .ant-table-filter-column-title{padding:0 0 0 2.3em}.ant-table-wrapper-rtl .ant-table-filter-trigger{margin:-4px 4px -4px -8px}.ant-dropdown-menu-submenu-rtl.ant-table-filter-dropdown-submenu .ant-checkbox-wrapper+span,.ant-dropdown-menu-submenu-rtl.ant-table-filter-dropdown .ant-checkbox-wrapper+span,.ant-dropdown-rtl .ant-table-filter-dropdown-submenu .ant-checkbox-wrapper+span,.ant-dropdown-rtl .ant-table-filter-dropdown .ant-checkbox-wrapper+span{padding-right:8px;padding-left:0}.ant-table-wrapper-rtl .ant-table-selection{text-align:center}.ant-table-wrapper-rtl .ant-table-row-indent{float:right}.ant-table-wrapper-rtl .ant-table-row-expand-icon{float:right}.ant-table-wrapper-rtl .ant-table-row-indent+.ant-table-row-expand-icon{margin-right:0;margin-left:8px}.ant-table-wrapper-rtl .ant-table-row-expand-icon:after{transform:rotate(-90deg)}.ant-table-wrapper-rtl .ant-table-row-expand-icon-collapsed:before{transform:rotate(180deg)}.ant-table-wrapper-rtl .ant-table-row-expand-icon-collapsed:after{transform:rotate(0deg)}.ant-radio-group{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-block;font-size:0}.ant-radio-group .ant-badge-count{z-index:1}.ant-radio-group>.ant-badge:not(:first-child)>.ant-radio-button-wrapper{border-left:none}.ant-radio-wrapper{box-sizing:border-box;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:inline-flex;align-items:baseline;margin:0 8px 0 0;cursor:pointer}.ant-radio-wrapper-disabled{cursor:not-allowed}.ant-radio-wrapper:after{display:inline-block;width:0;overflow:hidden;content:"\a0"}.ant-radio-wrapper.ant-radio-wrapper-in-form-item input[type=radio]{width:14px;height:14px}.ant-radio{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;top:.2em;display:inline-block;outline:none;cursor:pointer}.ant-radio-input:focus+.ant-radio-inner,.ant-radio-wrapper:hover .ant-radio,.ant-radio:hover .ant-radio-inner{border-color:#296df3}.ant-radio-input:focus+.ant-radio-inner{box-shadow:0 0 0 3px rgba(41,109,243,.12)}.ant-radio-checked:after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #296df3;border-radius:50%;visibility:hidden;animation:antRadioEffect .36s ease-in-out;animation-fill-mode:both;content:""}.ant-radio-wrapper:hover .ant-radio:after,.ant-radio:hover:after{visibility:visible}.ant-radio-inner{position:relative;top:0;left:0;display:block;width:16px;height:16px;background-color:#fff;border:1px solid #d9d9d9;border-radius:50%;transition:all .3s}.ant-radio-inner:after{position:absolute;top:50%;left:50%;display:block;width:16px;height:16px;margin-top:-8px;margin-left:-8px;background-color:#296df3;border-top:0;border-left:0;border-radius:16px;transform:scale(0);opacity:0;transition:all .3s cubic-bezier(.78,.14,.15,.86);content:" "}.ant-radio-input{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;cursor:pointer;opacity:0}.ant-radio.ant-radio-disabled .ant-radio-inner{border-color:#d9d9d9}.ant-radio-checked .ant-radio-inner{border-color:#296df3}.ant-radio-checked .ant-radio-inner:after{transform:scale(.5);opacity:1;transition:all .3s cubic-bezier(.78,.14,.15,.86)}.ant-radio-disabled{cursor:not-allowed}.ant-radio-disabled .ant-radio-inner{background-color:#f5f5f5;cursor:not-allowed}.ant-radio-disabled .ant-radio-inner:after{background-color:rgba(0,0,0,.2)}.ant-radio-disabled .ant-radio-input{cursor:not-allowed}.ant-radio-disabled+span{color:rgba(0,0,0,.25);cursor:not-allowed}span.ant-radio+*{padding-right:8px;padding-left:8px}.ant-radio-button-wrapper{position:relative;display:inline-block;height:32px;margin:0;padding:0 15px;color:rgba(0,10,36,.65);font-size:14px;line-height:30px;background:#fff;border-color:#d9d9d9;border-style:solid;border-width:1.02px 1px 1px 0;cursor:pointer;transition:color .3s,background .3s,border-color .3s,box-shadow .3s}.ant-radio-button-wrapper a{color:rgba(0,10,36,.65)}.ant-radio-button-wrapper>.ant-radio-button{position:absolute;top:0;left:0;z-index:-1;width:100%;height:100%}.ant-radio-group-large .ant-radio-button-wrapper{height:40px;font-size:16px;line-height:38px}.ant-radio-group-small .ant-radio-button-wrapper{height:24px;padding:0 7px;line-height:22px}.ant-radio-button-wrapper:not(:first-child):before{position:absolute;top:-1px;left:-1px;display:block;box-sizing:content-box;width:1px;height:100%;padding:1px 0;background-color:#d9d9d9;transition:background-color .3s;content:""}.ant-radio-button-wrapper:first-child{border-left:1px solid #d9d9d9;border-radius:4px 0 0 4px}.ant-radio-button-wrapper:last-child{border-radius:0 4px 4px 0}.ant-radio-button-wrapper:first-child:last-child{border-radius:4px}.ant-radio-button-wrapper:hover{position:relative;color:#296df3}.ant-radio-button-wrapper:focus-within{box-shadow:0 0 0 3px rgba(41,109,243,.12)}.ant-radio-button-wrapper .ant-radio-inner,.ant-radio-button-wrapper input[type=checkbox],.ant-radio-button-wrapper input[type=radio]{width:0;height:0;opacity:0;pointer-events:none}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled){z-index:1;color:#296df3;background:#fff;border-color:#296df3}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):before{background-color:#296df3}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):first-child{border-color:#296df3}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{color:#4e86f5;border-color:#4e86f5}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover:before{background-color:#4e86f5}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active{color:#0d57e8;border-color:#0d57e8}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active:before{background-color:#0d57e8}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):focus-within{box-shadow:0 0 0 3px rgba(41,109,243,.12)}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled){color:#fff;background:#296df3;border-color:#296df3}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{color:#fff;background:#4e86f5;border-color:#4e86f5}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active{color:#fff;background:#0d57e8;border-color:#0d57e8}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):focus-within{box-shadow:0 0 0 3px rgba(41,109,243,.12)}.ant-radio-button-wrapper-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;cursor:not-allowed}.ant-radio-button-wrapper-disabled:first-child,.ant-radio-button-wrapper-disabled:hover{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9}.ant-radio-button-wrapper-disabled:first-child{border-left-color:#d9d9d9}.ant-radio-button-wrapper-disabled.ant-radio-button-wrapper-checked{color:rgba(0,0,0,.25);background-color:#e6e6e6;border-color:#d9d9d9;box-shadow:none}@keyframes antRadioEffect{0%{transform:scale(1);opacity:.5}to{transform:scale(1.6);opacity:0}}.ant-radio-group.ant-radio-group-rtl{direction:rtl}.ant-radio-wrapper.ant-radio-wrapper-rtl{margin-right:0;margin-left:8px;direction:rtl}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl{border-right-width:0;border-left-width:1px}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper:not(:first-child):before{right:-1px;left:0}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper:first-child{border-right:1px solid #d9d9d9;border-radius:0 4px 4px 0}.ant-radio-button-wrapper-checked:not([class*=" ant-radio-button-wrapper-disabled"]).ant-radio-button-wrapper:first-child{border-right-color:#4e86f5}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper:last-child{border-radius:4px 0 0 4px}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper-disabled:first-child{border-right-color:#d9d9d9}.ant-typography{color:rgba(0,10,36,.85);word-break:break-word}.ant-typography.ant-typography-secondary{color:rgba(0,10,36,.65)}.ant-typography.ant-typography-success{color:#26c992}.ant-typography.ant-typography-warning{color:#ffb924}.ant-typography.ant-typography-danger{color:#ef4872}a.ant-typography.ant-typography-danger:active,a.ant-typography.ant-typography-danger:focus{color:#c9325d}a.ant-typography.ant-typography-danger:hover{color:#fc7492}.ant-typography.ant-typography-disabled{color:rgba(0,0,0,.25);cursor:not-allowed;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-typography p,div.ant-typography{margin-bottom:1em}.ant-typography h1,div.ant-typography-h1,div.ant-typography-h1>textarea,h1.ant-typography{margin-bottom:.5em;color:rgba(0,10,36,.85);font-weight:600;font-size:38px;line-height:1.23}.ant-typography h2,div.ant-typography-h2,div.ant-typography-h2>textarea,h2.ant-typography{margin-bottom:.5em;color:rgba(0,10,36,.85);font-weight:600;font-size:30px;line-height:1.35}.ant-typography h3,div.ant-typography-h3,div.ant-typography-h3>textarea,h3.ant-typography{margin-bottom:.5em;color:rgba(0,10,36,.85);font-weight:600;font-size:24px;line-height:1.35}.ant-typography h4,div.ant-typography-h4,div.ant-typography-h4>textarea,h4.ant-typography{margin-bottom:.5em;color:rgba(0,10,36,.85);font-weight:600;font-size:20px;line-height:1.4}.ant-typography h5,div.ant-typography-h5,div.ant-typography-h5>textarea,h5.ant-typography{margin-bottom:.5em;color:rgba(0,10,36,.85);font-weight:600;font-size:16px;line-height:1.5}.ant-typography+h1.ant-typography,.ant-typography+h2.ant-typography,.ant-typography+h3.ant-typography,.ant-typography+h4.ant-typography,.ant-typography+h5.ant-typography{margin-top:1.2em}.ant-typography div+h1,.ant-typography div+h2,.ant-typography div+h3,.ant-typography div+h4,.ant-typography div+h5,.ant-typography h1+h1,.ant-typography h1+h2,.ant-typography h1+h3,.ant-typography h1+h4,.ant-typography h1+h5,.ant-typography h2+h1,.ant-typography h2+h2,.ant-typography h2+h3,.ant-typography h2+h4,.ant-typography h2+h5,.ant-typography h3+h1,.ant-typography h3+h2,.ant-typography h3+h3,.ant-typography h3+h4,.ant-typography h3+h5,.ant-typography h4+h1,.ant-typography h4+h2,.ant-typography h4+h3,.ant-typography h4+h4,.ant-typography h4+h5,.ant-typography h5+h1,.ant-typography h5+h2,.ant-typography h5+h3,.ant-typography h5+h4,.ant-typography h5+h5,.ant-typography li+h1,.ant-typography li+h2,.ant-typography li+h3,.ant-typography li+h4,.ant-typography li+h5,.ant-typography p+h1,.ant-typography p+h2,.ant-typography p+h3,.ant-typography p+h4,.ant-typography p+h5,.ant-typography ul+h1,.ant-typography ul+h2,.ant-typography ul+h3,.ant-typography ul+h4,.ant-typography ul+h5{margin-top:1.2em}a.ant-typography-ellipsis,span.ant-typography-ellipsis{display:inline-block;max-width:100%}.ant-typography a,a.ant-typography{color:#296df3;outline:none;cursor:pointer;transition:color .3s;text-decoration:none}.ant-typography a:focus-visible,.ant-typography a:hover,a.ant-typography:focus-visible,a.ant-typography:hover{color:#5493ff}.ant-typography a:active,a.ant-typography:active{color:#184ecc}.ant-typography a:active,.ant-typography a:hover,a.ant-typography:active,a.ant-typography:hover{text-decoration:none}.ant-typography a.ant-typography-disabled,.ant-typography a[disabled],a.ant-typography.ant-typography-disabled,a.ant-typography[disabled]{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-typography a.ant-typography-disabled:active,.ant-typography a.ant-typography-disabled:hover,.ant-typography a[disabled]:active,.ant-typography a[disabled]:hover,a.ant-typography.ant-typography-disabled:active,a.ant-typography.ant-typography-disabled:hover,a.ant-typography[disabled]:active,a.ant-typography[disabled]:hover{color:rgba(0,0,0,.25)}.ant-typography a.ant-typography-disabled:active,.ant-typography a[disabled]:active,a.ant-typography.ant-typography-disabled:active,a.ant-typography[disabled]:active{pointer-events:none}.ant-typography code{margin:0 .2em;padding:.2em .4em .1em;font-size:85%;background:hsla(0,0%,58.8%,.1);border:1px solid hsla(0,0%,39.2%,.2);border-radius:3px}.ant-typography kbd{margin:0 .2em;padding:.15em .4em .1em;font-size:90%;background:hsla(0,0%,58.8%,.06);border:solid hsla(0,0%,39.2%,.2);border-width:1px 1px 2px;border-radius:3px}.ant-typography mark{padding:0;background-color:#ffea9e}.ant-typography ins,.ant-typography u{text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.ant-typography del,.ant-typography s{text-decoration:line-through}.ant-typography strong{font-weight:600}.ant-typography-copy,.ant-typography-edit,.ant-typography-expand{color:#296df3;outline:none;cursor:pointer;transition:color .3s;margin-left:4px}.ant-typography-copy:focus-visible,.ant-typography-copy:hover,.ant-typography-edit:focus-visible,.ant-typography-edit:hover,.ant-typography-expand:focus-visible,.ant-typography-expand:hover{color:#5493ff}.ant-typography-copy:active,.ant-typography-edit:active,.ant-typography-expand:active{color:#184ecc}.ant-typography-copy-success,.ant-typography-copy-success:focus,.ant-typography-copy-success:hover{color:#26c992}.ant-typography-edit-content{position:relative}div.ant-typography-edit-content{left:-12px;margin-top:-5px;margin-bottom:calc(1em - 5px)}.ant-typography-edit-content-confirm{position:absolute;right:10px;bottom:8px;color:rgba(0,10,36,.65);font-weight:400;font-size:14px;font-style:normal;pointer-events:none}.ant-typography-edit-content textarea{height:1em;margin:0!important;-moz-transition:none}.ant-typography ol,.ant-typography ul{margin:0 0 1em;padding:0}.ant-typography ol li,.ant-typography ul li{margin:0 0 0 20px;padding:0 0 0 4px}.ant-typography ul{list-style-type:circle}.ant-typography ul ul{list-style-type:disc}.ant-typography ol{list-style-type:decimal}.ant-typography blockquote,.ant-typography pre{margin:1em 0}.ant-typography pre{padding:.4em .6em;white-space:pre-wrap;word-wrap:break-word;background:hsla(0,0%,58.8%,.1);border:1px solid hsla(0,0%,39.2%,.2);border-radius:3px}.ant-typography pre code{display:inline;margin:0;padding:0;font-size:inherit;font-family:inherit;background:transparent;border:0}.ant-typography blockquote{padding:0 0 0 .6em;border-left:4px solid hsla(0,0%,39.2%,.2);opacity:.85}.ant-typography-single-line{white-space:nowrap}.ant-typography-ellipsis-single-line{overflow:hidden;text-overflow:ellipsis}a.ant-typography-ellipsis-single-line,span.ant-typography-ellipsis-single-line{vertical-align:bottom}.ant-typography-ellipsis-multiple-line{display:-webkit-box;overflow:hidden;-webkit-line-clamp:3; - /*! autoprefixer: ignore next */-webkit-box-orient:vertical}.ant-typography-rtl{direction:rtl}.ant-typography-rtl .ant-typography-copy,.ant-typography-rtl .ant-typography-edit,.ant-typography-rtl .ant-typography-expand{margin-right:4px;margin-left:0}.ant-typography-rtl .ant-typography-expand{float:left}div.ant-typography-edit-content.ant-typography-rtl{right:-12px;left:auto}.ant-typography-rtl .ant-typography-edit-content-confirm{right:auto;left:10px}.ant-typography-rtl.ant-typography ol li,.ant-typography-rtl.ant-typography ul li{margin:0 20px 0 0;padding:0 4px 0 0}.normalState___rTQ99{position:static;height:100%}.normalState___rTQ99 .backNormal___1gKZt{display:none}.maxState___2W7kq{position:fixed;top:0;right:0;bottom:0;left:0;z-index:999}.maxState___2W7kq .innerWrap___7Y-5N{position:absolute;right:0;bottom:0;left:0;background:#fff}.maxState___2W7kq .backNormal___1gKZt{display:block;height:30px;padding-right:20px;color:#02a7f0;font-size:22px;line-height:30px;text-align:right}.maxState___2W7kq .backNormal___1gKZt .fullscreenExitIcon___xj4Wz{cursor:pointer}.sqlEditor___3RiYN{min-width:0;height:100%;border:1px solid #eee}.sqlEditor___3RiYN .ace_editor{font-family:"Menlo","Monaco","Ubuntu Mono","Consolas","source-code-pro"!important}.fullScreenBtnBox___2USxq{display:flex;justify-content:end}.ant-pro-card{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;margin:0;padding:0;background-color:#fff;border-radius:4px}.ant-pro-card-col{width:100%}.ant-pro-card-border{border:1px solid #f0f0f0}.ant-pro-card-hoverable{cursor:pointer;transition:box-shadow .3s,border-color .3s}.ant-pro-card-hoverable:hover{border-color:transparent;box-shadow:0 1px 2px -2px rgba(0,0,0,.16),0 3px 6px 0 rgba(0,0,0,.12),0 5px 12px 4px rgba(0,0,0,.09)}.ant-pro-card-hoverable.ant-pro-card-checked:hover{border-color:#296df3}.ant-pro-card-checked{background-color:#e3ecfd;border-color:#296df3}.ant-pro-card-checked:after{position:absolute;top:2px;right:2px;width:0;height:0;border-left:6px solid #296df3;border-bottom:6px solid #296df3;border-color:#296df3 #296df3 transparent transparent;border-style:solid;border-width:6px;border-top-right-radius:2px;content:""}.ant-pro-card:focus{background-color:#e3ecfd;border-color:#296df3}.ant-pro-card-size-small .ant-pro-card-header{padding:8px 12px 0}.ant-pro-card-size-small .ant-pro-card-header-border{padding-bottom:8px}.ant-pro-card-size-small .ant-pro-card-title{font-size:14px}.ant-pro-card-size-small .ant-pro-card-body{padding:12px}.ant-pro-card-ghost{background-color:transparent}.ant-pro-card-ghost>.ant-pro-card-header{padding-right:0;padding-bottom:16px;padding-left:0}.ant-pro-card-ghost>.ant-pro-card-body{padding:0;background-color:transparent}.ant-pro-card-split>.ant-pro-card-body{padding:0}.ant-pro-card-split-vertical{border-right:1px solid #f0f0f0}.ant-pro-card-split-horizontal{border-bottom:1px solid #f0f0f0}.ant-pro-card-contain-card>.ant-pro-card-body{display:flex}.ant-pro-card-body-direction-column{flex-direction:column}.ant-pro-card-body-wrap{flex-wrap:wrap}.ant-pro-card-collapse>.ant-pro-card-header{padding-bottom:16px;border-bottom:0}.ant-pro-card-collapse>.ant-pro-card-body{display:none}.ant-pro-card-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px 0}.ant-pro-card-header-border{padding-bottom:16px;border-bottom:1px solid #f0f0f0}.ant-pro-card-header-collapsible{cursor:pointer}.ant-pro-card-title{color:rgba(0,10,36,.85);font-weight:500;font-size:16px}.ant-pro-card-extra{color:rgba(0,10,36,.85)}.ant-pro-card-type-inner .ant-pro-card-header{background-color:#fafafa}.ant-pro-card-collapsible-icon{margin-right:8px;color:rgba(0,0,0,.75)}.ant-pro-card-collapsible-icon :hover{color:#5493ff}.ant-pro-card-collapsible-icon svg{transition:transform .2s}.ant-pro-card-body{display:block;box-sizing:border-box;height:100%;padding:24px}.ant-pro-card-body-center{display:flex;align-items:center;justify-content:center}.ant-pro-card-col-0{display:none}.ant-pro-card-col-24{flex-shrink:0;width:100%}.ant-pro-card-col-23{flex-shrink:0;width:95.83333333%}.ant-pro-card-col-22{flex-shrink:0;width:91.66666667%}.ant-pro-card-col-21{flex-shrink:0;width:87.5%}.ant-pro-card-col-20{flex-shrink:0;width:83.33333333%}.ant-pro-card-col-19{flex-shrink:0;width:79.16666667%}.ant-pro-card-col-18{flex-shrink:0;width:75%}.ant-pro-card-col-17{flex-shrink:0;width:70.83333333%}.ant-pro-card-col-16{flex-shrink:0;width:66.66666667%}.ant-pro-card-col-15{flex-shrink:0;width:62.5%}.ant-pro-card-col-14{flex-shrink:0;width:58.33333333%}.ant-pro-card-col-13{flex-shrink:0;width:54.16666667%}.ant-pro-card-col-12{flex-shrink:0;width:50%}.ant-pro-card-col-11{flex-shrink:0;width:45.83333333%}.ant-pro-card-col-10{flex-shrink:0;width:41.66666667%}.ant-pro-card-col-9{flex-shrink:0;width:37.5%}.ant-pro-card-col-8{flex-shrink:0;width:33.33333333%}.ant-pro-card-col-7{flex-shrink:0;width:29.16666667%}.ant-pro-card-col-6{flex-shrink:0;width:25%}.ant-pro-card-col-5{flex-shrink:0;width:20.83333333%}.ant-pro-card-col-4{flex-shrink:0;width:16.66666667%}.ant-pro-card-col-3{flex-shrink:0;width:12.5%}.ant-pro-card-col-2{flex-shrink:0;width:8.33333333%}.ant-pro-card-col-1{flex-shrink:0;width:4.16666667%}.ant-pro-card-tabs .ant-tabs-top>.ant-tabs-nav{margin-bottom:0}.ant-pro-card-tabs .ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-list{margin-top:8px;padding-left:16px}.ant-pro-card-tabs .ant-tabs-bottom>.ant-tabs-nav{margin-top:0}.ant-pro-card-tabs .ant-tabs-bottom>.ant-tabs-nav .ant-tabs-nav-list{padding-left:16px}.ant-pro-card-tabs .ant-tabs-left .ant-tabs-content-holder .ant-tabs-content .ant-tabs-tabpane{padding-left:0}.ant-pro-card-tabs .ant-tabs-left>.ant-tabs-nav{margin-right:0}.ant-pro-card-tabs .ant-tabs-left>.ant-tabs-nav .ant-tabs-nav-list{padding-top:16px}.ant-pro-card-tabs .ant-tabs-right .ant-tabs-content-holder .ant-tabs-content .ant-tabs-tabpane{padding-right:0}.ant-pro-card-tabs .ant-tabs-right>.ant-tabs-nav .ant-tabs-nav-list{padding-top:16px}.ant-pro-card-loading{overflow:hidden}.ant-pro-card-loading .ant-pro-card-body{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-pro-card-loading-content{width:100%}.ant-pro-card-loading-content p{margin:0}.ant-pro-card-loading-block{height:14px;margin:4px 0;background:linear-gradient(90deg,rgba(207,216,220,.2),rgba(207,216,220,.4),rgba(207,216,220,.2));background-size:600% 600%;border-radius:4px;animation:card-loading 1.4s ease infinite}@keyframes card-loading{0%,to{background-position:0 50%}50%{background-position:100% 50%}}.ant-pro-core-label-tip{display:inline-flex;align-items:center;max-width:100%}.ant-pro-core-label-tip-icon{display:block;margin-left:4px;cursor:pointer}.ant-pro-core-label-tip-icon:hover{color:#5493ff}.ant-pro-core-label-tip-title{display:inline-flex;flex:1 1}.ant-pro-core-label-tip-subtitle{margin-left:8px;color:rgba(0,10,36,.65);font-weight:400;font-size:14px;white-space:nowrap}.ant-pro-core-label-tip-title-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;word-break:keep-all}.ant-pro-card-actions{margin:0;padding:0;list-style:none;background:#fff;border-top:1px solid #f0f0f0}.ant-pro-card-actions:before{display:table;content:""}.ant-pro-card-actions:after{display:table;clear:both;content:""}.ant-pro-card-actions .ant-space{grid-gap:0!important;gap:0!important;width:100%}.ant-pro-card-actions .ant-space-item,.ant-pro-card-actions>li{flex:1 1;float:left;margin:12px 0;color:rgba(0,10,36,.65);text-align:center}.ant-pro-card-actions .ant-space-item>a,.ant-pro-card-actions>li>a{color:rgba(0,10,36,.65);transition:color .3s}.ant-pro-card-actions .ant-space-item>a:hover,.ant-pro-card-actions>li>a:hover{color:#5493ff}.ant-pro-card-actions .ant-space-item>span,.ant-pro-card-actions>li>span{position:relative;display:block;min-width:32px;font-size:14px;line-height:1.5715;cursor:pointer}.ant-pro-card-actions .ant-space-item>span:hover,.ant-pro-card-actions>li>span:hover{color:#5493ff;transition:color .3s}.ant-pro-card-actions .ant-space-item>span>.anticon,.ant-pro-card-actions .ant-space-item>span a:not(.ant-btn),.ant-pro-card-actions>li>span>.anticon,.ant-pro-card-actions>li>span a:not(.ant-btn){display:inline-block;width:100%;color:rgba(0,10,36,.65);line-height:22px;transition:color .3s}.ant-pro-card-actions .ant-space-item>span>.anticon:hover,.ant-pro-card-actions .ant-space-item>span a:not(.ant-btn):hover,.ant-pro-card-actions>li>span>.anticon:hover,.ant-pro-card-actions>li>span a:not(.ant-btn):hover{color:#5493ff}.ant-pro-card-actions .ant-space-item>span>.anticon,.ant-pro-card-actions>li>span>.anticon{font-size:16px;line-height:22px}.ant-pro-card-actions .ant-space-item:not(:last-child),.ant-pro-card-actions>li:not(:last-child){border-right:1px solid #f0f0f0}.ant-pro-card-divider{flex:none;width:1px;margin:24px 8px;background-color:#f0f0f0}.ant-pro-card-divider-horizontal{width:auto;height:1px;margin:8px 24px}.ant-pro-card-size-small .ant-pro-card-divider{margin:12px 8px}.ant-pro-card-size-small .ant-pro-card-divider-horizontal{margin:8px 12px}.ant-card{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;background:#fff;border-radius:4px}.ant-card-rtl{direction:rtl}.ant-card-hoverable{cursor:pointer;transition:box-shadow .3s,border-color .3s}.ant-card-hoverable:hover{border-color:transparent;box-shadow:0 1px 2px -2px rgba(0,0,0,.16),0 3px 6px 0 rgba(0,0,0,.12),0 5px 12px 4px rgba(0,0,0,.09)}.ant-card-bordered{border:1px solid #f0f0f0}.ant-card-head{min-height:48px;margin-bottom:-1px;padding:0 24px;color:rgba(0,10,36,.85);font-weight:500;font-size:16px;background:transparent;border-bottom:1px solid #f0f0f0;border-radius:4px 4px 0 0}.ant-card-head:before{display:table;content:""}.ant-card-head:after{display:table;clear:both;content:""}.ant-card-head-wrapper{display:flex;align-items:center}.ant-card-head-title{display:inline-block;flex:1 1;padding:16px 0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-card-head-title>.ant-typography,.ant-card-head-title>.ant-typography-edit-content{left:0;margin-top:0;margin-bottom:0}.ant-card-head .ant-tabs-top{clear:both;margin-bottom:-17px;color:rgba(0,10,36,.85);font-weight:400;font-size:14px}.ant-card-head .ant-tabs-top-bar{border-bottom:1px solid #f0f0f0}.ant-card-extra{margin-left:auto;padding:16px 0;color:rgba(0,10,36,.85);font-weight:400;font-size:14px}.ant-card-rtl .ant-card-extra{margin-right:auto;margin-left:0}.ant-card-body{padding:24px}.ant-card-body:before{display:table;content:""}.ant-card-body:after{display:table;clear:both;content:""}.ant-card-contain-grid .ant-card-body{display:flex;flex-wrap:wrap}.ant-card-contain-grid:not(.ant-card-loading) .ant-card-body{margin:-1px 0 0 -1px;padding:0}.ant-card-grid{width:33.33%;padding:24px;border:0;border-radius:0;box-shadow:1px 0 0 0 #f0f0f0,0 1px 0 0 #f0f0f0,1px 1px 0 0 #f0f0f0,inset 1px 0 0 0 #f0f0f0,inset 0 1px 0 0 #f0f0f0;transition:all .3s}.ant-card-grid-hoverable:hover{position:relative;z-index:1;box-shadow:0 1px 2px -2px rgba(0,0,0,.16),0 3px 6px 0 rgba(0,0,0,.12),0 5px 12px 4px rgba(0,0,0,.09)}.ant-card-contain-tabs>.ant-card-head .ant-card-head-title{min-height:32px;padding-bottom:0}.ant-card-contain-tabs>.ant-card-head .ant-card-extra{padding-bottom:0}.ant-card-bordered .ant-card-cover{margin-top:-1px;margin-right:-1px;margin-left:-1px}.ant-card-cover>*{display:block;width:100%}.ant-card-cover img{border-radius:4px 4px 0 0}.ant-card-actions{display:flex;margin:0;padding:0;list-style:none;background:#fff;border-top:1px solid #f0f0f0}.ant-card-actions:before{display:table;content:""}.ant-card-actions:after{display:table;clear:both;content:""}.ant-card-actions>li{margin:12px 0;color:rgba(0,10,36,.65);text-align:center}.ant-card-actions>li>span{position:relative;display:block;min-width:32px;font-size:14px;line-height:1.5715;cursor:pointer}.ant-card-actions>li>span:hover{color:#296df3;transition:color .3s}.ant-card-actions>li>span>.anticon,.ant-card-actions>li>span a:not(.ant-btn){display:inline-block;width:100%;color:rgba(0,10,36,.65);line-height:22px;transition:color .3s}.ant-card-actions>li>span>.anticon:hover,.ant-card-actions>li>span a:not(.ant-btn):hover{color:#296df3}.ant-card-actions>li>span>.anticon{font-size:16px;line-height:22px}.ant-card-actions>li:not(:last-child){border-right:1px solid #f0f0f0}.ant-card-rtl .ant-card-actions>li:not(:last-child){border-right:none;border-left:1px solid #f0f0f0}.ant-card-type-inner .ant-card-head{padding:0 24px;background:#fafafa}.ant-card-type-inner .ant-card-head-title{padding:12px 0;font-size:14px}.ant-card-type-inner .ant-card-body{padding:16px 24px}.ant-card-type-inner .ant-card-extra{padding:13.5px 0}.ant-card-meta{display:flex;margin:-4px 0}.ant-card-meta:before{display:table;content:""}.ant-card-meta:after{display:table;clear:both;content:""}.ant-card-meta-avatar{padding-right:16px}.ant-card-rtl .ant-card-meta-avatar{padding-right:0;padding-left:16px}.ant-card-meta-detail{flex:1 1;overflow:hidden}.ant-card-meta-detail>div:not(:last-child){margin-bottom:8px}.ant-card-meta-title{overflow:hidden;color:rgba(0,10,36,.85);font-weight:500;font-size:16px;white-space:nowrap;text-overflow:ellipsis}.ant-card-meta-description{color:rgba(0,10,36,.65)}.ant-card-loading{overflow:hidden}.ant-card-loading .ant-card-body{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-card-small>.ant-card-head{min-height:36px;padding:0 12px;font-size:14px}.ant-card-small>.ant-card-head>.ant-card-head-wrapper>.ant-card-head-title{padding:8px 0}.ant-card-small>.ant-card-head>.ant-card-head-wrapper>.ant-card-extra{padding:8px 0;font-size:14px}.ant-card-small>.ant-card-body{padding:12px}.ant-steps{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:flex;width:100%;font-size:0;text-align:left;text-align:initial}.ant-steps-item{position:relative;display:inline-block;flex:1 1;overflow:hidden;vertical-align:top}.ant-steps-item-container{outline:none}.ant-steps-item:last-child{flex:none}.ant-steps-item:last-child>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title:after,.ant-steps-item:last-child>.ant-steps-item-container>.ant-steps-item-tail{display:none}.ant-steps-item-content,.ant-steps-item-icon{display:inline-block;vertical-align:top}.ant-steps-item-icon{width:32px;height:32px;margin:0 8px 0 0;font-size:16px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";line-height:32px;text-align:center;border:1px solid rgba(0,0,0,.25);border-radius:32px;transition:background-color .3s,border-color .3s}.ant-steps-item-icon .ant-steps-icon{position:relative;top:-.5px;color:#296df3;line-height:1}.ant-steps-item-tail{position:absolute;top:12px;left:0;width:100%;padding:0 10px}.ant-steps-item-tail:after{display:inline-block;width:100%;height:1px;background:#f0f0f0;border-radius:1px;transition:background .3s;content:""}.ant-steps-item-title{position:relative;display:inline-block;padding-right:16px;color:rgba(0,10,36,.85);font-size:16px;line-height:32px}.ant-steps-item-title:after{position:absolute;top:16px;left:100%;display:block;width:9999px;height:1px;background:#f0f0f0;content:""}.ant-steps-item-subtitle{display:inline;margin-left:8px;color:rgba(0,10,36,.65);font-weight:400;font-size:14px}.ant-steps-item-description{color:rgba(0,10,36,.65);font-size:14px}.ant-steps-item-wait .ant-steps-item-icon{background-color:#fff;border-color:rgba(0,0,0,.25)}.ant-steps-item-wait .ant-steps-item-icon>.ant-steps-icon{color:rgba(0,0,0,.25)}.ant-steps-item-wait .ant-steps-item-icon>.ant-steps-icon .ant-steps-icon-dot{background:rgba(0,0,0,.25)}.ant-steps-item-wait>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title{color:rgba(0,10,36,.65)}.ant-steps-item-wait>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title:after{background-color:#f0f0f0}.ant-steps-item-wait>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-description{color:rgba(0,10,36,.65)}.ant-steps-item-wait>.ant-steps-item-container>.ant-steps-item-tail:after{background-color:#f0f0f0}.ant-steps-item-process .ant-steps-item-icon{background-color:#fff;border-color:#296df3}.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon{color:#296df3}.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon .ant-steps-icon-dot{background:#296df3}.ant-steps-item-process>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title{color:rgba(0,10,36,.85)}.ant-steps-item-process>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title:after{background-color:#f0f0f0}.ant-steps-item-process>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-description{color:rgba(0,10,36,.85)}.ant-steps-item-process>.ant-steps-item-container>.ant-steps-item-tail:after{background-color:#f0f0f0}.ant-steps-item-process>.ant-steps-item-container>.ant-steps-item-icon{background:#296df3}.ant-steps-item-process>.ant-steps-item-container>.ant-steps-item-icon .ant-steps-icon{color:#fff}.ant-steps-item-process>.ant-steps-item-container>.ant-steps-item-title{font-weight:500}.ant-steps-item-finish .ant-steps-item-icon{background-color:#fff;border-color:#296df3}.ant-steps-item-finish .ant-steps-item-icon>.ant-steps-icon{color:#296df3}.ant-steps-item-finish .ant-steps-item-icon>.ant-steps-icon .ant-steps-icon-dot{background:#296df3}.ant-steps-item-finish>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title{color:rgba(0,10,36,.85)}.ant-steps-item-finish>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title:after{background-color:#296df3}.ant-steps-item-finish>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-description{color:rgba(0,10,36,.65)}.ant-steps-item-finish>.ant-steps-item-container>.ant-steps-item-tail:after{background-color:#296df3}.ant-steps-item-error .ant-steps-item-icon{background-color:#fff;border-color:#ef4872}.ant-steps-item-error .ant-steps-item-icon>.ant-steps-icon{color:#ef4872}.ant-steps-item-error .ant-steps-item-icon>.ant-steps-icon .ant-steps-icon-dot{background:#ef4872}.ant-steps-item-error>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title{color:#ef4872}.ant-steps-item-error>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title:after{background-color:#f0f0f0}.ant-steps-item-error>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-description{color:#ef4872}.ant-steps-item-error>.ant-steps-item-container>.ant-steps-item-tail:after{background-color:#f0f0f0}.ant-steps-item.ant-steps-next-error .ant-steps-item-title:after{background:#ef4872}.ant-steps-item-disabled{cursor:not-allowed}.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button]{cursor:pointer}.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button] .ant-steps-item-description,.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button] .ant-steps-item-icon .ant-steps-icon,.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button] .ant-steps-item-subtitle,.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button] .ant-steps-item-title{transition:color .3s}.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button]:hover .ant-steps-item-description,.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button]:hover .ant-steps-item-subtitle,.ant-steps .ant-steps-item:not(.ant-steps-item-active)>.ant-steps-item-container[role=button]:hover .ant-steps-item-title{color:#296df3}.ant-steps .ant-steps-item:not(.ant-steps-item-active):not(.ant-steps-item-process)>.ant-steps-item-container[role=button]:hover .ant-steps-item-icon{border-color:#296df3}.ant-steps .ant-steps-item:not(.ant-steps-item-active):not(.ant-steps-item-process)>.ant-steps-item-container[role=button]:hover .ant-steps-item-icon .ant-steps-icon{color:#296df3}.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item{padding-left:16px;white-space:nowrap}.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:first-child{padding-left:0}.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:last-child .ant-steps-item-title{padding-right:0}.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item-tail{display:none}.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item-description{max-width:140px;white-space:normal}.ant-steps-item-custom>.ant-steps-item-container>.ant-steps-item-icon{height:auto;background:none;border:0}.ant-steps-item-custom>.ant-steps-item-container>.ant-steps-item-icon>.ant-steps-icon{top:0;left:.5px;width:32px;height:32px;font-size:24px;line-height:32px}.ant-steps-item-custom.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon{color:#296df3}.ant-steps:not(.ant-steps-vertical) .ant-steps-item-custom .ant-steps-item-icon{width:auto;background:none}.ant-steps-small.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item{padding-left:12px}.ant-steps-small.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:first-child{padding-left:0}.ant-steps-small .ant-steps-item-icon{width:24px;height:24px;margin:0 8px 0 0;font-size:12px;line-height:24px;text-align:center;border-radius:24px}.ant-steps-small .ant-steps-item-title{padding-right:12px;font-size:14px;line-height:24px}.ant-steps-small .ant-steps-item-title:after{top:12px}.ant-steps-small .ant-steps-item-description{color:rgba(0,10,36,.65);font-size:14px}.ant-steps-small .ant-steps-item-tail{top:8px}.ant-steps-small .ant-steps-item-custom .ant-steps-item-icon{width:inherit;height:inherit;line-height:inherit;background:none;border:0;border-radius:0}.ant-steps-small .ant-steps-item-custom .ant-steps-item-icon>.ant-steps-icon{font-size:24px;line-height:24px;transform:none}.ant-steps-vertical{display:flex;flex-direction:column}.ant-steps-vertical>.ant-steps-item{display:block;flex:1 0 auto;padding-left:0;overflow:visible}.ant-steps-vertical>.ant-steps-item .ant-steps-item-icon{float:left;margin-right:16px}.ant-steps-vertical>.ant-steps-item .ant-steps-item-content{display:block;min-height:48px;overflow:hidden}.ant-steps-vertical>.ant-steps-item .ant-steps-item-title{line-height:32px}.ant-steps-vertical>.ant-steps-item .ant-steps-item-description{padding-bottom:12px}.ant-steps-vertical>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{position:absolute;top:0;left:15px;width:1px;height:100%;padding:38px 0 6px}.ant-steps-vertical>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail:after{width:1px;height:100%}.ant-steps-vertical>.ant-steps-item:not(:last-child)>.ant-steps-item-container>.ant-steps-item-tail{display:block}.ant-steps-vertical>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title:after{display:none}.ant-steps-vertical.ant-steps-small .ant-steps-item-container .ant-steps-item-tail{position:absolute;top:0;left:11px;padding:30px 0 6px}.ant-steps-vertical.ant-steps-small .ant-steps-item-container .ant-steps-item-title{line-height:24px}.ant-steps-label-vertical .ant-steps-item{overflow:visible}.ant-steps-label-vertical .ant-steps-item-tail{margin-left:58px;padding:3.5px 24px}.ant-steps-label-vertical .ant-steps-item-content{display:block;width:116px;margin-top:8px;text-align:center}.ant-steps-label-vertical .ant-steps-item-icon{display:inline-block;margin-left:42px}.ant-steps-label-vertical .ant-steps-item-title{padding-right:0;padding-left:0}.ant-steps-label-vertical .ant-steps-item-title:after{display:none}.ant-steps-label-vertical .ant-steps-item-subtitle{display:block;margin-bottom:4px;margin-left:0;line-height:1.5715}.ant-steps-label-vertical.ant-steps-small:not(.ant-steps-dot) .ant-steps-item-icon{margin-left:46px}.ant-steps-dot .ant-steps-item-title,.ant-steps-dot.ant-steps-small .ant-steps-item-title{line-height:1.5715}.ant-steps-dot .ant-steps-item-tail,.ant-steps-dot.ant-steps-small .ant-steps-item-tail{top:2px;width:100%;margin:0 0 0 70px;padding:0}.ant-steps-dot .ant-steps-item-tail:after,.ant-steps-dot.ant-steps-small .ant-steps-item-tail:after{width:calc(100% - 20px);height:3px;margin-left:12px}.ant-steps-dot .ant-steps-item:first-child .ant-steps-icon-dot,.ant-steps-dot.ant-steps-small .ant-steps-item:first-child .ant-steps-icon-dot{left:2px}.ant-steps-dot .ant-steps-item-icon,.ant-steps-dot.ant-steps-small .ant-steps-item-icon{width:8px;height:8px;margin-left:67px;padding-right:0;line-height:8px;background:transparent;border:0}.ant-steps-dot .ant-steps-item-icon .ant-steps-icon-dot,.ant-steps-dot.ant-steps-small .ant-steps-item-icon .ant-steps-icon-dot{position:relative;float:left;width:100%;height:100%;border-radius:100px;transition:all .3s}.ant-steps-dot .ant-steps-item-icon .ant-steps-icon-dot:after,.ant-steps-dot.ant-steps-small .ant-steps-item-icon .ant-steps-icon-dot:after{position:absolute;top:-12px;left:-26px;width:60px;height:32px;background:rgba(0,0,0,.001);content:""}.ant-steps-dot .ant-steps-item-content,.ant-steps-dot.ant-steps-small .ant-steps-item-content{width:140px}.ant-steps-dot .ant-steps-item-process .ant-steps-item-icon,.ant-steps-dot.ant-steps-small .ant-steps-item-process .ant-steps-item-icon{position:relative;top:-1px;width:10px;height:10px;line-height:10px;background:none}.ant-steps-dot .ant-steps-item-process .ant-steps-icon:first-child .ant-steps-icon-dot,.ant-steps-dot.ant-steps-small .ant-steps-item-process .ant-steps-icon:first-child .ant-steps-icon-dot{left:0}.ant-steps-vertical.ant-steps-dot .ant-steps-item-icon{margin-top:13px;margin-left:0;background:none}.ant-steps-vertical.ant-steps-dot .ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{top:6.5px;left:-9px;margin:0;padding:22px 0 4px}.ant-steps-vertical.ant-steps-dot.ant-steps-small .ant-steps-item-icon{margin-top:10px}.ant-steps-vertical.ant-steps-dot.ant-steps-small .ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{top:3.5px}.ant-steps-vertical.ant-steps-dot .ant-steps-item:first-child .ant-steps-icon-dot{left:0}.ant-steps-vertical.ant-steps-dot .ant-steps-item-content{width:inherit}.ant-steps-vertical.ant-steps-dot .ant-steps-item-process .ant-steps-item-container .ant-steps-item-icon .ant-steps-icon-dot{top:-1px;left:-1px}.ant-steps-navigation{padding-top:12px}.ant-steps-navigation.ant-steps-small .ant-steps-item-container{margin-left:-12px}.ant-steps-navigation .ant-steps-item{overflow:visible;text-align:center}.ant-steps-navigation .ant-steps-item-container{display:inline-block;height:100%;margin-left:-16px;padding-bottom:12px;text-align:left;transition:opacity .3s}.ant-steps-navigation .ant-steps-item-container .ant-steps-item-content{max-width:auto}.ant-steps-navigation .ant-steps-item-container .ant-steps-item-title{max-width:100%;padding-right:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-steps-navigation .ant-steps-item-container .ant-steps-item-title:after{display:none}.ant-steps-navigation .ant-steps-item:not(.ant-steps-item-active) .ant-steps-item-container[role=button]{cursor:pointer}.ant-steps-navigation .ant-steps-item:not(.ant-steps-item-active) .ant-steps-item-container[role=button]:hover{opacity:.85}.ant-steps-navigation .ant-steps-item:last-child{flex:1 1}.ant-steps-navigation .ant-steps-item:last-child:after{display:none}.ant-steps-navigation .ant-steps-item:after{position:absolute;top:50%;left:100%;display:inline-block;width:12px;height:12px;margin-top:-14px;margin-left:-2px;border:1px solid rgba(0,0,0,.25);border-bottom:none;border-left:none;transform:rotate(45deg);content:""}.ant-steps-navigation .ant-steps-item:before{position:absolute;bottom:0;left:50%;display:inline-block;width:0;height:2px;background-color:#296df3;transition:width .3s,left .3s;transition-timing-function:ease-out;content:""}.ant-steps-navigation .ant-steps-item.ant-steps-item-active:before{left:0;width:100%}.ant-steps-navigation.ant-steps-vertical>.ant-steps-item{margin-right:0!important}.ant-steps-navigation.ant-steps-vertical>.ant-steps-item:before{display:none}.ant-steps-navigation.ant-steps-vertical>.ant-steps-item.ant-steps-item-active:before{top:0;right:0;left:unset;display:block;width:3px;height:calc(100% - 24px)}.ant-steps-navigation.ant-steps-vertical>.ant-steps-item:after{position:relative;top:-2px;left:50%;display:block;width:8px;height:8px;margin-bottom:8px;text-align:center;transform:rotate(135deg)}.ant-steps-navigation.ant-steps-vertical>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{visibility:hidden}.ant-steps-navigation.ant-steps-horizontal>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{visibility:hidden}.ant-steps-rtl{direction:rtl}.ant-steps.ant-steps-rtl .ant-steps-item-icon{margin-right:0;margin-left:8px}.ant-steps-rtl .ant-steps-item-tail{right:0;left:auto}.ant-steps-rtl .ant-steps-item-title{padding-right:0;padding-left:16px}.ant-steps-rtl .ant-steps-item-title .ant-steps-item-subtitle{float:left;margin-right:8px;margin-left:0}.ant-steps-rtl .ant-steps-item-title:after{right:100%;left:auto}.ant-steps-rtl.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item{padding-right:16px;padding-left:0}.ant-steps-rtl.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:first-child{padding-right:0}.ant-steps-rtl.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:last-child .ant-steps-item-title{padding-left:0}.ant-steps-rtl .ant-steps-item-custom .ant-steps-item-icon>.ant-steps-icon{right:.5px;left:auto}.ant-steps-rtl.ant-steps-navigation.ant-steps-small .ant-steps-item-container{margin-right:-12px;margin-left:0}.ant-steps-rtl.ant-steps-navigation .ant-steps-item-container{margin-right:-16px;margin-left:0;text-align:right}.ant-steps-rtl.ant-steps-navigation .ant-steps-item-container .ant-steps-item-title{padding-left:0}.ant-steps-rtl.ant-steps-navigation .ant-steps-item:after{right:100%;left:auto;margin-right:-2px;margin-left:0;transform:rotate(225deg)}.ant-steps-rtl.ant-steps-small.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item{padding-right:12px;padding-left:0}.ant-steps-rtl.ant-steps-small.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:first-child{padding-right:0}.ant-steps-rtl.ant-steps-small .ant-steps-item-title{padding-right:0;padding-left:12px}.ant-steps-rtl.ant-steps-vertical>.ant-steps-item .ant-steps-item-icon{float:right;margin-right:0;margin-left:16px}.ant-steps-rtl.ant-steps-vertical>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{right:16px;left:auto}.ant-steps-rtl.ant-steps-vertical.ant-steps-small .ant-steps-item-container .ant-steps-item-tail{right:12px;left:auto}.ant-steps-rtl.ant-steps-label-vertical .ant-steps-item-title{padding-left:0}.ant-steps-rtl.ant-steps-dot .ant-steps-item-tail,.ant-steps-rtl.ant-steps-dot.ant-steps-small .ant-steps-item-tail{margin:0 70px 0 0}.ant-steps-rtl.ant-steps-dot .ant-steps-item-tail:after,.ant-steps-rtl.ant-steps-dot.ant-steps-small .ant-steps-item-tail:after{margin-right:12px;margin-left:0}.ant-steps-rtl.ant-steps-dot .ant-steps-item:first-child .ant-steps-icon-dot,.ant-steps-rtl.ant-steps-dot.ant-steps-small .ant-steps-item:first-child .ant-steps-icon-dot{right:2px;left:auto}.ant-steps-rtl.ant-steps-dot .ant-steps-item-icon,.ant-steps-rtl.ant-steps-dot.ant-steps-small .ant-steps-item-icon{margin-right:67px;margin-left:0}.ant-steps-rtl.ant-steps-dot .ant-steps-item-icon .ant-steps-icon-dot,.ant-steps-rtl.ant-steps-dot.ant-steps-small .ant-steps-item-icon .ant-steps-icon-dot{float:right}.ant-steps-rtl.ant-steps-dot .ant-steps-item-icon .ant-steps-icon-dot:after,.ant-steps-rtl.ant-steps-dot.ant-steps-small .ant-steps-item-icon .ant-steps-icon-dot:after{right:-26px;left:auto}.ant-steps-rtl.ant-steps-vertical.ant-steps-dot .ant-steps-item-icon{margin-right:0;margin-left:16px}.ant-steps-rtl.ant-steps-vertical.ant-steps-dot .ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{right:-9px;left:auto}.ant-steps-rtl.ant-steps-vertical.ant-steps-dot .ant-steps-item:first-child .ant-steps-icon-dot{right:0;left:auto}.ant-steps-rtl.ant-steps-vertical.ant-steps-dot .ant-steps-item-process .ant-steps-icon-dot{right:-2px;left:auto}.ant-steps-rtl.ant-steps-with-progress.ant-steps-vertical>.ant-steps-item{padding-right:4px}.ant-steps-rtl.ant-steps-with-progress.ant-steps-vertical>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{right:19px}.ant-steps-rtl.ant-steps-with-progress.ant-steps-small.ant-steps-vertical>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{right:15px}.ant-steps-rtl.ant-steps-with-progress.ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item:first-child{padding-right:4px;padding-left:0}.ant-steps-rtl.ant-steps-with-progress.ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item:first-child.ant-steps-item-active{padding-right:4px}.ant-steps-with-progress .ant-steps-item{padding-top:4px}.ant-steps-with-progress .ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{top:4px;left:19px}.ant-steps-with-progress.ant-steps-horizontal .ant-steps-item:first-child,.ant-steps-with-progress.ant-steps-small.ant-steps-horizontal .ant-steps-item:first-child{padding-bottom:4px;padding-left:4px}.ant-steps-with-progress.ant-steps-small>.ant-steps-item>.ant-steps-item-container>.ant-steps-item-tail{left:15px}.ant-steps-with-progress.ant-steps-vertical .ant-steps-item{padding-left:4px}.ant-steps-with-progress.ant-steps-label-vertical .ant-steps-item .ant-steps-item-tail{top:14px!important}.ant-steps-with-progress .ant-steps-item-icon{position:relative}.ant-steps-with-progress .ant-steps-item-icon .ant-progress{position:absolute;top:-5px;right:-5px;bottom:-5px;left:-5px}.ant-progress{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-block}.ant-progress-line{position:relative;width:100%;font-size:14px}.ant-progress-steps{display:inline-block}.ant-progress-steps-outer{display:flex;flex-direction:row;align-items:center}.ant-progress-steps-item{flex-shrink:0;min-width:2px;margin-right:2px;background:#f3f3f3;transition:all .3s}.ant-progress-steps-item-active{background:#296df3}.ant-progress-small.ant-progress-line,.ant-progress-small.ant-progress-line .ant-progress-text .anticon{font-size:12px}.ant-progress-outer{display:inline-block;width:100%;margin-right:0;padding-right:0}.ant-progress-show-info .ant-progress-outer{margin-right:calc(-2em - 8px);padding-right:calc(2em + 8px)}.ant-progress-inner{position:relative;display:inline-block;width:100%;overflow:hidden;vertical-align:middle;background-color:#f5f5f5;border-radius:100px}.ant-progress-circle-trail{stroke:#f5f5f5}.ant-progress-circle-path{animation:ant-progress-appear .3s}.ant-progress-inner:not(.ant-progress-circle-gradient) .ant-progress-circle-path{stroke:#296df3}.ant-progress-bg,.ant-progress-success-bg{position:relative;background-color:#296df3;border-radius:100px;transition:all .4s cubic-bezier(.08,.82,.17,1) 0s}.ant-progress-success-bg{position:absolute;top:0;left:0;background-color:#26c992}.ant-progress-text{display:inline-block;width:2em;margin-left:8px;color:rgba(0,10,36,.85);font-size:1em;line-height:1;white-space:nowrap;text-align:left;vertical-align:middle;word-break:normal}.ant-progress-text .anticon{font-size:14px}.ant-progress-status-active .ant-progress-bg:before{position:absolute;top:0;right:0;bottom:0;left:0;background:#fff;border-radius:10px;opacity:0;animation:ant-progress-active 2.4s cubic-bezier(.23,1,.32,1) infinite;content:""}.ant-progress-status-exception .ant-progress-bg{background-color:#ef4872}.ant-progress-status-exception .ant-progress-text{color:#ef4872}.ant-progress-status-exception .ant-progress-inner:not(.ant-progress-circle-gradient) .ant-progress-circle-path{stroke:#ef4872}.ant-progress-status-success .ant-progress-bg{background-color:#26c992}.ant-progress-status-success .ant-progress-text{color:#26c992}.ant-progress-status-success .ant-progress-inner:not(.ant-progress-circle-gradient) .ant-progress-circle-path{stroke:#26c992}.ant-progress-circle .ant-progress-inner{position:relative;line-height:1;background-color:transparent}.ant-progress-circle .ant-progress-text{position:absolute;top:50%;left:50%;width:100%;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:1em;line-height:1;white-space:normal;text-align:center;transform:translate(-50%,-50%)}.ant-progress-circle .ant-progress-text .anticon{font-size:1.16666667em}.ant-progress-circle.ant-progress-status-exception .ant-progress-text{color:#ef4872}.ant-progress-circle.ant-progress-status-success .ant-progress-text{color:#26c992}@keyframes ant-progress-active{0%{transform:translateX(-100%) scaleX(0);opacity:.1}20%{transform:translateX(-100%) scaleX(0);opacity:.5}to{transform:translateX(0) scaleX(1);opacity:0}}.ant-progress-rtl{direction:rtl}.ant-progress-rtl.ant-progress-show-info .ant-progress-outer{margin-right:0;margin-left:calc(-2em - 8px);padding-right:0;padding-left:calc(2em + 8px)}.ant-progress-rtl .ant-progress-success-bg{right:0;left:auto}.ant-progress-rtl.ant-progress-line .ant-progress-text,.ant-progress-rtl.ant-progress-steps .ant-progress-text{margin-right:8px;margin-left:0;text-align:right}.pageContainer___1YXb3{position:absolute;top:55px;right:0;bottom:0;left:0;background:#fff}.pageContainer___1YXb3.externalPageContainer___1TSgX{margin:0!important}.searchBar___2v1Cs .ant-form-item-label{width:70px}.main___qRCgn{position:absolute;top:0;right:0;bottom:0;left:0;display:flex}.main___qRCgn .ant-tabs{height:100%!important}.main___qRCgn .ant-tabs .ant-tabs-content{height:100%!important}.main___qRCgn .ant-tabs .ant-tabs-content .ant-tabs-tabpane{height:100%}.rightSide___ooQY-{position:relative;z-index:1;min-width:250px;height:100%;margin-left:4px;padding:10px;overflow:hidden}.rightSide___ooQY- .ant-form-item{margin-bottom:6px}.rightSide___ooQY- .ant-form-item .ant-form-item-label{width:70px}.rightSide___ooQY- .ant-form-item .ant-form-item-control{min-width:100px}.rightListSide___2muVJ{position:relative;z-index:2;flex:1 1;height:100%;background-color:#fff}.rightListSide___2muVJ .ant-tabs-card.ant-tabs-bottom>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.rightListSide___2muVJ .ant-tabs-card.ant-tabs-bottom>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.rightListSide___2muVJ .ant-tabs-card.ant-tabs-top>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab,.rightListSide___2muVJ .ant-tabs-card.ant-tabs-top>div>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab{margin-left:0}.rightListSide___2muVJ .ant-tabs>.ant-tabs-nav .ant-tabs-nav-add,.rightListSide___2muVJ .ant-tabs>div>.ant-tabs-nav .ant-tabs-nav-add{margin-left:0}.leftListSide___3npiR{position:relative;z-index:2;flex:1 1;height:100%;background-color:#fff}.tableTotal___1VSZg{margin:0 2px;color:#296df3;font-weight:700}.tableDetaildrawer___2PDIJ .ant-drawer-header{padding:10px 45px 10px 10px}.tableDetaildrawer___2PDIJ .ant-drawer-close{padding:10px}.tableDetaildrawer___2PDIJ .ant-drawer-body{padding:0 10px 10px}.tableDetaildrawer___2PDIJ .ant-tabs-top>.ant-tabs-nav{margin-bottom:8px}.tableDetailTable___14pfB .ant-table-cell,.tableDetailTable___14pfB .resultTableRow>td{padding:8px;font-size:12px}.sqlEditor___1ewr3{min-width:0;height:100%;border:1px solid #eee}.sqlEditor___1ewr3 .ace_editor{font-family:"Menlo","Monaco","Ubuntu Mono","Consolas","source-code-pro"!important}.sqlOprBar___1FYEt{margin-top:-10px;padding:5px;display:flex}.sqlOprBar___1FYEt .sqlOprBarLeftBox___24kL8{flex:1 1 200px}.sqlOprBar___1FYEt .sqlOprBarRightBox___3ZFrE{flex:0 1 210px}.sqlOprBar___1FYEt .ant-btn-round.ant-btn-sm{font-size:12px}.sqlOprBar___1FYEt .ant-btn-primary{color:#fff;background:#02a7f0;border-color:#02a7f0}.sqlOprBar___1FYEt .ant-segmented-item-selected{color:#fff;background:#02a7f0;border-color:#02a7f0}.sqlOprIcon___3WhIP{margin-right:30px;color:#02a7f0;font-size:22px}.sqlOprIcon___3WhIP:hover{cursor:pointer;opacity:.8}.sqlOprIcon___3WhIP:active{opacity:.7}.sqlOprBtn___22eSD{margin-right:30px;vertical-align:super!important}.sqlOprBtn___22eSD:hover{cursor:pointer;opacity:.8}.sqlOprBtn___22eSD:active{opacity:.7}.sqlOprSwitch___4zfeE{float:right;margin-right:10px!important}.is-sql-full-select{background-color:#02a7f0}.cjjWdp:hover{z-index:10}.sqlMain___2KqMi{display:flex;flex-direction:row;height:100%}.sqlMain___2KqMi .sqlEditorWrapper___-8V62{flex:1 1;height:100%;overflow:hidden}.sqlMain___2KqMi .sqlParams___3VPC6{width:20%;height:100%!important;overflow:auto}.sqlMain___2KqMi .hideSqlParams___1tDWo{width:0;height:100%!important;overflow:auto}.sqlParamsBody___wHl2x .header___3A-0E{display:flex;padding:10px;font-weight:700}.sqlParamsBody___wHl2x .header___3A-0E .title___1ZIlX{flex:1 1}.sqlParamsBody___wHl2x .header___3A-0E .icon___3egme{display:flex;align-items:center;margin-right:10px!important;cursor:pointer}.sqlParamsBody___wHl2x .paramsList___YmGR3 .paramsItem___3oqte{display:flex;padding:10px}.sqlParamsBody___wHl2x .paramsList___YmGR3 .paramsItem___3oqte .ant-list-item-action{margin-left:5px}.sqlParamsBody___wHl2x .paramsList___YmGR3 .paramsItem___3oqte .name___3zLJQ{flex:1 1;width:80%;overflow:hidden;font-size:12px;text-overflow:ellipsis}.sqlParamsBody___wHl2x .paramsList___YmGR3 .paramsItem___3oqte .name___3zLJQ:hover{cursor:pointer}.sqlParamsBody___wHl2x .paramsList___YmGR3 .paramsItem___3oqte .icon___3egme{margin-left:10px}.disableIcon___G1CbW{vertical-align:super!important;background:#7d7f80!important;border-color:#7d7f80!important}.disableIcon___G1CbW .anticon .anticon-play-circle{color:#fff}.disableIcon___G1CbW:hover{cursor:not-allowed;opacity:1}.sqlTaskListWrap___1PsW7{position:relative;width:262px;border-top:0!important;border-radius:0}.sqlTaskListWrap___1PsW7 .ant-card-head{min-height:20px}.sqlTaskListWrap___1PsW7 .ant-card-head-title{padding:8px 0}.sqlTaskList___fGovo{position:absolute!important;top:42px;right:0;bottom:0;left:0;overflow:auto}.sqlBottmWrap___2nkn6{display:flex;height:100%}.sqlBottmWrap___2nkn6.small{top:334px}.sqlBottmWrap___2nkn6.middle{top:384px}.sqlResultWrap___16rbx{position:relative;display:flex;flex:1 1;flex-direction:column;overflow:auto;border:1px solid #eee;border-top:0;border-left:0}.sqlToolBar___3ZW8u{display:flex;flex-direction:row-reverse;align-items:center;height:41px;padding:5px 0;text-align:right}.sqlResultPane___2J4Kp{flex:1 1;border-top:1px solid #eee}.sqlToolBtn___27ZyH{margin-right:15px}.runScriptBtn___39Ds3{margin-right:15px;background-color:#e87954;border-color:#e87954}.runScriptBtn___39Ds3:hover{border-color:#f89878;background:#f89878}.runScriptBtn___39Ds3:focus{border-color:#f89878;background:#f89878}.taskFailed___1Kx9E{padding:20px 20px 0}.sqlResultContent___3TpKZ{position:absolute;top:50%;width:100%;color:rgba(0,0,0,.25);font-size:16px;text-align:center}.sqlResultLog___1xHPV{padding:20px;word-wrap:break-word}.tableList___3hI4i{position:absolute!important;top:160px;right:0;bottom:26px;left:0;overflow-x:hidden;overflow-y:auto;border-bottom:1px solid #eee}.tablePage___2LhQK{position:absolute!important;bottom:0;left:0;z-index:1;width:100%;min-width:250px;overflow:hidden}.tableListItem___27d6w{width:88%;overflow:hidden;font-size:12px;text-overflow:ellipsis}.tableListItem___27d6w:hover{cursor:pointer}.tableItem___127XC.ant-list-item{padding:6px 0 6px 6px}.tableItem___127XC .ant-list-item-action{margin-left:12px!important}.tableItem___127XC:hover{background:#dee4e9;border-bottom:1px solid #f0f0f0}.tableItem___127XC.active{background:#a0c5e8}.taskIcon___3aBIV{margin-right:10px;color:#1890ff;font-size:14px}.taskSuccessIcon___3XL39{margin-right:10px;color:#1890ff;font-size:14px;color:#67c23a}.taskFailIcon___U7M6_{margin-right:10px;color:#1890ff;font-size:14px;color:#f56c6c}.resultFailIcon___3oFSk{margin-right:8px;color:#f56c6c}.taskItem___1y3vX{padding:10px 8px!important;font-size:12px;cursor:pointer}.taskItem___1y3vX.ant-list-item{justify-content:flex-start}.taskItem___1y3vX:hover{background:#dee4e9}.activeTask___YBkj9{background:#a0c5e8}.resultTable___2DZmh{width:100%}.resultTable___2DZmh .ant-table-body{width:100%;overflow:auto!important}.resultTable___2DZmh .ant-table-cell,.resultTable___2DZmh .resultTableRow>td{padding:8px;font-size:12px}.taskLogWrap___3_C6-{word-wrap:break-word}.siteTagPlus___1rPSE{background:#fff;border-style:dashed}.editTag___1sXJQ{margin-bottom:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.tagInput___1OZzG{width:78px;margin-right:8px;vertical-align:top}.outside___1sN2g{position:relative;height:100%}.collapseRightBtn___3zLQQ{position:absolute;top:calc(50% + 50px);right:0;z-index:100;display:flex;align-items:center;height:70px;color:#fff;font-size:12px;background-color:rgba(40,46,54,.2);border-radius:24px 0 0 24px;cursor:pointer;transition:all .3s ease}.collapseLeftBtn___18RNq{position:absolute;top:calc(50% + 45px);left:0;z-index:100;display:flex;align-items:center;height:70px;color:#fff;font-size:12px;background-color:rgba(40,46,54,.2);border-radius:0 24px 24px 0;cursor:pointer;transition:all .3s ease}.detail___2ufaP .titleCollapse___dJM7U{float:right;padding-right:18px;color:#1890ff;line-height:35px;text-align:right;cursor:pointer}.detail___2ufaP .tableTitle___1XX8H{display:inline-block;width:85%;margin-left:15px;overflow:hidden;line-height:35px;white-space:nowrap;text-overflow:ellipsis;cursor:pointer}.detail___2ufaP .ant-divider-horizontal{margin:0}.search___mqcqG{margin-left:10px}.middleArea___eJA2_ .ant-tabs-nav .ant-tabs-tab{border:none;border-right:1px solid #f0f0f0;border-radius:0!important}.middleArea___eJA2_ .ant-tabs-nav-add{border-radius:0!important}.middleArea___eJA2_ .ant-tabs-tab .ant-tabs-tab-remove .closeTab{opacity:0}.middleArea___eJA2_ .ant-tabs-tab .ant-tabs-tab-remove .dot{opacity:1}.middleArea___eJA2_ .ant-tabs-tab:hover .ant-tabs-tab-remove .closeTab{opacity:1!important}.middleArea___eJA2_ .ant-tabs-tab:hover .ant-tabs-tab-remove .dot{opacity:0}.menu___368H_{position:relative;z-index:1;height:100%;padding:5px;overflow:hidden;overflow-x:hidden;overflow-y:auto}.menu___368H_ .ant-form{margin:-2px}.menuList___27tJX{position:absolute!important;top:95px;right:0;bottom:26px;left:0;overflow-x:hidden;overflow-y:auto;border-bottom:1px solid #eee}.menuList___27tJX .menuItem___3tI3I.ant-list-item{padding:6px 0 6px 14px}.menuList___27tJX .menuItem___3tI3I .ant-list-item-action{margin-left:12px!important}.menuList___27tJX .menuItem___3tI3I:hover{background:#dee4e9;border-bottom:1px solid #f0f0f0}.menuList___27tJX .menuItem___3tI3I:hover .icon___3egme{display:block}.menuList___27tJX .menuItem___3tI3I.active{background:#a0c5e8}.menuList___27tJX .menuItem___3tI3I .menuListItem___1C6z1{width:90%;overflow:hidden;font-size:12px;white-space:nowrap;text-overflow:ellipsis}.menuList___27tJX .menuItem___3tI3I .menuListItem___1C6z1:hover{cursor:pointer}.menuList___27tJX .menuItem___3tI3I .icon___3egme{display:none;margin-right:15px!important;cursor:pointer}.menuList___27tJX .menuItem___3tI3I .menuIcon___34eY3{display:flex}.scriptFile___2mstI{width:100%;margin:10px;overflow:hidden;font-size:14px;white-space:nowrap;text-overflow:ellipsis}.scriptFile___2mstI .icon___3egme{margin-right:10px}.sqlScriptName___38RPg{width:93%!important;margin:14px 0 0 14px!important}.fileIcon___2-aJM{width:20px!important;height:20px!important;padding-top:2px!important;padding-right:5px!important;vertical-align:middle}.itemName___50W0I{vertical-align:middle}.paneName___38IRg{width:100px;overflow:hidden;font-size:12px!important;white-space:nowrap;text-overflow:ellipsis}.titleIcon___3_Z-9{width:16px!important;height:16px!important;margin:0 3px 4px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field{max-width:100%}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-xs{width:104px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-s{width:216px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-sm{width:216px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-m{width:328px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-md{width:328px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-l{width:440px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-lg{width:440px}.ant-form>div:not(.ant-pro-form-light-filter) .pro-field-xl{width:552px}.ant-pro-form-group-title{margin-bottom:16px;font-weight:700}.ant-pro-form-group-container{flex-wrap:wrap;max-width:100%}.ant-pro-form-group-container>div.ant-space-item{max-width:100%}.ant-pro-form-group-twoLine{display:block;width:100%}.ant-pro-form-group-twoLine .ant-pro-form-group-title{width:100%;margin:8px 0}.ant-pro-form-group-twoLine .ant-pro-form-group-container{padding-left:16px}.ant-pro-form-group-twoLine .ant-form-item,.ant-pro-form-group-twoLine .ant-space-item{width:100%}.ant-pro-form-group-twoLine .ant-form-item-control{display:flex;align-items:center;justify-content:flex-end}.ant-pro-form-group-twoLine .ant-form-item-control-input{align-items:center;justify-content:flex-end}.ant-pro-form-group-twoLine .ant-form-item-control-input-content{flex:none}.ant-form:not(.ant-form-horizontal) .ant-pro-form-list-item:not(.ant-pro-form-list-item-show-label) .ant-form-item-label{display:none}.ant-pro-form-list{max-width:100%}.ant-pro-form-list-item.ant-pro-form-list-item-show-label .ant-form-item-label{display:inline-block}.ant-pro-form-list-item:first-of-type div:first-of-type .ant-form-item .ant-form-item-label{display:inline-block}.ant-pro-form-list-action{display:flex;height:32px;margin-bottom:24px;line-height:32px}.ant-pro-form-list .ant-pro-card .ant-pro-card-extra .ant-pro-form-list-action{margin-bottom:0}.ant-pro-form-list-action-icon{margin-left:8px;cursor:pointer;transition:color .3s ease-in-out}.ant-pro-form-list-action-icon:hover{color:#5493ff}.ant-pro-form-list-creator-button-top{margin-bottom:24px}.ant-pro-field-light-wrapper-collapse-label{padding:1}.ant-pro-field-light-wrapper-container .ant-form-item{margin-bottom:0}.ant-pro-core-field-dropdown-label{cursor:pointer}.ant-pro-core-field-dropdown-overlay{min-width:200px;margin-top:4px;background-color:#fff;box-shadow:0 1px 2px -2px rgba(0,0,0,.16),0 3px 6px 0 rgba(0,0,0,.12),0 5px 12px 4px rgba(0,0,0,.09)}.ant-pro-core-field-dropdown-content{padding:16px}.ant-pro-core-dropdown-footer{display:flex;justify-content:space-between;padding:16px 16px 16px 8px;border-top:1px solid #f0f0f0}.ant-pro-core-field-label{display:inline-flex;grid-gap:4px;gap:4px;align-items:center;height:30px;padding:0 4px;font-size:14px;line-height:30px;border-radius:2px;cursor:pointer}.ant-pro-core-field-label:hover{background-color:rgba(0,0,0,.1)}.ant-pro-core-field-label-active{padding:0 12px;background-color:rgba(0,0,0,.04)}.ant-pro-core-field-label-active.ant-pro-core-field-label-allow-clear:hover:not(.ant-pro-core-field-label-disabled) .ant-pro-core-field-label-arrow{display:none}.ant-pro-core-field-label-active.ant-pro-core-field-label-allow-clear:hover:not(.ant-pro-core-field-label-disabled) .ant-pro-core-field-label-close{display:inline-block}.ant-pro-core-field-label-icon{height:12px;padding:1px;color:rgba(0,0,0,.45);font-size:12px;vertical-align:middle}.ant-pro-core-field-label-icon.ant-pro-core-field-label-close{display:none;height:14px;padding:3px;color:#fff;font-size:8px;background-color:rgba(0,0,0,.25);border-radius:50%}.ant-pro-core-field-label-icon.ant-pro-core-field-label-close:hover{background-color:rgba(0,0,0,.45)}.ant-pro-core-field-label-disabled{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-pro-core-field-label-disabled .ant-pro-core-field-label-icon{color:rgba(0,0,0,.25)}.ant-pro-core-field-label-small{height:24px;padding:0 4px;font-size:12px;line-height:24px}.ant-pro-core-field-label-small.ant-pro-core-field-label-active{padding:0 8px}.ant-pro-core-field-label-small .ant-pro-core-field-label-icon{padding:0}.ant-pro-core-field-label-small .ant-pro-core-field-label-close{margin-top:-2px;padding:3px;font-size:6px}.ant-pro-core-field-label-bordered{height:32px;padding:0 12px;border:1px solid #d9d9d9;border-radius:4px}.ant-pro-core-field-label-bordered.ant-pro-core-field-label-small{height:24px;padding:0 8px}.ant-pro-core-field-label-bordered.ant-pro-core-field-label-active{background-color:#fff}.ant-pro-inline-error-form-item-multiple{padding:6px 8px 12px}.ant-pro-inline-error-form-item-progress-success .ant-progress-bg{background-color:#26c992}.ant-pro-inline-error-form-item-progress-error .ant-progress-bg{background-color:#ef4872}.ant-pro-inline-error-form-item-progress-warning .ant-progress-bg{background-color:#ffb924}.ant-pro-inline-error-form-item-rule{margin:0;padding:0;list-style:none}.ant-pro-inline-error-form-item-rule-content{display:flex;align-items:center}.ant-pro-inline-error-form-item-rule-content-icon-default{display:flex;align-items:center;justify-content:center;width:14px;height:22px}.ant-pro-inline-error-form-item-rule-content-icon-default-circle{width:6px;height:6px;background-color:rgba(0,10,36,.65);border-radius:4px}.ant-pro-inline-error-form-item-rule-content-icon-loading{color:#296df3}.ant-pro-inline-error-form-item-rule-content-icon-error{color:#ef4872}.ant-pro-inline-error-form-item-rule-content-icon-success{color:#26c992}.ant-pro-inline-error-form-item-rule-content-text{color:rgba(0,10,36,.85)}.ant-image{position:relative;display:inline-block}.ant-image-img{width:100%;height:auto;vertical-align:middle}.ant-image-img-placeholder{background-color:#f5f5f5;background-image:url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE0LjUgMi41aC0xM0EuNS41IDAgMDAxIDN2MTBhLjUuNSAwIDAwLjUuNWgxM2EuNS41IDAgMDAuNS0uNVYzYS41LjUgMCAwMC0uNS0uNXpNNS4yODEgNC43NWExIDEgMCAwMTAgMiAxIDEgMCAwMTAtMnptOC4wMyA2LjgzYS4xMjcuMTI3IDAgMDEtLjA4MS4wM0gyLjc2OWEuMTI1LjEyNSAwIDAxLS4wOTYtLjIwN2wyLjY2MS0zLjE1NmEuMTI2LjEyNiAwIDAxLjE3Ny0uMDE2bC4wMTYuMDE2TDcuMDggMTAuMDlsMi40Ny0yLjkzYS4xMjYuMTI2IDAgMDEuMTc3LS4wMTZsLjAxNS4wMTYgMy41ODggNC4yNDRhLjEyNy4xMjcgMCAwMS0uMDIuMTc1eiIgZmlsbD0iIzhDOEM4QyIvPjwvc3ZnPg==");background-repeat:no-repeat;background-position:50%;background-size:30%}.ant-image-mask{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;color:#fff;background:rgba(0,0,0,.5);cursor:pointer;opacity:0;transition:opacity .3s}.ant-image-mask-info{padding:0 4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-image-mask-info .anticon{-webkit-margin-end:4px;margin-inline-end:4px}.ant-image-mask:hover{opacity:1}.ant-image-placeholder{position:absolute;top:0;right:0;bottom:0;left:0}.ant-image-preview{pointer-events:none;height:100%;text-align:center}.ant-image-preview.ant-zoom-appear,.ant-image-preview.ant-zoom-enter{transform:none;opacity:0;animation-duration:.3s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-image-preview-mask{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;height:100%;background-color:rgba(0,0,0,.45)}.ant-image-preview-mask-hidden{display:none}.ant-image-preview-wrap{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;outline:0}.ant-image-preview-body{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.ant-image-preview-img{max-width:100%;max-height:100%;vertical-align:middle;transform:scaleX(1);cursor:-webkit-grab;cursor:grab;transition:transform .3s cubic-bezier(.215,.61,.355,1) 0s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:auto}.ant-image-preview-img-wrapper{position:absolute;top:0;right:0;bottom:0;left:0;transition:transform .3s cubic-bezier(.215,.61,.355,1) 0s}.ant-image-preview-img-wrapper:before{display:inline-block;width:1px;height:50%;margin-right:-1px;content:""}.ant-image-preview-moving .ant-image-preview-img{cursor:-webkit-grabbing;cursor:grabbing}.ant-image-preview-moving .ant-image-preview-img-wrapper{transition-duration:0s}.ant-image-preview-wrap{z-index:1080}.ant-image-preview-operations-wrapper{position:fixed;top:0;right:0;z-index:1081;width:100%}.ant-image-preview-operations{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;font-feature-settings:"tnum","tnum";display:flex;flex-direction:row-reverse;align-items:center;color:hsla(0,0%,100%,.85);list-style:none;background:rgba(0,0,0,.1);pointer-events:auto}.ant-image-preview-operations-operation{margin-left:12px;padding:12px;cursor:pointer;transition:all .3s}.ant-image-preview-operations-operation:hover{background:rgba(0,0,0,.2)}.ant-image-preview-operations-operation-disabled{color:hsla(0,0%,100%,.25);pointer-events:none}.ant-image-preview-operations-operation:last-of-type{margin-left:0}.ant-image-preview-operations-progress{position:absolute;left:50%;transform:translateX(-50%)}.ant-image-preview-operations-icon{font-size:18px}.ant-image-preview-switch-left,.ant-image-preview-switch-right{position:fixed;top:50%;right:8px;z-index:1081;display:flex;align-items:center;justify-content:center;width:44px;height:44px;color:hsla(0,0%,100%,.85);background:rgba(0,0,0,.1);border-radius:50%;transform:translateY(-50%);cursor:pointer;transition:all .3s;pointer-events:auto}.ant-image-preview-switch-left:hover,.ant-image-preview-switch-right:hover{background:rgba(0,0,0,.2)}.ant-image-preview-switch-left-disabled,.ant-image-preview-switch-left-disabled:hover,.ant-image-preview-switch-right-disabled,.ant-image-preview-switch-right-disabled:hover{color:hsla(0,0%,100%,.25);background:rgba(0,0,0,.1);cursor:not-allowed}.ant-image-preview-switch-left-disabled:hover>.anticon,.ant-image-preview-switch-left-disabled>.anticon,.ant-image-preview-switch-right-disabled:hover>.anticon,.ant-image-preview-switch-right-disabled>.anticon{cursor:not-allowed}.ant-image-preview-switch-left>.anticon,.ant-image-preview-switch-right>.anticon{font-size:18px}.ant-image-preview-switch-left{left:8px}.ant-image-preview-switch-right{right:8px}.ant-picker-status-error.ant-picker,.ant-picker-status-error.ant-picker:not([disabled]):hover{background-color:#fff;border-color:#ef4872}.ant-picker-status-error.ant-picker-focused,.ant-picker-status-error.ant-picker:focus{border-color:#fc7492;box-shadow:0 0 0 2px rgba(239,72,114,.2);border-right-width:1px;outline:0}.ant-picker-status-error.ant-picker .ant-picker-active-bar{background:#fc7492}.ant-picker-status-warning.ant-picker,.ant-picker-status-warning.ant-picker:not([disabled]):hover{background-color:#fff;border-color:#ffb924}.ant-picker-status-warning.ant-picker-focused,.ant-picker-status-warning.ant-picker:focus{border-color:#ffcc4d;box-shadow:0 0 0 2px rgba(255,185,36,.2);border-right-width:1px;outline:0}.ant-picker-status-warning.ant-picker .ant-picker-active-bar{background:#ffcc4d}.ant-picker{box-sizing:border-box;margin:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";padding:4px 11px;position:relative;display:inline-flex;align-items:center;background:#fff;border:1px solid #d9d9d9;border-radius:4px;transition:border .3s,box-shadow .3s}.ant-picker-focused,.ant-picker:hover{border-color:#4e86f5;border-right-width:1px}.ant-picker-focused{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-picker.ant-picker-disabled{background:#f5f5f5;border-color:#d9d9d9;cursor:not-allowed}.ant-picker.ant-picker-disabled .ant-picker-suffix{color:rgba(0,0,0,.25)}.ant-picker.ant-picker-borderless{background-color:transparent!important;border-color:transparent!important;box-shadow:none!important}.ant-picker-input{position:relative;display:inline-flex;align-items:center;width:100%}.ant-picker-input>input{position:relative;display:inline-block;width:100%;min-width:0;color:rgba(0,10,36,.85);font-size:14px;line-height:1.5715;background-color:#fff;background-image:none;border-radius:4px;transition:all .3s;flex:auto;min-width:1px;height:auto;padding:0;background:transparent;border:0}.ant-picker-input>input::-webkit-input-placeholder{color:#bfbfbf;-webkit-user-select:none;user-select:none}.ant-picker-input>input:-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-picker-input>input::-ms-input-placeholder{color:#bfbfbf;-ms-user-select:none;user-select:none}.ant-picker-input>input::placeholder{color:#bfbfbf;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-picker-input>input:-ms-input-placeholder{text-overflow:ellipsis}.ant-picker-input>input:placeholder-shown{text-overflow:ellipsis}.ant-picker-input>input:hover{border-color:#4e86f5;border-right-width:1px}.ant-picker-input>input-focused,.ant-picker-input>input:focus{border-color:#5493ff;box-shadow:0 0 0 2px rgba(41,109,243,.2);border-right-width:1px;outline:0}.ant-picker-input>input-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-picker-input>input-disabled:hover{border-color:#d9d9d9;border-right-width:1px}.ant-picker-input>input[disabled]{color:rgba(0,0,0,.25);background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;cursor:not-allowed;opacity:1}.ant-picker-input>input[disabled]:hover{border-color:#d9d9d9;border-right-width:1px}.ant-picker-input>input-borderless,.ant-picker-input>input-borderless-disabled,.ant-picker-input>input-borderless-focused,.ant-picker-input>input-borderless:focus,.ant-picker-input>input-borderless:hover,.ant-picker-input>input-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-picker-input>input{max-width:100%;height:auto;min-height:32px;line-height:1.5715;vertical-align:bottom;transition:all .3s,height 0s}.ant-picker-input>input-lg{padding:6.5px 11px;font-size:16px}.ant-picker-input>input-sm{padding:0 7px}.ant-picker-input>input:focus{box-shadow:none}.ant-picker-input>input[disabled]{background:transparent}.ant-picker-input:hover .ant-picker-clear{opacity:1}.ant-picker-input-placeholder>input{color:#bfbfbf}.ant-picker-large{padding:6.5px 11px}.ant-picker-large .ant-picker-input>input{font-size:16px}.ant-picker-small{padding:0 7px}.ant-picker-suffix{display:flex;flex:none;align-self:center;margin-left:4px;color:rgba(0,0,0,.25);line-height:1;pointer-events:none}.ant-picker-suffix>*{vertical-align:top}.ant-picker-suffix>:not(:last-child){margin-right:8px}.ant-picker-clear{position:absolute;top:50%;right:0;color:rgba(0,0,0,.25);line-height:1;background:#fff;transform:translateY(-50%);cursor:pointer;opacity:0;transition:opacity .3s,color .3s}.ant-picker-clear>*{vertical-align:top}.ant-picker-clear:hover{color:rgba(0,10,36,.65)}.ant-picker-separator{position:relative;display:inline-block;width:1em;height:16px;color:rgba(0,0,0,.25);font-size:16px;vertical-align:top;cursor:default}.ant-picker-focused .ant-picker-separator{color:rgba(0,10,36,.65)}.ant-picker-disabled .ant-picker-range-separator .ant-picker-separator{cursor:not-allowed}.ant-picker-range{position:relative;display:inline-flex}.ant-picker-range .ant-picker-clear{right:11px}.ant-picker-range:hover .ant-picker-clear{opacity:1}.ant-picker-range .ant-picker-active-bar{bottom:-1px;height:2px;margin-left:11px;background:#296df3;opacity:0;transition:all .3s ease-out;pointer-events:none}.ant-picker-range.ant-picker-focused .ant-picker-active-bar{opacity:1}.ant-picker-range-separator{align-items:center;padding:0 8px;line-height:1}.ant-picker-range.ant-picker-small .ant-picker-clear{right:7px}.ant-picker-range.ant-picker-small .ant-picker-active-bar{margin-left:7px}.ant-picker-dropdown{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:absolute;top:-9999px;left:-9999px;z-index:1050}.ant-picker-dropdown-hidden{display:none}.ant-picker-dropdown-placement-bottomLeft .ant-picker-range-arrow{top:2.58561808px;display:block;transform:rotate(-135deg) translateY(1px)}.ant-picker-dropdown-placement-topLeft .ant-picker-range-arrow{bottom:2.58561808px;display:block;transform:rotate(45deg)}.ant-picker-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-picker-dropdown-placement-topLeft,.ant-picker-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-picker-dropdown-placement-topRight,.ant-picker-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-picker-dropdown-placement-topLeft,.ant-picker-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-picker-dropdown-placement-topRight{animation-name:antSlideDownIn}.ant-picker-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-picker-dropdown-placement-bottomLeft,.ant-picker-dropdown.ant-slide-up-appear.ant-slide-up-appear-active.ant-picker-dropdown-placement-bottomRight,.ant-picker-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-picker-dropdown-placement-bottomLeft,.ant-picker-dropdown.ant-slide-up-enter.ant-slide-up-enter-active.ant-picker-dropdown-placement-bottomRight{animation-name:antSlideUpIn}.ant-picker-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-picker-dropdown-placement-topLeft,.ant-picker-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-picker-dropdown-placement-topRight{animation-name:antSlideDownOut}.ant-picker-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-picker-dropdown-placement-bottomLeft,.ant-picker-dropdown.ant-slide-up-leave.ant-slide-up-leave-active.ant-picker-dropdown-placement-bottomRight{animation-name:antSlideUpOut}.ant-picker-dropdown-range{padding:7.54247233px 0}.ant-picker-dropdown-range-hidden{display:none}.ant-picker-dropdown .ant-picker-panel>.ant-picker-time-panel{padding-top:4px}.ant-picker-ranges{margin-bottom:0;padding:4px 12px;overflow:hidden;line-height:34px;text-align:left;list-style:none}.ant-picker-ranges>li{display:inline-block}.ant-picker-ranges .ant-picker-preset>.ant-tag-blue{color:#296df3;background:#e3ecfd;border-color:#86acf8;cursor:pointer}.ant-picker-ranges .ant-picker-ok{float:right;margin-left:8px}.ant-picker-range-wrapper{display:flex}.ant-picker-range-arrow{position:absolute;z-index:1;width:11.3137085px;height:11.3137085px;margin-left:16.5px;box-shadow:2px 2px 6px -2px rgba(0,0,0,.1);transition:left .3s ease-out;border-radius:0 0 2px;pointer-events:none}.ant-picker-range-arrow:before{position:absolute;top:-11.3137085px;left:-11.3137085px;width:33.9411255px;height:33.9411255px;background:#fff;background-repeat:no-repeat;background-position:-10px -10px;content:"";-webkit-clip-path:inset(33% 33%);clip-path:inset(33% 33%);-webkit-clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z");clip-path:path("M 9.849242404917499 24.091883092036785 A 5 5 0 0 1 13.384776310850237 22.627416997969522 L 20.627416997969522 22.627416997969522 A 2 2 0 0 0 22.627416997969522 20.627416997969522 L 22.627416997969522 13.384776310850237 A 5 5 0 0 1 24.091883092036785 9.849242404917499 L 23.091883092036785 9.849242404917499 L 9.849242404917499 23.091883092036785 Z")}.ant-picker-panel-container{overflow:hidden;vertical-align:top;background:#fff;border-radius:4px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);transition:margin .3s}.ant-picker-panel-container .ant-picker-panels{display:inline-flex;flex-wrap:nowrap;direction:ltr}.ant-picker-panel-container .ant-picker-panel{vertical-align:top;background:transparent;border-width:0 0 1px;border-radius:0}.ant-picker-panel-container .ant-picker-panel .ant-picker-content,.ant-picker-panel-container .ant-picker-panel table{text-align:center}.ant-picker-panel-container .ant-picker-panel-focused{border-color:#f0f0f0}.ant-picker-compact-item:not(.ant-picker-compact-last-item):not(.ant-picker-compact-item-rtl){margin-right:-1px}.ant-picker-compact-item:not(.ant-picker-compact-last-item).ant-picker-compact-item-rtl{margin-left:-1px}.ant-picker-compact-item:active,.ant-picker-compact-item:focus,.ant-picker-compact-item:hover{z-index:2}.ant-picker-compact-item.ant-picker-focused{z-index:2}.ant-picker-compact-item[disabled]{z-index:0}.ant-picker-compact-item:not(.ant-picker-compact-first-item):not(.ant-picker-compact-last-item).ant-picker{border-radius:0}.ant-picker-compact-item.ant-picker.ant-picker-compact-first-item:not(.ant-picker-compact-last-item):not(.ant-picker-compact-item-rtl){border-top-right-radius:0;border-bottom-right-radius:0}.ant-picker-compact-item.ant-picker.ant-picker-compact-last-item:not(.ant-picker-compact-first-item):not(.ant-picker-compact-item-rtl){border-top-left-radius:0;border-bottom-left-radius:0}.ant-picker-compact-item.ant-picker.ant-picker-compact-item-rtl.ant-picker-compact-first-item:not(.ant-picker-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-picker-compact-item.ant-picker.ant-picker-compact-item-rtl.ant-picker-compact-last-item:not(.ant-picker-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-picker-panel{display:inline-flex;flex-direction:column;text-align:center;background:#fff;border:1px solid #f0f0f0;border-radius:4px;outline:none}.ant-picker-panel-focused{border-color:#296df3}.ant-picker-date-panel,.ant-picker-decade-panel,.ant-picker-month-panel,.ant-picker-quarter-panel,.ant-picker-time-panel,.ant-picker-week-panel,.ant-picker-year-panel{display:flex;flex-direction:column;width:280px}.ant-picker-header{display:flex;padding:0 8px;color:rgba(0,10,36,.85);border-bottom:1px solid #f0f0f0}.ant-picker-header>*{flex:none}.ant-picker-header button{padding:0;color:rgba(0,0,0,.25);line-height:40px;background:transparent;border:0;cursor:pointer;transition:color .3s}.ant-picker-header>button{min-width:1.6em;font-size:14px}.ant-picker-header>button:hover{color:rgba(0,10,36,.85)}.ant-picker-header-view{flex:auto;font-weight:500;line-height:40px}.ant-picker-header-view button{color:inherit;font-weight:inherit}.ant-picker-header-view button:not(:first-child){margin-left:8px}.ant-picker-header-view button:hover{color:#296df3}.ant-picker-next-icon,.ant-picker-prev-icon,.ant-picker-super-next-icon,.ant-picker-super-prev-icon{position:relative;display:inline-block;width:7px;height:7px}.ant-picker-next-icon:before,.ant-picker-prev-icon:before,.ant-picker-super-next-icon:before,.ant-picker-super-prev-icon:before{position:absolute;top:0;left:0;display:inline-block;width:7px;height:7px;border:0 solid;border-width:1.5px 0 0 1.5px;content:""}.ant-picker-super-next-icon:after,.ant-picker-super-prev-icon:after{position:absolute;top:4px;left:4px;display:inline-block;width:7px;height:7px;border:0 solid;border-width:1.5px 0 0 1.5px;content:""}.ant-picker-prev-icon,.ant-picker-super-prev-icon{transform:rotate(-45deg)}.ant-picker-next-icon,.ant-picker-super-next-icon{transform:rotate(135deg)}.ant-picker-content{width:100%;table-layout:fixed;border-collapse:collapse}.ant-picker-content td,.ant-picker-content th{position:relative;min-width:24px;font-weight:400}.ant-picker-content th{height:30px;color:rgba(0,10,36,.85);line-height:30px}.ant-picker-cell{padding:3px 0;color:rgba(0,0,0,.25);cursor:pointer}.ant-picker-cell-in-view{color:rgba(0,10,36,.85)}.ant-picker-cell:before{position:absolute;top:50%;right:0;left:0;z-index:1;height:24px;transform:translateY(-50%);transition:all .3s;content:""}.ant-picker-cell:hover:not(.ant-picker-cell-in-view) .ant-picker-cell-inner,.ant-picker-cell:hover:not(.ant-picker-cell-selected):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end):not(.ant-picker-cell-range-hover-start):not(.ant-picker-cell-range-hover-end) .ant-picker-cell-inner{background:#f5f5f5}.ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner:before{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;border:1px solid #296df3;border-radius:4px;content:""}.ant-picker-cell-in-view.ant-picker-cell-in-range{position:relative}.ant-picker-cell-in-view.ant-picker-cell-in-range:before{background:#e3ecfd}.ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner,.ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner,.ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner{color:#fff;background:#296df3}.ant-picker-cell-in-view.ant-picker-cell-range-end:not(.ant-picker-cell-range-end-single):before,.ant-picker-cell-in-view.ant-picker-cell-range-start:not(.ant-picker-cell-range-start-single):before{background:#e3ecfd}.ant-picker-cell-in-view.ant-picker-cell-range-start:before{left:50%}.ant-picker-cell-in-view.ant-picker-cell-range-end:before{right:50%}.ant-picker-cell-in-view.ant-picker-cell-range-hover-end.ant-picker-cell-range-end-single:after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-end.ant-picker-cell-range-start.ant-picker-cell-range-end.ant-picker-cell-range-start-near-hover:after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-end:not(.ant-picker-cell-in-range):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end):after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-start.ant-picker-cell-range-start-single:after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-start.ant-picker-cell-range-start.ant-picker-cell-range-end.ant-picker-cell-range-end-near-hover:after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-start:not(.ant-picker-cell-in-range):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end):after,.ant-picker-cell-in-view.ant-picker-cell-range-hover:not(.ant-picker-cell-in-range):after{position:absolute;top:50%;z-index:0;height:24px;border-top:1px dashed #8aaff8;border-bottom:1px dashed #8aaff8;transform:translateY(-50%);transition:all .3s;content:""}.ant-picker-cell-range-hover-end:after,.ant-picker-cell-range-hover-start:after,.ant-picker-cell-range-hover:after{right:0;left:2px}.ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover:before,.ant-picker-cell-in-view.ant-picker-cell-range-end.ant-picker-cell-range-hover:before,.ant-picker-cell-in-view.ant-picker-cell-range-end:not(.ant-picker-cell-range-end-single).ant-picker-cell-range-hover-end:before,.ant-picker-cell-in-view.ant-picker-cell-range-start.ant-picker-cell-range-hover:before,.ant-picker-cell-in-view.ant-picker-cell-range-start:not(.ant-picker-cell-range-start-single).ant-picker-cell-range-hover-start:before,.ant-picker-panel>:not(.ant-picker-date-panel) .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-end:before,.ant-picker-panel>:not(.ant-picker-date-panel) .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-start:before{background:#d2e0fc}.ant-picker-cell-in-view.ant-picker-cell-range-start:not(.ant-picker-cell-range-start-single):not(.ant-picker-cell-range-end) .ant-picker-cell-inner{border-radius:4px 0 0 4px}.ant-picker-cell-in-view.ant-picker-cell-range-end:not(.ant-picker-cell-range-end-single):not(.ant-picker-cell-range-start) .ant-picker-cell-inner{border-radius:0 4px 4px 0}.ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-end .ant-picker-cell-inner:after,.ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-start .ant-picker-cell-inner:after{position:absolute;top:0;bottom:0;z-index:-1;background:#d2e0fc;transition:all .3s;content:""}.ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-start .ant-picker-cell-inner:after{right:-6px;left:0}.ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-end .ant-picker-cell-inner:after{right:0;left:-6px}.ant-picker-cell-range-hover.ant-picker-cell-range-start:after{right:50%}.ant-picker-cell-range-hover.ant-picker-cell-range-end:after{left:50%}.ant-picker-cell-in-view.ant-picker-cell-range-hover-edge-start:not(.ant-picker-cell-range-hover-edge-start-near-range):after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-start:after,.ant-picker-cell-in-view.ant-picker-cell-start.ant-picker-cell-range-hover-edge-start.ant-picker-cell-range-hover-edge-start-near-range:after,tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover-end:first-child:after,tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover:first-child:after{left:6px;border-left:1px dashed #8aaff8;border-top-left-radius:4px;border-bottom-left-radius:4px}.ant-picker-cell-in-view.ant-picker-cell-end.ant-picker-cell-range-hover-edge-end.ant-picker-cell-range-hover-edge-end-near-range:after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-edge-end:not(.ant-picker-cell-range-hover-edge-end-near-range):after,.ant-picker-cell-in-view.ant-picker-cell-range-hover-end:after,tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child:after,tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover:last-child:after{right:6px;border-right:1px dashed #8aaff8;border-top-right-radius:4px;border-bottom-right-radius:4px}.ant-picker-cell-disabled{color:rgba(0,0,0,.25);pointer-events:none}.ant-picker-cell-disabled .ant-picker-cell-inner{background:transparent}.ant-picker-cell-disabled:before{background:rgba(0,0,0,.04)}.ant-picker-cell-disabled.ant-picker-cell-today .ant-picker-cell-inner:before{border-color:rgba(0,0,0,.25)}.ant-picker-decade-panel .ant-picker-content,.ant-picker-month-panel .ant-picker-content,.ant-picker-quarter-panel .ant-picker-content,.ant-picker-year-panel .ant-picker-content{height:264px}.ant-picker-decade-panel .ant-picker-cell-inner,.ant-picker-month-panel .ant-picker-cell-inner,.ant-picker-quarter-panel .ant-picker-cell-inner,.ant-picker-year-panel .ant-picker-cell-inner{padding:0 8px}.ant-picker-quarter-panel .ant-picker-content{height:56px}.ant-picker-footer{width:-webkit-min-content;width:-moz-min-content;width:min-content;min-width:100%;line-height:38px;text-align:center;border-bottom:1px solid transparent}.ant-picker-panel .ant-picker-footer{border-top:1px solid #f0f0f0}.ant-picker-footer-extra{padding:0 12px;line-height:38px;text-align:left}.ant-picker-footer-extra:not(:last-child){border-bottom:1px solid #f0f0f0}.ant-picker-now{text-align:left}.ant-picker-today-btn{color:#296df3}.ant-picker-today-btn:hover{color:#5493ff}.ant-picker-today-btn:active{color:#184ecc}.ant-picker-today-btn.ant-picker-today-btn-disabled{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-picker-decade-panel .ant-picker-cell-inner{padding:0 4px}.ant-picker-decade-panel .ant-picker-cell:before{display:none}.ant-picker-month-panel .ant-picker-body,.ant-picker-quarter-panel .ant-picker-body,.ant-picker-year-panel .ant-picker-body{padding:0 8px}.ant-picker-month-panel .ant-picker-cell-inner,.ant-picker-quarter-panel .ant-picker-cell-inner,.ant-picker-year-panel .ant-picker-cell-inner{width:60px}.ant-picker-month-panel .ant-picker-cell-range-hover-start:after,.ant-picker-quarter-panel .ant-picker-cell-range-hover-start:after,.ant-picker-year-panel .ant-picker-cell-range-hover-start:after{left:14px;border-left:1px dashed #8aaff8;border-radius:4px 0 0 4px}.ant-picker-panel-rtl .ant-picker-month-panel .ant-picker-cell-range-hover-start:after,.ant-picker-panel-rtl .ant-picker-quarter-panel .ant-picker-cell-range-hover-start:after,.ant-picker-panel-rtl .ant-picker-year-panel .ant-picker-cell-range-hover-start:after{right:14px;border-right:1px dashed #8aaff8;border-radius:0 4px 4px 0}.ant-picker-month-panel .ant-picker-cell-range-hover-end:after,.ant-picker-quarter-panel .ant-picker-cell-range-hover-end:after,.ant-picker-year-panel .ant-picker-cell-range-hover-end:after{right:14px;border-right:1px dashed #8aaff8;border-radius:0 4px 4px 0}.ant-picker-panel-rtl .ant-picker-month-panel .ant-picker-cell-range-hover-end:after,.ant-picker-panel-rtl .ant-picker-quarter-panel .ant-picker-cell-range-hover-end:after,.ant-picker-panel-rtl .ant-picker-year-panel .ant-picker-cell-range-hover-end:after{left:14px;border-left:1px dashed #8aaff8;border-radius:4px 0 0 4px}.ant-picker-week-panel .ant-picker-body{padding:8px 12px}.ant-picker-week-panel .ant-picker-cell-selected .ant-picker-cell-inner,.ant-picker-week-panel .ant-picker-cell .ant-picker-cell-inner,.ant-picker-week-panel .ant-picker-cell:hover .ant-picker-cell-inner{background:transparent!important}.ant-picker-week-panel-row td{transition:background .3s}.ant-picker-week-panel-row:hover td{background:#f5f5f5}.ant-picker-week-panel-row-selected:hover td,.ant-picker-week-panel-row-selected td{background:#296df3}.ant-picker-week-panel-row-selected:hover td.ant-picker-cell-week,.ant-picker-week-panel-row-selected td.ant-picker-cell-week{color:hsla(0,0%,100%,.5)}.ant-picker-week-panel-row-selected:hover td.ant-picker-cell-today .ant-picker-cell-inner:before,.ant-picker-week-panel-row-selected td.ant-picker-cell-today .ant-picker-cell-inner:before{border-color:#fff}.ant-picker-week-panel-row-selected:hover td .ant-picker-cell-inner,.ant-picker-week-panel-row-selected td .ant-picker-cell-inner{color:#fff}.ant-picker-date-panel .ant-picker-body{padding:8px 12px}.ant-picker-date-panel .ant-picker-content{width:252px}.ant-picker-date-panel .ant-picker-content th{width:36px}.ant-picker-datetime-panel{display:flex}.ant-picker-datetime-panel .ant-picker-time-panel{border-left:1px solid #f0f0f0}.ant-picker-datetime-panel .ant-picker-date-panel,.ant-picker-datetime-panel .ant-picker-time-panel{transition:opacity .3s}.ant-picker-datetime-panel-active .ant-picker-date-panel,.ant-picker-datetime-panel-active .ant-picker-time-panel{opacity:.3}.ant-picker-datetime-panel-active .ant-picker-date-panel-active,.ant-picker-datetime-panel-active .ant-picker-time-panel-active{opacity:1}.ant-picker-time-panel{width:auto;min-width:auto}.ant-picker-time-panel .ant-picker-content{display:flex;flex:auto;height:224px}.ant-picker-time-panel-column{flex:1 0 auto;width:56px;margin:0;padding:0;overflow-y:hidden;text-align:left;list-style:none;transition:background .3s}.ant-picker-time-panel-column:after{display:block;height:196px;content:""}.ant-picker-datetime-panel .ant-picker-time-panel-column:after{height:198px}.ant-picker-time-panel-column:not(:first-child){border-left:1px solid #f0f0f0}.ant-picker-time-panel-column-active{background:rgba(227,236,253,.2)}.ant-picker-time-panel-column:hover{overflow-y:auto}.ant-picker-time-panel-column>li{margin:0;padding:0}.ant-picker-time-panel-column>li.ant-picker-time-panel-cell .ant-picker-time-panel-cell-inner{display:block;width:100%;height:28px;margin:0;padding:0 0 0 14px;color:rgba(0,10,36,.85);line-height:28px;border-radius:0;cursor:pointer;transition:background .3s}.ant-picker-time-panel-column>li.ant-picker-time-panel-cell .ant-picker-time-panel-cell-inner:hover{background:#f5f5f5}.ant-picker-time-panel-column>li.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner{background:#e3ecfd}.ant-picker-time-panel-column>li.ant-picker-time-panel-cell-disabled .ant-picker-time-panel-cell-inner{color:rgba(0,0,0,.25);background:transparent;cursor:not-allowed}:root .ant-picker-range-wrapper .ant-picker-month-panel .ant-picker-cell,:root .ant-picker-range-wrapper .ant-picker-year-panel .ant-picker-cell,_:-ms-fullscreen .ant-picker-range-wrapper .ant-picker-month-panel .ant-picker-cell,_:-ms-fullscreen .ant-picker-range-wrapper .ant-picker-year-panel .ant-picker-cell{padding:21px 0}.ant-picker-rtl{direction:rtl}.ant-picker-rtl .ant-picker-suffix{margin-right:4px;margin-left:0}.ant-picker-rtl .ant-picker-clear{right:auto;left:0}.ant-picker-rtl .ant-picker-separator{transform:rotate(180deg)}.ant-picker-panel-rtl .ant-picker-header-view button:not(:first-child){margin-right:8px;margin-left:0}.ant-picker-rtl.ant-picker-range .ant-picker-clear{right:auto;left:11px}.ant-picker-rtl.ant-picker-range .ant-picker-active-bar{margin-right:11px;margin-left:0}.ant-picker-rtl.ant-picker-range.ant-picker-small .ant-picker-active-bar{margin-right:7px}.ant-picker-dropdown-rtl .ant-picker-ranges{text-align:right}.ant-picker-dropdown-rtl .ant-picker-ranges .ant-picker-ok{float:left;margin-right:8px;margin-left:0}.ant-picker-panel-rtl{direction:rtl}.ant-picker-panel-rtl .ant-picker-prev-icon,.ant-picker-panel-rtl .ant-picker-super-prev-icon{transform:rotate(135deg)}.ant-picker-panel-rtl .ant-picker-next-icon,.ant-picker-panel-rtl .ant-picker-super-next-icon{transform:rotate(-45deg)}.ant-picker-cell .ant-picker-cell-inner{position:relative;z-index:2;display:inline-block;min-width:24px;height:24px;line-height:24px;border-radius:4px;transition:background .3s,border .3s}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-start:before{right:50%;left:0}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-end:before{right:0;left:50%}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-start.ant-picker-cell-range-end:before{right:50%;left:50%}.ant-picker-panel-rtl .ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-start .ant-picker-cell-inner:after{right:0;left:-6px}.ant-picker-panel-rtl .ant-picker-date-panel .ant-picker-cell-in-view.ant-picker-cell-in-range.ant-picker-cell-range-hover-end .ant-picker-cell-inner:after{right:-6px;left:0}.ant-picker-panel-rtl .ant-picker-cell-range-hover.ant-picker-cell-range-start:after{right:0;left:50%}.ant-picker-panel-rtl .ant-picker-cell-range-hover.ant-picker-cell-range-end:after{right:50%;left:0}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-start:not(.ant-picker-cell-range-start-single):not(.ant-picker-cell-range-end) .ant-picker-cell-inner{border-radius:0 4px 4px 0}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-end:not(.ant-picker-cell-range-end-single):not(.ant-picker-cell-range-start) .ant-picker-cell-inner{border-radius:4px 0 0 4px}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-hover-edge-start:not(.ant-picker-cell-range-hover-edge-start-near-range):after,.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:after,.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-start.ant-picker-cell-range-hover-edge-start.ant-picker-cell-range-hover-edge-start-near-range:after,.ant-picker-panel-rtl tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover:not(.ant-picker-cell-selected):first-child:after{right:6px;left:0;border-right:1px dashed #8aaff8;border-left:none;border-radius:0 4px 4px 0}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-end.ant-picker-cell-range-hover-edge-end.ant-picker-cell-range-hover-edge-end-near-range:after,.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-hover-edge-end:not(.ant-picker-cell-range-hover-edge-end-near-range):after,.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-range-hover-end:after,.ant-picker-panel-rtl tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover:not(.ant-picker-cell-selected):last-child:after{right:0;left:6px;border-right:none;border-left:1px dashed #8aaff8;border-radius:4px 0 0 4px}.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-end.ant-picker-cell-range-hover-start.ant-picker-cell-range-hover-edge-end:not(.ant-picker-cell-range-hover):after,.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-start.ant-picker-cell-range-hover-edge-start:not(.ant-picker-cell-range-hover):after,.ant-picker-panel-rtl .ant-picker-cell-in-view.ant-picker-cell-start.ant-picker-cell-range-hover-end.ant-picker-cell-range-hover-edge-start:not(.ant-picker-cell-range-hover):after,.ant-picker-panel-rtl tr>.ant-picker-cell-in-view.ant-picker-cell-end.ant-picker-cell-range-hover.ant-picker-cell-range-hover-edge-end:first-child:after,.ant-picker-panel-rtl tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover-end:first-child:after,.ant-picker-panel-rtl tr>.ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child:after,.ant-picker-panel-rtl tr>.ant-picker-cell-in-view.ant-picker-cell-start.ant-picker-cell-range-hover.ant-picker-cell-range-hover-edge-start:last-child:after{right:6px;left:6px;border-right:1px dashed #8aaff8;border-left:1px dashed #8aaff8;border-radius:4px}.ant-picker-dropdown-rtl .ant-picker-footer-extra{direction:rtl;text-align:right}.ant-picker-panel-rtl .ant-picker-time-panel{direction:ltr}.ant-pro-field-date-picker-light .ant-calendar-picker,.ant-pro-field-date-picker-light .ant-picker{position:absolute;width:80px;height:28px;overflow:hidden;visibility:hidden}.ant-pro-field-index-column{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px}.ant-pro-field-index-column-border{color:#fff;font-size:12px;line-height:12px;background-color:#314659;border-radius:9px}.ant-pro-field-index-column-border.top-three{background-color:#979797}.ant-badge{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:inline-block;line-height:1}.ant-badge-count{z-index:auto;min-width:20px;height:20px;padding:0 6px;color:#fff;font-weight:400;font-size:12px;line-height:20px;white-space:nowrap;text-align:center;background:#ef4872;border-radius:10px;box-shadow:0 0 0 1px #fff}.ant-badge-count a,.ant-badge-count a:hover{color:#fff}.ant-badge-count-sm{min-width:14px;height:14px;padding:0;font-size:12px;line-height:14px;border-radius:7px}.ant-badge-multiple-words{padding:0 8px}.ant-badge-dot{z-index:auto;width:6px;min-width:6px;height:6px;background:#ef4872;border-radius:100%;box-shadow:0 0 0 1px #fff}.ant-badge-dot.ant-scroll-number{transition:background 1.5s}.ant-badge-count,.ant-badge-dot,.ant-badge .ant-scroll-number-custom-component{position:absolute;top:0;right:0;transform:translate(50%,-50%);transform-origin:100% 0}.ant-badge-count.anticon-spin,.ant-badge-dot.anticon-spin,.ant-badge .ant-scroll-number-custom-component.anticon-spin{animation:antBadgeLoadingCircle 1s linear infinite}.ant-badge-status{line-height:inherit;vertical-align:baseline}.ant-badge-status-dot{position:relative;top:-1px;display:inline-block;width:6px;height:6px;vertical-align:middle;border-radius:50%}.ant-badge-status-success{background-color:#26c992}.ant-badge-status-processing{position:relative;background-color:#296df3}.ant-badge-status-processing:after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #296df3;border-radius:50%;animation:antStatusProcessing 1.2s ease-in-out infinite;content:""}.ant-badge-status-default{background-color:#d9d9d9}.ant-badge-status-error{background-color:#ef4872}.ant-badge-status-warning{background-color:#ffb924}.ant-badge-status-pink{background:#eb2f96}.ant-badge-status-magenta{background:#eb2f96}.ant-badge-status-red{background:#f5222d}.ant-badge-status-volcano{background:#fa541c}.ant-badge-status-orange{background:#fa8c16}.ant-badge-status-yellow{background:#fadb14}.ant-badge-status-gold{background:#ffb924}.ant-badge-status-cyan{background:#13c2c2}.ant-badge-status-lime{background:#a0d911}.ant-badge-status-green{background:#26c992}.ant-badge-status-blue{background:#296df3}.ant-badge-status-geekblue{background:#2f54eb}.ant-badge-status-purple{background:#722ed1}.ant-badge-status-text{margin-left:8px;color:rgba(0,10,36,.85);font-size:14px}.ant-badge-zoom-appear,.ant-badge-zoom-enter{animation:antZoomBadgeIn .3s cubic-bezier(.12,.4,.29,1.46);animation-fill-mode:both}.ant-badge-zoom-leave{animation:antZoomBadgeOut .3s cubic-bezier(.71,-.46,.88,.6);animation-fill-mode:both}.ant-badge-not-a-wrapper .ant-badge-zoom-appear,.ant-badge-not-a-wrapper .ant-badge-zoom-enter{animation:antNoWrapperZoomBadgeIn .3s cubic-bezier(.12,.4,.29,1.46)}.ant-badge-not-a-wrapper .ant-badge-zoom-leave{animation:antNoWrapperZoomBadgeOut .3s cubic-bezier(.71,-.46,.88,.6)}.ant-badge-not-a-wrapper:not(.ant-badge-status){vertical-align:middle}.ant-badge-not-a-wrapper .ant-badge-count,.ant-badge-not-a-wrapper .ant-scroll-number-custom-component{transform:none}.ant-badge-not-a-wrapper .ant-scroll-number,.ant-badge-not-a-wrapper .ant-scroll-number-custom-component{position:relative;top:auto;display:block;transform-origin:50% 50%}@keyframes antStatusProcessing{0%{transform:scale(.8);opacity:.5}to{transform:scale(2.4);opacity:0}}.ant-scroll-number{overflow:hidden;direction:ltr}.ant-scroll-number-only{position:relative;display:inline-block;height:20px;transition:all .3s cubic-bezier(.645,.045,.355,1);-webkit-transform-style:preserve-3d;-webkit-backface-visibility:hidden}.ant-scroll-number-only>p.ant-scroll-number-only-unit{height:20px;margin:0;-webkit-transform-style:preserve-3d;-webkit-backface-visibility:hidden}.ant-scroll-number-symbol{vertical-align:top}@keyframes antZoomBadgeIn{0%{transform:scale(0) translate(50%,-50%);opacity:0}to{transform:scale(1) translate(50%,-50%)}}@keyframes antZoomBadgeOut{0%{transform:scale(1) translate(50%,-50%)}to{transform:scale(0) translate(50%,-50%);opacity:0}}@keyframes antNoWrapperZoomBadgeIn{0%{transform:scale(0);opacity:0}to{transform:scale(1)}}@keyframes antNoWrapperZoomBadgeOut{0%{transform:scale(1)}to{transform:scale(0);opacity:0}}@keyframes antBadgeLoadingCircle{0%{transform-origin:50%}to{transform:translate(50%,-50%) rotate(1turn);transform-origin:50%}}.ant-ribbon-wrapper{position:relative}.ant-ribbon{box-sizing:border-box;margin:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:absolute;top:8px;height:22px;padding:0 8px;color:#fff;line-height:22px;white-space:nowrap;background-color:#296df3;border-radius:2px}.ant-ribbon-text{color:#fff}.ant-ribbon-corner{position:absolute;top:100%;width:8px;height:8px;color:currentcolor;border:4px solid;transform:scaleY(.75);transform-origin:top}.ant-ribbon-corner:after{position:absolute;top:-4px;left:-4px;width:inherit;height:inherit;color:rgba(0,0,0,.25);border:inherit;content:""}.ant-ribbon-color-pink{color:#eb2f96;background:#eb2f96}.ant-ribbon-color-magenta{color:#eb2f96;background:#eb2f96}.ant-ribbon-color-red{color:#f5222d;background:#f5222d}.ant-ribbon-color-volcano{color:#fa541c;background:#fa541c}.ant-ribbon-color-orange{color:#fa8c16;background:#fa8c16}.ant-ribbon-color-yellow{color:#fadb14;background:#fadb14}.ant-ribbon-color-gold{color:#ffb924;background:#ffb924}.ant-ribbon-color-cyan{color:#13c2c2;background:#13c2c2}.ant-ribbon-color-lime{color:#a0d911;background:#a0d911}.ant-ribbon-color-green{color:#26c992;background:#26c992}.ant-ribbon-color-blue{color:#296df3;background:#296df3}.ant-ribbon-color-geekblue{color:#2f54eb;background:#2f54eb}.ant-ribbon-color-purple{color:#722ed1;background:#722ed1}.ant-ribbon.ant-ribbon-placement-end{right:-8px;border-bottom-right-radius:0}.ant-ribbon.ant-ribbon-placement-end .ant-ribbon-corner{right:0;border-color:currentcolor transparent transparent currentcolor}.ant-ribbon.ant-ribbon-placement-start{left:-8px;border-bottom-left-radius:0}.ant-ribbon.ant-ribbon-placement-start .ant-ribbon-corner{left:0;border-color:currentcolor currentcolor transparent transparent}.ant-badge-rtl{direction:rtl}.ant-badge-rtl.ant-badge:not(.ant-badge-not-a-wrapper) .ant-badge-count,.ant-badge-rtl.ant-badge:not(.ant-badge-not-a-wrapper) .ant-badge-dot,.ant-badge-rtl.ant-badge:not(.ant-badge-not-a-wrapper) .ant-scroll-number-custom-component{right:auto;left:0;direction:ltr;transform:translate(-50%,-50%);transform-origin:0 0}.ant-badge-rtl.ant-badge:not(.ant-badge-not-a-wrapper) .ant-scroll-number-custom-component{right:auto;left:0;transform:translate(-50%,-50%);transform-origin:0 0}.ant-badge-rtl .ant-badge-status-text{margin-right:8px;margin-left:0}.ant-badge:not(.ant-badge-not-a-wrapper).ant-badge-rtl .ant-badge-zoom-appear,.ant-badge:not(.ant-badge-not-a-wrapper).ant-badge-rtl .ant-badge-zoom-enter{animation-name:antZoomBadgeInRtl}.ant-badge:not(.ant-badge-not-a-wrapper).ant-badge-rtl .ant-badge-zoom-leave{animation-name:antZoomBadgeOutRtl}.ant-ribbon-rtl{direction:rtl}.ant-ribbon-rtl.ant-ribbon-placement-end{right:unset;left:-8px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.ant-ribbon-rtl.ant-ribbon-placement-end .ant-ribbon-corner{right:unset;left:0;border-color:currentcolor currentcolor transparent transparent}.ant-ribbon-rtl.ant-ribbon-placement-end .ant-ribbon-corner:after{border-color:currentcolor currentcolor transparent transparent}.ant-ribbon-rtl.ant-ribbon-placement-start{right:-8px;left:unset;border-bottom-right-radius:0;border-bottom-left-radius:2px}.ant-ribbon-rtl.ant-ribbon-placement-start .ant-ribbon-corner{right:0;left:unset;border-color:currentcolor transparent transparent currentcolor}.ant-ribbon-rtl.ant-ribbon-placement-start .ant-ribbon-corner:after{border-color:currentcolor transparent transparent currentcolor}@keyframes antZoomBadgeInRtl{0%{transform:scale(0) translate(-50%,-50%);opacity:0}to{transform:scale(1) translate(-50%,-50%)}}@keyframes antZoomBadgeOutRtl{0%{transform:scale(1) translate(-50%,-50%)}to{transform:scale(0) translate(-50%,-50%);opacity:0}}.ant-pro-field-checkbox-vertical .ant-checkbox-group-item{display:flex;margin-right:0}.ant-pro-field-radio-vertical .ant-radio-wrapper{display:block;margin-right:0}.ant-rate{box-sizing:border-box;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;font-feature-settings:"tnum","tnum";display:inline-block;margin:0;padding:0;color:#fadb14;font-size:20px;line-height:unset;list-style:none;outline:none}.ant-rate-disabled .ant-rate-star{cursor:default}.ant-rate-disabled .ant-rate-star>div:hover{transform:scale(1)}.ant-rate-star{position:relative;display:inline-block;color:inherit;cursor:pointer}.ant-rate-star:not(:last-child){margin-right:8px}.ant-rate-star>div{transition:all .3s,outline 0s}.ant-rate-star>div:hover{transform:scale(1.1)}.ant-rate-star>div:focus{outline:0}.ant-rate-star>div:focus-visible{outline:1px dashed #fadb14;transform:scale(1.1)}.ant-rate-star-first,.ant-rate-star-second{color:#f0f0f0;transition:all .3s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-rate-star-first .anticon,.ant-rate-star-second .anticon{vertical-align:middle}.ant-rate-star-first{position:absolute;top:0;left:0;width:50%;height:100%;overflow:hidden;opacity:0}.ant-rate-star-half .ant-rate-star-first,.ant-rate-star-half .ant-rate-star-second{opacity:1}.ant-rate-star-full .ant-rate-star-second,.ant-rate-star-half .ant-rate-star-first{color:inherit}.ant-rate-text{display:inline-block;margin:0 8px;font-size:14px}.ant-rate-rtl{direction:rtl}.ant-rate-rtl .ant-rate-star:not(:last-child){margin-right:0;margin-left:8px}.ant-rate-rtl .ant-rate-star-first{right:0;left:auto}.ant-slider{box-sizing:border-box;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;height:12px;margin:10px 6px;padding:4px 0;cursor:pointer;touch-action:none}.ant-slider-vertical{width:12px;height:100%;margin:6px 10px;padding:0 4px}.ant-slider-vertical .ant-slider-rail{width:4px;height:100%}.ant-slider-vertical .ant-slider-track{width:4px}.ant-slider-vertical .ant-slider-handle{margin-top:-6px;margin-left:-5px}.ant-slider-vertical .ant-slider-mark{top:0;left:12px;width:18px;height:100%}.ant-slider-vertical .ant-slider-mark-text{left:4px;white-space:nowrap}.ant-slider-vertical .ant-slider-step{width:4px;height:100%}.ant-slider-vertical .ant-slider-dot{top:auto;margin-left:-2px}.ant-slider-tooltip .ant-tooltip-inner{min-width:unset}.ant-slider-rtl.ant-slider-vertical .ant-slider-handle{margin-right:-5px;margin-left:0}.ant-slider-rtl.ant-slider-vertical .ant-slider-mark{right:12px;left:auto}.ant-slider-rtl.ant-slider-vertical .ant-slider-mark-text{right:4px;left:auto}.ant-slider-rtl.ant-slider-vertical .ant-slider-dot{right:2px;left:auto}.ant-slider-with-marks{margin-bottom:28px}.ant-slider-rail{position:absolute;width:100%;height:4px;background-color:#f5f5f5;border-radius:4px;transition:background-color .3s}.ant-slider-track{position:absolute;height:4px;background-color:#86acf8;border-radius:4px;transition:background-color .3s}.ant-slider-handle{position:absolute;width:14px;height:14px;margin-top:-5px;background-color:#fff;border:2px solid #86acf8;border-radius:50%;box-shadow:0;cursor:pointer;transition:border-color .3s,box-shadow .6s,transform .3s cubic-bezier(.18,.89,.32,1.28)}.ant-slider-handle-dragging{z-index:1}.ant-slider-handle:focus{border-color:#548af5;outline:none;box-shadow:0 0 0 5px rgba(41,109,243,.12)}.ant-slider-handle.ant-tooltip-open{border-color:#296df3}.ant-slider-handle:after{position:absolute;top:-6px;right:-6px;bottom:-6px;left:-6px;content:""}.ant-slider:hover .ant-slider-rail{background-color:#e1e1e1}.ant-slider:hover .ant-slider-track{background-color:#6193f6}.ant-slider:hover .ant-slider-handle:not(.ant-tooltip-open){border-color:#6193f6}.ant-slider-mark{position:absolute;top:14px;left:0;width:100%;font-size:14px}.ant-slider-mark-text{position:absolute;display:inline-block;color:rgba(0,10,36,.65);text-align:center;word-break:keep-all;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-slider-mark-text-active{color:rgba(0,10,36,.85)}.ant-slider-step{position:absolute;width:100%;height:4px;background:transparent;pointer-events:none}.ant-slider-dot{position:absolute;top:-2px;width:8px;height:8px;background-color:#fff;border:2px solid #f0f0f0;border-radius:50%;cursor:pointer}.ant-slider-dot-active{border-color:#94b6f9}.ant-slider-disabled{cursor:not-allowed}.ant-slider-disabled .ant-slider-rail{background-color:#f5f5f5!important}.ant-slider-disabled .ant-slider-track{background-color:rgba(0,0,0,.25)!important}.ant-slider-disabled .ant-slider-dot,.ant-slider-disabled .ant-slider-handle{background-color:#fff;border-color:rgba(0,0,0,.25)!important;box-shadow:none;cursor:not-allowed}.ant-slider-disabled .ant-slider-dot,.ant-slider-disabled .ant-slider-mark-text{cursor:not-allowed!important}.ant-slider-rtl{direction:rtl}.ant-slider-rtl .ant-slider-mark{right:0;left:auto}.ant-cascader-checkbox{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;top:.2em;line-height:1;white-space:nowrap;outline:none;cursor:pointer}.ant-cascader-checkbox-input:focus+.ant-cascader-checkbox-inner,.ant-cascader-checkbox-wrapper:hover .ant-cascader-checkbox-inner,.ant-cascader-checkbox:hover .ant-cascader-checkbox-inner{border-color:#296df3}.ant-cascader-checkbox-checked:after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #296df3;border-radius:2px;visibility:hidden;animation:antCheckboxEffect .36s ease-in-out;animation-fill-mode:backwards;content:""}.ant-cascader-checkbox-wrapper:hover .ant-cascader-checkbox:after,.ant-cascader-checkbox:hover:after{visibility:visible}.ant-cascader-checkbox-inner{position:relative;top:0;left:0;display:block;width:16px;height:16px;direction:ltr;background-color:#fff;border:1px solid #d9d9d9;border-radius:2px;border-collapse:separate;transition:all .3s}.ant-cascader-checkbox-inner:after{position:absolute;top:50%;left:21.5%;display:table;width:5.71428571px;height:9.14285714px;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(0) translate(-50%,-50%);opacity:0;transition:all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;content:" "}.ant-cascader-checkbox-input{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;width:100%;height:100%;cursor:pointer;opacity:0}.ant-cascader-checkbox-checked .ant-cascader-checkbox-inner:after{position:absolute;display:table;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(1) translate(-50%,-50%);opacity:1;transition:all .2s cubic-bezier(.12,.4,.29,1.46) .1s;content:" "}.ant-cascader-checkbox-checked .ant-cascader-checkbox-inner{background-color:#296df3;border-color:#296df3}.ant-cascader-checkbox-disabled{cursor:not-allowed}.ant-cascader-checkbox-disabled.ant-cascader-checkbox-checked .ant-cascader-checkbox-inner:after{border-color:rgba(0,0,0,.25);animation-name:none}.ant-cascader-checkbox-disabled .ant-cascader-checkbox-input{cursor:not-allowed;pointer-events:none}.ant-cascader-checkbox-disabled .ant-cascader-checkbox-inner{background-color:#f5f5f5;border-color:#d9d9d9!important}.ant-cascader-checkbox-disabled .ant-cascader-checkbox-inner:after{border-color:#f5f5f5;border-collapse:separate;animation-name:none}.ant-cascader-checkbox-disabled+span{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-cascader-checkbox-disabled:hover:after,.ant-cascader-checkbox-wrapper:hover .ant-cascader-checkbox-disabled:after{visibility:hidden}.ant-cascader-checkbox-wrapper{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-flex;align-items:baseline;line-height:unset;cursor:pointer}.ant-cascader-checkbox-wrapper:after{display:inline-block;width:0;overflow:hidden;content:"\a0"}.ant-cascader-checkbox-wrapper.ant-cascader-checkbox-wrapper-disabled{cursor:not-allowed}.ant-cascader-checkbox-wrapper+.ant-cascader-checkbox-wrapper{margin-left:8px}.ant-cascader-checkbox-wrapper.ant-cascader-checkbox-wrapper-in-form-item input[type=checkbox]{width:14px;height:14px}.ant-cascader-checkbox+span{padding-right:8px;padding-left:8px}.ant-cascader-checkbox-group{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-block}.ant-cascader-checkbox-group-item{margin-right:8px}.ant-cascader-checkbox-group-item:last-child{margin-right:0}.ant-cascader-checkbox-group-item+.ant-cascader-checkbox-group-item{margin-left:0}.ant-cascader-checkbox-indeterminate .ant-cascader-checkbox-inner{background-color:#fff;border-color:#d9d9d9}.ant-cascader-checkbox-indeterminate .ant-cascader-checkbox-inner:after{top:50%;left:50%;width:8px;height:8px;background-color:#296df3;border:0;transform:translate(-50%,-50%) scale(1);opacity:1;content:" "}.ant-cascader-checkbox-indeterminate.ant-cascader-checkbox-disabled .ant-cascader-checkbox-inner:after{background-color:rgba(0,0,0,.25);border-color:rgba(0,0,0,.25)}.ant-cascader{width:184px}.ant-cascader-checkbox{top:0;margin-right:8px}.ant-cascader-menus{display:flex;flex-wrap:nowrap;align-items:flex-start}.ant-cascader-menus.ant-cascader-menu-empty .ant-cascader-menu{width:100%;height:auto}.ant-cascader-menu{flex-grow:1;min-width:111px;height:180px;margin:-4px 0;padding:4px 0;overflow:auto;vertical-align:top;list-style:none;border-right:1px solid #f0f0f0;-ms-overflow-style:-ms-autohiding-scrollbar}.ant-cascader-menu-item{display:flex;flex-wrap:nowrap;align-items:center;padding:5px 12px;overflow:hidden;line-height:22px;white-space:nowrap;text-overflow:ellipsis;cursor:pointer;transition:all .3s}.ant-cascader-menu-item:hover{background:#f5f5f5}.ant-cascader-menu-item-disabled{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-cascader-menu-item-disabled:hover{background:transparent}.ant-cascader-menu-empty .ant-cascader-menu-item{color:rgba(0,0,0,.25);cursor:default;pointer-events:none}.ant-cascader-menu-item-active:not(.ant-cascader-menu-item-disabled),.ant-cascader-menu-item-active:not(.ant-cascader-menu-item-disabled):hover{font-weight:600;background-color:#e3ecfd}.ant-cascader-menu-item-content{flex:auto}.ant-cascader-menu-item-expand .ant-cascader-menu-item-expand-icon,.ant-cascader-menu-item-loading-icon{margin-left:4px;color:rgba(0,10,36,.65);font-size:10px}.ant-cascader-menu-item-disabled.ant-cascader-menu-item-expand .ant-cascader-menu-item-expand-icon,.ant-cascader-menu-item-disabled.ant-cascader-menu-item-loading-icon{color:rgba(0,0,0,.25)}.ant-cascader-menu-item-keyword{color:#ef4872}.ant-cascader-compact-item:not(.ant-cascader-compact-last-item):not(.ant-cascader-compact-item-rtl){margin-right:-1px}.ant-cascader-compact-item:not(.ant-cascader-compact-last-item).ant-cascader-compact-item-rtl{margin-left:-1px}.ant-cascader-compact-item:active,.ant-cascader-compact-item:focus,.ant-cascader-compact-item:hover{z-index:2}.ant-cascader-compact-item[disabled]{z-index:0}.ant-cascader-compact-item:not(.ant-cascader-compact-first-item):not(.ant-cascader-compact-last-item).ant-cascader{border-radius:0}.ant-cascader-compact-item.ant-cascader.ant-cascader-compact-first-item:not(.ant-cascader-compact-last-item):not(.ant-cascader-compact-item-rtl){border-top-right-radius:0;border-bottom-right-radius:0}.ant-cascader-compact-item.ant-cascader.ant-cascader-compact-last-item:not(.ant-cascader-compact-first-item):not(.ant-cascader-compact-item-rtl){border-top-left-radius:0;border-bottom-left-radius:0}.ant-cascader-compact-item.ant-cascader.ant-cascader-compact-item-rtl.ant-cascader-compact-first-item:not(.ant-cascader-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-cascader-compact-item.ant-cascader.ant-cascader-compact-item-rtl.ant-cascader-compact-last-item:not(.ant-cascader-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-cascader-rtl .ant-cascader-menu-item-expand-icon,.ant-cascader-rtl .ant-cascader-menu-item-loading-icon{margin-right:4px;margin-left:0}.ant-cascader-rtl .ant-cascader-checkbox{top:0;margin-right:0;margin-left:8px}@keyframes ant-tree-node-fx-do-not-use{0%{opacity:0}to{opacity:1}}@keyframes antCheckboxEffect{0%{transform:scale(1);opacity:.5}to{transform:scale(1.6);opacity:0}}.ant-select-tree-checkbox{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;top:.2em;line-height:1;white-space:nowrap;outline:none;cursor:pointer}.ant-select-tree-checkbox-input:focus+.ant-select-tree-checkbox-inner,.ant-select-tree-checkbox-wrapper:hover .ant-select-tree-checkbox-inner,.ant-select-tree-checkbox:hover .ant-select-tree-checkbox-inner{border-color:#296df3}.ant-select-tree-checkbox-checked:after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #296df3;border-radius:2px;visibility:hidden;animation:antCheckboxEffect .36s ease-in-out;animation-fill-mode:backwards;content:""}.ant-select-tree-checkbox-wrapper:hover .ant-select-tree-checkbox:after,.ant-select-tree-checkbox:hover:after{visibility:visible}.ant-select-tree-checkbox-inner{position:relative;top:0;left:0;display:block;width:16px;height:16px;direction:ltr;background-color:#fff;border:1px solid #d9d9d9;border-radius:2px;border-collapse:separate;transition:all .3s}.ant-select-tree-checkbox-inner:after{position:absolute;top:50%;left:21.5%;display:table;width:5.71428571px;height:9.14285714px;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(0) translate(-50%,-50%);opacity:0;transition:all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;content:" "}.ant-select-tree-checkbox-input{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;width:100%;height:100%;cursor:pointer;opacity:0}.ant-select-tree-checkbox-checked .ant-select-tree-checkbox-inner:after{position:absolute;display:table;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(1) translate(-50%,-50%);opacity:1;transition:all .2s cubic-bezier(.12,.4,.29,1.46) .1s;content:" "}.ant-select-tree-checkbox-checked .ant-select-tree-checkbox-inner{background-color:#296df3;border-color:#296df3}.ant-select-tree-checkbox-disabled{cursor:not-allowed}.ant-select-tree-checkbox-disabled.ant-select-tree-checkbox-checked .ant-select-tree-checkbox-inner:after{border-color:rgba(0,0,0,.25);animation-name:none}.ant-select-tree-checkbox-disabled .ant-select-tree-checkbox-input{cursor:not-allowed;pointer-events:none}.ant-select-tree-checkbox-disabled .ant-select-tree-checkbox-inner{background-color:#f5f5f5;border-color:#d9d9d9!important}.ant-select-tree-checkbox-disabled .ant-select-tree-checkbox-inner:after{border-color:#f5f5f5;border-collapse:separate;animation-name:none}.ant-select-tree-checkbox-disabled+span{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-select-tree-checkbox-disabled:hover:after,.ant-select-tree-checkbox-wrapper:hover .ant-select-tree-checkbox-disabled:after{visibility:hidden}.ant-select-tree-checkbox-wrapper{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-flex;align-items:baseline;line-height:unset;cursor:pointer}.ant-select-tree-checkbox-wrapper:after{display:inline-block;width:0;overflow:hidden;content:"\a0"}.ant-select-tree-checkbox-wrapper.ant-select-tree-checkbox-wrapper-disabled{cursor:not-allowed}.ant-select-tree-checkbox-wrapper+.ant-select-tree-checkbox-wrapper{margin-left:8px}.ant-select-tree-checkbox-wrapper.ant-select-tree-checkbox-wrapper-in-form-item input[type=checkbox]{width:14px;height:14px}.ant-select-tree-checkbox+span{padding-right:8px;padding-left:8px}.ant-select-tree-checkbox-group{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";display:inline-block}.ant-select-tree-checkbox-group-item{margin-right:8px}.ant-select-tree-checkbox-group-item:last-child{margin-right:0}.ant-select-tree-checkbox-group-item+.ant-select-tree-checkbox-group-item{margin-left:0}.ant-select-tree-checkbox-indeterminate .ant-select-tree-checkbox-inner{background-color:#fff;border-color:#d9d9d9}.ant-select-tree-checkbox-indeterminate .ant-select-tree-checkbox-inner:after{top:50%;left:50%;width:8px;height:8px;background-color:#296df3;border:0;transform:translate(-50%,-50%) scale(1);opacity:1;content:" "}.ant-select-tree-checkbox-indeterminate.ant-select-tree-checkbox-disabled .ant-select-tree-checkbox-inner:after{background-color:rgba(0,0,0,.25);border-color:rgba(0,0,0,.25)}.ant-tree-select-dropdown{padding:8px 4px}.ant-tree-select-dropdown-rtl{direction:rtl}.ant-tree-select-dropdown .ant-select-tree{border-radius:0}.ant-tree-select-dropdown .ant-select-tree-list-holder-inner{align-items:stretch}.ant-tree-select-dropdown .ant-select-tree-list-holder-inner .ant-select-tree-treenode .ant-select-tree-node-content-wrapper{flex:auto}.ant-select-tree{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";background:#fff;border-radius:4px;transition:background-color .3s}.ant-select-tree-focused:not(:hover):not(.ant-select-tree-active-focused){background:#e3ecfd}.ant-select-tree-list-holder-inner{align-items:flex-start}.ant-select-tree.ant-select-tree-block-node .ant-select-tree-list-holder-inner{align-items:stretch}.ant-select-tree.ant-select-tree-block-node .ant-select-tree-list-holder-inner .ant-select-tree-node-content-wrapper{flex:auto}.ant-select-tree.ant-select-tree-block-node .ant-select-tree-list-holder-inner .ant-select-tree-treenode.dragging{position:relative}.ant-select-tree.ant-select-tree-block-node .ant-select-tree-list-holder-inner .ant-select-tree-treenode.dragging:after{position:absolute;top:0;right:0;bottom:4px;left:0;border:1px solid #296df3;opacity:0;animation:ant-tree-node-fx-do-not-use .3s;animation-play-state:running;animation-fill-mode:forwards;content:"";pointer-events:none}.ant-select-tree .ant-select-tree-treenode{display:flex;align-items:flex-start;padding:0 0 4px;outline:none}.ant-select-tree .ant-select-tree-treenode-disabled .ant-select-tree-node-content-wrapper{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-select-tree .ant-select-tree-treenode-disabled .ant-select-tree-node-content-wrapper:hover{background:transparent}.ant-select-tree .ant-select-tree-treenode-active .ant-select-tree-node-content-wrapper{background:#f5f5f5}.ant-select-tree .ant-select-tree-treenode:not(.ant-select-tree .ant-select-tree-treenode-disabled).filter-node .ant-select-tree-title{color:inherit;font-weight:500}.ant-select-tree .ant-select-tree-treenode-draggable .ant-select-tree-draggable-icon{width:24px;line-height:24px;text-align:center;visibility:visible;opacity:.2;transition:opacity .3s}.ant-select-tree-treenode:hover .ant-select-tree .ant-select-tree-treenode-draggable .ant-select-tree-draggable-icon{opacity:.45}.ant-select-tree .ant-select-tree-treenode-draggable.ant-select-tree-treenode-disabled .ant-select-tree-draggable-icon{visibility:hidden}.ant-select-tree-indent{align-self:stretch;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-select-tree-indent-unit{display:inline-block;width:24px}.ant-select-tree-draggable-icon{visibility:hidden}.ant-select-tree-switcher{position:relative;flex:none;align-self:stretch;width:24px;margin:0;line-height:24px;text-align:center;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-select-tree-switcher .ant-select-tree-switcher-icon,.ant-select-tree-switcher .ant-tree-switcher-icon{display:inline-block;font-size:10px;vertical-align:baseline}.ant-select-tree-switcher .ant-select-tree-switcher-icon svg,.ant-select-tree-switcher .ant-tree-switcher-icon svg{transition:transform .3s}.ant-select-tree-switcher-noop{cursor:default}.ant-select-tree-switcher_close .ant-select-tree-switcher-icon svg{transform:rotate(-90deg)}.ant-select-tree-switcher-loading-icon{color:#296df3}.ant-select-tree-switcher-leaf-line{position:relative;z-index:1;display:inline-block;width:100%;height:100%}.ant-select-tree-switcher-leaf-line:before{position:absolute;top:0;right:12px;bottom:-4px;margin-left:-1px;border-right:1px solid #d9d9d9;content:" "}.ant-select-tree-switcher-leaf-line:after{position:absolute;width:10px;height:14px;border-bottom:1px solid #d9d9d9;content:" "}.ant-select-tree-checkbox{top:auto;margin:4px 8px 0 0}.ant-select-tree .ant-select-tree-node-content-wrapper{position:relative;z-index:auto;min-height:24px;margin:0;padding:0 4px;color:inherit;line-height:24px;background:transparent;border-radius:4px;cursor:pointer;transition:all .3s,border 0s,line-height 0s,box-shadow 0s}.ant-select-tree .ant-select-tree-node-content-wrapper:hover{background-color:#f5f5f5}.ant-select-tree .ant-select-tree-node-content-wrapper.ant-select-tree-node-selected{background-color:#bed2fb}.ant-select-tree .ant-select-tree-node-content-wrapper .ant-select-tree-iconEle{display:inline-block;width:24px;height:24px;line-height:24px;text-align:center;vertical-align:top}.ant-select-tree .ant-select-tree-node-content-wrapper .ant-select-tree-iconEle:empty{display:none}.ant-select-tree-unselectable .ant-select-tree-node-content-wrapper:hover{background-color:transparent}.ant-select-tree-node-content-wrapper{line-height:24px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-select-tree-node-content-wrapper .ant-tree-drop-indicator{position:absolute;z-index:1;height:2px;background-color:#296df3;border-radius:1px;pointer-events:none}.ant-select-tree-node-content-wrapper .ant-tree-drop-indicator:after{position:absolute;top:-3px;left:-6px;width:8px;height:8px;background-color:transparent;border:2px solid #296df3;border-radius:50%;content:""}.ant-select-tree .ant-select-tree-treenode.drop-container>[draggable]{box-shadow:0 0 0 2px #296df3}.ant-select-tree-show-line .ant-select-tree-indent-unit{position:relative;height:100%}.ant-select-tree-show-line .ant-select-tree-indent-unit:before{position:absolute;top:0;right:12px;bottom:-4px;border-right:1px solid #d9d9d9;content:""}.ant-select-tree-show-line .ant-select-tree-indent-unit-end:before{display:none}.ant-select-tree-show-line .ant-select-tree-switcher{background:#fff}.ant-select-tree-show-line .ant-select-tree-switcher-line-icon{vertical-align:-.15em}.ant-select-tree .ant-select-tree-treenode-leaf-last .ant-select-tree-switcher-leaf-line:before{top:auto!important;bottom:auto!important;height:14px!important}.ant-tree-select-dropdown-rtl .ant-select-tree .ant-select-tree-switcher_close .ant-select-tree-switcher-icon svg{transform:rotate(90deg)}.ant-tree-select-dropdown-rtl .ant-select-tree .ant-select-tree-switcher-loading-icon{transform:scaleY(-1)}.ant-pro-table-dropdown{width:auto}.ant-pro-select-item-option-content-light{color:#296df3}.ant-pro-select-item-option-content{flex:auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ant-pro-field-dropdown{width:auto}.ant-pro-field-select-light-select .ant-select{position:absolute;width:153px;height:28px;visibility:hidden}.ant-pro-field-select-light-select .ant-select-selector{height:28px}.ant-pro-field-select-light-select.ant-pro-field-select-light-select-searchable .ant-select{width:200px}.ant-pro-field-select-light-select.ant-pro-field-select-light-select-searchable .ant-select-selector{height:28px}.ant-pro-table .ant-pro-table-search{margin-bottom:16px;padding:24px 24px 0;background:#fff}.ant-pro-table .ant-pro-table-search-ghost{background:transparent}.ant-pro-table .ant-pro-table-search:before{display:table;content:""}.ant-pro-table .ant-pro-table-search:after{display:table;clear:both;content:""}.ant-pro-table .ant-pro-table-search.ant-pro-table-form{margin:0;padding:0 16px;overflow:unset}.ant-pro-table .ant-pro-table-search-light{margin-bottom:0;padding:16px 0}.ant-pro-table .ant-pro-table-search-form-option .ant-form-item{margin:0}.ant-pro-table .ant-pro-table-search-form-option .ant-form-item-label{opacity:0}.ant-pro-table .ant-pro-table-search-form-option .ant-form-item-control-input{justify-content:flex-start}@media (max-width:575px){.ant-pro-table .ant-pro-table-search{height:auto!important;padding-bottom:24px}.ant-pro-table .ant-pro-table-search .ant-form-item-label{min-width:80px;text-align:left}}.ant-divider{box-sizing:border-box;margin:0;padding:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";border-top:1px solid rgba(0,0,0,.06)}.ant-divider-vertical{position:relative;top:-.06em;display:inline-block;height:.9em;margin:0 8px;vertical-align:middle;border-top:0;border-left:1px solid rgba(0,0,0,.06)}.ant-divider-horizontal{display:flex;clear:both;width:100%;min-width:100%;margin:24px 0}.ant-divider-horizontal.ant-divider-with-text{display:flex;align-items:center;margin:16px 0;color:rgba(0,10,36,.85);font-weight:500;font-size:16px;white-space:nowrap;text-align:center;border-top:0;border-top-color:rgba(0,0,0,.06)}.ant-divider-horizontal.ant-divider-with-text:after,.ant-divider-horizontal.ant-divider-with-text:before{position:relative;width:50%;border-top:1px solid transparent;border-top-color:inherit;border-bottom:0;transform:translateY(50%);content:""}.ant-divider-horizontal.ant-divider-with-text-left:before{width:5%}.ant-divider-horizontal.ant-divider-with-text-left:after{width:95%}.ant-divider-horizontal.ant-divider-with-text-right:before{width:95%}.ant-divider-horizontal.ant-divider-with-text-right:after{width:5%}.ant-divider-inner-text{display:inline-block;padding:0 1em}.ant-divider-dashed{background:none;border:dashed rgba(0,0,0,.06);border-width:1px 0 0}.ant-divider-horizontal.ant-divider-with-text.ant-divider-dashed:after,.ant-divider-horizontal.ant-divider-with-text.ant-divider-dashed:before{border-style:dashed none none}.ant-divider-vertical.ant-divider-dashed{border-width:0 0 0 1px}.ant-divider-plain.ant-divider-with-text{color:rgba(0,10,36,.85);font-weight:400;font-size:14px}.ant-divider-horizontal.ant-divider-with-text-left.ant-divider-no-default-orientation-margin-left:before{width:0}.ant-divider-horizontal.ant-divider-with-text-left.ant-divider-no-default-orientation-margin-left:after{width:100%}.ant-divider-horizontal.ant-divider-with-text-left.ant-divider-no-default-orientation-margin-left .ant-divider-inner-text{padding-left:0}.ant-divider-horizontal.ant-divider-with-text-right.ant-divider-no-default-orientation-margin-right:before{width:100%}.ant-divider-horizontal.ant-divider-with-text-right.ant-divider-no-default-orientation-margin-right:after{width:0}.ant-divider-horizontal.ant-divider-with-text-right.ant-divider-no-default-orientation-margin-right .ant-divider-inner-text{padding-right:0}.ant-divider-rtl{direction:rtl}.ant-divider-rtl.ant-divider-horizontal.ant-divider-with-text-left:before{width:95%}.ant-divider-rtl.ant-divider-horizontal.ant-divider-with-text-left:after{width:5%}.ant-divider-rtl.ant-divider-horizontal.ant-divider-with-text-right:before{width:5%}.ant-divider-rtl.ant-divider-horizontal.ant-divider-with-text-right:after{width:95%}.ant-pro-form-light-filter{line-height:30px}.ant-pro-form-light-filter:before{display:block;height:0;visibility:hidden;content:"."}.ant-pro-form-light-filter-small{line-height:1.5715}.ant-pro-form-light-filter-container{display:flex;flex-wrap:wrap;margin-top:-8px;margin-right:-4px}.ant-pro-form-light-filter-item{margin-top:8px;white-space:nowrap}.ant-pro-form-light-filter-item:not(:last-child){margin-right:8px}.ant-pro-form-light-filter-formlabel{margin-bottom:2px}.ant-pro-form-light-filter-line{min-width:198px}.ant-pro-form-light-filter-line .ant-form-item{flex-direction:column;margin-bottom:0}.ant-pro-form-light-filter-line:not(:first-child){margin-top:16px;margin-bottom:8px}.ant-pro-form-light-filter .ant-form-item{margin-bottom:0}.ant-pro-form-light-filter-collapse-icon{width:32px;height:32px;line-height:35px;border-radius:50%}.ant-pro-form-light-filter-effective .ant-pro-form-light-filter-collapse-icon{background-color:rgba(0,0,0,.04)}.ant-pro-steps-form-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;min-width:520px;max-width:100%;margin:auto}.ant-pro-steps-form-steps-container{max-width:1160px;margin:auto}.ant-pro-steps-form-steps-container .ant-steps-vertical{height:100%}.ant-pro-steps-form-step{display:none;margin-top:32px}.ant-pro-steps-form-step-active{display:block}.ant-pro-steps-form-step>form{max-width:100%}.pro-table-tooltip-text span{color:#fff}.ant-pro-table{z-index:1}.ant-pro-table:not(:root):-webkit-full-screen{min-height:100vh;overflow:auto;background:#fff}.ant-pro-table:not(:root):-ms-fullscreen{min-height:100vh;overflow:auto;background:#fff}.ant-pro-table:not(:root):fullscreen{min-height:100vh;overflow:auto;background:#fff}.ant-pro-table-extra{margin-bottom:16px}.ant-pro-table-polling .ant-pro-table-list-toolbar-setting-item .anticon.anticon-reload{transform:rotate(0deg);animation:turn 1s linear infinite}.ant-pro-table td.ant-table-cell>a{font-size:14px}.ant-pro-table .ant-table .ant-table-tbody .ant-table-wrapper:only-child .ant-table{margin:0}.ant-pro-table .ant-table.ant-table-middle .ant-pro-table{margin:-12px -8px}@keyframes turn{0%{transform:rotate(0deg)}25%{transform:rotate(90deg)}50%{transform:rotate(180deg)}75%{transform:rotate(270deg)}to{transform:rotate(1turn)}}.ant-pro-table-toolbar{display:flex;align-items:center;justify-content:space-between;height:64px;padding:0 24px}.ant-pro-table-toolbar-option{display:flex;align-items:center;justify-content:flex-end}.ant-pro-table-toolbar-title{flex:1 1;color:rgba(0,10,36,.85);font-weight:500;font-size:16px;line-height:24px;opacity:.85}@media (max-width:480px){.ant-pro-table .ant-table{width:100%;overflow-x:auto}.ant-pro-table .ant-table-tbody>tr>td,.ant-pro-table .ant-table-tbody>tr>th,.ant-pro-table .ant-table-thead>tr>td,.ant-pro-table .ant-table-thead>tr>th{white-space:pre}.ant-pro-table .ant-table-tbody>tr>td>span,.ant-pro-table .ant-table-tbody>tr>th>span,.ant-pro-table .ant-table-thead>tr>td>span,.ant-pro-table .ant-table-thead>tr>th>span{display:block}}@media (max-width:575px){.ant-pro-table-toolbar{flex-direction:column;align-items:flex-start;justify-content:flex-start;height:auto;margin-bottom:16px;margin-left:16px;padding:16px 8px 8px;line-height:normal}.ant-pro-table-toolbar-title{margin-bottom:16px}.ant-pro-table-toolbar-option{display:flex;justify-content:space-between;width:100%}.ant-pro-table-toolbar-default-option{display:flex;flex:1 1;align-items:center;justify-content:flex-end}}.ant-pro-table-column-setting{width:auto}.ant-pro-table-column-setting-title{display:flex;align-items:center;justify-content:space-between;height:32px}.ant-pro-table-column-setting-overlay .ant-popover-inner-content{width:200px;padding:0 0 8px}.ant-pro-table-column-setting-overlay .ant-tree-node-content-wrapper:hover{background-color:transparent}.ant-pro-table-column-setting-overlay .ant-tree-draggable-icon{cursor:-webkit-grab;cursor:grab}.ant-pro-table-column-setting-overlay .ant-tree-treenode{align-items:center}.ant-pro-table-column-setting-overlay .ant-tree-treenode:hover{background-color:#e3ecfd}.ant-pro-table-column-setting-overlay .ant-tree-treenode:hover .ant-pro-table-column-setting-list-item-option{display:block}.ant-pro-table-column-setting-overlay .ant-tree-treenode .ant-tree-checkbox{top:0;margin:0 4px 0 0}.ant-pro-table-column-setting-list{display:flex;flex-direction:column;width:100%;padding-top:8px}.ant-pro-table-column-setting-list.ant-pro-table-column-setting-list-group{padding-top:0}.ant-pro-table-column-setting-list-title{margin-top:6px;margin-bottom:6px;padding-left:24px;color:rgba(0,10,36,.65);font-size:12px}.ant-pro-table-column-setting-list-item{display:flex;align-items:center}.ant-pro-table-column-setting-list-item-title{flex:1 1}.ant-pro-table-column-setting-list-item-option{display:none;float:right;cursor:pointer}.ant-pro-table-column-setting-list-item-option>span>span.anticon{color:#296df3}.ant-pro-table-column-setting-list-item-option>span+span{margin-left:8px}.ant-pro-table-list-toolbar{line-height:1}.ant-pro-table-list-toolbar-container{display:flex;justify-content:space-between;padding:16px 0}.ant-pro-table-list-toolbar-container-mobile{flex-direction:column}.ant-pro-table-list-toolbar-title{display:flex;align-items:center;justify-content:flex-start;color:rgba(0,10,36,.85);font-weight:500;font-size:16px}.ant-pro-table-list-toolbar-search:not(:last-child){display:flex;align-items:center;justify-content:flex-start}.ant-pro-table-list-toolbar-setting-item{margin:0 4px;color:rgba(0,0,0,.75);font-size:16px;cursor:pointer}.ant-pro-table-list-toolbar-setting-item>span{display:block;width:100%;height:100%}.ant-pro-table-list-toolbar-setting-item:hover{color:#5493ff}.ant-pro-table-list-toolbar-left{display:flex;align-items:center;justify-content:flex-start}.ant-pro-table-list-toolbar-right{display:flex;justify-content:flex-end}.ant-pro-table-list-toolbar-extra-line{margin-bottom:16px}.ant-pro-table-list-toolbar-filter{display:flex;align-items:center}.ant-pro-table-list-toolbar-filter:not(:last-child){margin-right:16px}.ant-pro-table-list-toolbar-filter div.ant-pro-table-search{margin:0;padding:0}.ant-pro-table-list-toolbar-inline-menu-item{display:inline-block;margin-right:24px;cursor:pointer;opacity:.75}.ant-pro-table-list-toolbar-inline-menu-item-active{font-weight:700;opacity:1}.ant-pro-table-list-toolbar-dropdownmenu-label{font-weight:700;font-size:16px;text-align:center;cursor:pointer}.ant-pro-table-list-toolbar .ant-tabs-top>.ant-tabs-nav{margin-bottom:0}.ant-pro-table-list-toolbar .ant-tabs-top>.ant-tabs-nav:before{border-bottom:0}.ant-pro-table-list-toolbar .ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-list{margin-top:0}.ant-pro-table-list-toolbar .ant-tabs-top>.ant-tabs-nav .ant-tabs-nav-list .ant-tabs-tab{padding-top:0}@media (max-width:575px){.ant-pro-table-list-toolbar-container{display:flex;flex-wrap:wrap}.ant-pro-table-list-toolbar-left{margin-bottom:16px}}.ant-alert{box-sizing:border-box;margin:0;color:rgba(0,10,36,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";position:relative;display:flex;align-items:center;padding:8px 15px;word-wrap:break-word;border-radius:4px}.ant-alert-content{flex:1 1;min-width:0}.ant-alert-icon{margin-right:8px}.ant-alert-description{display:none;font-size:14px;line-height:22px}.ant-alert-success{background-color:#f0fff7;border:1px solid #a1f0cd}.ant-alert-success .ant-alert-icon{color:#26c992}.ant-alert-info{background-color:#f0f7ff;border:1px solid #a6ccff}.ant-alert-info .ant-alert-icon{color:#296df3}.ant-alert-warning{background-color:#fffdf0;border:1px solid #ffea9e}.ant-alert-warning .ant-alert-icon{color:#ffb924}.ant-alert-error{background-color:#fff0f1;border:1px solid #ffc7cf}.ant-alert-error .ant-alert-icon{color:#ef4872}.ant-alert-error .ant-alert-description>pre{margin:0;padding:0}.ant-alert-action{margin-left:8px}.ant-alert-close-icon{margin-left:8px;padding:0;overflow:hidden;font-size:12px;line-height:12px;background-color:transparent;border:none;outline:none;cursor:pointer}.ant-alert-close-icon .anticon-close{color:rgba(0,10,36,.65);transition:color .3s}.ant-alert-close-icon .anticon-close:hover{color:rgba(0,0,0,.75)}.ant-alert-close-text{color:rgba(0,10,36,.65);transition:color .3s}.ant-alert-close-text:hover{color:rgba(0,0,0,.75)}.ant-alert-with-description{align-items:flex-start;padding:15px 15px 15px 24px}.ant-alert-with-description.ant-alert-no-icon{padding:15px}.ant-alert-with-description .ant-alert-icon{margin-right:15px;font-size:24px}.ant-alert-with-description .ant-alert-message{display:block;margin-bottom:4px;color:rgba(0,10,36,.85);font-size:16px}.ant-alert-message{color:rgba(0,10,36,.85)}.ant-alert-with-description .ant-alert-description{display:block}.ant-alert.ant-alert-motion-leave{overflow:hidden;opacity:1;transition:max-height .3s cubic-bezier(.78,.14,.15,.86),opacity .3s cubic-bezier(.78,.14,.15,.86),padding-top .3s cubic-bezier(.78,.14,.15,.86),padding-bottom .3s cubic-bezier(.78,.14,.15,.86),margin-bottom .3s cubic-bezier(.78,.14,.15,.86)}.ant-alert.ant-alert-motion-leave-active{max-height:0;margin-bottom:0!important;padding-top:0;padding-bottom:0;opacity:0}.ant-alert-banner{margin-bottom:0;border:0;border-radius:0}.ant-alert.ant-alert-rtl{direction:rtl}.ant-alert-rtl .ant-alert-icon{margin-right:auto;margin-left:8px}.ant-alert-rtl .ant-alert-action{margin-right:8px;margin-left:auto}.ant-alert-rtl .ant-alert-close-icon{margin-right:8px;margin-left:auto}.ant-alert-rtl.ant-alert-with-description{padding-right:24px;padding-left:15px}.ant-alert-rtl.ant-alert-with-description .ant-alert-icon{margin-right:auto;margin-left:15px}.ant-pro-table-alert{margin-bottom:16px}.ant-pro-table-alert .ant-alert.ant-alert-no-icon{padding:12px 24px}.ant-pro-table-alert-info{display:flex;align-items:center;transition:all .3s}.ant-pro-table-alert-info-content{flex:1 1}.ant-pro-table-alert-info-option{min-width:48px;padding-left:16px}.userAvatar___9hXSy{width:24px;height:24px;border-radius:50%}.userText___rJvtU{margin-left:10px}.xflow-algo-node{z-index:10;display:flex;width:180px;height:36px;line-height:36px;text-align:center;background-color:#fff;border:1px solid #c2c8d5;border-radius:2px;box-shadow:-1px -1px 4px 0 hsla(0,0%,87.5%,.5),-2px 2px 4px 0 hsla(0,0%,95.7%,.5),2px 3px 8px 2px hsla(0,0%,59.2%,.05);transition:all .15s ease-in-out}.xflow-algo-node:hover{background-color:#fff;border:1px solid #3057e3;box-shadow:0 0 3px 3px rgba(48,86,227,.15);cursor:move}.xflow-algo-node .icon{display:flex;align-items:center;justify-content:center;width:36px}.xflow-algo-node .label{width:108px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-break:break-word}.xflow-algo-node .status{width:36px}.xflow-algo-node.panel-node{border:0}.x6-node-selected .xflow-algo-node{background-color:rgba(48,86,227,.05);border:1px solid #3057e3;box-shadow:0 0 3px 3px rgba(48,86,227,.15)}.x6-node-selected .xflow-algo-node:hover{background-color:#fff;box-shadow:0 0 5px 5px rgba(48,86,227,.15)}.dag-solution-layout .xflow-canvas-root .xflow-algo-node{height:72px!important;line-height:72px!important}.dataSourceTooltipWrapper{max-width:500px}.dataSourceTooltipWrapper .ant-tooltip-inner{padding:0}.dataSourceTooltipWrapper .dataSourceTooltip{width:300px;background:#fff;border-radius:5px;color:#4d4d4d;padding:15px;opacity:.9;font-size:11px;box-shadow:0 0 5px #d8d8d8}.dataSourceTooltipWrapper .dataSourceTooltip p{margin-bottom:0;font-size:13px;padding:4px;line-height:18px;overflow:hidden;display:flex;flex-direction:row}.dataSourceTooltipWrapper .dataSourceTooltip p .dataSourceTooltipLabel{display:block;width:64px;color:grey}.dataSourceTooltipWrapper .dataSourceTooltip p .dataSourceTooltipValue{flex:1 1;display:block;width:220px;padding:0 4px;word-break:break-all}.xflow-group-node:hover{border:1px solid #c1cdf7}.xflow-group-node .xflow-group-header{font-size:14px}.x6-node-selected .xflow-group-node{border:1px solid #c1cdf7;box-shadow:0 0 3px 3px rgb(64 169 12.75%)}.ant-modal{box-sizing:border-box;color:rgba(0,0,0,.85);font-size:14px;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum","tnum";pointer-events:none;position:relative;top:100px;width:auto;max-width:calc(100vw - 32px);margin:0 auto;padding:0 0 24px}.ant-modal.ant-zoom-appear,.ant-modal.ant-zoom-enter{transform:none;opacity:0;animation-duration:.3s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ant-modal-mask{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;height:100%;background-color:rgba(0,0,0,.45)}.ant-modal-mask-hidden{display:none}.ant-modal-wrap{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;outline:0}.ant-modal-wrap{z-index:1000}.ant-modal-title{margin:0;color:rgba(0,0,0,.85);font-weight:500;font-size:16px;line-height:22px;word-wrap:break-word}.ant-modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:0;border-radius:2px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);pointer-events:auto}.ant-modal-close{position:absolute;top:0;right:0;z-index:10;padding:0;color:rgba(0,0,0,.45);font-weight:700;line-height:1;text-decoration:none;background:transparent;border:0;outline:0;cursor:pointer;transition:color .3s}.ant-modal-close-x{display:block;width:54px;height:54px;font-size:16px;font-style:normal;line-height:54px;text-align:center;text-transform:none;text-rendering:auto}.ant-modal-close:focus,.ant-modal-close:hover{color:rgba(0,0,0,.75);text-decoration:none}.ant-modal-header{padding:16px 24px;color:rgba(0,0,0,.85);background:#fff;border-bottom:1px solid #f0f0f0;border-radius:2px 2px 0 0}.ant-modal-body{padding:24px;font-size:14px;line-height:1.5715;word-wrap:break-word}.ant-modal-footer{padding:10px 16px;text-align:right;background:transparent;border-top:1px solid #f0f0f0;border-radius:0 0 2px 2px}.ant-modal-footer .ant-btn+.ant-btn:not(.ant-dropdown-trigger){margin-bottom:0;margin-left:8px}.ant-modal-open{overflow:hidden}.ant-modal-centered{text-align:center}.ant-modal-centered:before{display:inline-block;width:0;height:100%;vertical-align:middle;content:""}.ant-modal-centered .ant-modal{top:0;display:inline-block;padding-bottom:0;text-align:left;vertical-align:middle}@media (max-width:767px){.ant-modal{max-width:calc(100vw - 16px);margin:8px auto}.ant-modal-centered .ant-modal{flex:1 1}}.ant-modal-confirm .ant-modal-header{display:none}.ant-modal-confirm .ant-modal-body{padding:32px 32px 24px}.ant-modal-confirm-body-wrapper:before{display:table;content:""}.ant-modal-confirm-body-wrapper:after{display:table;clear:both;content:""}.ant-modal-confirm-body .ant-modal-confirm-title{display:block;overflow:hidden;color:rgba(0,0,0,.85);font-weight:500;font-size:16px;line-height:1.4}.ant-modal-confirm-body .ant-modal-confirm-content{margin-top:8px;color:rgba(0,0,0,.85);font-size:14px}.ant-modal-confirm-body>.anticon{float:left;margin-right:16px;font-size:22px}.ant-modal-confirm-body>.anticon+.ant-modal-confirm-title+.ant-modal-confirm-content{margin-left:38px}.ant-modal-confirm .ant-modal-confirm-btns{margin-top:24px;text-align:right}.ant-modal-confirm .ant-modal-confirm-btns .ant-btn+.ant-btn{margin-bottom:0;margin-left:8px}.ant-modal-confirm-error .ant-modal-confirm-body>.anticon{color:#ff4d4f}.ant-modal-confirm-confirm .ant-modal-confirm-body>.anticon,.ant-modal-confirm-warning .ant-modal-confirm-body>.anticon{color:#faad14}.ant-modal-confirm-info .ant-modal-confirm-body>.anticon{color:#1890ff}.ant-modal-confirm-success .ant-modal-confirm-body>.anticon{color:#52c41a}.ant-modal-confirm .ant-zoom-leave .ant-modal-confirm-btns{pointer-events:none}.ant-modal-wrap-rtl{direction:rtl}.ant-modal-wrap-rtl .ant-modal-close{right:auto;left:0}.ant-modal-wrap-rtl .ant-modal-footer{text-align:left}.ant-modal-wrap-rtl .ant-modal-footer .ant-btn+.ant-btn{margin-right:8px;margin-left:0}.ant-modal-wrap-rtl .ant-modal-confirm-body{direction:rtl}.ant-modal-wrap-rtl .ant-modal-confirm-body>.anticon{float:right;margin-right:0;margin-left:16px}.ant-modal-wrap-rtl .ant-modal-confirm-body>.anticon+.ant-modal-confirm-title+.ant-modal-confirm-content{margin-right:38px;margin-left:0}.ant-modal-wrap-rtl .ant-modal-confirm-btns{text-align:left}.ant-modal-wrap-rtl .ant-modal-confirm-btns .ant-btn+.ant-btn{margin-right:8px;margin-left:0}.ant-modal-wrap-rtl.ant-modal-centered .ant-modal{text-align:right}.dag-solution .__dumi-default-previewer-actions{border:0}.dag-solution-layout{position:relative;height:610px;border:1px solid #d9d9d9}.dag-solution-layout .xflow-x6-canvas{background:#fafafa}.dag-solution-layout .x6-edge:hover path:nth-child(2){stroke:#3056e3;stroke-width:2px}.dag-solution-layout .x6-edge.x6-edge-selected path:nth-child(2){stroke:#3056e3;stroke-width:2px}.dag-solution-layout .xflow-canvas-dnd-node-tree{border-right:1px solid #d9d9d9}.dag-solution-layout .xflow-workspace-toolbar-top{background-image:linear-gradient(180deg,#fff,#fafafa);border-bottom:1px solid #d9d9d9}.dag-solution-layout .xflow-workspace-toolbar-bottom{text-align:center;background:#fff;border-top:1px solid #d9d9d9}.dag-solution-layout .xflow-modal-container{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000}.dag-solution-layout .xflow-collapse-panel .xflow-collapse-panel-header{display:flex;align-items:center;justify-content:space-evenly;background:#f7f8fa}.dag-solution-layout .xflow-collapse-panel .xflow-collapse-panel-header .ant-input-affix-wrapper{padding:2px 11px}.dag-solution-layout .xflow-collapse-panel .xflow-collapse-panel-body{background:#f7f8fa}.dag-solution-layout .xflow-collapse-panel .xflow-collapse-panel-body .xflow-collapse-header{padding:12px 8px}.dag-solution-layout .xflow-collapse-panel .xflow-node-dnd-panel-footer{display:none}.dag-solution-layout .xflow-json-form .tabs .ant-tabs-nav{box-shadow:unset}.xflow-default-node{z-index:10;display:flex;width:180px;height:36px;line-height:36px;text-align:center;background-color:#fff;border:1px solid #1890ff;border-radius:2px;box-shadow:-1px -1px 4px 0 hsla(0,0%,87.5%,.5),-2px 2px 4px 0 hsla(0,0%,95.7%,.5),2px 3px 8px 2px hsla(0,0%,59.2%,.05);transition:all .15s ease-in-out}.xflow-default-node:hover{background-color:#fff;border:1px solid #3057e3;box-shadow:0 0 3px 3px rgba(48,86,227,.15);cursor:move}.xflow-default-node .icon{width:36px}.xflow-default-node .label{width:108px;overflow:hidden;text-overflow:ellipsis}.xflow-default-node .status{width:36px}.xflow-default-node.panel-node{border:0}.x6-node-selected .xflow-default-node{background-color:rgba(48,86,227,.05);border:1px solid #3057e3;box-shadow:0 0 3px 3px rgba(48,86,227,.15)}.x6-node-selected .xflow-default-node:hover{background-color:#fff;box-shadow:0 0 5px 5px rgba(48,86,227,.15)}.xflow-default-group-node{z-index:9;width:100%;height:100%;background-color:hsla(0,0%,100%,.65);border:1px solid hsla(0,0%,100%,.25);border-radius:4px;box-shadow:0 1px 3px 0 rgb(17 49 96/12%),0 0 0 1px rgb(17 49 96/4%);cursor:-webkit-grab;cursor:grab}.xflow-default-group-node:hover{background-color:rgba(227,244,255,.45);border:1px solid #1890ff;box-shadow:0 0 3px 3px rgba(64,169,255,.2);cursor:move}.xflow-default-group-node .xflow-group-header{display:flex;justify-content:space-between;padding:0 12px;font-size:14px;line-height:38px}.xflow-default-group-node .xflow-group-header .header-left{width:80%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.xflow-default-group-node .xflow-group-header .header-right{display:inline-flex;align-items:center}.xflow-default-group-node .xflow-group-header .header-right span.anticon{margin-left:8px}.x6-node-selected .xflow-default-group-node{background-color:rgba(243,249,255,.92);border:1px solid #1890ff;box-shadow:0 0 3px 3px rgba(64,169,255,.2)}.x6-node-selected .xflow-default-group-node:hover{background-color:rgba(243,249,255,.6)}.xflow-canvas-root{position:absolute;top:0;right:0;bottom:0;left:0}.xflow-x6-canvas{width:100%;height:100%}.xflow-app-workspace{position:relative;width:100%;height:100%}.xflow-hide{display:none}.x6-widget-dnd.dragging{cursor:-webkit-grabbing!important;cursor:grabbing!important}.xflow-collapse-panel{border-right:1px solid #d9d9d9}.xflow-collapse-panel .disabled{position:relative;opacity:.45}.xflow-collapse-panel .disabled:before{position:absolute;top:0;right:0;bottom:0;left:0;z-index:999;cursor:not-allowed;content:""}.xflow-collapse-panel-node-wrapper{display:flex;align-items:center;justify-content:center;width:100%;cursor:-webkit-grab;cursor:grab}.xflow-collapse-panel-header{display:flex;justify-content:space-evenly;background:#fff;border-bottom:1px solid #d9d9d9}.xflow-collapse-panel-header-title{font-size:16px}.xflow-collapse-panel-header-search{width:100%;padding:0 12px}.xflow-collapse-panel-body{padding:0;overflow-x:hidden;overflow-y:auto;background:#fff}.xflow-collapse-panel-footer{display:flex;justify-content:space-evenly;background:#fff;border-top:1px solid #d9d9d9}.xflow-collapse-panel-footer-title{font-size:16px}.xflow-collapse-panel .xflow-collapse-search-list{height:100%;margin:0;padding:8px 0;overflow-y:auto;list-style:none}.xflow-collapse-panel .xflow-collapse-search-list-item{margin:0;padding:4px 0}.xflow-collapse-panel .xflow-collapse-list{height:100%;margin:0;padding:0;overflow-y:auto;list-style:none}.xflow-collapse-panel .xflow-collapse-list-item{margin:0;padding:0}.xflow-collapse-panel .xflow-collapse-list-item.close .xflow-collapse-content{height:0;transform:scaleY(0)}.xflow-collapse-panel .xflow-collapse-header{display:flex;justify-content:space-between;padding:8px 16px;color:rgba(0,0,0,.65);line-height:1.5;cursor:pointer;transition:all .3s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.xflow-collapse-panel .xflow-collapse-header:hover{background:#f5f5f5}.xflow-collapse-panel .xflow-collapse-header-icon{display:flex;align-items:center;justify-content:center;width:24px}.xflow-collapse-panel .xflow-collapse-header-icon svg{transition:all .5s}.xflow-collapse-panel .xflow-collapse-header-label{flex:1 1}.xflow-collapse-panel .xflow-collapse-header-extra{width:auto}.xflow-collapse-panel .xflow-collapse-content{height:100%;height:auto;overflow:hidden;transform:scaleY(1);transition:scale .15s ease-in-out}.xflow-collapse-panel .xflow-collapse-content-item{padding:4px 0;transition:all .5s}.xflow-collapse-panel .xflow-collapse-content-item:hover{background:#f5f5f5}.x6-menu{position:relative;display:inline-block;min-width:160px;min-height:32px;margin:0;padding:4px 0;background-color:#fff;outline:0;box-shadow:0 2px 10px rgba(0,0,0,.12)}.x6-menu-item{position:relative}.x6-menu-item-active>.x6-menu-item-button,.x6-menu-item:hover>.x6-menu-item-button{color:#262626;background:#f5f5f5}.x6-menu-item-divider{display:block;width:100%;height:1px;margin:4px 0;background:hsla(0,0%,58.8%,.2);pointer-events:none}.x6-menu-item-button{position:relative;display:flex;align-content:center;align-items:center;justify-content:space-between;width:100%;height:28px;padding:0 12px;color:#595959;text-align:left;background:transparent;border:none;outline:none;box-shadow:none;cursor:pointer}.x6-menu-item-hidden{display:none}.x6-menu-item-disabled:hover>.x6-menu-item-button,.x6-menu-item-disabled>.x6-menu-item-button{color:#595959;background-color:transparent;cursor:not-allowed;opacity:.4}.x6-menu-item-icon{position:absolute;top:50%;left:6px;display:none;width:24px;height:24px;margin-top:-12px;font-size:13px}.x6-menu-item-text{padding-right:56px;overflow:hidden;font-size:13px;white-space:nowrap;text-overflow:ellipsis}.x6-menu-item-hotkey{font-size:13px;opacity:.75}.x6-menu-submenu-arrow,.x6-menu-submenu.x6-menu-item-disabled:hover>.x6-menu-item-button>.x6-menu-submenu-arrow{position:absolute;top:10px;right:12px;width:0;height:0;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:5px solid #262626;opacity:.4;pointer-events:none}.x6-menu-submenu-menu,.x6-menu-submenu.x6-menu-item-disabled:hover>.x6-menu-submenu-menu{position:absolute;top:-5px;left:100%;z-index:9999;min-width:200px;margin-left:-4px;padding:5px 0;background:#fff;box-shadow:0 2px 10px rgba(0,0,0,.12);transform:translateX(-10px);visibility:hidden;opacity:0;transition:all .25s cubic-bezier(.3,1.2,.2,1)}.x6-menu-submenu.x6-menu-item-active>.x6-menu-item-button>.x6-menu-submenu-arrow,.x6-menu-submenu:hover>.x6-menu-item-button>.x6-menu-submenu-arrow{opacity:.75}.x6-menu-submenu.x6-menu-item-active>.x6-menu-submenu-menu,.x6-menu-submenu:hover>.x6-menu-submenu-menu{transform:translateX(0);visibility:visible;opacity:1}.x6-menu.x6-menu-has-icon .x6-menu-item-button{padding-left:30px}.x6-menu.x6-menu-has-icon .x6-menu-item-button .x6-menu-item-icon{display:flex;align-items:center;justify-content:center}.x6-menu.x6-menu-has-icon .x6-menu-item-button .x6-menu-item-text{padding-left:2px}.xflow-menu-mask{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1000}.xflow-menu-mask .x6-dropdown{overflow:visible;pointer-events:all}.xflow-menu-mask .xflow-context-menu-anchor{position:absolute;z-index:1;background-color:#fff}@keyframes xflow-processing-line{to{stroke-dashoffset:-1000}}.dag-extension-container .x6-edge{stroke-width:1px}.dag-extension-container .x6-edge.success path:nth-child(2){stroke:#d5d5d5!important}.dag-extension-container .x6-edge.success path:nth-child(3){fill:#d5d5d5!important;stroke:#d5d5d5!important}.dag-extension-container .x6-edge.error{stroke-width:2px}.dag-extension-container .x6-edge.error path:nth-child(2){stroke:rgba(245,34,45,.45)!important;stroke-width:2px}.dag-extension-container .x6-edge.processing path:nth-child(2){animation:xflow-processing-line 30s linear infinite;stroke:rgba(57,202,116,.8);stroke-width:2px;stroke-dasharray:8px,2px}.dag-extension-container .x6-edge.x6-edge-selected path:nth-child(2){stroke:#1890ff;stroke-width:2px}.dag-extension-container .x6-edge:hover path:nth-child(2){stroke:#1890ff;stroke-width:2px}.dag-extension-container .x6-edge.hoverHighlight path:nth-child(2){stroke:#1890ff;stroke-width:2px}.dag-extension-container .x6-port .xflow-port-group .xflow-port-arrow{display:none}.dag-extension-container .x6-port .xflow-port-group.available .xflow-port{stroke:rgba(57,202,116,.6);r:8;stroke-width:8px}.dag-extension-container .x6-port .xflow-port-group.connected .xflow-port-arrow{display:block}.dag-extension-container .x6-port .xflow-port-group.connected .xflow-port{display:none}.dag-extension-container .x6-port .xflow-port-group.adsorbed .xflow-port{stroke:rgba(57,202,116,.85);r:10;stroke-width:10px}.layout-top-bottom .x6-port .xflow-port-group .xflow-port-arrow{display:none}.layout-top-bottom .x6-port .xflow-port-group.connected .xflow-port-arrow{display:block}.layout-top-bottom .x6-port .xflow-port-group.connected .xflow-port{display:none}.layout-left-right .x6-port .xflow-port-group .xflow-port-arrow{display:none}.layout-left-right .x6-port .xflow-port-group.connected .xflow-port-arrow{display:block;transform:translateY(5px) rotate(270deg)!important}.layout-left-right .x6-port .xflow-port-group.connected .xflow-port{display:none}.flow-extension-container .x6-edge{stroke-width:1px}.flow-extension-container .x6-edge.success path:nth-child(2){stroke:#888!important}.flow-extension-container .x6-edge.success path:nth-child(3){fill:#888!important;stroke:#888!important}.flow-extension-container .x6-edge.error{stroke-width:2px}.flow-extension-container .x6-edge.error path:nth-child(2){stroke:rgba(245,34,45,.45)!important;stroke-width:2px}.flow-extension-container .x6-edge.guideProcessing path:nth-child(2){stroke:rgba(57,202,116,.8);stroke-width:2px;stroke-dasharray:8px,2px}.flow-extension-container .x6-edge.guideProcessing path:nth-child(2):local{animation:processing-line 30s linear infinite}.flow-extension-container .x6-edge.x6-edge-selected path:nth-child(2){stroke:#1890ff;stroke-width:2px}.flow-extension-container .x6-edge:hover path:nth-child(2){stroke:#1890ff;stroke-width:2px}.flow-extension-container .x6-edge.hoverHighlight path:nth-child(2){stroke:#1890ff;stroke-width:2px}.flow-extension-container .x6-widget-transform{margin:-1px 0 0 -1px;padding:0;border:1px solid #239edd}.flow-extension-container .x6-widget-transform>div{border:1px solid #239edd}.flow-extension-container .x6-widget-transform>div:hover{background-color:#3dafe4}.flow-extension-container .x6-widget-transform-active-handle{background-color:#3dafe4}.flow-extension-container .x6-widget-transform-resize{border-radius:0}.flow-extension-container .x6-widget-selection-inner{border:1px solid #239edd}.flow-extension-container .x6-widget-selection-box{opacity:0}.xflow-form-checkbox{margin-bottom:2px!important}.xflow-form-checkbox :global .ant-checkbox-wrapper{width:100%;overflow:hidden}.xflow-form-input :global .ant-input-clear-icon{color:rgba(0,0,0,.25)}.xflow-json-form{height:100%}.xflow-json-form label{font-size:12px}.xflow-json-form .ant-form-item{margin-bottom:12px}.xflow-json-form .ant-form-item .ant-form-item-label{padding-bottom:4px}.xflow-json-form .ant-form-item .ant-form-item-label>label{color:#666}.xflow-json-form .ant-form-item .ant-form-item-control .ant-checkbox-wrapper{color:#666}.xflow-json-form .ant-form-item-explain,.xflow-json-form .ant-form-item-extra{font-size:12px}.xflow-json-form .ant-form-item-explain-error>div{word-break:break-all}.xflow-json-form .ant-form-item-extra{margin-top:4px}.xflow-json-form .tabs{flex-direction:column;height:100%}.xflow-json-form .tabs .ant-tabs-nav{box-shadow:0 0 16px -5px rgba(0,0,0,.2)}.xflow-json-form .tabs .ant-tabs-nav .ant-tabs-nav-list{width:100%}.xflow-json-form .tabs .ant-tabs-nav .ant-tabs-nav-list .ant-tabs-tab{font-size:12px}.xflow-json-form .tabs .ant-tabs-nav .ant-tabs-nav-list .ant-tabs-tab-active{border-bottom-width:0}.xflow-json-form .tabs .ant-tabs-nav .ant-tabs-nav-list .ant-tabs-tab .ant-tabs-tab-btn{font-weight:400;text-align:center}.xflow-json-form .tabs .ant-tabs-content-holder{padding:0 16px;overflow-y:auto}.xflow-json-form .tabs.xTab .ant-tabs-nav .ant-tabs-nav-list{box-sizing:border-box;height:40px;background-color:#fff;border-bottom:1px solid #d9d9d9}.xflow-json-form .tabs.xTab .ant-tabs-nav .ant-tabs-nav-list .ant-tabs-tab{background-color:#fff}.xflow-json-form .tabs.xTab .ant-tabs-nav .ant-tabs-nav-list .ant-tabs-tab .ant-tabs-tab-btn{width:100%}.xflow-json-form .tabs.singleTab .ant-tabs-tab{width:100%}.xflow-json-form .tabs.coupleTab .ant-tabs-tab{width:50%;margin-right:0;border-right-width:0}.xflow-json-form .tabs.coupleTab .ant-tabs-tab:last-of-type{border-right-width:1px}.xflow-json-form .tabs.ternateTab .ant-tabs-tab{width:33%;margin-right:0;border-right-width:0}.xflow-json-form .tabs.ternateTab .ant-tabs-tab:last-of-type{border-right-width:1px}.xflow-json-schema-form{border-left:1px solid #d9d9d9}.xflow-json-schema-form-body{position:relative;width:100%;height:100%}.xflow-json-schema-form-header{display:flex;justify-content:space-evenly;background:#fff;border-bottom:1px solid #d9d9d9}.xflow-json-schema-form-header-title{font-size:16px}.xflow-json-schema-form-footer{display:flex;justify-content:space-evenly;background:#fff;border-top:1px solid #d9d9d9}.xflow-json-schema-form-footer-title{font-size:16px}.text-truncate{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.xflow-minimap{z-index:999;background:#fff;box-shadow:0 0 10px 0 rgba(0,0,0,.15)}.xflow-minimap .x6-widget-minimap .x6-graph{background:hsla(0,0%,100%,.9)}.xflow-minimap .x6-widget-minimap{background:rgba(34,34,34,.05)}.xflow-node-dnd-panel{border-right:1px solid #d9d9d9}.xflow-node-dnd-panel-header{display:flex;justify-content:space-evenly;background:#fff;border-bottom:1px solid #d9d9d9}.xflow-node-dnd-panel-header-title{font-size:16px}.xflow-node-dnd-panel-header-search{width:100%;padding:0 12px}.xflow-node-dnd-panel-body{padding:8px 0;overflow-x:hidden;overflow-y:auto;background:#fff}.xflow-node-dnd-panel-body .ant-tree-iconEle.ant-tree-icon__customize{display:none!important;width:auto;margin-right:0;color:rgba(0,0,0,.45)}.xflow-node-dnd-panel-body .ant-tree{background:unset}.xflow-node-dnd-panel-body .ant-tree-switcher{display:flex;align-items:center;justify-content:center}.xflow-node-dnd-panel-body .ant-tree-node-content-wrapper{display:flex;align-items:center;padding-left:0;overflow:hidden}.xflow-node-dnd-panel-body-list{margin:0;padding:0}.xflow-node-dnd-panel-body-list-item{margin:0;padding:4px 12px;overflow:hidden;list-style-type:none}.xflow-node-dnd-panel-body-list-item .xflow-node-dnd-panel-node-wrapper{justify-content:center}.xflow-node-dnd-panel-tree-leaf{position:relative}.xflow-node-dnd-panel-tree-leaf .ant-tree-iconEle{display:none}.xflow-node-dnd-panel-tree-leaf .ant-tree-title{padding:2px}.xflow-node-dnd-panel-node-wrapper{display:flex;align-items:center;width:100%}.xflow-node-dnd-panel-footer{display:flex;justify-content:space-evenly;background:#fff;border-top:1px solid #d9d9d9}.xflow-node-dnd-panel-footer-title{font-size:16px}.xflow-dnd-node{width:100%;height:40px}.x6-dropdown{position:absolute;top:-9999px;left:-9999px;z-index:9999;display:block;max-height:320px;overflow-y:scroll;border-radius:3px;box-shadow:0 1px 6px rgba(0,0,0,.2)}.x6-dropdown-hidden{display:none}.x6-dropdown-overlay{display:inline-block}.x6-dropdown.slide-down-appear.slide-down-appear-active.x6-dropdown-placement-bottomCenter,.x6-dropdown.slide-down-appear.slide-down-appear-active.x6-dropdown-placement-bottomLeft,.x6-dropdown.slide-down-appear.slide-down-appear-active.x6-dropdown-placement-bottomRight,.x6-dropdown.slide-down-enter.slide-down-enter-active.x6-dropdown-placement-bottomCenter,.x6-dropdown.slide-down-enter.slide-down-enter-active.x6-dropdown-placement-bottomLeft,.x6-dropdown.slide-down-enter.slide-down-enter-active.x6-dropdown-placement-bottomRight{animation-name:x6SlideUpIn}.x6-dropdown.slide-up-appear.slide-up-appear-active.x6-dropdown-placement-topCenter,.x6-dropdown.slide-up-appear.slide-up-appear-active.x6-dropdown-placement-topLeft,.x6-dropdown.slide-up-appear.slide-up-appear-active.x6-dropdown-placement-topRight,.x6-dropdown.slide-up-enter.slide-up-enter-active.x6-dropdown-placement-topCenter,.x6-dropdown.slide-up-enter.slide-up-enter-active.x6-dropdown-placement-topLeft,.x6-dropdown.slide-up-enter.slide-up-enter-active.x6-dropdown-placement-topRight{animation-name:x6SlideDownIn}.x6-dropdown.slide-down-leave.slide-down-leave-active.x6-dropdown-placement-bottomCenter,.x6-dropdown.slide-down-leave.slide-down-leave-active.x6-dropdown-placement-bottomLeft,.x6-dropdown.slide-down-leave.slide-down-leave-active.x6-dropdown-placement-bottomRight{animation-name:x6SlideUpOut}.x6-dropdown.slide-up-leave.slide-up-leave-active.x6-dropdown-placement-topCenter,.x6-dropdown.slide-up-leave.slide-up-leave-active.x6-dropdown-placement-topLeft,.x6-dropdown.slide-up-leave.slide-up-leave-active.x6-dropdown-placement-topRight{animation-name:x6SlideDownOut}@keyframes x6SlideUpIn{0%{transform:scaleY(.8);transform-origin:0 0;opacity:0}to{transform:scaleY(1);transform-origin:0 0;opacity:1}}@keyframes x6SlideUpOut{0%{transform:scaleY(1);transform-origin:0 0;opacity:1}to{transform:scaleY(.8);transform-origin:0 0;opacity:0}}@keyframes x6SlideDownIn{0%{transform:scaleY(.8);transform-origin:100% 100%;opacity:0}to{transform:scaleY(1);transform-origin:100% 100%;opacity:1}}@keyframes x6SlideDownOut{0%{transform:scaleY(1);transform-origin:100% 100%;opacity:1}to{transform:scaleY(.8);transform-origin:100% 100%;opacity:0}}.x6-toolbar{display:flex;flex-direction:row;height:28px;margin:0;padding:0 0 0 4px;overflow:hidden}.x6-toolbar-content{display:flex;flex:1 1;flex-direction:row;justify-content:space-between;overflow:hidden}.x6-toolbar-content-extras,.x6-toolbar-content-inner,.x6-toolbar-group,.x6-toolbar-item,.x6-toolbar-item-icon,.x6-toolbar-item-text{display:flex;flex-direction:row}.x6-toolbar-content-extras{align-content:center;align-items:center;font-size:14px}.x6-toolbar-group:before{align-self:center;width:1px;height:40%;margin:0 6px;background-color:rgba(0,0,0,.15);content:" ";pointer-events:none}.x6-toolbar-group:first-child:before{content:none}.x6-toolbar-item{align-content:center;align-items:center;margin:0;padding:0 4px;color:#595959;background-color:transparent;border:0;border-radius:2px;outline:none;box-shadow:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.x6-toolbar-item.x6-toolbar-item-hidden{display:none}.x6-toolbar-item.x6-toolbar-item-disabled,.x6-toolbar-item.x6-toolbar-item-disabled:hover{cursor:not-allowed;opacity:.4}.x6-toolbar-item.x6-toolbar-item-disabled .x6-toolbar-item-icon .x6-toolbar-item:active{transform:none}.x6-toolbar-item-icon,.x6-toolbar-item-text{align-content:center;align-items:center}.x6-toolbar-item-icon{font-size:14px;transition:transform 50ms ease}.x6-toolbar-item-icon:active{transform:scale(1.27201965)}.x6-toolbar-item-text{padding-left:4px;font-size:12px}.x6-toolbar-item-dropdown-wrap{margin-top:-13px}.x6-toolbar-item-dropdown-arrow{width:0;height:0;margin-left:6px;border-color:#262626 transparent transparent;border-style:solid;border-width:5px 4px 0;opacity:.4}.x6-toolbar.x6-toolbar-hover-effect{height:32px}.x6-toolbar.x6-toolbar-hover-effect .x6-toolbar-item{margin:4px 2px 4px 0;padding:0 6px;color:#595959}.x6-toolbar.x6-toolbar-hover-effect .x6-toolbar-item-disabled.x6-toolbar-item:hover{color:#595959;background-color:transparent}.x6-toolbar.x6-toolbar-hover-effect .x6-toolbar-item-disabled.x6-toolbar-item:hover .x6-toolbar-item-dropdown-arrow{opacity:.4}.x6-toolbar-item.x6-toolbar-item-active,.x6-toolbar.x6-toolbar-hover-effect .x6-toolbar-item.x6-toolbar-item-active,.x6-toolbar.x6-toolbar-hover-effect .x6-toolbar-item:hover{color:#262626;background-color:#e0e0e0}.x6-toolbar-item.x6-toolbar-item-active .x6-toolbar-item-dropdown-arrow,.x6-toolbar.x6-toolbar-hover-effect .x6-toolbar-item.x6-toolbar-item-active .x6-toolbar-item-dropdown-arrow,.x6-toolbar.x6-toolbar-hover-effect .x6-toolbar-item:hover .x6-toolbar-item-dropdown-arrow{opacity:.75}.x6-toolbar-item.x6-toolbar-item-active{margin:4px 0}.x6-toolbar.x6-toolbar-big{height:32px}.x6-toolbar.x6-toolbar-big .x6-toolbar-content-extras{font-size:16px}.x6-toolbar.x6-toolbar-big .x6-toolbar-item{margin:4px 4px 4px 0;padding:0 5px;border-radius:3px}.x6-toolbar.x6-toolbar-big .x6-toolbar-item-text{font-size:14px}.x6-toolbar.x6-toolbar-big .x6-toolbar-item-icon{font-size:16px}.x6-toolbar.x6-toolbar-hover-effect.x6-toolbar-big{height:40px}.x6-toolbar.x6-toolbar-hover-effect.x6-toolbar-big .x6-toolbar-item{padding:0 10px}.x6-toolbar.x6-toolbar-small{height:22px}.x6-toolbar.x6-toolbar-small .x6-toolbar-content-extras{font-size:12px}.x6-toolbar.x6-toolbar-small .x6-toolbar-item{padding:0 3px}.x6-toolbar.x6-toolbar-small .x6-toolbar-item-text{margin-right:2px;padding-left:2px;font-size:10px}.x6-toolbar.x6-toolbar-small .x6-toolbar-item-icon{font-size:12px}.x6-toolbar.x6-toolbar-small .x6-toolbar-item.x6-toolbar-item-active{margin:2px 0}.x6-toolbar.x6-toolbar-hover-effect.x6-toolbar-small{height:28px}.x6-toolbar.x6-toolbar-hover-effect.x6-toolbar-small .x6-toolbar-item{margin:4px 2px 4px 0;padding:0 5px}.x6-toolbar.x6-toolbar-hover-effect.x6-toolbar-small .x6-toolbar-item.x6-toolbar-item-active{margin:4px 2px 4px 0}.x6-toolbar.x6-toolbar-align-right .x6-toolbar-content{flex-direction:row-reverse}.xflow-toolbar{position:absolute;z-index:99;display:flex;height:40px;background:#fff}.xflow-toolbar-root{display:flex;justify-content:space-between;width:100%}.xflow-toolbar-root.horizontal-center{justify-content:center}.xflow-toolbar-root.vertical{flex-direction:column}.xflow-toolbar-root .x6-toolbar.x6-toolbar-hover-effect{align-items:center;height:100%}.xflow-toolbar-root .x6-toolbar-content{height:100%}.xflow-toolbar.vertical{right:unset;left:unset;width:32px;height:auto;border:1px solid rgba(0,0,0,.04);border-radius:4px;box-shadow:0 0 20px rgb(0 0 0/1%)}.xflow-toolbar.vertical .x6-toolbar.x6-toolbar-hover-effect{height:auto;padding:8px 0}.xflow-toolbar.vertical .x6-toolbar-content-inner,.xflow-toolbar.vertical .x6-toolbar-group{flex-direction:column}.xflow-toolbar.vertical .x6-toolbar-item{margin:0;padding:6px 8px;color:#595959}.xflow-toolbar.horizontal{right:0;left:0}.xflow-toolbar.horizontal .x6-toolbar.x6-toolbar-hover-effect{height:40px;line-height:40px}.flowchart-extension-container .x6-edge{stroke-width:1px}.flowchart-extension-container .x6-edge.success path:nth-child(2){stroke:#888!important}.flowchart-extension-container .x6-edge.success path:nth-child(3){fill:#888!important;stroke:#888!important}.flowchart-extension-container .x6-edge.error{stroke-width:2px}.flowchart-extension-container .x6-edge.error path:nth-child(2){stroke:rgba(245,34,45,.45)!important;stroke-width:2px}.flowchart-extension-container .x6-edge.guideProcessing path:nth-child(2){stroke:rgba(57,202,116,.8);stroke-width:2px;stroke-dasharray:8px,2px}.flowchart-extension-container .x6-edge.guideProcessing path:nth-child(2):local{animation:processing-line 30s linear infinite}.flowchart-extension-container .x6-edge.x6-edge-selected path:nth-child(2){stroke:#1890ff;stroke-width:2px}.flowchart-extension-container .x6-edge:hover path:nth-child(2){stroke:#1890ff;stroke-width:2px}.flowchart-extension-container .x6-edge.hoverHighlight path:nth-child(2){stroke:#1890ff;stroke-width:2px}@keyframes processing-line{to{stroke-dashoffset:-1000}}.flowchart-extension-container .x6-widget-transform{margin:-1px 0 0 -1px;padding:0;border:1px solid #239edd}.flowchart-extension-container .x6-widget-transform>div{border:1px solid #239edd}.flowchart-extension-container .x6-widget-transform>div:hover{background-color:#3dafe4}.flowchart-extension-container .x6-widget-transform-active-handle{background-color:#3dafe4}.flowchart-extension-container .x6-widget-transform-resize{border-radius:0}.flowchart-extension-container .x6-widget-selection-inner{border:1px solid #239edd}.flowchart-extension-container .x6-widget-selection-box{opacity:0}.flowchart-extension-container.xflow-app-workspace{overflow:hidden;border:1px solid #d9d9d9}.flowchart-extension-container.xflow-app-workspace .xflow-workspace-panel{z-index:1;background:#fff}.flowchart-extension-container.xflow-app-workspace svg{overflow:visible!important}.flowchart-extension-container.xflow-app-workspace .x6-edge{stroke-width:1px}.flowchart-extension-container.xflow-app-workspace .x6-edge.x6-edge-selected path:nth-child(2){stroke:#1890ff}.flowchart-extension-container.xflow-app-workspace .x6-edge:hover path:nth-child(2){stroke:#1890ff}.flowchart-extension-container.xflow-app-workspace .x6-edge.hoverHighlight path:nth-child(2){stroke:#1890ff}.flowchart-extension-container.xflow-app-workspace .x6-port>circle{stroke:#69c0ff}.flowchart-extension-container.xflow-app-workspace .x6-widget-transform{box-sizing:border-box!important;margin:0;padding:0;border:2px solid #3572f9;box-shadow:0 4px 4px 0 #dbe6ff}.flowchart-extension-container.xflow-app-workspace .x6-widget-transform>div{width:8px;height:8px;background-color:#fff;border:1px solid #3572f9}.flowchart-extension-container.xflow-app-workspace .xflow-json-form .ant-tabs-content-holder{padding:0!important}.flowchart-container-collpase{transition:left .5s}.flowchart-container-collpase-wrapper{position:relative;width:100%;height:100%}.flowchart-container-collpase-nodes{border-right:1px solid #d9d9d9}.flowchart-container-collpase-icon{position:absolute;z-index:99;width:20px;color:#aaa;font-size:12px;text-align:center;background:#fff;border:1px solid #ccc;transform:translateY(-50%);cursor:pointer}.flowchart-container-collpase-icon:hover{color:#2b84c0}.flowchart-container-collpase .xflow-workspace-panel{transition:left .5s}.flowchart-editor-panel-body{padding:12px}.flowchart-editor-panel-body .flowchart-editor-color-container{width:24px;height:24px;padding:4px;border:1px solid #eee;border-radius:2px}.flowchart-editor-panel-body .flowchart-editor-panel-group{display:flex;flex-direction:column;grid-gap:8px;margin-bottom:12px;padding-bottom:12px;font-size:12px}.flowchart-editor-panel-body .flowchart-editor-panel-group:first-child{border-bottom:1px solid #ccc}.flowchart-editor-panel-body .flowchart-editor-panel-group:last-child{margin-bottom:0}.flowchart-editor-panel-body .flowchart-editor-panel-group input,.flowchart-editor-panel-body .flowchart-editor-panel-group select{height:24px}.flowchart-editor-panel-body .flowchart-editor-panel-group h5{margin:0;color:rgba(0,0,0,.85)}.flowchart-editor-panel-body .flowchart-editor-panel-group .group{display:flex;flex-direction:row;align-items:center}.flowchart-editor-panel-body .flowchart-editor-panel-group .group>label{margin-right:8px;color:rgba(0,0,0,.45);word-break:keep-all}.flowchart-editor-panel-body .flowchart-editor-panel-group .split{display:flex;grid-gap:8px}.flowchart-editor-panel-body .flowchart-editor-panel-group .addon-before-group{position:relative;display:flex;flex-direction:row;width:100%;height:100%;overflow:hidden;vertical-align:center;border:1px solid #d9d9d9;border-radius:2px}.flowchart-editor-panel-body .flowchart-editor-panel-group .addon-before-group>span{position:absolute;top:0;right:0;display:block;width:20px;color:rgba(0,0,0,.8509803921568627);line-height:24px;text-align:center;background-color:#fafafa;cursor:pointer}.flowchart-editor-panel-body .flowchart-editor-panel-group .addon-before-group:hover>span{display:none}.flowchart-editor-panel-body .flowchart-editor-edge-stroke-style,.flowchart-editor-panel-body .flowchart-editor-edge-text-style,.flowchart-editor-panel-body .flowchart-editor-node-text-style{display:flex;flex-direction:row;grid-gap:8px}.flowchart-editor-panel-body .ant-input-number{width:100%}.flowchart-editor-canvas-panel{display:flex;justify-content:center;padding-top:60px;color:#aaa}.flowchart-editor-pick-color-container{position:fixed;top:0;right:0;bottom:0;left:0;z-index:999;background:rgba(0,0,0,.25)}.flowchart-editor-pick-color-container .flowchart-editor-popover{position:absolute;top:50%;left:50%;padding:12px;background:#fff;transform:translate(-50%,-50%)}.flowchart-editor-pick-color-container .sketch-picker{box-sizing:border-box!important;padding:0!important;border-radius:none!important;box-shadow:none!important}.flowchart-editor-pick-color-container .foolter{display:flex;flex-direction:row;justify-content:space-between;margin-top:12px}.flowchart-extension-container .xflow-editor-panel-collpase{color:rgba(0,0,0,.85);font-size:12px;transition:right .5s}.flowchart-extension-container .xflow-editor-panel-collpase-wrapper{position:relative;width:100%;height:100%}.flowchart-extension-container .xflow-editor-panel-collpase-icon{position:absolute;z-index:99;width:20px;color:#aaa;text-align:center;background:#fff;border:1px solid #ccc;transform:translateY(-50%);cursor:pointer}.flowchart-extension-container .xflow-editor-panel-collpase-icon:hover{color:#2b84c0}.flowchart-extension-container .xflow-editor-panel-collpase .xflow-workspace-panel{transition:left .5s}.xflow-group-node{z-index:9;width:100%;height:100%;background-color:hsla(0,0%,100%,.65);border:1px solid hsla(0,0%,100%,.25);border-radius:4px;box-shadow:0 1px 3px 0 rgb(17 49 96/12%),0 0 0 1px rgb(17 49 96/4%);cursor:-webkit-grab;cursor:grab}.xflow-group-node:hover{background-color:rgba(227,244,255,.45);border:1px solid #1890ff;box-shadow:0 0 3px 3px rgba(64,169,255,.2);cursor:move}.xflow-group-node .xflow-group-header{display:flex;justify-content:space-between;padding:0 12px;line-height:38px}.xflow-group-node .xflow-group-header .header-left{width:80%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.xflow-group-node .xflow-group-header .header-right{display:inline-flex;align-items:center}.xflow-group-node .xflow-group-header .header-right span.anticon{margin-left:8px}.x6-node-selected .xflow-group-node{background-color:rgba(243,249,255,.92);border:1px solid #1890ff;box-shadow:0 0 3px 3px rgba(64,169,255,.2)}.x6-node-selected .xflow-group-node:hover{background-color:rgba(243,249,255,.6)}.flowchart-extension-container .xflow-node-panel{color:rgba(0,0,0,.85);font-size:12px}.flowchart-extension-container .xflow-node-panel-header{display:flex;justify-content:space-evenly;background:#fff;border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9}.flowchart-extension-container .xflow-node-panel-header-title{font-size:16px}.flowchart-extension-container .xflow-node-panel-header-search{width:100%;padding:0 12px}.flowchart-extension-container .xflow-node-panel-custom{display:flex;flex-wrap:wrap;grid-gap:5px;background:#fff;cursor:-webkit-grab;cursor:grab}.flowchart-extension-container .xflow-node-panel-official{grid-gap:5px;background:#fff;cursor:-webkit-grab;cursor:grab;display:grid;grid-template-columns:repeat(auto-fit,minmax(24px,1fr))}.flowchart-extension-container .xflow-node-panel-node-wrapper{display:flex;justify-content:center;cursor:pointer}.flowchart-extension-container .xflow-node-panel .ant-collapse-content-box{padding:12px}.flowchart-extension-container .xflow-node-panel .ant-collapse-content{border-top:none}.flowchart-extension-container .xflow-node-panel .ant-collapse-header{color:rgba(0,0,0,.85);font-size:12px}.flowchart-extension-container .xflow-node-panel-collpase{color:rgba(0,0,0,.85);font-size:12px;transition:left .5s}.flowchart-extension-container .xflow-node-panel-collpase-wrapper{position:relative;width:100%;height:100%}.flowchart-extension-container .xflow-node-panel-collpase-nodes{border-right:1px solid #d9d9d9}.flowchart-extension-container .xflow-node-panel-collpase-icon{position:absolute;z-index:99;width:20px;color:#aaa;text-align:center;background:#fff;border:1px solid #ccc;transform:translateY(-50%);cursor:pointer}.flowchart-extension-container .xflow-node-panel-collpase-icon:hover{color:#2b84c0}.loginWarp___33ulX{display:flex;flex-direction:column;height:100vh;overflow:auto}.loginWarp___33ulX .content___kTcj0{flex:1 1;padding:32px 0 24px}.loginWarp___33ulX .content___kTcj0 .formContent___3iWSs{display:flex;flex:1 1;flex-direction:column;height:100%;padding:132px 0 24px;overflow:auto;background:inherit}.loginWarp___33ulX .content___kTcj0 .formContent___3iWSs .formBox___1lEWr{min-width:480px;max-width:500px;margin:0 auto}.loginMain___2JIcS{margin:120px auto auto;padding:20px;background:#fff;border-radius:5px;box-shadow:0 0 10px 2px #eee}.title___14Nxn{margin-bottom:20px;font-size:24px;text-align:center}.input___27HLt{margin-bottom:20px}.signInBtn___XM5qM{width:100%;margin:20px 0;height:40px}.tool___KFjf1{display:flex;flex-direction:row-reverse}.button___gm0Ja{margin-left:10px}:root:root{--primary-color:#f87653;--blue:#296df3;--deep-blue:#446dff;--chat-blue:#1b4aef;--body-background:#f7fafa;--deep-background:#f0f0f0;--light-background:#f5f5f5;--component-background:#fff;--header-color:#edf2f2;--text-color:#181a1a;--text-color-secondary:#3d4242;--text-color-third:#626a6a;--text-color-fourth:#889191;--text-color-fifth:#afb6b6;--text-color-six:#a3a4a6;--text-color-fifth-4:hsla(180,5%,70%,0.4);--tooltip-max-width:350px;--success-color:#52c41a;--processing-color:#ff2442;--error-color:#ff4d4f;--highlight-color:#ff4d4f}#root,body,html{height:100%}.colorWeak{-webkit-filter:invert(80%);filter:invert(80%)}.ant-layout{min-height:100vh}canvas{display:block}body{text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}ol,ul{list-style:none}@media (max-width:480px){.ant-table{width:100%;overflow-x:auto}.ant-table-tbody>tr>td,.ant-table-tbody>tr>th,.ant-table-thead>tr>td,.ant-table-thead>tr>th{white-space:pre}.ant-table-tbody>tr>td>span,.ant-table-tbody>tr>th>span,.ant-table-thead>tr>td>span,.ant-table-thead>tr>th>span{display:block}}@media (-ms-high-contrast:none),screen and (-ms-high-contrast:active){body .ant-design-pro>.ant-layout{min-height:100vh}}.ant-card-body{padding:24px!important}.ant-pro-page-container-children-content{margin:12px 12px 0!important}.ant-page-header{padding-bottom:10px!important}.ant-spin-spinning{display:flex!important;align-items:center!important;justify-content:center!important}.ant-table-selection-extra .ant-dropdown-trigger{display:none!important}.initialLoading .ant-spin-spinning{max-height:none!important}.initialLoading .loadingPlaceholder{height:100vh}.ellipsis{overflow:hidden;text-overflow:ellipsis}.ant-menu-dark.ant-menu-horizontal>.ant-menu-item,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu{font-weight:700;font-size:14px}.ant-menu-dark.ant-menu-horizontal>.ant-menu-item>a,.ant-menu-dark.ant-menu-horizontal>.ant-menu-item>span>a,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu>a,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu>span>a{color:#fff}.ant-pro-top-nav-header-logo h1{font-size:18px}.ant-layout-header{background:linear-gradient(90deg,#153d8f,#0a276d);background-color:rgba(0,0,0,.2);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.customizeHeader{background-color:rgba(0,0,0,.2);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.ant-pro-top-nav-header-main-left{min-width:100px!important}.ant-pro-top-nav-header-logo{min-width:100px!important}.link{color:#296df3;cursor:pointer}.closeTab{position:relative;width:10px;height:10px}.closeTab:after,.closeTab:before{position:absolute;top:-2px;left:0;width:1px;height:10px;background-color:#323232;content:" "}.closeTab:before{transform:rotate(45deg)}.closeTab:after{transform:rotate(-45deg)}.dot{float:right;width:8px;height:8px;background:#bfbfbf;border-radius:100%}.bdWrapper{margin:-24px}.bdWrapper .ant-layout-sider{top:48px!important}.logo{position:relative;padding-bottom:5px;color:#fff;font-size:20px;font-weight:700;padding-right:50px}.ant-notification-topRight{right:240px!important}.g6ContextMenuContainer{font-size:12px;color:#545454}.g6ContextMenuContainer li{cursor:pointer;list-style-type:none;list-style:none;margin-left:0}.g6ContextMenuContainer ul{width:100%;padding:0}.g6ContextMenuContainer li:hover{color:#aaa} \ No newline at end of file diff --git a/webapp/packages/supersonic-fe/supersonic-webapp/version.js b/webapp/packages/supersonic-fe/supersonic-webapp/version.js index 609562fa0..1fec802ad 100644 --- a/webapp/packages/supersonic-fe/supersonic-webapp/version.js +++ b/webapp/packages/supersonic-fe/supersonic-webapp/version.js @@ -1,4 +1,4 @@ feVersion={ - "commitId": "cf043d8f0099a86e2194ce93623bb384603ef45d", - "updateTime": "Sun Jul 16 2023 20:07:04 GMT+0800 (China Standard Time)" + "commitId": "078a81038f60d1a220e26b78b67156ff406a484d", + "updateTime": "Sun Jul 30 2023 23:33:24 GMT+0800 (China Standard Time)" } \ No newline at end of file