From e1911bc81b9929399180423404636c63bc41788a Mon Sep 17 00:00:00 2001 From: mainmain <57514971+mainmainer@users.noreply.github.com> Date: Tue, 29 Aug 2023 20:06:34 +0800 Subject: [PATCH] [release][project] supersonic 0.7.3 version backend update (#40) * [improvement] add some features * [improvement] revise CHANGELOG --------- Co-authored-by: zuopengge --- CHANGELOG.md | 10 + assembly/bin/build-chat.sh | 2 +- assembly/bin/build-ide.sh | 2 +- assembly/bin/build-semantic.sh | 2 +- assembly/bin/build-standalone.sh | 2 +- assembly/bin/start-chat.sh | 2 +- assembly/bin/start-semantic.sh | 2 +- assembly/bin/start-standalone.sh | 4 +- .../authorization/service/AuthService.java | 2 +- .../repository/Impl/UserRepositoryImpl.java | 2 +- .../authentication/rest/UserController.java | 6 +- .../authentication/utils/UserTokenUtils.java | 7 +- .../application/AuthServiceImpl.java | 7 +- ...LOptimizer.java => SemanticCorrector.java} | 4 +- .../chat/api/component/SemanticLayer.java | 14 +- .../supersonic/chat/api/pojo/ChatContext.java | 1 + .../supersonic/chat/api/pojo/ModelSchema.java | 1 + .../chat/api/pojo/SchemaElement.java | 10 +- .../chat/api/pojo/SemanticParseInfo.java | 22 +- .../api/pojo/request/ExecuteQueryReq.java | 3 + .../chat/api/pojo/response/AggregateInfo.java | 1 - .../chat/api/pojo/response/ParseResp.java | 9 +- .../chat/api/pojo/response/SearchResp.java | 1 + .../chat/api/pojo/response/ShowCaseResp.java | 18 + .../tencent/supersonic/chat/agent/Agent.java | 10 +- .../supersonic/chat/agent/tool/AgentTool.java | 3 - .../chat/agent/tool/RuleQueryTool.java | 7 + .../chat/aspect/TimeCostAspect.java | 99 + .../chat/config/AggregatorConfig.java | 4 +- .../BaseSemanticCorrector.java} | 6 +- .../DateFieldCorrector.java | 15 +- .../chat/corrector/FieldCorrector.java | 17 + .../chat/corrector/FieldValueCorrector.java | 48 + .../chat/corrector/FunctionCorrector.java | 16 + .../QueryFilterAppend.java | 10 +- .../SelectFieldAppendCorrector.java | 20 +- .../TableNameCorrector.java | 10 +- .../supersonic/chat/mapper/EntityMapper.java | 16 +- .../chat/mapper/FuzzyNameMapper.java | 41 +- .../chat/mapper/HanlpDictMapper.java | 11 +- .../supersonic/chat/mapper/MapperHelper.java | 27 +- .../supersonic/chat/mapper/MatchStrategy.java | 4 +- .../chat/mapper/QueryFilterMapper.java | 22 +- .../chat/mapper/QueryMatchStrategy.java | 51 +- .../chat/mapper/SearchMatchStrategy.java | 27 +- .../chat/parser/SatisfactionChecker.java | 9 +- .../chat/parser/llm/dsl/DSLDateHelper.java | 9 - .../chat/parser/llm/dsl/DSLParseResult.java | 12 +- .../chat/parser/llm/dsl/LLMDSLParser.java | 345 +- .../llm/interpret/MetricInterpretParser.java | 35 +- .../llm/time/LLMTimeEnhancementParse.java | 14 +- .../embedding/EmbeddingBasedParser.java | 34 +- .../embedding/EmbeddingConfig.java | 2 +- .../embedding/EmbeddingEntityResolver.java | 18 +- .../{ => plugin}/embedding/EmbeddingResp.java | 2 +- .../embedding/RecallRetrieval.java | 2 +- .../function/FunctionBasedParser.java | 62 +- .../{ => plugin}/function/FunctionFiled.java | 2 +- .../{ => plugin}/function/FunctionReq.java | 2 +- .../{ => plugin}/function/FunctionResp.java | 2 +- .../function/HeuristicModelResolver.java | 102 +- .../function/ModelMatchResult.java | 2 +- .../{ => plugin}/function/ModelResolver.java | 5 +- .../{ => plugin}/function/Parameters.java | 2 +- .../chat/parser/rule/AgentCheckParser.java | 19 +- .../chat/parser/rule/AggregateTypeParser.java | 2 + .../parser/rule/ContextInheritParser.java | 16 +- .../chat/parser/rule/QueryModeParser.java | 7 +- .../chat/parser/rule/TimeRangeParser.java | 10 +- .../chat/persistence/dataobject/AgentDO.java | 72 +- .../dataobject/AgentDOExample.java | 85 +- .../persistence/dataobject/ChatParseDO.java | 142 + .../persistence/dataobject/ChatQueryDO.java | 79 +- .../dataobject/ChatQueryDOExample.java | 162 +- .../chat/persistence/dataobject/CostType.java | 23 + .../chat/persistence/dataobject/PluginDO.java | 2 +- .../dataobject/PluginDOExample.java | 66 +- .../persistence/dataobject/StatisticsDO.java | 54 + .../persistence/mapper/ChatParseMapper.java | 17 + .../persistence/mapper/ChatQueryDOMapper.java | 1 + .../persistence/mapper/StatisticsMapper.java | 12 + .../mapper/custom/ShowCaseCustomMapper.java | 12 + .../repository/ChatQueryRepository.java | 23 +- .../repository/StatisticsRepository.java | 11 + .../impl/ChatConfigRepositoryImpl.java | 13 +- .../impl/ChatContextRepositoryImpl.java | 5 +- .../impl/ChatQueryRepositoryImpl.java | 99 +- .../repository/impl/PluginRepositoryImpl.java | 7 +- .../impl/StatisticsRepositoryImpl.java | 29 + .../supersonic/chat/plugin/PluginManager.java | 43 +- .../chat/plugin/PluginParseConfig.java | 15 +- .../chat/query/HeuristicQuerySelector.java | 12 +- .../query/dsl/optimizer/FieldCorrector.java | 17 - .../dsl/optimizer/FunctionCorrector.java | 16 - .../DSLQuery.java => llm/dsl/DslQuery.java} | 32 +- .../chat/query/{ => llm}/dsl/LLMReq.java | 2 +- .../chat/query/{ => llm}/dsl/LLMResp.java | 4 +- .../query/metricInterpret/LLmAnswerReq.java | 2 +- .../query/metricInterpret/LLmAnswerResp.java | 6 +- .../metricInterpret/MetricInterpretQuery.java | 30 +- .../query/plugin/webpage/WebPageQuery.java | 23 +- .../plugin/webservice/WebServiceQuery.java | 11 +- .../plugin/webservice/WebServiceResponse.java | 1 + .../chat/query/rule/RuleSemanticQuery.java | 24 +- .../query/rule/entity/EntityDetailQuery.java | 2 +- .../query/rule/entity/EntityFilterQuery.java | 5 +- .../query/rule/entity/EntityListQuery.java | 13 +- .../query/rule/metric/MetricEntityQuery.java | 15 +- .../query/rule/metric/MetricGroupByQuery.java | 6 +- .../supersonic/chat/rest/AgentController.java | 10 +- .../chat/rest/ChatConfigController.java | 46 +- .../supersonic/chat/rest/ChatController.java | 17 +- .../chat/rest/ChatQueryController.java | 14 +- .../chat/rest/PluginController.java | 34 +- .../chat/rest/RecommendController.java | 21 +- .../supersonic/chat/service/AgentService.java | 9 +- .../supersonic/chat/service/ChatService.java | 22 +- .../chat/service/SemanticService.java | 96 +- .../chat/service/StatisticsService.java | 9 + .../chat/service/impl/AgentServiceImpl.java | 44 +- .../chat/service/impl/ChatServiceImpl.java | 62 +- .../chat/service/impl/ConfigServiceImpl.java | 44 +- .../chat/service/impl/PluginServiceImpl.java | 15 +- .../chat/service/impl/QueryServiceImpl.java | 88 +- .../service/impl/RecommendServiceImpl.java | 21 +- .../chat/service/impl/SearchServiceImpl.java | 31 +- .../service/impl/StatisticsServiceImpl.java | 25 + .../chat/utils/ChatConfigHelper.java | 9 +- .../chat/utils/ComponentFactory.java | 10 +- .../supersonic/chat/utils/DictMetaHelper.java | 40 +- .../chat/utils/QueryReqBuilder.java | 28 +- .../chat/utils/SchemaMatchHelper.java | 4 +- chat/core/src/main/python/bin/install.sh | 2 +- chat/core/src/main/python/bin/run.sh | 2 +- chat/core/src/main/python/bin/service.sh | 2 +- chat/core/src/main/python/llm/api_service.py | 31 +- .../llm/few_shot_example/sql_exampler.py | 296 -- .../main/python/llm/preset_retrieval/run.py | 11 +- chat/core/src/main/python/llm/run_config.py | 1 - .../src/main/python/llm/sql/constructor.py | 53 - .../src/main/python/llm/sql/output_parser.py | 20 +- .../src/main/python/llm/sql/prompt_maker.py | 111 +- chat/core/src/main/python/llm/sql/run.py | 65 +- .../main/python/llm/util/chromadb_instance.py | 10 - .../main/resources/mapper/ChatParseMapper.xml | 35 + .../resources/mapper/ChatQueryDOMapper.xml | 482 ++- .../resources/mapper/StatisticsMapper.xml | 35 + .../mapper/custom/ShowCaseCustomMapper.xml | 70 + .../parser/TimeRangeParserTest.java | 23 +- ...erTest.java => LoadRemoveServiceTest.java} | 4 +- .../chat/parser/llm/dsl/LLMDslParserTest.java | 12 + .../corrector}/DateFieldCorrectorTest.java | 11 +- .../corrector/FieldValueCorrectorTest.java | 66 + .../SelectFieldAppendCorrectorTest.java | 17 +- .../supersonic/chat/test/ChatBizLauncher.java | 4 +- .../test/context/MockBeansConfiguration.java | 26 +- .../collection/trie/bintrie/BaseNode.java | 20 +- .../knowledge/dictionary}/ModelInfoStat.java | 2 +- .../builder/WordBuilderFactory.java | 2 +- .../semantic/LocalSemanticLayer.java | 9 +- .../semantic/ModelSchemaBuilder.java | 8 +- .../semantic/RemoteSemanticLayer.java | 57 +- .../knowledge/service/LoadRemoveService.java | 55 + .../knowledge/service/SchemaService.java | 4 +- .../knowledge/service/SearchService.java | 27 +- .../knowledge}/utils/NatureHelper.java | 4 +- .../supersonic/common/pojo/DateConf.java | 10 +- .../common/pojo/QueryAuthorization.java | 4 + .../supersonic/common/util/ChatGptHelper.java | 107 +- .../supersonic/common/util/DateUtils.java | 2 + .../FieldAndValueAcquireVisitor.java | 84 + .../jsqlparser/FiledValueReplaceVisitor.java | 46 + .../util/jsqlparser/FilterExpression.java | 14 + .../jsqlparser/OrderByAcquireVisitor.java | 25 + .../jsqlparser/SqlParserSelectHelper.java | 188 + ...rUtils.java => SqlParserUpdateHelper.java} | 156 +- .../util/calcite/SqlParseUtilsTest.java | 5 +- .../jsqlparser/CCJSqlParserUtilsTest.java | 244 -- .../jsqlparser/SqlParserSelectHelperTest.java | 190 + .../jsqlparser/SqlParserUpdateHelperTest.java | 198 + docs/images/supersonic_components.png | Bin 238835 -> 280901 bytes docs/images/wechat_contact.jpeg | Bin 124959 -> 0 bytes launchers/chat/src/main/bin/run.sh | 2 +- launchers/chat/src/main/bin/service.sh | 2 +- .../main/resources/META-INF/spring.factories | 28 +- .../src/main/resources/db/chat-schema-h2.sql | 339 +- launchers/semantic/src/main/bin/run.sh | 2 +- launchers/semantic/src/main/bin/service.sh | 2 +- launchers/standalone/src/main/bin/run.sh | 2 +- launchers/standalone/src/main/bin/service.sh | 2 +- .../com/tencent/supersonic/ConfigureDemo.java | 101 +- .../main/resources/META-INF/spring.factories | 32 +- .../src/main/resources/application-local.yaml | 3 + .../src/main/resources/db/data-h2.sql | 3389 ++++++----------- .../src/main/resources/db/schema-h2.sql | 926 ++--- .../src/main/resources/db/sql-update.sql | 30 +- .../supersonic/integration/BaseQueryTest.java | 4 + .../integration/EntityQueryTest.java | 4 +- .../integration/MetricInterpretTest.java | 8 +- .../integration/MetricQueryTest.java | 28 +- .../integration/MockConfiguration.java | 9 +- .../integration/llm/LLMDslParserTest.java | 43 + .../integration/mapper/MapperTest.java | 46 + .../integration/plugin/BasePluginTest.java | 2 +- .../plugin/PluginRecognizeTest.java | 18 +- .../tencent/supersonic/util/DataUtils.java | 28 +- .../src/test/resources/application-local.yaml | 3 + .../src/test/resources/db/schema-h2.sql | 937 ++--- .../semantic/api/model/pojo/DimValueMap.java | 5 - .../semantic/api/model/request/DomainReq.java | 3 + .../model/application/CatalogImpl.java | 14 +- .../application/DatabaseServiceImpl.java | 16 +- .../application/DimensionServiceImpl.java | 36 +- .../model/application/DomainServiceImpl.java | 21 +- .../model/application/MetricServiceImpl.java | 11 +- .../model/application/ModelServiceImpl.java | 74 +- .../model/domain/DatabaseService.java | 4 +- .../model/domain/DimensionService.java | 1 - .../semantic/model/domain/MetricService.java | 3 +- .../semantic/model/domain/ModelService.java | 2 + .../adaptor/engineadapter/H2Adaptor.java | 7 +- .../adaptor/engineadapter/MysqlAdaptor.java | 7 +- .../model/domain/dataobject/DatabaseDO.java | 2 +- .../domain/dataobject/DatabaseDOExample.java | 66 +- .../model/domain/dataobject/DatasourceDO.java | 2 +- .../dataobject/DatasourceDOExample.java | 66 +- .../domain/dataobject/DatasourceRelaDO.java | 2 +- .../dataobject/DatasourceRelaDOExample.java | 66 +- .../model/domain/dataobject/DimensionDO.java | 2 +- .../domain/dataobject/DimensionDOExample.java | 66 +- .../domain/dataobject/DomainDOExample.java | 66 +- .../model/domain/dataobject/MetricDO.java | 159 +- .../domain/dataobject/MetricDOExample.java | 66 +- .../model/domain/dataobject/ModelDO.java | 128 +- .../domain/dataobject/ModelDOExample.java | 66 +- .../model/domain/dataobject/ViewInfoDO.java | 13 +- .../domain/dataobject/ViewInfoDOExample.java | 66 +- .../model/domain/utils/DomainConvert.java | 7 +- .../model/domain/utils/MetricConverter.java | 7 +- .../model/rest/DimensionController.java | 28 +- .../semantic/model/rest/MetricController.java | 13 +- .../semantic/model/rest/ModelController.java | 30 +- .../mapper/custom/MetricDOCustomMapper.xml | 2 +- .../query/parser/calcite/sql/Renderer.java | 1 - .../calcite/sql/node/DataSourceNode.java | 34 +- .../parser/convert/CalculateAggConverter.java | 38 +- .../convert/DefaultDimValueConverter.java | 8 +- .../query/parser/convert/MultiSourceJoin.java | 2 - .../convert/ParserDefaultConverter.java | 8 +- .../semantic/query/rest/QueryController.java | 11 +- .../semantic/query/rest/SchemaController.java | 32 +- .../query/service/QueryServiceImpl.java | 3 +- .../semantic/query/service/SchemaService.java | 9 +- .../query/service/SchemaServiceImpl.java | 24 +- .../query/utils/DataPermissionAOP.java | 111 +- .../semantic/query/utils/DateUtils.java | 13 + .../semantic/query/utils/DimValueAspect.java | 49 +- .../query/utils/QueryReqConverter.java | 6 +- .../query/utils/QueryStructUtils.java | 7 +- .../semantic/query/utils/QueryUtils.java | 46 +- 260 files changed, 6466 insertions(+), 7108 deletions(-) rename chat/api/src/main/java/com/tencent/supersonic/chat/api/component/{DSLOptimizer.java => SemanticCorrector.java} (56%) create mode 100644 chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/ShowCaseResp.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/aspect/TimeCostAspect.java rename chat/core/src/main/java/com/tencent/supersonic/chat/{query/dsl/optimizer/BaseDSLOptimizer.java => corrector/BaseSemanticCorrector.java} (86%) rename chat/core/src/main/java/com/tencent/supersonic/chat/{query/dsl/optimizer => corrector}/DateFieldCorrector.java (52%) create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldCorrector.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldValueCorrector.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FunctionCorrector.java rename chat/core/src/main/java/com/tencent/supersonic/chat/{query/dsl/optimizer => corrector}/QueryFilterAppend.java (83%) rename chat/core/src/main/java/com/tencent/supersonic/chat/{query/dsl/optimizer => corrector}/SelectFieldAppendCorrector.java (52%) rename chat/core/src/main/java/com/tencent/supersonic/chat/{query/dsl/optimizer => corrector}/TableNameCorrector.java (51%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/embedding/EmbeddingBasedParser.java (87%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/embedding/EmbeddingConfig.java (90%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/embedding/EmbeddingEntityResolver.java (94%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/embedding/EmbeddingResp.java (72%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/embedding/RecallRetrieval.java (74%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/FunctionBasedParser.java (82%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/FunctionFiled.java (66%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/FunctionReq.java (81%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/FunctionResp.java (61%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/HeuristicModelResolver.java (65%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/ModelMatchResult.java (68%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/ModelResolver.java (77%) rename chat/core/src/main/java/com/tencent/supersonic/chat/parser/{ => plugin}/function/Parameters.java (80%) create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatParseDO.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/CostType.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/StatisticsDO.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatParseMapper.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/StatisticsMapper.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/custom/ShowCaseCustomMapper.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/StatisticsRepository.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/StatisticsRepositoryImpl.java delete mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FieldCorrector.java delete mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FunctionCorrector.java rename chat/core/src/main/java/com/tencent/supersonic/chat/query/{dsl/DSLQuery.java => llm/dsl/DslQuery.java} (69%) rename chat/core/src/main/java/com/tencent/supersonic/chat/query/{ => llm}/dsl/LLMReq.java (90%) rename chat/core/src/main/java/com/tencent/supersonic/chat/query/{ => llm}/dsl/LLMResp.java (76%) create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/service/StatisticsService.java create mode 100644 chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/StatisticsServiceImpl.java delete mode 100644 chat/core/src/main/python/llm/few_shot_example/sql_exampler.py delete mode 100644 chat/core/src/main/python/llm/sql/constructor.py delete mode 100644 chat/core/src/main/python/llm/util/chromadb_instance.py create mode 100644 chat/core/src/main/resources/mapper/ChatParseMapper.xml create mode 100644 chat/core/src/main/resources/mapper/StatisticsMapper.xml create mode 100644 chat/core/src/main/resources/mapper/custom/ShowCaseCustomMapper.xml rename chat/core/src/test/java/com/tencent/supersonic/chat/mapper/{MapperHelperTest.java => LoadRemoveServiceTest.java} (90%) create mode 100644 chat/core/src/test/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDslParserTest.java rename chat/core/src/test/java/com/tencent/supersonic/chat/query/{dsl/optimizer => llm/dsl/corrector}/DateFieldCorrectorTest.java (78%) create mode 100644 chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/FieldValueCorrectorTest.java rename chat/core/src/test/java/com/tencent/supersonic/chat/query/{dsl/optimizer => llm/dsl/corrector}/SelectFieldAppendCorrectorTest.java (53%) rename chat/{core/src/main/java/com/tencent/supersonic/chat/mapper => knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary}/ModelInfoStat.java (86%) create mode 100644 chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/LoadRemoveService.java rename chat/{core/src/main/java/com/tencent/supersonic/chat => knowledge/src/main/java/com/tencent/supersonic/knowledge}/utils/NatureHelper.java (98%) create mode 100644 common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FieldAndValueAcquireVisitor.java create mode 100644 common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FiledValueReplaceVisitor.java create mode 100644 common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FilterExpression.java create mode 100644 common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/OrderByAcquireVisitor.java create mode 100644 common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelper.java rename common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/{CCJSqlParserUtils.java => SqlParserUpdateHelper.java} (56%) delete mode 100644 common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/CCJSqlParserUtilsTest.java create mode 100644 common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelperTest.java create mode 100644 common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserUpdateHelperTest.java delete mode 100644 docs/images/wechat_contact.jpeg create mode 100644 launchers/standalone/src/test/java/com/tencent/supersonic/integration/llm/LLMDslParserTest.java create mode 100644 launchers/standalone/src/test/java/com/tencent/supersonic/integration/mapper/MapperTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a83be5058..b33b6a7f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,17 @@ - "Breaking Changes" describes any changes that may break existing functionality or cause compatibility issues with previous versions. +## SuperSonic [0.7.3] - 2023-08-29 +### Added +- meet checkstyle code requirements +- save parseInfo after parsing +- add time statistics +- add agent + +### Updated +- dsl where condition is used for front-end display +- dsl remove context inheritance ## SuperSonic [0.7.2] - 2023-08-12 diff --git a/assembly/bin/build-chat.sh b/assembly/bin/build-chat.sh index 6305f9d8a..e00ab2fa9 100755 --- a/assembly/bin/build-chat.sh +++ b/assembly/bin/build-chat.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash sbinDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$sbinDir/.." && pwd -P) +baseDir=$(readlink -f $sbinDir/../) runtimeDir=$baseDir/runtime buildDir=$baseDir/build diff --git a/assembly/bin/build-ide.sh b/assembly/bin/build-ide.sh index 87bfda75e..b2bcd0ca3 100755 --- a/assembly/bin/build-ide.sh +++ b/assembly/bin/build-ide.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash sbinDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$sbinDir/.." && pwd -P) +baseDir=$(readlink -f $sbinDir/../) buildDir=$baseDir/build cd $baseDir/bin diff --git a/assembly/bin/build-semantic.sh b/assembly/bin/build-semantic.sh index 1c969081b..5eefb3845 100755 --- a/assembly/bin/build-semantic.sh +++ b/assembly/bin/build-semantic.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash sbinDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$sbinDir/.." && pwd -P) +baseDir=$(readlink -f $sbinDir/../) runtimeDir=$baseDir/runtime buildDir=$baseDir/build diff --git a/assembly/bin/build-standalone.sh b/assembly/bin/build-standalone.sh index b14435eca..efa2324e8 100755 --- a/assembly/bin/build-standalone.sh +++ b/assembly/bin/build-standalone.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash sbinDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$sbinDir/.." && pwd -P) +baseDir=$(readlink -f $sbinDir/../) runtimeDir=$baseDir/runtime buildDir=$baseDir/build diff --git a/assembly/bin/start-chat.sh b/assembly/bin/start-chat.sh index 0ee1435fe..87e1920b4 100755 --- a/assembly/bin/start-chat.sh +++ b/assembly/bin/start-chat.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash sbinDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$sbinDir/.." && pwd -P) +baseDir=$(readlink -f $sbinDir/../) runtimeDir=$baseDir/../runtime buildDir=$baseDir/build diff --git a/assembly/bin/start-semantic.sh b/assembly/bin/start-semantic.sh index 0175de675..1c070b83b 100755 --- a/assembly/bin/start-semantic.sh +++ b/assembly/bin/start-semantic.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash sbinDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$sbinDir/.." && pwd -P) +baseDir=$(readlink -f $sbinDir/../) runtimeDir=$baseDir/../runtime buildDir=$baseDir/build diff --git a/assembly/bin/start-standalone.sh b/assembly/bin/start-standalone.sh index 3cb9aff0f..80fb3099d 100755 --- a/assembly/bin/start-standalone.sh +++ b/assembly/bin/start-standalone.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash sbinDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$sbinDir/.." && pwd -P) +baseDir=$(readlink -f $sbinDir/../) runtimeDir=$baseDir/../runtime buildDir=$baseDir/build @@ -29,4 +29,4 @@ rm -fr ${buildDir}/supersonic-webapp #start standalone service sh ${runtimeDir}/supersonic-standalone/bin/service.sh restart #start llm service -sh ${runtimeDir}/supersonic-standalone/llm/bin/service.sh restart +sh ${runtimeDir}/supersonic-standalone/llm/bin/service.sh restart \ No newline at end of file diff --git a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/service/AuthService.java b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/service/AuthService.java index 60415954f..184ffeba0 100644 --- a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/service/AuthService.java +++ b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/service/AuthService.java @@ -5,7 +5,7 @@ import com.tencent.supersonic.auth.api.authorization.pojo.AuthGroup; import com.tencent.supersonic.auth.api.authorization.request.QueryAuthResReq; import com.tencent.supersonic.auth.api.authorization.response.AuthorizedResourceResp; import java.util.List; -import javax.servlet.http.HttpServletRequest; + public interface AuthService { diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/persistence/repository/Impl/UserRepositoryImpl.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/persistence/repository/Impl/UserRepositoryImpl.java index 520e2c71f..00f6643e5 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/persistence/repository/Impl/UserRepositoryImpl.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/persistence/repository/Impl/UserRepositoryImpl.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.auth.authentication.persistence.repository.Impl; +package com.tencent.supersonic.auth.authentication.persistence.repository.impl; import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO; diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/rest/UserController.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/rest/UserController.java index 1eabf48e6..123818553 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/rest/UserController.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/rest/UserController.java @@ -11,12 +11,12 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.PathVariable; @RestController @RequestMapping("/api/auth/user") diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/UserTokenUtils.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/UserTokenUtils.java index 4c55a84b1..c8749ad43 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/UserTokenUtils.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/UserTokenUtils.java @@ -9,7 +9,6 @@ import static com.tencent.supersonic.auth.api.authentication.constant.UserConsta import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_ID; import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME; import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_PASSWORD; - 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; @@ -22,9 +21,11 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; +@Slf4j @Component public class UserTokenUtils { @@ -68,7 +69,9 @@ public class UserTokenUtils { public UserWithPassword getUserWithPassword(HttpServletRequest request) { String token = request.getHeader(authenticationConfig.getTokenHttpHeaderKey()); if (StringUtils.isBlank(token)) { - throw new AccessException("token is blank, get user failed"); + String message = "token is blank, get user failed"; + log.warn("{}, uri: {}", message, request.getServletPath()); + throw new AccessException(message); } final Claims claims = getClaims(token); Long userId = Long.parseLong(claims.getOrDefault(TOKEN_USER_ID, 0).toString()); 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 2f5cda273..9053a8229 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 @@ -12,13 +12,16 @@ import com.tencent.supersonic.auth.api.authorization.response.AuthorizedResource import com.tencent.supersonic.auth.api.authorization.service.AuthService; import com.tencent.supersonic.auth.api.authorization.pojo.AuthGroup; import com.tencent.supersonic.auth.api.authorization.pojo.AuthRule; -import com.tencent.supersonic.common.util.S2ThreadContext; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import java.util.*; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.Map; +import java.util.ArrayList; import java.util.stream.Collectors; @Service diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/DSLOptimizer.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticCorrector.java similarity index 56% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/component/DSLOptimizer.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticCorrector.java index 2ad042f6b..e228d1af3 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/DSLOptimizer.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticCorrector.java @@ -3,7 +3,7 @@ package com.tencent.supersonic.chat.api.component; import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; import net.sf.jsqlparser.JSQLParserException; -public interface DSLOptimizer { - CorrectionInfo rewriter(CorrectionInfo correctionInfo) throws JSQLParserException; +public interface SemanticCorrector { + CorrectionInfo corrector(CorrectionInfo correctionInfo) throws JSQLParserException; } 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 4fc92178d..fb931fdff 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 @@ -6,14 +6,15 @@ import com.tencent.supersonic.chat.api.pojo.ModelSchema; import com.tencent.supersonic.common.pojo.enums.AuthType; 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.semantic.api.model.response.DimensionResp; import com.tencent.supersonic.semantic.api.model.response.ModelResp; +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 java.util.List; /** @@ -31,22 +32,13 @@ 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); - List getModelSchema(); - List getModelSchema(List ids); - ModelSchema getModelSchema(Long model, Boolean cacheEnable); - PageInfo getDimensionPage(PageDimensionReq pageDimensionCmd); - PageInfo getMetricPage(PageMetricReq pageMetricCmd); - List getDomainList(User user); - List getModelList(AuthType authType, Long domainId, User user); } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ChatContext.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ChatContext.java index 254ff7c65..aa0cdf088 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ChatContext.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ChatContext.java @@ -6,6 +6,7 @@ import lombok.Data; public class ChatContext { private Integer chatId; + private Integer agentId; private String queryText; private SemanticParseInfo parseInfo = new SemanticParseInfo(); private String user; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ModelSchema.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ModelSchema.java index c190561a8..d365ace86 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ModelSchema.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/ModelSchema.java @@ -32,6 +32,7 @@ public class ModelSchema { break; case VALUE: element = dimensionValues.stream().filter(e -> e.getId() == elementID).findFirst(); + break; default: } 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 index d583fe30b..c260416cd 100644 --- 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 @@ -1,18 +1,19 @@ 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; import lombok.Getter; +import lombok.Builder; import lombok.NoArgsConstructor; @Data @Getter @Builder @NoArgsConstructor -//@AllArgsConstructor public class SchemaElement implements Serializable { private Long model; @@ -23,11 +24,8 @@ public class SchemaElement implements Serializable { private SchemaElementType type; private List alias; -// public SchemaElement() { -// } - public SchemaElement(Long model, Long id, String name, String bizName, - Long useCnt, SchemaElementType type, List alias) { + Long useCnt, SchemaElementType type, List alias) { this.model = model; this.id = id; this.name = name; 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 d11ae10d1..671aa91a4 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,23 +1,26 @@ package com.tencent.supersonic.chat.api.pojo; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.LinkedHashSet; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.Comparator; + import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.response.EntityInfo; import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.Order; import com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; import lombok.Data; @Data public class SemanticParseInfo { + private Integer id; private String queryMode; private SchemaElement model; private Set metrics = new TreeSet<>(new SchemaNameLengthComparator()); @@ -33,7 +36,7 @@ public class SemanticParseInfo { private double score; private List elementMatches = new ArrayList<>(); private Map properties = new HashMap<>(); - + private EntityInfo entityInfo; public Long getModelId() { return model != null ? model.getId() : 0L; } @@ -43,7 +46,6 @@ public class SemanticParseInfo { } private static class SchemaNameLengthComparator implements Comparator { - @Override public int compare(SchemaElement o1, SchemaElement o2) { int len1 = o1.getName().length(); diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/ExecuteQueryReq.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/ExecuteQueryReq.java index 51ce237a2..061dc4c5e 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/ExecuteQueryReq.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/request/ExecuteQueryReq.java @@ -9,8 +9,11 @@ import lombok.Data; public class ExecuteQueryReq { private User user; + private Integer agentId; private Integer chatId; private String queryText; + private Long queryId; + private Integer parseId; private SemanticParseInfo parseInfo; private boolean saveAnswer = true; } 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 index 57acac1f6..aebbeb1b0 100644 --- 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 @@ -6,6 +6,5 @@ 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/response/ParseResp.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/ParseResp.java index e096199cc..e8fc10db8 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/ParseResp.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/ParseResp.java @@ -1,12 +1,13 @@ package com.tencent.supersonic.chat.api.pojo.response; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.Getter; +import lombok.Builder; import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +import java.util.List; @Data @Getter @@ -14,9 +15,9 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor public class ParseResp { - private Integer chatId; private String queryText; + private Long queryId; private ParseState state; private List selectedParses; private List candidateParses; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResp.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResp.java index 72abbed20..5a1fae483 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResp.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/SearchResp.java @@ -3,6 +3,7 @@ package com.tencent.supersonic.chat.api.pojo.response; import java.util.List; import lombok.Data; + @Data public class SearchResp { diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/ShowCaseResp.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/ShowCaseResp.java new file mode 100644 index 000000000..9b386e3c5 --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/response/ShowCaseResp.java @@ -0,0 +1,18 @@ +package com.tencent.supersonic.chat.api.pojo.response; + + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ShowCaseResp { + + private Map> showCaseMap; + + private int pageSize; + + private int current; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/agent/Agent.java b/chat/core/src/main/java/com/tencent/supersonic/chat/agent/Agent.java index f8cc93925..a747b53b8 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/agent/Agent.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/agent/Agent.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.chat.agent.tool.AgentToolType; import com.tencent.supersonic.common.pojo.RecordInfo; +import java.util.Objects; import lombok.Data; import org.springframework.util.CollectionUtils; import java.util.List; @@ -23,7 +24,6 @@ public class Agent extends RecordInfo { private Integer status; private List examples; private String agentConfig; - public List getTools(AgentToolType type) { Map map = JSONObject.parseObject(agentConfig, Map.class); if (CollectionUtils.isEmpty(map) || map.get("tools") == null) { @@ -31,7 +31,13 @@ public class Agent extends RecordInfo { } List toolList = (List) map.get("tools"); return toolList.stream() - .filter(tool -> type.name().equals(tool.get("type"))) + .filter(tool -> { + if (Objects.isNull(type)) { + return true; + } + return type.name().equals(tool.get("type")); + } + ) .map(JSONObject::toJSONString) .collect(Collectors.toList()); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/AgentTool.java b/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/AgentTool.java index de51051c3..126e89245 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/AgentTool.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/AgentTool.java @@ -1,12 +1,9 @@ package com.tencent.supersonic.chat.agent.tool; - import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/RuleQueryTool.java b/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/RuleQueryTool.java index 63e8bdd49..0da793120 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/RuleQueryTool.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/agent/tool/RuleQueryTool.java @@ -2,12 +2,19 @@ package com.tencent.supersonic.chat.agent.tool; import lombok.Data; +import org.apache.commons.collections.CollectionUtils; import java.util.List; @Data public class RuleQueryTool extends AgentTool { + private List modelIds; + private List queryModes; + public boolean isContainsAllModel() { + return CollectionUtils.isNotEmpty(modelIds) && modelIds.contains(-1L); + } + } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/aspect/TimeCostAspect.java b/chat/core/src/main/java/com/tencent/supersonic/chat/aspect/TimeCostAspect.java new file mode 100644 index 000000000..7d4e0de0b --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/aspect/TimeCostAspect.java @@ -0,0 +1,99 @@ +/* +//package com.tencent.supersonic.chat.aspect; +// +//import lombok.extern.slf4j.Slf4j; +//import org.aspectj.lang.JoinPoint; +//import org.aspectj.lang.ProceedingJoinPoint; +//import org.aspectj.lang.annotation.*; +//import org.springframework.stereotype.Component; +// +//import java.util.HashMap; +//import java.util.Map; +// +//@Aspect +//@Component +//@Slf4j +//public class TimeCostAspect { +// +// ThreadLocal startTime = new ThreadLocal<>(); +// +// ThreadLocal> map = new ThreadLocal<>(); +// +// @Pointcut("execution(public * com.tencent.supersonic.chat.mapper.HanlpDictMapper.*(*))") +// //@Pointcut("execution(* public com.tencent.supersonic.chat.parser.*.*(..))") +// //@Pointcut("execution(* com.tencent.supersonic.chat.mapper.*Mapper.map(..)) ") +// //@Pointcut("execution(* com.tencent.supersonic.chat.mapper.HanlpDictMapper.map(..)) ") +// //@Pointcut("execution(* com.tencent.supersonic.chat.parser.rule.QueryModeParser.*(..)) ") +// public void point() { +// } +// +// @Around("point()") +// public void doAround(ProceedingJoinPoint joinPoint) throws Throwable { +// long start = System.currentTimeMillis(); +// try { +// log.info("切面开始"); +// Object result = joinPoint.proceed(); +// log.info("切面开始"); +// if (result == null) { +// //如果切到了 没有返回类型的void方法,这里直接返回 +// //return null; +// } +// long end = System.currentTimeMillis(); +// log.info("==================="); +// String targetClassName = joinPoint.getSignature().getDeclaringTypeName(); +// String MethodName = joinPoint.getSignature().getName(); +// String typeStr = joinPoint.getSignature().getDeclaringType().toString().split(" ")[0]; +// log.info("类/接口:" + targetClassName + "(" + typeStr + ")"); +// log.info("方法:" + MethodName); +// Long total = end - start; +// log.info("耗时: " + total + " ms!"); +// map.get().put(targetClassName + "_" + MethodName, total); +// //return result; +// } catch (Throwable e) { +// long end = System.currentTimeMillis(); +// log.info("====around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " +// + e.getMessage()); +// throw e; +// } +// } +// +//// //对Controller下面的方法执行前进行切入,初始化开始时间 +//// @Before(value = "execution(* com.appleyk.controller.*.*(..))") +//// public void beforMehhod(JoinPoint jp) { +//// startTime.set(System.currentTimeMillis()); +//// } +//// +//// //对Controller下面的方法执行后进行切入,统计方法执行的次数和耗时情况 +//// //注意,这里的执行方法统计的数据不止包含Controller下面的方法,也包括环绕切入的所有方法的统计信息 +//// @AfterReturning(value = "execution(* com.appleyk.controller.*.*(..))") +//// public void afterMehhod(JoinPoint jp) { +//// long end = System.currentTimeMillis(); +//// long total = end - startTime.get(); +//// String methodName = jp.getSignature().getName(); +//// log.info("连接点方法为:" + methodName + ",执行总耗时为:" +total+"ms"); +//// +//// //重新new一个map +//// Map map = new HashMap<>(); +//////从map2中将最后的 连接点方法给移除了,替换成最终的,避免连接点方法多次进行叠加计算 +//// //由于map2受ThreadLocal的保护,这里不支持remove,因此,需要单开一个map进行数据交接 +//// for(Map.Entry entry:map2.get().entrySet()){ +//// if(entry.getKey().equals(methodName)){ +//// map.put(methodName, total); +//// +//// }else{ +//// map.put(entry.getKey(), entry.getValue()); +//// } +//// } +//// +//// for (Map.Entry entry :map1.get().entrySet()) { +//// for(Map.Entry entry2 :map.entrySet()){ +//// if(entry.getKey().equals(entry2.getKey())){ +//// System.err.println(entry.getKey()+",被调用次数:"+entry.getValue()+",综合耗时:"+entry2.getValue()+"ms"); +//// } +//// } +//// +//// } +//// } +// +//} +*/ diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/config/AggregatorConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/config/AggregatorConfig.java index 3fabb66e1..30733e6cc 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/config/AggregatorConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/config/AggregatorConfig.java @@ -3,11 +3,9 @@ package com.tencent.supersonic.chat.config; import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; - -@Configuration @Data +@Configuration public class AggregatorConfig { - @Value("${metric.aggregator.ratio.enable:true}") private Boolean enableRatio; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/BaseDSLOptimizer.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/BaseSemanticCorrector.java similarity index 86% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/BaseDSLOptimizer.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/corrector/BaseSemanticCorrector.java index 72810d7c6..9b4e80e41 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/BaseDSLOptimizer.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/BaseSemanticCorrector.java @@ -1,6 +1,6 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; +package com.tencent.supersonic.chat.corrector; -import com.tencent.supersonic.chat.api.component.DSLOptimizer; +import com.tencent.supersonic.chat.api.component.SemanticCorrector; import com.tencent.supersonic.chat.api.pojo.SchemaElement; import com.tencent.supersonic.chat.api.pojo.SemanticSchema; import com.tencent.supersonic.common.util.ContextUtils; @@ -13,7 +13,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @Slf4j -public abstract class BaseDSLOptimizer implements DSLOptimizer { +public abstract class BaseSemanticCorrector implements SemanticCorrector { public static final String DATE_FIELD = "数据日期"; protected Map getFieldToBizName(Long modelId) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/DateFieldCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/DateFieldCorrector.java similarity index 52% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/DateFieldCorrector.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/corrector/DateFieldCorrector.java index 14ce36d23..5273579cd 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/DateFieldCorrector.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/DateFieldCorrector.java @@ -1,23 +1,24 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; +package com.tencent.supersonic.chat.corrector; import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; import com.tencent.supersonic.chat.parser.llm.dsl.DSLDateHelper; -import com.tencent.supersonic.common.util.jsqlparser.CCJSqlParserUtils; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserSelectHelper; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; @Slf4j -public class DateFieldCorrector extends BaseDSLOptimizer { +public class DateFieldCorrector extends BaseSemanticCorrector { @Override - public CorrectionInfo rewriter(CorrectionInfo correctionInfo) { + public CorrectionInfo corrector(CorrectionInfo correctionInfo) { String sql = correctionInfo.getSql(); - List whereFields = CCJSqlParserUtils.getWhereFields(sql); - if (CollectionUtils.isEmpty(whereFields) || !whereFields.contains(BaseDSLOptimizer.DATE_FIELD)) { + List whereFields = SqlParserSelectHelper.getWhereFields(sql); + if (CollectionUtils.isEmpty(whereFields) || !whereFields.contains(DATE_FIELD)) { String currentDate = DSLDateHelper.getCurrentDate(correctionInfo.getParseInfo().getModelId()); - sql = CCJSqlParserUtils.addWhere(sql, BaseDSLOptimizer.DATE_FIELD, currentDate); + sql = SqlParserUpdateHelper.addWhere(sql, DATE_FIELD, currentDate); } correctionInfo.setSql(sql); return correctionInfo; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldCorrector.java new file mode 100644 index 000000000..648f78564 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldCorrector.java @@ -0,0 +1,17 @@ +package com.tencent.supersonic.chat.corrector; + +import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FieldCorrector extends BaseSemanticCorrector { + + @Override + public CorrectionInfo corrector(CorrectionInfo correctionInfo) { + String replaceFields = SqlParserUpdateHelper.replaceFields(correctionInfo.getSql(), + getFieldToBizName(correctionInfo.getParseInfo().getModelId())); + correctionInfo.setSql(replaceFields); + return correctionInfo; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldValueCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldValueCorrector.java new file mode 100644 index 000000000..f450cffb5 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FieldValueCorrector.java @@ -0,0 +1,48 @@ +package com.tencent.supersonic.chat.corrector; + +import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; +import com.tencent.supersonic.chat.parser.llm.dsl.DSLParseResult; +import com.tencent.supersonic.chat.query.llm.dsl.LLMReq; +import com.tencent.supersonic.chat.query.llm.dsl.LLMReq.ElementValue; +import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; +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 FieldValueCorrector extends BaseSemanticCorrector { + + @Override + public CorrectionInfo corrector(CorrectionInfo correctionInfo) { + + Object context = correctionInfo.getParseInfo().getProperties().get(Constants.CONTEXT); + if (Objects.isNull(context)) { + return correctionInfo; + } + + DSLParseResult dslParseResult = JsonUtil.toObject(JsonUtil.toString(context), DSLParseResult.class); + if (Objects.isNull(dslParseResult) || Objects.isNull(dslParseResult.getLlmReq())) { + return correctionInfo; + } + LLMReq llmReq = dslParseResult.getLlmReq(); + List linking = llmReq.getLinking(); + if (CollectionUtils.isEmpty(linking)) { + return correctionInfo; + } + + Map> fieldValueToFieldNames = linking.stream().collect( + Collectors.groupingBy(ElementValue::getFieldValue, + Collectors.mapping(ElementValue::getFieldName, Collectors.toSet()))); + + String sql = SqlParserUpdateHelper.replaceValueFields(correctionInfo.getSql(), fieldValueToFieldNames); + correctionInfo.setSql(sql); + return correctionInfo; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FunctionCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FunctionCorrector.java new file mode 100644 index 000000000..13cffe5c2 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/FunctionCorrector.java @@ -0,0 +1,16 @@ +package com.tencent.supersonic.chat.corrector; + +import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FunctionCorrector extends BaseSemanticCorrector { + + @Override + public CorrectionInfo corrector(CorrectionInfo correctionInfo) { + String replaceFunction = SqlParserUpdateHelper.replaceFunction(correctionInfo.getSql()); + correctionInfo.setSql(replaceFunction); + return correctionInfo; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/QueryFilterAppend.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/QueryFilterAppend.java similarity index 83% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/QueryFilterAppend.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/corrector/QueryFilterAppend.java index 6e6806b47..b7d843fb7 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/QueryFilterAppend.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/QueryFilterAppend.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; +package com.tencent.supersonic.chat.corrector; import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; import com.tencent.supersonic.common.pojo.Constants; import com.tencent.supersonic.common.util.StringUtil; -import com.tencent.supersonic.common.util.jsqlparser.CCJSqlParserUtils; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; import java.util.Objects; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -15,17 +15,17 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @Slf4j -public class QueryFilterAppend extends BaseDSLOptimizer { +public class QueryFilterAppend extends BaseSemanticCorrector { @Override - public CorrectionInfo rewriter(CorrectionInfo correctionInfo) throws JSQLParserException { + public CorrectionInfo corrector(CorrectionInfo correctionInfo) throws JSQLParserException { String queryFilter = getQueryFilter(correctionInfo.getQueryFilters()); String sql = correctionInfo.getSql(); if (StringUtils.isNotEmpty(queryFilter)) { log.info("add queryFilter to sql :{}", queryFilter); Expression expression = CCJSqlParserUtil.parseCondExpression(queryFilter); - sql = CCJSqlParserUtils.addWhere(sql, expression); + sql = SqlParserUpdateHelper.addWhere(sql, expression); } correctionInfo.setSql(sql); return correctionInfo; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/SelectFieldAppendCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/SelectFieldAppendCorrector.java similarity index 52% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/SelectFieldAppendCorrector.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/corrector/SelectFieldAppendCorrector.java index 33e1e96c9..6098ab4aa 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/SelectFieldAppendCorrector.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/SelectFieldAppendCorrector.java @@ -1,7 +1,8 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; +package com.tencent.supersonic.chat.corrector; import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; -import com.tencent.supersonic.common.util.jsqlparser.CCJSqlParserUtils; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserSelectHelper; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; import java.util.ArrayList; import java.util.HashSet; @@ -10,25 +11,28 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; @Slf4j -public class SelectFieldAppendCorrector extends BaseDSLOptimizer { +public class SelectFieldAppendCorrector extends BaseSemanticCorrector { @Override - public CorrectionInfo rewriter(CorrectionInfo correctionInfo) { + public CorrectionInfo corrector(CorrectionInfo correctionInfo) { String sql = correctionInfo.getSql(); - if (CCJSqlParserUtils.hasAggregateFunction(sql)) { + if (SqlParserSelectHelper.hasAggregateFunction(sql)) { return correctionInfo; } - Set selectFields = new HashSet<>(CCJSqlParserUtils.getSelectFields(sql)); - Set whereFields = new HashSet<>(CCJSqlParserUtils.getWhereFields(sql)); + Set selectFields = new HashSet<>(SqlParserSelectHelper.getSelectFields(sql)); + Set whereFields = new HashSet<>(SqlParserSelectHelper.getWhereFields(sql)); + if (CollectionUtils.isEmpty(selectFields) || CollectionUtils.isEmpty(whereFields)) { return correctionInfo; } + whereFields.addAll(SqlParserSelectHelper.getOrderByFields(sql)); whereFields.removeAll(selectFields); whereFields.remove(TimeDimensionEnum.DAY.getName()); whereFields.remove(TimeDimensionEnum.WEEK.getName()); whereFields.remove(TimeDimensionEnum.MONTH.getName()); - String replaceFields = CCJSqlParserUtils.addFieldsToSelect(sql, new ArrayList<>(whereFields)); + + String replaceFields = SqlParserUpdateHelper.addFieldsToSelect(sql, new ArrayList<>(whereFields)); correctionInfo.setSql(replaceFields); return correctionInfo; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/TableNameCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/TableNameCorrector.java similarity index 51% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/TableNameCorrector.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/corrector/TableNameCorrector.java index 1604e4b9c..8d5b907c5 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/TableNameCorrector.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/corrector/TableNameCorrector.java @@ -1,19 +1,19 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; +package com.tencent.supersonic.chat.corrector; import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; -import com.tencent.supersonic.common.util.jsqlparser.CCJSqlParserUtils; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; import lombok.extern.slf4j.Slf4j; @Slf4j -public class TableNameCorrector extends BaseDSLOptimizer { +public class TableNameCorrector extends BaseSemanticCorrector { public static final String TABLE_PREFIX = "t_"; @Override - public CorrectionInfo rewriter(CorrectionInfo correctionInfo) { + public CorrectionInfo corrector(CorrectionInfo correctionInfo) { Long modelId = correctionInfo.getParseInfo().getModelId(); String sqlOutput = correctionInfo.getSql(); - String replaceTable = CCJSqlParserUtils.replaceTable(sqlOutput, TABLE_PREFIX + modelId); + String replaceTable = SqlParserUpdateHelper.replaceTable(sqlOutput, TABLE_PREFIX + modelId); correctionInfo.setSql(replaceTable); return correctionInfo; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/EntityMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/EntityMapper.java index 388b76212..f5c60bb1d 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/EntityMapper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/EntityMapper.java @@ -2,19 +2,19 @@ package com.tencent.supersonic.chat.mapper; import com.tencent.supersonic.chat.api.component.SchemaMapper; -import com.tencent.supersonic.chat.api.pojo.ModelSchema; 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.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.ModelSchema; import com.tencent.supersonic.chat.service.SemanticService; import com.tencent.supersonic.common.util.ContextUtils; -import java.util.List; -import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.util.CollectionUtils; +import java.util.List; +import java.util.stream.Collectors; @Slf4j @@ -33,7 +33,7 @@ public class EntityMapper implements SchemaMapper { continue; } List valueSchemaElements = schemaElementMatchList.stream().filter(schemaElementMatch -> - SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())) + SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())) .collect(Collectors.toList()); for (SchemaElementMatch schemaElementMatch : valueSchemaElements) { if (!entity.getId().equals(schemaElementMatch.getElement().getId())) { @@ -51,7 +51,7 @@ public class EntityMapper implements SchemaMapper { } private boolean checkExistSameEntitySchemaElements(SchemaElementMatch valueSchemaElementMatch, - List schemaElementMatchList) { + List schemaElementMatchList) { List entitySchemaElements = schemaElementMatchList.stream().filter(schemaElementMatch -> SchemaElementType.ENTITY.equals(schemaElementMatch.getElement().getType())) .collect(Collectors.toList()); 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 index 0dc646005..c3b5af4d9 100644 --- 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 @@ -2,12 +2,12 @@ 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.SchemaElement; -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.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SemanticSchema; +import com.tencent.supersonic.chat.api.pojo.QueryContext; import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.knowledge.service.SchemaService; import com.tencent.supersonic.knowledge.utils.HanlpHelper; @@ -43,13 +43,13 @@ public class FuzzyNameMapper implements SchemaMapper { log.debug("after db mapper,mapInfo:{}", queryContext.getMapInfo()); } - private void detectAndAddToSchema(QueryContext queryContext, List terms, List Models, + private void detectAndAddToSchema(QueryContext queryContext, List terms, List models, SchemaElementType schemaElementType) { try { - Map> ModelResultSet = getResultSet(queryContext, terms, Models); + Map> modelResultSet = getResultSet(queryContext, terms, models); - addToSchemaMapInfo(ModelResultSet, queryContext.getMapInfo(), schemaElementType); + addToSchemaMapInfo(modelResultSet, queryContext.getMapInfo(), schemaElementType); } catch (Exception e) { log.error("detectAndAddToSchema error", e); @@ -57,20 +57,21 @@ public class FuzzyNameMapper implements SchemaMapper { } private Map> getResultSet(QueryContext queryContext, List terms, - List Models) { + List models) { String queryText = queryContext.getRequest().getQueryText(); MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); + Set modelIds = mapperHelper.getModelIds(queryContext.getRequest()); Double metricDimensionThresholdConfig = getThreshold(queryContext, mapperHelper); - Map> nameToItems = getNameToItems(Models); + Map> nameToItems = getNameToItems(models); Map regOffsetToLength = terms.stream().sorted(Comparator.comparing(Term::length)) .collect(Collectors.toMap(Term::getOffset, term -> term.word.length(), (value1, value2) -> value2)); - Map> ModelResultSet = new HashMap<>(); + Map> modelResultSet = new HashMap<>(); for (Integer startIndex = 0; startIndex <= queryText.length() - 1; ) { for (Integer endIndex = startIndex; endIndex <= queryText.length(); ) { endIndex = mapperHelper.getStepIndex(regOffsetToLength, endIndex); @@ -86,8 +87,12 @@ public class FuzzyNameMapper implements SchemaMapper { || mapperHelper.getSimilarity(detectSegment, name) < metricDimensionThresholdConfig) { continue; } - Set preSchemaElements = ModelResultSet.putIfAbsent(detectSegment, - schemaElements); + if (!CollectionUtils.isEmpty(modelIds)) { + schemaElements = schemaElements.stream() + .filter(schemaElement -> modelIds.contains(schemaElement.getModel())) + .collect(Collectors.toSet()); + } + Set preSchemaElements = modelResultSet.putIfAbsent(detectSegment, schemaElements); if (Objects.nonNull(preSchemaElements)) { preSchemaElements.addAll(schemaElements); } @@ -95,7 +100,7 @@ public class FuzzyNameMapper implements SchemaMapper { } startIndex = mapperHelper.getStepIndex(regOffsetToLength, startIndex); } - return ModelResultSet; + return modelResultSet; } private Double getThreshold(QueryContext queryContext, MapperHelper mapperHelper) { @@ -103,9 +108,9 @@ public class FuzzyNameMapper implements SchemaMapper { Double metricDimensionThresholdConfig = mapperHelper.getMetricDimensionThresholdConfig(); Double metricDimensionMinThresholdConfig = mapperHelper.getMetricDimensionMinThresholdConfig(); - Map> ModelElementMatches = queryContext.getMapInfo() + Map> modelElementMatches = queryContext.getMapInfo() .getModelElementMatches(); - boolean existElement = ModelElementMatches.entrySet().stream() + boolean existElement = modelElementMatches.entrySet().stream() .anyMatch(entry -> entry.getValue().size() >= 1); if (!existElement) { @@ -114,13 +119,13 @@ public class FuzzyNameMapper implements SchemaMapper { metricDimensionThresholdConfig = halfThreshold >= metricDimensionMinThresholdConfig ? halfThreshold : metricDimensionMinThresholdConfig; log.info("ModelElementMatches:{} , not exist Element metricDimensionThresholdConfig reduce by half:{}", - ModelElementMatches, metricDimensionThresholdConfig); + modelElementMatches, metricDimensionThresholdConfig); } return metricDimensionThresholdConfig; } - private Map> getNameToItems(List Models) { - return Models.stream().collect( + private Map> getNameToItems(List models) { + return models.stream().collect( Collectors.toMap(SchemaElement::getName, a -> { Set result = new HashSet<>(); result.add(a); 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 index 063822984..e8dda8f42 100644 --- 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 @@ -9,7 +9,7 @@ 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.service.SemanticService; -import com.tencent.supersonic.chat.utils.NatureHelper; +import com.tencent.supersonic.knowledge.utils.NatureHelper; import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.knowledge.dictionary.DictWordType; import com.tencent.supersonic.knowledge.dictionary.MapResult; @@ -21,6 +21,7 @@ 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.collections.CollectionUtils; @@ -37,10 +38,13 @@ public class HanlpDictMapper implements SchemaMapper { for (Term term : terms) { log.info("word:{},nature:{},frequency:{}", term.word, term.nature.toString(), term.getFrequency()); } - Long modelId = queryContext.getRequest().getModelId(); QueryMatchStrategy matchStrategy = ContextUtils.getBean(QueryMatchStrategy.class); - Map> matchResult = matchStrategy.match(queryText, terms, modelId); + MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); + Set detectModelIds = mapperHelper.getModelIds(queryContext.getRequest()); + + Map> matchResult = matchStrategy.match(queryContext.getRequest(), terms, + detectModelIds); List matches = getMatches(matchResult); @@ -51,6 +55,7 @@ public class HanlpDictMapper implements SchemaMapper { convertTermsToSchemaMapInfo(matches, queryContext.getMapInfo(), terms); } + private void convertTermsToSchemaMapInfo(List mapResults, SchemaMapInfo schemaMap, List terms) { if (CollectionUtils.isEmpty(mapResults)) { return; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MapperHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MapperHelper.java index 2366f1cc7..81c19c0cc 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MapperHelper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MapperHelper.java @@ -1,10 +1,16 @@ package com.tencent.supersonic.chat.mapper; import com.hankcs.hanlp.algorithm.EditDistance; -import com.tencent.supersonic.chat.utils.NatureHelper; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.service.AgentService; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.knowledge.utils.NatureHelper; +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.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -84,5 +90,24 @@ public class MapperHelper { detectSegment.length()); } + public Set getModelIds(QueryReq request) { + + Long modelId = request.getModelId(); + + AgentService agentService = ContextUtils.getBean(AgentService.class); + + Set detectModelIds = agentService.getDslToolsModelIds(request.getAgentId(), null); + if (Objects.nonNull(detectModelIds)) { + detectModelIds = detectModelIds.stream().filter(entry -> entry > 0).collect(Collectors.toSet()); + } + if (Objects.nonNull(modelId) && modelId > 0 && Objects.nonNull(detectModelIds)) { + if (detectModelIds.contains(modelId)) { + Set result = new HashSet<>(); + result.add(modelId); + return result; + } + } + return detectModelIds; + } } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchStrategy.java index 1a25a6475..481e9c128 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/MatchStrategy.java @@ -1,15 +1,17 @@ package com.tencent.supersonic.chat.mapper; import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.knowledge.dictionary.MapResult; import java.util.List; import java.util.Map; +import java.util.Set; /** * match strategy */ public interface MatchStrategy { - Map> match(String text, List terms, Long detectModelId); + Map> match(QueryReq queryReq, List terms, Set detectModelId); } \ No newline at end of file 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 index cd9e7dd31..a6adf47ae 100644 --- 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 @@ -3,25 +3,25 @@ package com.tencent.supersonic.chat.mapper; import com.google.common.collect.Lists; import com.tencent.supersonic.chat.api.component.SchemaMapper; 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.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +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.QueryFilters; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.common.pojo.Constants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.CollectionUtils; @Slf4j public class QueryFilterMapper implements SchemaMapper { - private Long FREQUENCY = 9999999L; - private double SIMILARITY = 1.0; + private Long frequency = 9999999L; + private double similarity = 1.0; @Override public void map(QueryContext queryContext) { @@ -49,7 +49,7 @@ public class QueryFilterMapper implements SchemaMapper { } private List addValueSchemaElementMatch(List candidateElementMatches, - QueryFilters queryFilter) { + QueryFilters queryFilter) { if (queryFilter == null || CollectionUtils.isEmpty(queryFilter.getFilters())) { return candidateElementMatches; } @@ -65,9 +65,9 @@ public class QueryFilterMapper implements SchemaMapper { .build(); SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() .element(element) - .frequency(FREQUENCY) + .frequency(frequency) .word(String.valueOf(filter.getValue())) - .similarity(SIMILARITY) + .similarity(similarity) .detectWord(Constants.EMPTY) .build(); candidateElementMatches.add(schemaElementMatch); @@ -76,7 +76,7 @@ public class QueryFilterMapper implements SchemaMapper { } private boolean checkExistSameValueSchemaElementMatch(QueryFilter queryFilter, - List schemaElementMatches) { + List schemaElementMatches) { List valueSchemaElements = schemaElementMatches.stream().filter(schemaElementMatch -> SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())) .collect(Collectors.toList()); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryMatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryMatchStrategy.java index f3507cc36..f449f8233 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryMatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/QueryMatchStrategy.java @@ -1,8 +1,8 @@ package com.tencent.supersonic.chat.mapper; import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.common.pojo.Constants; -import com.tencent.supersonic.knowledge.dictionary.DictWordType; import com.tencent.supersonic.knowledge.dictionary.MapResult; import com.tencent.supersonic.knowledge.service.SearchService; import java.util.ArrayList; @@ -32,7 +32,8 @@ public class QueryMatchStrategy implements MatchStrategy { private MapperHelper mapperHelper; @Override - public Map> match(String text, List terms, Long detectModelId) { + public Map> match(QueryReq queryReq, List terms, Set detectModelIds) { + String text = queryReq.getQueryText(); if (Objects.isNull(terms) || StringUtils.isEmpty(text)) { return null; } @@ -43,18 +44,19 @@ public class QueryMatchStrategy implements MatchStrategy { List offsetList = terms.stream().sorted(Comparator.comparing(Term::getOffset)) .map(term -> term.getOffset()).collect(Collectors.toList()); - log.debug("retryCount:{},terms:{},regOffsetToLength:{},offsetList:{},detectModelId:{}", terms, - regOffsetToLength, offsetList, detectModelId); + log.debug("retryCount:{},terms:{},regOffsetToLength:{},offsetList:{},detectModelIds:{}", terms, + regOffsetToLength, offsetList, detectModelIds); - List detects = detect(text, regOffsetToLength, offsetList, detectModelId); + List detects = detect(queryReq, regOffsetToLength, offsetList, detectModelIds); Map> result = new HashMap<>(); result.put(MatchText.builder().regText(text).detectSegment(text).build(), detects); return result; } - private List detect(String text, Map regOffsetToLength, List offsetList, - Long detectModelId) { + private List detect(QueryReq queryReq, Map regOffsetToLength, List offsetList, + Set detectModelIds) { + String text = queryReq.getQueryText(); List results = Lists.newArrayList(); for (Integer index = 0; index <= text.length() - 1; ) { @@ -65,7 +67,7 @@ public class QueryMatchStrategy implements MatchStrategy { int offset = mapperHelper.getStepOffset(offsetList, index); i = mapperHelper.getStepIndex(regOffsetToLength, i); if (i <= text.length()) { - List mapResults = detectByStep(text, detectModelId, index, i, offset); + List mapResults = detectByStep(queryReq, detectModelIds, index, i, offset); selectMapResultInOneRound(mapResultRowSet, mapResults); } } @@ -102,16 +104,19 @@ public class QueryMatchStrategy implements MatchStrategy { return a.getName() + Constants.UNDERLINE + String.join(Constants.UNDERLINE, a.getNatures()); } - private List detectByStep(String text, Long detectModelId, Integer index, Integer i, int offset) { + private List detectByStep(QueryReq queryReq, Set detectModelIds, Integer index, Integer i, + int offset) { + String text = queryReq.getQueryText(); + Integer agentId = queryReq.getAgentId(); String detectSegment = text.substring(index, i); // step1. pre search Integer oneDetectionMaxSize = mapperHelper.getOneDetectionMaxSize(); - LinkedHashSet mapResults = SearchService.prefixSearch(detectSegment, oneDetectionMaxSize) - .stream().collect(Collectors.toCollection(LinkedHashSet::new)); + LinkedHashSet mapResults = SearchService.prefixSearch(detectSegment, oneDetectionMaxSize, agentId, + detectModelIds).stream().collect(Collectors.toCollection(LinkedHashSet::new)); // step2. suffix search - LinkedHashSet suffixMapResults = SearchService.suffixSearch(detectSegment, oneDetectionMaxSize) - .stream().collect(Collectors.toCollection(LinkedHashSet::new)); + LinkedHashSet suffixMapResults = SearchService.suffixSearch(detectSegment, oneDetectionMaxSize, + agentId, detectModelIds).stream().collect(Collectors.toCollection(LinkedHashSet::new)); mapResults.addAll(suffixMapResults); @@ -121,27 +126,15 @@ public class QueryMatchStrategy implements MatchStrategy { // step3. merge pre/suffix result mapResults = mapResults.stream().sorted((a, b) -> -(b.getName().length() - a.getName().length())) .collect(Collectors.toCollection(LinkedHashSet::new)); - // step4. filter by classId - if (Objects.nonNull(detectModelId) && detectModelId > 0) { - log.debug("detectModelId:{}, before parseResults:{}", mapResults); - mapResults = mapResults.stream().map(entry -> { - List natures = entry.getNatures().stream().filter( - nature -> nature.startsWith(DictWordType.NATURE_SPILT + detectModelId) || (nature.startsWith( - DictWordType.NATURE_SPILT)) - ).collect(Collectors.toList()); - entry.setNatures(natures); - return entry; - }).collect(Collectors.toCollection(LinkedHashSet::new)); - log.info("after modelId parseResults:{}", mapResults); - } - // step5. filter by similarity + + // step4. filter by similarity mapResults = mapResults.stream() .filter(term -> mapperHelper.getSimilarity(detectSegment, term.getName()) >= mapperHelper.getThresholdMatch(term.getNatures())) .filter(term -> CollectionUtils.isNotEmpty(term.getNatures())) .collect(Collectors.toCollection(LinkedHashSet::new)); - log.debug("after isSimilarity parseResults:{}", mapResults); + log.info("after isSimilarity parseResults:{}", mapResults); mapResults = mapResults.stream().map(parseResult -> { parseResult.setOffset(offset); @@ -149,7 +142,7 @@ public class QueryMatchStrategy implements MatchStrategy { return parseResult; }).collect(Collectors.toCollection(LinkedHashSet::new)); - // step6. take only one dimension or 10 metric/dimension value per rond. + // step5. take only one dimension or 10 metric/dimension value per rond. List dimensionMetrics = mapResults.stream() .filter(entry -> mapperHelper.existDimensionValues(entry.getNatures())) .collect(Collectors.toList()) diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/SearchMatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/SearchMatchStrategy.java index bf3eb9be9..a3299a22b 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/SearchMatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/SearchMatchStrategy.java @@ -2,12 +2,14 @@ package com.tencent.supersonic.chat.mapper; import com.google.common.collect.Lists; import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.knowledge.dictionary.DictWordType; import com.tencent.supersonic.knowledge.dictionary.MapResult; import com.tencent.supersonic.knowledge.service.SearchService; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; @@ -23,9 +25,8 @@ public class SearchMatchStrategy implements MatchStrategy { private static final int SEARCH_SIZE = 3; @Override - public Map> match(String text, List originals, - Long detectModelId) { - + public Map> match(QueryReq queryReq, List originals, Set detectModelIds) { + String text = queryReq.getQueryText(); Map regOffsetToLength = originals.stream() .filter(entry -> !entry.nature.toString().startsWith(DictWordType.NATURE_SPILT)) .collect(Collectors.toMap(Term::getOffset, value -> value.word.length(), @@ -51,24 +52,16 @@ public class SearchMatchStrategy implements MatchStrategy { String detectSegment = text.substring(detectIndex); if (StringUtils.isNotEmpty(detectSegment)) { - List mapResults = SearchService.prefixSearch(detectSegment); - List suffixMapResults = SearchService.suffixSearch(detectSegment, SEARCH_SIZE); + List mapResults = SearchService.prefixSearch(detectSegment, + SearchService.SEARCH_SIZE, queryReq.getAgentId(), detectModelIds); + List suffixMapResults = SearchService.suffixSearch(detectSegment, SEARCH_SIZE, + queryReq.getAgentId(), detectModelIds); mapResults.addAll(suffixMapResults); // remove entity name where search mapResults = mapResults.stream().filter(entry -> { List natures = entry.getNatures().stream() .filter(nature -> !nature.endsWith(DictWordType.ENTITY.getType())) - .filter(nature -> { - if (Objects.isNull(detectModelId) || detectModelId <= 0) { - return true; - } - if (nature.startsWith(DictWordType.NATURE_SPILT + detectModelId) - && nature.startsWith(DictWordType.NATURE_SPILT)) { - return true; - } - return false; - } - ).collect(Collectors.toList()); + .collect(Collectors.toList()); if (CollectionUtils.isEmpty(natures)) { return false; } @@ -84,4 +77,4 @@ public class SearchMatchStrategy implements MatchStrategy { ); return regTextMap; } -} \ 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 index e678714ee..ac6eaab93 100644 --- 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 @@ -2,8 +2,9 @@ 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.chat.query.dsl.DSLQuery; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.query.llm.dsl.DslQuery; import lombok.extern.slf4j.Slf4j; /** @@ -21,7 +22,7 @@ public class SatisfactionChecker { // check all the parse info in candidate public static boolean check(QueryContext queryContext) { for (SemanticQuery query : queryContext.getCandidateQueries()) { - if (query.getQueryMode().equals(DSLQuery.QUERY_MODE)) { + if (query.getQueryMode().equals(DslQuery.QUERY_MODE)) { continue; } if (checkThreshold(queryContext.getRequest().getQueryText(), query.getParseInfo())) { @@ -32,7 +33,7 @@ public class SatisfactionChecker { } private static boolean checkThreshold(String queryText, SemanticParseInfo semanticParseInfo) { - int queryTextLength = queryText.length(); + int queryTextLength = queryText.replaceAll(" ", "").length(); double degree = semanticParseInfo.getScore() / queryTextLength; if (queryTextLength > QUERY_TEXT_LENGTH_THRESHOLD) { if (degree < LONG_TEXT_THRESHOLD) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLDateHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLDateHelper.java index 46dac8beb..55a4026c9 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLDateHelper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLDateHelper.java @@ -6,15 +6,6 @@ public class DSLDateHelper { public static String getCurrentDate(Long modelId) { return DateUtils.getBeforeDate(4); -// ChatConfigFilter filter = new ChatConfigFilter(); -// filter.setModelId(modelId); -// -// List configResps = ContextUtils.getBean(ConfigService.class).search(filter, null); -// if (CollectionUtils.isEmpty(configResps)) { -// return -// } -// ChatConfigResp chatConfigResp = configResps.get(0); -// chatConfigResp.getChatDetailConfig().getChatDefaultConfig().get } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLParseResult.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLParseResult.java index 6a9590ff2..ab73f04f8 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLParseResult.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/DSLParseResult.java @@ -2,13 +2,21 @@ package com.tencent.supersonic.chat.parser.llm.dsl; import com.tencent.supersonic.chat.agent.tool.DslTool; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; -import com.tencent.supersonic.chat.plugin.PluginParseResult; -import com.tencent.supersonic.chat.query.dsl.LLMResp; +import com.tencent.supersonic.chat.query.llm.dsl.LLMReq; +import com.tencent.supersonic.chat.query.llm.dsl.LLMResp; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@Builder +@AllArgsConstructor +@NoArgsConstructor public class DSLParseResult { + private LLMReq llmReq; + private LLMResp llmResp; private QueryReq request; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDSLParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDSLParser.java index d89e2b551..6e92200bd 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDSLParser.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDSLParser.java @@ -1,42 +1,51 @@ package com.tencent.supersonic.chat.parser.llm.dsl; -import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; -import com.tencent.supersonic.chat.agent.Agent; import com.tencent.supersonic.chat.agent.tool.AgentToolType; import com.tencent.supersonic.chat.agent.tool.DslTool; +import com.tencent.supersonic.chat.api.component.SemanticCorrector; import com.tencent.supersonic.chat.api.component.SemanticParser; import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; 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.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.QueryFilter; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.config.LLMConfig; +import com.tencent.supersonic.chat.corrector.BaseSemanticCorrector; import com.tencent.supersonic.chat.parser.SatisfactionChecker; -import com.tencent.supersonic.chat.parser.function.ModelResolver; +import com.tencent.supersonic.chat.parser.plugin.function.ModelResolver; import com.tencent.supersonic.chat.query.QueryManager; -import com.tencent.supersonic.chat.query.dsl.DSLQuery; -import com.tencent.supersonic.chat.query.dsl.LLMReq; -import com.tencent.supersonic.chat.query.dsl.LLMReq.ElementValue; -import com.tencent.supersonic.chat.query.dsl.LLMResp; -import com.tencent.supersonic.chat.query.dsl.optimizer.BaseDSLOptimizer; +import com.tencent.supersonic.chat.query.llm.dsl.DslQuery; +import com.tencent.supersonic.chat.query.llm.dsl.LLMReq; +import com.tencent.supersonic.chat.query.llm.dsl.LLMReq.ElementValue; +import com.tencent.supersonic.chat.query.llm.dsl.LLMResp; import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; import com.tencent.supersonic.chat.service.AgentService; import com.tencent.supersonic.chat.utils.ComponentFactory; import com.tencent.supersonic.common.pojo.Constants; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.pojo.DateConf.DateMode; import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.common.util.jsqlparser.FilterExpression; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserSelectHelper; import com.tencent.supersonic.knowledge.service.SchemaService; +import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import java.util.ArrayList; -import java.util.Collection; +import java.util.Arrays; 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.function.Function; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -49,104 +58,217 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; @Slf4j -public class LLMDSLParser implements SemanticParser { +public class LLMDslParser implements SemanticParser { - public static final double FUNCTION_BONUS_THRESHOLD = 201; + public static final double function_bonus_threshold = 201; @Override public void parse(QueryContext queryCtx, ChatContext chatCtx) { - final LLMConfig llmConfig = ContextUtils.getBean(LLMConfig.class); + QueryReq request = queryCtx.getRequest(); + LLMConfig llmConfig = ContextUtils.getBean(LLMConfig.class); if (StringUtils.isEmpty(llmConfig.getUrl()) || SatisfactionChecker.check(queryCtx)) { - log.info("llmConfig:{}, skip function parser, queryText:{}", llmConfig, - queryCtx.getRequest().getQueryText()); + log.info("llmConfig:{}, skip function parser, queryText:{}", llmConfig, request.getQueryText()); return; } - - List dslTools = getDslTools(queryCtx.getRequest().getAgentId()); - Set distinctModelIds = dslTools.stream().map(DslTool::getModelIds) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); try { - ModelResolver modelResolver = ComponentFactory.getModelResolver(); - Long modelId = modelResolver.resolve(queryCtx, chatCtx, distinctModelIds); - log.info("resolve modelId:{},dslModels:{}", modelId, distinctModelIds); - + Long modelId = getModelId(queryCtx, chatCtx, request.getAgentId()); if (Objects.isNull(modelId) || modelId <= 0) { return; } - Optional dslToolOptional = dslTools.stream().filter(tool -> - tool.getModelIds().contains(modelId)).findFirst(); - if (!dslToolOptional.isPresent()) { + + DslTool dslTool = getDslTool(request, modelId); + if (Objects.isNull(dslTool)) { log.info("no dsl tool in this agent, skip dsl parser"); return; } - DslTool dslTool = dslToolOptional.get(); - LLMResp llmResp = requestLLM(queryCtx, modelId); + + LLMReq llmReq = getLlmReq(queryCtx, modelId); + LLMResp llmResp = requestLLM(llmReq, modelId, llmConfig); + if (Objects.isNull(llmResp)) { return; } - PluginSemanticQuery semanticQuery = QueryManager.createPluginQuery(DSLQuery.QUERY_MODE); + DSLParseResult dslParseResult = DSLParseResult.builder().request(request).dslTool(dslTool).llmReq(llmReq) + .llmResp(llmResp).build(); - SemanticParseInfo parseInfo = semanticQuery.getParseInfo(); - if (Objects.nonNull(modelId) && modelId > 0) { - parseInfo.getElementMatches().addAll(queryCtx.getMapInfo().getMatchedElements(modelId)); - } - DSLParseResult dslParseResult = new DSLParseResult(); - dslParseResult.setRequest(queryCtx.getRequest()); - dslParseResult.setLlmResp(llmResp); - dslParseResult.setDslTool(dslToolOptional.get()); + SemanticParseInfo parseInfo = getParseInfo(queryCtx, modelId, dslTool, dslParseResult); + + String correctorSql = getCorrectorSql(queryCtx, parseInfo, llmResp.getSqlOutput()); + + llmResp.setCorrectorSql(correctorSql); + + setFilter(correctorSql, modelId, parseInfo); - Map properties = new HashMap<>(); - properties.put(Constants.CONTEXT, dslParseResult); - properties.put("type", "internal"); - properties.put("name", dslTool.getName()); - parseInfo.setProperties(properties); - parseInfo.setScore(FUNCTION_BONUS_THRESHOLD); - parseInfo.setQueryMode(semanticQuery.getQueryMode()); - SchemaElement Model = new SchemaElement(); - Model.setModel(modelId); - Model.setId(modelId); - parseInfo.setModel(Model); - queryCtx.getCandidateQueries().add(semanticQuery); } catch (Exception e) { log.error("LLMDSLParser error", e); } } + public void setFilter(String correctorSql, Long modelId, SemanticParseInfo parseInfo) { - private LLMResp requestLLM(QueryContext queryCtx, Long modelId) { - long startTime = System.currentTimeMillis(); - String queryText = queryCtx.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; + List expressions = SqlParserSelectHelper.getFilterExpression(correctorSql); + if (CollectionUtils.isEmpty(expressions)) { + return; } + //set dataInfo + try { + DateConf dateInfo = getDateInfo(expressions); + parseInfo.setDateInfo(dateInfo); + } catch (Exception e) { + log.error("set dateInfo error :", e); + } + + //set filter + try { + Map bizNameToElement = getBizNameToElement(modelId); + List result = getDimensionFilter(bizNameToElement, expressions); + parseInfo.getDimensionFilters().addAll(result); + } catch (Exception e) { + log.error("set dimensionFilter error :", e); + } + } + + private List getDimensionFilter(Map bizNameToElement, + List filterExpressions) { + List result = Lists.newArrayList(); + for (FilterExpression expression : filterExpressions) { + QueryFilter dimensionFilter = new QueryFilter(); + dimensionFilter.setValue(expression.getFieldValue()); + String bizName = expression.getFieldName(); + SchemaElement schemaElement = bizNameToElement.get(bizName); + if (Objects.isNull(schemaElement)) { + continue; + } + String fieldName = schemaElement.getName(); + dimensionFilter.setName(fieldName); + dimensionFilter.setBizName(bizName); + dimensionFilter.setElementID(schemaElement.getId()); + + FilterOperatorEnum operatorEnum = FilterOperatorEnum.getSqlOperator(expression.getOperator()); + dimensionFilter.setOperator(operatorEnum); + result.add(dimensionFilter); + } + return result; + } + + private DateConf getDateInfo(List filterExpressions) { + List dateExpressions = filterExpressions.stream() + .filter(expression -> { + List nameList = TimeDimensionEnum.getNameList(); + if (StringUtils.isEmpty(expression.getFieldName())) { + return false; + } + return nameList.contains(expression.getFieldName().toLowerCase()); + }).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(dateExpressions)) { + return new DateConf(); + } + DateConf dateInfo = new DateConf(); + dateInfo.setDateMode(DateMode.BETWEEN); + FilterExpression firstExpression = dateExpressions.get(0); + + FilterOperatorEnum firstOperator = FilterOperatorEnum.getSqlOperator(firstExpression.getOperator()); + if (FilterOperatorEnum.EQUALS.equals(firstOperator) && Objects.nonNull(firstExpression.getFieldValue())) { + dateInfo.setStartDate(firstExpression.getFieldValue().toString()); + dateInfo.setEndDate(firstExpression.getFieldValue().toString()); + dateInfo.setDateMode(DateMode.BETWEEN); + return dateInfo; + } + if (containOperators(firstExpression, firstOperator, FilterOperatorEnum.GREATER_THAN, + FilterOperatorEnum.GREATER_THAN_EQUALS)) { + dateInfo.setStartDate(firstExpression.getFieldValue().toString()); + if (hasSecondDate(dateExpressions)) { + dateInfo.setEndDate(dateExpressions.get(1).getFieldValue().toString()); + } + } + if (containOperators(firstExpression, firstOperator, FilterOperatorEnum.MINOR_THAN, + FilterOperatorEnum.MINOR_THAN_EQUALS)) { + dateInfo.setEndDate(firstExpression.getFieldValue().toString()); + if (hasSecondDate(dateExpressions)) { + dateInfo.setStartDate(dateExpressions.get(1).getFieldValue().toString()); + } + } + return dateInfo; + } + + private boolean containOperators(FilterExpression expression, FilterOperatorEnum firstOperator, + FilterOperatorEnum... operatorEnums) { + return (Arrays.asList(operatorEnums).contains(firstOperator) && Objects.nonNull(expression.getFieldValue())); + } + + private boolean hasSecondDate(List dateExpressions) { + return dateExpressions.size() > 1 && Objects.nonNull(dateExpressions.get(1).getFieldValue()); + } + + private String getCorrectorSql(QueryContext queryCtx, SemanticParseInfo parseInfo, String sql) { + + CorrectionInfo correctionInfo = CorrectionInfo.builder() + .queryFilters(queryCtx.getRequest().getQueryFilters()).sql(sql) + .parseInfo(parseInfo).build(); + + List dslCorrections = ComponentFactory.getSqlCorrections(); + + dslCorrections.forEach(dslCorrection -> { + try { + dslCorrection.corrector(correctionInfo); + log.info("sqlCorrection:{} sql:{}", dslCorrection.getClass().getSimpleName(), + correctionInfo.getSql()); + } catch (Exception e) { + log.error("sqlCorrection:{} execute error,correctionInfo:{}", dslCorrection, correctionInfo, e); + } + }); + return correctionInfo.getSql(); + } + + private SemanticParseInfo getParseInfo(QueryContext queryCtx, Long modelId, DslTool dslTool, + DSLParseResult dslParseResult) { + PluginSemanticQuery semanticQuery = QueryManager.createPluginQuery(DslQuery.QUERY_MODE); + SemanticParseInfo parseInfo = semanticQuery.getParseInfo(); + parseInfo.getElementMatches().addAll(queryCtx.getMapInfo().getMatchedElements(modelId)); + + Map properties = new HashMap<>(); + properties.put(Constants.CONTEXT, dslParseResult); + properties.put("type", "internal"); + properties.put("name", dslTool.getName()); + + parseInfo.setProperties(properties); + parseInfo.setScore(function_bonus_threshold); + parseInfo.setQueryMode(semanticQuery.getQueryMode()); SemanticSchema semanticSchema = ContextUtils.getBean(SchemaService.class).getSemanticSchema(); Map modelIdToName = semanticSchema.getModelIdToName(); - LLMReq llmReq = new LLMReq(); - llmReq.setQueryText(queryText); - LLMReq.LLMSchema llmSchema = new LLMReq.LLMSchema(); - llmSchema.setModelName(modelIdToName.get(modelId)); - llmSchema.setDomainName(modelIdToName.get(modelId)); - List fieldNameList = getFieldNameList(queryCtx, modelId, semanticSchema); - fieldNameList.add(BaseDSLOptimizer.DATE_FIELD); - llmSchema.setFieldNameList(fieldNameList); - llmReq.setSchema(llmSchema); - List linking = new ArrayList<>(); - linking.addAll(getValueList(queryCtx, modelId, semanticSchema)); - llmReq.setLinking(linking); - String currentDate = DSLDateHelper.getCurrentDate(modelId); - llmReq.setCurrentDate(currentDate); + SchemaElement model = new SchemaElement(); + model.setModel(modelId); + model.setId(modelId); + model.setName(modelIdToName.get(modelId)); + parseInfo.setModel(model); + queryCtx.getCandidateQueries().add(semanticQuery); + return parseInfo; + } - log.info("requestLLM request, modelId:{},llmReq:{}", modelId, llmReq); + private DslTool getDslTool(QueryReq request, Long modelId) { + AgentService agentService = ContextUtils.getBean(AgentService.class); + List dslTools = agentService.getDslTools(request.getAgentId(), AgentToolType.DSL); + Optional dslToolOptional = dslTools.stream().filter(tool -> tool.getModelIds().contains(modelId)) + .findFirst(); + return dslToolOptional.orElse(null); + } + + private Long getModelId(QueryContext queryCtx, ChatContext chatCtx, Integer agentId) { + AgentService agentService = ContextUtils.getBean(AgentService.class); + Set distinctModelIds = agentService.getDslToolsModelIds(agentId, AgentToolType.DSL); + ModelResolver modelResolver = ComponentFactory.getModelResolver(); + Long modelId = modelResolver.resolve(queryCtx, chatCtx, distinctModelIds); + log.info("resolve modelId:{},dslModels:{}", modelId, distinctModelIds); + return modelId; + } + + private LLMResp requestLLM(LLMReq llmReq, Long modelId, LLMConfig llmConfig) { String questUrl = llmConfig.getUrl() + llmConfig.getQueryToSqlPath(); - + long startTime = System.currentTimeMillis(); + log.info("requestLLM request, modelId:{},llmReq:{}", modelId, llmReq); RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); - try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -163,6 +285,27 @@ public class LLMDSLParser implements SemanticParser { return null; } + private LLMReq getLlmReq(QueryContext queryCtx, Long modelId) { + SemanticSchema semanticSchema = ContextUtils.getBean(SchemaService.class).getSemanticSchema(); + Map modelIdToName = semanticSchema.getModelIdToName(); + String queryText = queryCtx.getRequest().getQueryText(); + LLMReq llmReq = new LLMReq(); + llmReq.setQueryText(queryText); + LLMReq.LLMSchema llmSchema = new LLMReq.LLMSchema(); + llmSchema.setModelName(modelIdToName.get(modelId)); + llmSchema.setDomainName(modelIdToName.get(modelId)); + List fieldNameList = getFieldNameList(queryCtx, modelId, semanticSchema); + fieldNameList.add(BaseSemanticCorrector.DATE_FIELD); + llmSchema.setFieldNameList(fieldNameList); + llmReq.setSchema(llmSchema); + List linking = new ArrayList<>(); + linking.addAll(getValueList(queryCtx, modelId, semanticSchema)); + llmReq.setLinking(linking); + String currentDate = DSLDateHelper.getCurrentDate(modelId); + llmReq.setCurrentDate(currentDate); + return llmReq; + } + private List getValueList(QueryContext queryCtx, Long modelId, SemanticSchema semanticSchema) { Map itemIdToName = getItemIdToName(modelId, semanticSchema); @@ -170,23 +313,37 @@ public class LLMDSLParser implements SemanticParser { if (CollectionUtils.isEmpty(matchedElements)) { return new ArrayList<>(); } - Set valueMatches = matchedElements.stream() + Set valueMatches = matchedElements + .stream() + .filter(elementMatch -> !elementMatch.isInherited()) .filter(schemaElementMatch -> { SchemaElementType type = schemaElementMatch.getElement().getType(); return SchemaElementType.VALUE.equals(type) || SchemaElementType.ID.equals(type); }) - .map(elementMatch -> - { - ElementValue elementValue = new ElementValue(); - elementValue.setFieldName(itemIdToName.get(elementMatch.getElement().getId())); - elementValue.setFieldValue(elementMatch.getWord()); - return elementValue; - } - ) - .collect(Collectors.toSet()); + .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); } + + protected Map getBizNameToElement(Long modelId) { + SemanticSchema semanticSchema = ContextUtils.getBean(SchemaService.class).getSemanticSchema(); + List dimensions = semanticSchema.getDimensions(); + List metrics = semanticSchema.getMetrics(); + + List allElements = Lists.newArrayList(); + allElements.addAll(dimensions); + allElements.addAll(metrics); + return allElements.stream() + .filter(schemaElement -> schemaElement.getModel().equals(modelId)) + .collect(Collectors.toMap(SchemaElement::getBizName, Function.identity(), (value1, value2) -> value2)); + } + + private List getFieldNameList(QueryContext queryCtx, Long modelId, SemanticSchema semanticSchema) { Map itemIdToName = getItemIdToName(modelId, semanticSchema); @@ -197,9 +354,9 @@ public class LLMDSLParser implements SemanticParser { Set fieldNameList = matchedElements.stream() .filter(schemaElementMatch -> { SchemaElementType elementType = schemaElementMatch.getElement().getType(); - return SchemaElementType.METRIC.equals(elementType) || - SchemaElementType.DIMENSION.equals(elementType) || - SchemaElementType.VALUE.equals(elementType); + return SchemaElementType.METRIC.equals(elementType) + || SchemaElementType.DIMENSION.equals(elementType) + || SchemaElementType.VALUE.equals(elementType); }) .map(schemaElementMatch -> { SchemaElementType elementType = schemaElementMatch.getElement().getType(); @@ -220,18 +377,4 @@ public class LLMDSLParser implements SemanticParser { .collect(Collectors.toMap(SchemaElement::getId, SchemaElement::getName, (value1, value2) -> value2)); } - private List getDslTools(Integer agentId) { - AgentService agentService = ContextUtils.getBean(AgentService.class); - Agent agent = agentService.getAgent(agentId); - if (agent == null) { - return Lists.newArrayList(); - } - List tools = agent.getTools(AgentToolType.DSL); - if (CollectionUtils.isEmpty(tools)) { - return Lists.newArrayList(); - } - return tools.stream().map(tool -> JSONObject.parseObject(tool, DslTool.class)) - .collect(Collectors.toList()); - } - } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/interpret/MetricInterpretParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/interpret/MetricInterpretParser.java index 1ceab6c25..3577a10d6 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/interpret/MetricInterpretParser.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/interpret/MetricInterpretParser.java @@ -7,11 +7,17 @@ import com.tencent.supersonic.chat.agent.tool.AgentToolType; import com.tencent.supersonic.chat.agent.tool.MetricInterpretTool; import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.chat.api.component.SemanticParser; -import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.ModelSchema; import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.parser.SatisfactionChecker; -import com.tencent.supersonic.chat.query.metricInterpret.MetricInterpretQuery; +import com.tencent.supersonic.chat.query.metricinterpret.MetricInterpretQuery; import com.tencent.supersonic.chat.query.QueryManager; import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; import com.tencent.supersonic.chat.service.AgentService; @@ -22,7 +28,11 @@ import com.tencent.supersonic.semantic.api.model.enums.TimeDimensionEnum; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; -import java.util.*; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.HashMap; import java.util.stream.Collectors; @Slf4j @@ -34,7 +44,8 @@ public class MetricInterpretParser implements SemanticParser { log.info("skip MetricInterpretParser"); return; } - Map metricInterpretToolMap = getMetricInterpretTools(queryContext.getRequest().getAgentId()); + Map metricInterpretToolMap = + getMetricInterpretTools(queryContext.getRequest().getAgentId()); log.info("metric interpret tool : {}", metricInterpretToolMap); if (CollectionUtils.isEmpty(metricInterpretToolMap)) { return; @@ -50,8 +61,10 @@ public class MetricInterpretParser implements SemanticParser { } List metricOptions = metricInterpretTool.getMetricOptions(); if (!CollectionUtils.isEmpty(metricOptions)) { - List metricIds = metricOptions.stream().map(MetricOption::getMetricId).collect(Collectors.toList()); - buildQuery(modelId, queryContext, metricIds, elementMatches.get(modelId), metricInterpretTool.getName()); + List metricIds = metricOptions.stream() + .map(MetricOption::getMetricId).collect(Collectors.toList()); + String name = metricInterpretTool.getName(); + buildQuery(modelId, queryContext, metricIds, elementMatches.get(modelId), name); } } } @@ -82,7 +95,7 @@ public class MetricInterpretParser implements SemanticParser { if (agent == null) { return new HashMap<>(); } - List tools= agent.getTools(AgentToolType.INTERPRET); + List tools = agent.getTools(AgentToolType.INTERPRET); if (CollectionUtils.isEmpty(tools)) { return new HashMap<>(); } @@ -100,16 +113,16 @@ public class MetricInterpretParser implements SemanticParser { private SemanticParseInfo buildSemanticParseInfo(Long modelId, QueryReq queryReq, Set metrics, List schemaElementMatches, String toolName) { - SchemaElement Model = new SchemaElement(); - Model.setModel(modelId); - Model.setId(modelId); + SchemaElement model = new SchemaElement(); + model.setModel(modelId); + model.setId(modelId); SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); semanticParseInfo.setMetrics(metrics); SchemaElement dimension = new SchemaElement(); dimension.setBizName(TimeDimensionEnum.DAY.getName()); semanticParseInfo.setDimensions(Sets.newHashSet(dimension)); semanticParseInfo.setElementMatches(schemaElementMatches); - semanticParseInfo.setModel(Model); + semanticParseInfo.setModel(model); semanticParseInfo.setScore(queryReq.getQueryText().length()); DateConf dateConf = new DateConf(); dateConf.setDateMode(DateConf.DateMode.RECENT); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/time/LLMTimeEnhancementParse.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/time/LLMTimeEnhancementParse.java index 95ff25b0c..e55c50f31 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/time/LLMTimeEnhancementParse.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/llm/time/LLMTimeEnhancementParse.java @@ -17,7 +17,7 @@ public class LLMTimeEnhancementParse implements SemanticParser { @Override public void parse(QueryContext queryContext, ChatContext chatContext) { - log.info("before queryContext:{},chatContext:{}",queryContext,chatContext); + log.info("before queryContext:{},chatContext:{}", queryContext, chatContext); ChatGptHelper chatGptHelper = ContextUtils.getBean(ChatGptHelper.class); try { String inferredTime = chatGptHelper.inferredTime(queryContext.getRequest().getQueryText()); @@ -25,12 +25,12 @@ public class LLMTimeEnhancementParse implements SemanticParser { for (SemanticQuery query : queryContext.getCandidateQueries()) { DateConf dateInfo = query.getParseInfo().getDateInfo(); JSONObject jsonObject = JSON.parseObject(inferredTime); - if (jsonObject.containsKey("date")){ + if (jsonObject.containsKey("date")) { dateInfo.setDateMode(DateConf.DateMode.BETWEEN); dateInfo.setStartDate(jsonObject.getString("date")); dateInfo.setEndDate(jsonObject.getString("date")); query.getParseInfo().setDateInfo(dateInfo); - }else if (jsonObject.containsKey("start")){ + } else if (jsonObject.containsKey("start")) { dateInfo.setDateMode(DateConf.DateMode.BETWEEN); dateInfo.setStartDate(jsonObject.getString("start")); dateInfo.setEndDate(jsonObject.getString("end")); @@ -38,11 +38,13 @@ public class LLMTimeEnhancementParse implements SemanticParser { } } } - }catch (Exception exception){ - log.error("{} parse error,this reason is:{}",LLMTimeEnhancementParse.class.getSimpleName(), (Object) exception.getStackTrace()); + } catch (Exception exception) { + log.error("{} parse error,this reason is:{}", LLMTimeEnhancementParse.class.getSimpleName(), + (Object) exception.getStackTrace()); } - log.info("{} after queryContext:{},chatContext:{}",LLMTimeEnhancementParse.class.getSimpleName(),queryContext,chatContext); + log.info("{} after queryContext:{},chatContext:{}", + LLMTimeEnhancementParse.class.getSimpleName(), queryContext, chatContext); } 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/plugin/embedding/EmbeddingBasedParser.java similarity index 87% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingBasedParser.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/embedding/EmbeddingBasedParser.java index 48e9ea74d..c05178cdb 100644 --- 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/plugin/embedding/EmbeddingBasedParser.java @@ -1,8 +1,14 @@ -package com.tencent.supersonic.chat.parser.embedding; +package com.tencent.supersonic.chat.parser.plugin.embedding; import com.google.common.collect.Lists; import com.tencent.supersonic.chat.api.component.SemanticParser; -import com.tencent.supersonic.chat.api.pojo.*; +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.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.ModelSchema; import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.parser.ParseMode; @@ -10,12 +16,16 @@ 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.dsl.DSLQuery; +import com.tencent.supersonic.chat.query.llm.dsl.DslQuery; import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; import com.tencent.supersonic.chat.service.SemanticService; import com.tencent.supersonic.common.pojo.Constants; import com.tencent.supersonic.common.util.ContextUtils; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.HashMap; +import java.util.Comparator; import java.util.stream.Collectors; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import lombok.extern.slf4j.Slf4j; @@ -47,7 +57,7 @@ public class EmbeddingBasedParser implements SemanticParser { Map pluginMap = plugins.stream().collect(Collectors.toMap(Plugin::getId, p -> p)); for (RecallRetrieval embeddingRetrieval : embeddingRetrievals) { Plugin plugin = pluginMap.get(Long.parseLong(embeddingRetrieval.getId())); - if (plugin == null || DSLQuery.QUERY_MODE.equalsIgnoreCase(plugin.getType())) { + if (plugin == null || DslQuery.QUERY_MODE.equalsIgnoreCase(plugin.getType())) { continue; } Pair> pair = PluginManager.resolve(plugin, queryContext); @@ -88,12 +98,12 @@ public class EmbeddingBasedParser implements SemanticParser { if (modelId == null && !CollectionUtils.isEmpty(plugin.getModelList())) { modelId = plugin.getModelList().get(0); } - SchemaElement Model = new SchemaElement(); - Model.setModel(modelId); - Model.setId(modelId); + SchemaElement model = new SchemaElement(); + model.setModel(modelId); + model.setId(modelId); SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); semanticParseInfo.setElementMatches(schemaElementMatches); - semanticParseInfo.setModel(Model); + semanticParseInfo.setModel(model); Map properties = new HashMap<>(); PluginParseResult pluginParseResult = new PluginParseResult(); pluginParseResult.setPlugin(plugin); @@ -111,9 +121,9 @@ public class EmbeddingBasedParser implements SemanticParser { private void setEntity(Long modelId, SemanticParseInfo semanticParseInfo) { SemanticService semanticService = ContextUtils.getBean(SemanticService.class); - ModelSchema ModelSchema = semanticService.getModelSchema(modelId); - if (ModelSchema != null && ModelSchema.getEntity() != null) { - semanticParseInfo.setEntity(ModelSchema.getEntity()); + ModelSchema modelSchema = semanticService.getModelSchema(modelId); + if (modelSchema != null && modelSchema.getEntity() != null) { + semanticParseInfo.setEntity(modelSchema.getEntity()); } } 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/plugin/embedding/EmbeddingConfig.java similarity index 90% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingConfig.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/embedding/EmbeddingConfig.java index 9df4c6e8b..42c3b3db5 100644 --- 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/plugin/embedding/EmbeddingConfig.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.embedding; +package com.tencent.supersonic.chat.parser.plugin.embedding; import lombok.Data; import org.springframework.beans.factory.annotation.Value; 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/plugin/embedding/EmbeddingEntityResolver.java similarity index 94% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingEntityResolver.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/embedding/EmbeddingEntityResolver.java index 7ad5c1f8a..70fb33842 100644 --- 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/plugin/embedding/EmbeddingEntityResolver.java @@ -1,26 +1,26 @@ -package com.tencent.supersonic.chat.parser.embedding; +package com.tencent.supersonic.chat.parser.plugin.embedding; import com.alibaba.fastjson.JSONObject; -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.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.chat.api.pojo.request.QueryFilter; import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; import com.tencent.supersonic.chat.service.ConfigService; -import java.util.List; -import java.util.Objects; -import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; 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) { @@ -39,8 +39,8 @@ public class EmbeddingEntityResolver { } } entityId = getEntityValueFromSchemaMapInfo(modelId, queryCtx.getMapInfo(), entityElementId); - log.info("get entity id:{} from schema map Info :{} ", entityId, - JSONObject.toJSONString(queryCtx.getMapInfo())); + 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) { @@ -95,4 +95,4 @@ public class EmbeddingEntityResolver { 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/plugin/embedding/EmbeddingResp.java similarity index 72% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/EmbeddingResp.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/embedding/EmbeddingResp.java index c11db7c81..18777ddbc 100644 --- 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/plugin/embedding/EmbeddingResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.embedding; +package com.tencent.supersonic.chat.parser.plugin.embedding; import java.util.List; 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/plugin/embedding/RecallRetrieval.java similarity index 74% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/embedding/RecallRetrieval.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/embedding/RecallRetrieval.java index 64d141119..4d5470e4f 100644 --- 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/plugin/embedding/RecallRetrieval.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.embedding; +package com.tencent.supersonic.chat.parser.plugin.embedding; import lombok.Data; 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/plugin/function/FunctionBasedParser.java similarity index 82% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionBasedParser.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/FunctionBasedParser.java index f95732d18..c86b4bbdb 100644 --- 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/plugin/function/FunctionBasedParser.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; import com.alibaba.fastjson.JSON; import com.tencent.supersonic.chat.api.component.SemanticParser; @@ -15,13 +15,18 @@ import com.tencent.supersonic.chat.plugin.PluginParseConfig; 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.dsl.DSLQuery; +import com.tencent.supersonic.chat.query.llm.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.*; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; import java.util.stream.Collectors; import com.tencent.supersonic.common.util.JsonUtil; import lombok.extern.slf4j.Slf4j; @@ -39,11 +44,6 @@ import org.springframework.web.util.UriComponentsBuilder; @Slf4j public class FunctionBasedParser implements SemanticParser { - public static final double FUNCTION_BONUS_THRESHOLD = 200; - - public static final double SKIP_DSL_LENGTH = 10; - - @Override public void parse(QueryContext queryCtx, ChatContext chatCtx) { FunctionCallInfoConfig functionCallConfig = ContextUtils.getBean(FunctionCallInfoConfig.class); @@ -59,12 +59,17 @@ public class FunctionBasedParser implements SemanticParser { log.info("function call parser, plugin is empty, skip"); return; } - FunctionReq functionReq = FunctionReq.builder() - .queryText(queryCtx.getRequest().getQueryText()) - .pluginConfigs(functionDOList).build(); - FunctionResp functionResp = requestFunction(functionUrl, functionReq); + FunctionResp functionResp = new FunctionResp(); + if (functionDOList.size() == 1) { + functionResp.setToolSelection(functionDOList.iterator().next().getName()); + } else { + FunctionReq functionReq = FunctionReq.builder() + .queryText(queryCtx.getRequest().getQueryText()) + .pluginConfigs(functionDOList).build(); + functionResp = requestFunction(functionUrl, functionReq); + } log.info("requestFunction result:{}", functionResp.getToolSelection()); - if (skipFunction(queryCtx, functionResp)) { + if (skipFunction(functionResp)) { return; } PluginParseResult functionCallParseResult = new PluginParseResult(); @@ -80,10 +85,10 @@ public class FunctionBasedParser implements SemanticParser { functionCallParseResult.setPlugin(plugin); log.info("QueryManager PluginQueryModes:{}", QueryManager.getPluginQueryModes()); PluginSemanticQuery semanticQuery = QueryManager.createPluginQuery(toolSelection); - ModelResolver ModelResolver = ComponentFactory.getModelResolver(); + ModelResolver modelResolver = ComponentFactory.getModelResolver(); log.info("plugin ModelList:{}", plugin.getModelList()); Pair> pluginResolveResult = PluginManager.resolve(plugin, queryCtx); - Long modelId = ModelResolver.resolve(queryCtx, chatCtx, pluginResolveResult.getRight()); + Long modelId = modelResolver.resolve(queryCtx, chatCtx, pluginResolveResult.getRight()); log.info("FunctionBasedParser modelId:{}", modelId); if ((Objects.isNull(modelId) || modelId <= 0) && !plugin.isContainsAllModel()) { log.info("Model is null, skip the parse, select tool: {}", toolSelection); @@ -102,35 +107,24 @@ public class FunctionBasedParser implements SemanticParser { properties.put("type", "plugin"); properties.put("name", plugin.getName()); parseInfo.setProperties(properties); - parseInfo.setScore(FUNCTION_BONUS_THRESHOLD); + parseInfo.setScore(queryCtx.getRequest().getQueryText().length()); parseInfo.setQueryMode(semanticQuery.getQueryMode()); - SchemaElement Model = new SchemaElement(); - Model.setModel(modelId); - Model.setId(modelId); - parseInfo.setModel(Model); + SchemaElement model = new SchemaElement(); + model.setModel(modelId); + model.setId(modelId); + parseInfo.setModel(model); queryCtx.getCandidateQueries().add(semanticQuery); } - private boolean skipFunction(QueryContext queryCtx, FunctionResp functionResp) { - if (Objects.isNull(functionResp) || StringUtils.isBlank(functionResp.getToolSelection())) { - return true; - } - String queryText = queryCtx.getRequest().getQueryText(); - - if (functionResp.getToolSelection().equalsIgnoreCase(DSLQuery.QUERY_MODE) - && queryText.length() < SKIP_DSL_LENGTH) { - log.info("queryText length is :{}, less than the threshold :{}, skip dsl.", queryText.length(), - SKIP_DSL_LENGTH); - return true; - } - return false; + private boolean skipFunction(FunctionResp functionResp) { + return Objects.isNull(functionResp) || StringUtils.isBlank(functionResp.getToolSelection()); } private List getFunctionDO(Long modelId, QueryContext queryContext) { log.info("user decide Model:{}", modelId); List plugins = getPluginList(queryContext); List functionDOList = plugins.stream().filter(plugin -> { - if (DSLQuery.QUERY_MODE.equalsIgnoreCase(plugin.getType())) { + if (DslQuery.QUERY_MODE.equalsIgnoreCase(plugin.getType())) { return false; } if (plugin.getParseModeConfig() == null) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionFiled.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/FunctionFiled.java similarity index 66% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionFiled.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/FunctionFiled.java index 5c250ca51..e1ba0c4f6 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionFiled.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/FunctionFiled.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; import lombok.Data; 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/plugin/function/FunctionReq.java similarity index 81% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionReq.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/FunctionReq.java index ab4fa5a47..523a859ad 100644 --- 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/plugin/function/FunctionReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; import com.tencent.supersonic.chat.plugin.PluginParseConfig; import java.util.List; 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/plugin/function/FunctionResp.java similarity index 61% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/FunctionResp.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/FunctionResp.java index f27021481..0501b6100 100644 --- 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/plugin/function/FunctionResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/HeuristicModelResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/HeuristicModelResolver.java similarity index 65% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/HeuristicModelResolver.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/HeuristicModelResolver.java index e7c447258..b66217418 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/HeuristicModelResolver.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/HeuristicModelResolver.java @@ -1,29 +1,40 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; -import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.api.component.SemanticQuery; import lombok.extern.slf4j.Slf4j; -import java.util.*; +import java.util.Map; +import java.util.HashMap; +import java.util.Objects; +import java.util.List; +import java.util.HashSet; +import java.util.Set; import java.util.stream.Collectors; + import org.apache.commons.collections.CollectionUtils; @Slf4j public class HeuristicModelResolver implements ModelResolver { - protected static Long selectModelBySchemaElementCount(Map ModelQueryModes, - SchemaMapInfo schemaMap) { - Map ModelTypeMap = getModelTypeMap(schemaMap); - if (ModelTypeMap.size() == 1) { - Long ModelSelect = ModelTypeMap.entrySet().stream().collect(Collectors.toList()).get(0).getKey(); - if (ModelQueryModes.containsKey(ModelSelect)) { - log.info("selectModel with only one Model [{}]", ModelSelect); - return ModelSelect; + protected static Long selectModelBySchemaElementCount(Map modelQueryModes, + SchemaMapInfo schemaMap) { + Map modelTypeMap = getModelTypeMap(schemaMap); + if (modelTypeMap.size() == 1) { + Long modelSelect = modelTypeMap.entrySet().stream().collect(Collectors.toList()).get(0).getKey(); + if (modelQueryModes.containsKey(modelSelect)) { + log.info("selectModel with only one Model [{}]", modelSelect); + return modelSelect; } } else { - Map.Entry maxModel = ModelTypeMap.entrySet().stream() - .filter(entry -> ModelQueryModes.containsKey(entry.getKey())) + Map.Entry maxModel = modelTypeMap.entrySet().stream() + .filter(entry -> modelQueryModes.containsKey(entry.getKey())) .sorted((o1, o2) -> { int difference = o2.getValue().getCount() - o1.getValue().getCount(); if (difference == 0) { @@ -45,23 +56,24 @@ public class HeuristicModelResolver implements ModelResolver { * * @return false will use context Model, true will use other Model , maybe include context Model */ - protected static boolean isAllowSwitch(Map ModelQueryModes, SchemaMapInfo schemaMap, - ChatContext chatCtx, QueryReq searchCtx, Long modelId, Set restrictiveModels) { + protected static boolean isAllowSwitch(Map modelQueryModes, SchemaMapInfo schemaMap, + ChatContext chatCtx, QueryReq searchCtx, + Long modelId, Set restrictiveModels) { if (!Objects.nonNull(modelId) || modelId <= 0) { return true; } // except content Model, calculate the number of types for each Model, if numbers<=1 will not switch - Map ModelTypeMap = getModelTypeMap(schemaMap); - log.info("isAllowSwitch ModelTypeMap [{}]", ModelTypeMap); - long otherModelTypeNumBigOneCount = ModelTypeMap.entrySet().stream() - .filter(entry -> ModelQueryModes.containsKey(entry.getKey()) && !entry.getKey().equals(modelId)) + Map modelTypeMap = getModelTypeMap(schemaMap); + log.info("isAllowSwitch ModelTypeMap [{}]", modelTypeMap); + long otherModelTypeNumBigOneCount = modelTypeMap.entrySet().stream() + .filter(entry -> modelQueryModes.containsKey(entry.getKey()) && !entry.getKey().equals(modelId)) .filter(entry -> entry.getValue().getCount() > 1).count(); if (otherModelTypeNumBigOneCount >= 1) { return true; } // if query text only contain time , will not switch - if (!CollectionUtils.isEmpty(ModelQueryModes.values())) { - for (SemanticQuery semanticQuery : ModelQueryModes.values()) { + if (!CollectionUtils.isEmpty(modelQueryModes.values())) { + for (SemanticQuery semanticQuery : modelQueryModes.values()) { if (semanticQuery == null) { continue; } @@ -71,7 +83,8 @@ public class HeuristicModelResolver implements ModelResolver { } if (searchCtx.getQueryText() != null && semanticParseInfo.getDateInfo() != null) { if (semanticParseInfo.getDateInfo().getDetectWord() != null) { - if (semanticParseInfo.getDateInfo().getDetectWord().equalsIgnoreCase(searchCtx.getQueryText())) { + if (semanticParseInfo.getDateInfo().getDetectWord() + .equalsIgnoreCase(searchCtx.getQueryText())) { log.info("timeParseResults is not null , can not switch context , timeParseResults:{},", semanticParseInfo.getDateInfo()); return false; @@ -94,14 +107,14 @@ public class HeuristicModelResolver implements ModelResolver { } public static Map getModelTypeMap(SchemaMapInfo schemaMap) { - Map ModelCount = new HashMap<>(); + Map modelCount = new HashMap<>(); for (Map.Entry> entry : schemaMap.getModelElementMatches().entrySet()) { List schemaElementMatches = schemaMap.getMatchedElements(entry.getKey()); if (schemaElementMatches != null && schemaElementMatches.size() > 0) { - if (!ModelCount.containsKey(entry.getKey())) { - ModelCount.put(entry.getKey(), new ModelMatchResult()); + if (!modelCount.containsKey(entry.getKey())) { + modelCount.put(entry.getKey(), new ModelMatchResult()); } - ModelMatchResult ModelMatchResult = ModelCount.get(entry.getKey()); + ModelMatchResult modelMatchResult = modelCount.get(entry.getKey()); Set schemaElementTypes = new HashSet<>(); schemaElementMatches.stream() .forEach(schemaElementMatch -> schemaElementTypes.add( @@ -111,13 +124,13 @@ public class HeuristicModelResolver implements ModelResolver { ((int) ((o2.getSimilarity() - o1.getSimilarity()) * 100)) ).findFirst().orElse(null); if (schemaElementMatchMax != null) { - ModelMatchResult.setMaxSimilarity(schemaElementMatchMax.getSimilarity()); + modelMatchResult.setMaxSimilarity(schemaElementMatchMax.getSimilarity()); } - ModelMatchResult.setCount(schemaElementTypes.size()); + modelMatchResult.setCount(schemaElementTypes.size()); } } - return ModelCount; + return modelCount; } @@ -137,40 +150,41 @@ public class HeuristicModelResolver implements ModelResolver { .filter(restrictiveModels::contains) .collect(Collectors.toSet()); } - Map ModelQueryModes = new HashMap<>(); + Map modelQueryModes = new HashMap<>(); for (Long matchedModel : matchedModels) { - ModelQueryModes.put(matchedModel, null); + modelQueryModes.put(matchedModel, null); } - if(ModelQueryModes.size()==1){ - return ModelQueryModes.keySet().stream().findFirst().get(); + if (modelQueryModes.size() == 1) { + return modelQueryModes.keySet().stream().findFirst().get(); } - return resolve(ModelQueryModes, queryContext, chatCtx, - queryContext.getMapInfo(),restrictiveModels); + return resolve(modelQueryModes, queryContext, chatCtx, + queryContext.getMapInfo(), restrictiveModels); } - public Long resolve(Map ModelQueryModes, QueryContext queryContext, - ChatContext chatCtx, SchemaMapInfo schemaMap, Set restrictiveModels) { - Long selectModel = selectModel(ModelQueryModes, queryContext.getRequest(), chatCtx, schemaMap,restrictiveModels); + public Long resolve(Map modelQueryModes, QueryContext queryContext, + ChatContext chatCtx, SchemaMapInfo schemaMap, Set restrictiveModels) { + Long selectModel = selectModel(modelQueryModes, queryContext.getRequest(), + chatCtx, schemaMap, restrictiveModels); if (selectModel > 0) { log.info("selectModel {} ", selectModel); return selectModel; } // get the max SchemaElementType number - return selectModelBySchemaElementCount(ModelQueryModes, schemaMap); + return selectModelBySchemaElementCount(modelQueryModes, schemaMap); } - public Long selectModel(Map ModelQueryModes, QueryReq queryContext, - ChatContext chatCtx, - SchemaMapInfo schemaMap, Set restrictiveModels) { + public Long selectModel(Map modelQueryModes, QueryReq queryContext, + ChatContext chatCtx, + SchemaMapInfo schemaMap, Set restrictiveModels) { // if QueryContext has modelId and in ModelQueryModes - if (ModelQueryModes.containsKey(queryContext.getModelId())) { + if (modelQueryModes.containsKey(queryContext.getModelId())) { log.info("selectModel from QueryContext [{}]", queryContext.getModelId()); return queryContext.getModelId(); } // if ChatContext has modelId and in ModelQueryModes if (chatCtx.getParseInfo().getModelId() > 0) { Long modelId = chatCtx.getParseInfo().getModelId(); - if (!isAllowSwitch(ModelQueryModes, schemaMap, chatCtx, queryContext, modelId,restrictiveModels)) { + if (!isAllowSwitch(modelQueryModes, schemaMap, chatCtx, queryContext, modelId, restrictiveModels)) { log.info("selectModel from ChatContext [{}]", modelId); return modelId; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/ModelMatchResult.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/ModelMatchResult.java similarity index 68% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/ModelMatchResult.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/ModelMatchResult.java index 37cb8815a..391d673d5 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/ModelMatchResult.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/ModelMatchResult.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/ModelResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/ModelResolver.java similarity index 77% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/ModelResolver.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/ModelResolver.java index 7bb68ee66..e80b167a7 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/ModelResolver.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/ModelResolver.java @@ -1,13 +1,12 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.QueryContext; -import java.util.List; import java.util.Set; public interface ModelResolver { Long resolve(QueryContext queryContext, ChatContext chatCtx, Set restrictiveModels); -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/Parameters.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/Parameters.java similarity index 80% rename from chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/Parameters.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/Parameters.java index 453d4840b..c05dccae4 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/function/Parameters.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/plugin/function/Parameters.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.parser.function; +package com.tencent.supersonic.chat.parser.plugin.function; import java.util.List; import java.util.Map; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/AgentCheckParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/AgentCheckParser.java index 157c5c606..7171ad227 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/AgentCheckParser.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/parser/rule/AgentCheckParser.java @@ -13,7 +13,6 @@ import com.tencent.supersonic.chat.service.AgentService; import com.tencent.supersonic.common.util.ContextUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; -import java.util.Collection; import java.util.List; import java.util.stream.Collectors; @@ -32,16 +31,24 @@ public class AgentCheckParser implements SemanticParser { if (agent == null) { return; } - List queryModes = getRuleTools(agentId).stream().map(RuleQueryTool::getQueryModes) - .flatMap(Collection::stream).collect(Collectors.toList()); - if (CollectionUtils.isEmpty(queries)) { + List queryTools = getRuleTools(agentId); + if (CollectionUtils.isEmpty(queryTools)) { queries.clear(); return; } log.info("queries resolved:{} {}", agent.getName(), queries.stream().map(SemanticQuery::getQueryMode).collect(Collectors.toList())); - queries.removeIf(query -> - !queryModes.contains(query.getQueryMode())); + queries.removeIf(query -> { + for (RuleQueryTool tool : queryTools) { + if (!tool.getQueryModes().contains(query.getQueryMode())) { + return true; + } + if (tool.isContainsAllModel() || tool.getModelIds().contains(query.getParseInfo().getModelId())) { + return false; + } + } + return true; + }); log.info("rule queries witch can be supported by agent :{} {}", agent.getName(), queries.stream().map(SemanticQuery::getQueryMode).collect(Collectors.toList())); } 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 index 0b7925435..fbe90bb44 100644 --- 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 @@ -14,6 +14,7 @@ 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.AbstractMap; import java.util.HashMap; import java.util.Map; @@ -21,6 +22,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; + import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; 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 index 8de93c7b8..d2e2d13b1 100644 --- 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 @@ -1,12 +1,5 @@ package com.tencent.supersonic.chat.parser.rule; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.DIMENSION; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ID; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.METRIC; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.MODEL; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; - import com.tencent.supersonic.chat.api.component.SemanticParser; import com.tencent.supersonic.chat.api.component.SemanticQuery; import com.tencent.supersonic.chat.api.pojo.ChatContext; @@ -15,8 +8,8 @@ import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.query.QueryManager; import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; -import com.tencent.supersonic.chat.query.rule.metric.MetricEntityQuery; import com.tencent.supersonic.chat.query.rule.metric.MetricModelQuery; +import com.tencent.supersonic.chat.query.rule.metric.MetricEntityQuery; import com.tencent.supersonic.chat.query.rule.metric.MetricSemanticQuery; import java.util.AbstractMap; import java.util.ArrayList; @@ -28,6 +21,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.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.api.pojo.SchemaElementType.ENTITY; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.MODEL; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ID; + @Slf4j public class ContextInheritParser implements SemanticParser { 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 index 983d3cb62..536d994a9 100644 --- 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 @@ -1,9 +1,12 @@ 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.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; -import java.util.*; +import java.util.List; import lombok.extern.slf4j.Slf4j; @Slf4j 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 index 4b0624803..a94621b39 100644 --- 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 @@ -4,21 +4,23 @@ 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.QueryManager; 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 com.xkzhangsan.time.nlp.TimeNLP; -import com.xkzhangsan.time.nlp.TimeNLPUtil; + import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; +import java.util.Stack; import java.util.Date; import java.util.List; -import java.util.Stack; 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; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDO.java index 9777a9492..777b27f04 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDO.java @@ -4,17 +4,14 @@ import java.util.Date; public class AgentDO { /** - * */ private Integer id; /** - * */ private String name; /** - * */ private String description; @@ -24,83 +21,70 @@ public class AgentDO { private Integer status; /** - * */ private String examples; /** - * */ private String config; /** - * */ private String createdBy; /** - * */ private Date createdAt; /** - * */ private String updatedBy; /** - * */ private Date updatedAt; /** - * */ private Integer enableSearch; /** - * - * @return id + * @return id */ public Integer getId() { return id; } /** - * - * @param id + * @param id */ public void setId(Integer id) { this.id = id; } /** - * - * @return name + * @return name */ public String getName() { return name; } /** - * - * @param name + * @param name */ public void setName(String name) { this.name = name == null ? null : name.trim(); } /** - * - * @return description + * @return description */ public String getDescription() { return description; } /** - * - * @param description + * @param description */ public void setDescription(String description) { this.description = description == null ? null : description.trim(); @@ -123,114 +107,100 @@ public class AgentDO { } /** - * - * @return examples + * @return examples */ public String getExamples() { return examples; } /** - * - * @param examples + * @param examples */ public void setExamples(String examples) { this.examples = examples == null ? null : examples.trim(); } /** - * - * @return config + * @return config */ public String getConfig() { return config; } /** - * - * @param config + * @param config */ public void setConfig(String config) { this.config = config == null ? null : config.trim(); } /** - * - * @return created_by + * @return created_by */ public String getCreatedBy() { return createdBy; } /** - * - * @param createdBy + * @param createdBy */ public void setCreatedBy(String createdBy) { this.createdBy = createdBy == null ? null : createdBy.trim(); } /** - * - * @return created_at + * @return created_at */ public Date getCreatedAt() { return createdAt; } /** - * - * @param createdAt + * @param createdAt */ public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } /** - * - * @return updated_by + * @return updated_by */ public String getUpdatedBy() { return updatedBy; } /** - * - * @param updatedBy + * @param updatedBy */ public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy == null ? null : updatedBy.trim(); } /** - * - * @return updated_at + * @return updated_at */ public Date getUpdatedAt() { return updatedAt; } /** - * - * @param updatedAt + * @param updatedAt */ public void setUpdatedAt(Date updatedAt) { this.updatedAt = updatedAt; } /** - * - * @return enable_search + * @return enable_search */ public Integer getEnableSearch() { return enableSearch; } /** - * - * @param enableSearch + * @param enableSearch */ public void setEnableSearch(Integer enableSearch) { this.enableSearch = enableSearch; } -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDOExample.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDOExample.java index fb4bdda0f..c8ab99a65 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDOExample.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/AgentDOExample.java @@ -31,7 +31,6 @@ public class AgentDOExample { protected Integer limitEnd; /** - * * @mbg.generated */ public AgentDOExample() { @@ -39,7 +38,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public void setOrderByClause(String orderByClause) { @@ -47,7 +45,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public String getOrderByClause() { @@ -55,7 +52,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public void setDistinct(boolean distinct) { @@ -63,7 +59,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public boolean isDistinct() { @@ -71,7 +66,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public List getOredCriteria() { @@ -79,7 +73,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public void or(Criteria criteria) { @@ -87,7 +80,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public Criteria or() { @@ -97,7 +89,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public Criteria createCriteria() { @@ -109,7 +100,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ protected Criteria createCriteriaInternal() { @@ -118,7 +108,6 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public void clear() { @@ -128,15 +117,13 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public void setLimitStart(Integer limitStart) { - this.limitStart=limitStart; + this.limitStart = limitStart; } /** - * * @mbg.generated */ public Integer getLimitStart() { @@ -144,15 +131,13 @@ public class AgentDOExample { } /** - * * @mbg.generated */ public void setLimitEnd(Integer limitEnd) { - this.limitEnd=limitEnd; + this.limitEnd = limitEnd; } /** - * * @mbg.generated */ public Integer getLimitEnd() { @@ -954,38 +939,6 @@ public class AgentDOExample { 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; @@ -1021,5 +974,37 @@ public class AgentDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatParseDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatParseDO.java new file mode 100644 index 000000000..3f5a6d47d --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatParseDO.java @@ -0,0 +1,142 @@ +package com.tencent.supersonic.chat.persistence.dataobject; + +import java.util.Date; + + +public class ChatParseDO { + + /** + * questionId + */ + private Long questionId; + + /** + * chatId + */ + private Long chatId; + + /** + * parseId + */ + private Integer parseId; + + /** + * createTime + */ + private Date createTime; + + /** + * queryText + */ + private String queryText; + + /** + * userName + */ + private String userName; + + + /** + * parseInfo + */ + private String parseInfo; + + /** + * isCandidate + */ + private Integer isCandidate; + + /** + * return question_id + */ + public Long getQuestionId() { + return questionId; + } + + /** + * questionId + */ + public void setQuestionId(Long questionId) { + this.questionId = questionId; + } + + /** + * return create_time + */ + public Date getCreateTime() { + return createTime; + } + + /** + * createTime + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + /** + * return user_name + */ + public String getUserName() { + return userName; + } + + /** + * userName + */ + public void setUserName(String userName) { + this.userName = userName == null ? null : userName.trim(); + } + + /** + * return chat_id + */ + public Long getChatId() { + return chatId; + } + + /** + * chatId + */ + public void setChatId(Long chatId) { + this.chatId = chatId; + } + + /** + * return query_text + */ + public String getQueryText() { + return queryText; + } + + /** + * queryText + */ + public void setQueryText(String queryText) { + this.queryText = queryText == null ? null : queryText.trim(); + } + + public Integer getIsCandidate() { + return isCandidate; + } + + public Integer getParseId() { + return parseId; + } + + public String getParseInfo() { + return parseInfo; + } + + public void setParseId(Integer parseId) { + this.parseId = parseId; + } + + public void setIsCandidate(Integer isCandidate) { + this.isCandidate = isCandidate; + } + + public void setParseInfo(String parseInfo) { + this.parseInfo = parseInfo; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDO.java index 600f8b87e..6d5a8ec6e 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDO.java @@ -2,177 +2,196 @@ package com.tencent.supersonic.chat.persistence.dataobject; import java.util.Date; - public class ChatQueryDO { - /** - * questionId */ private Long questionId; /** - * createTime + */ + private Integer agentId; + + /** */ private Date createTime; /** - * userName */ private String userName; /** - * queryState */ private Integer queryState; /** - * chatId */ private Long chatId; /** - * score */ private Integer score; /** - * feedback */ private String feedback; /** - * queryText */ private String queryText; /** - * queryResponse */ private String queryResult; /** - * return question_id + * @return question_id */ public Long getQuestionId() { return questionId; } /** - * questionId + * @param questionId */ public void setQuestionId(Long questionId) { this.questionId = questionId; } /** - * return create_time + * @return agent_id + */ + public Integer getAgentId() { + return agentId; + } + + /** + * @param agentId + */ + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + /** + * @return create_time */ public Date getCreateTime() { return createTime; } /** - * createTime + * @param createTime */ public void setCreateTime(Date createTime) { this.createTime = createTime; } /** - * return user_name + * @return user_name */ public String getUserName() { return userName; } /** - * userName + * @param userName */ public void setUserName(String userName) { this.userName = userName == null ? null : userName.trim(); } /** - * return query_state + * + * @return query_state */ public Integer getQueryState() { return queryState; } /** - * queryState + * + * @param queryState */ public void setQueryState(Integer queryState) { this.queryState = queryState; } /** - * return chat_id + * + * @return chat_id */ public Long getChatId() { return chatId; } /** - * chatId + * + * @param chatId */ public void setChatId(Long chatId) { this.chatId = chatId; } /** - * return score + * + * @return score */ public Integer getScore() { return score; } /** - * score + * + * @param score */ public void setScore(Integer score) { this.score = score; } /** - * return feedback + * + * @return feedback */ public String getFeedback() { return feedback; } /** - * feedback + * + * @param feedback */ public void setFeedback(String feedback) { this.feedback = feedback == null ? null : feedback.trim(); } /** - * return query_text + * + * @return query_text */ public String getQueryText() { return queryText; } /** - * queryText + * + * @param queryText */ public void setQueryText(String queryText) { this.queryText = queryText == null ? null : queryText.trim(); } /** - * return query_response + * + * @return query_result */ public String getQueryResult() { return queryResult; } /** - * queryResponse + * + * @param queryResult */ 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/persistence/dataobject/ChatQueryDOExample.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDOExample.java index 836e6db25..b7b69d8cd 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDOExample.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/ChatQueryDOExample.java @@ -5,47 +5,92 @@ import java.util.Date; import java.util.List; public class ChatQueryDOExample { - + /** + * s2_chat_query + */ protected String orderByClause; + + /** + * s2_chat_query + */ protected boolean distinct; + + /** + * s2_chat_query + */ protected List oredCriteria; + + /** + * s2_chat_query + */ protected Integer limitStart; + + /** + * s2_chat_query + */ protected Integer limitEnd; + /** + * @mbg.generated + */ public ChatQueryDOExample() { oredCriteria = new ArrayList(); } - public String getOrderByClause() { - return orderByClause; - } - + /** + * @mbg.generated + */ public void setOrderByClause(String orderByClause) { this.orderByClause = orderByClause; } - public boolean isDistinct() { - return distinct; + /** + * @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) { @@ -54,35 +99,55 @@ public class ChatQueryDOExample { return criteria; } + /** + * @mbg.generated + */ protected Criteria createCriteriaInternal() { Criteria criteria = new Criteria(); return criteria; } + /** + * @mbg.generated + */ public void clear() { oredCriteria.clear(); orderByClause = null; distinct = false; } - public Integer getLimitStart() { - return limitStart; - } - + /** + * @mbg.generated + */ public void setLimitStart(Integer limitStart) { this.limitStart = limitStart; } - public Integer getLimitEnd() { - return limitEnd; + /** + * @mbg.generated + */ + public Integer getLimitStart() { + return limitStart; } + /** + * @mbg.generated + */ public void setLimitEnd(Integer limitEnd) { this.limitEnd = limitEnd; } - protected abstract static class GeneratedCriteria { + /** + * @mbg.generated + */ + public Integer getLimitEnd() { + return limitEnd; + } + /** + * s2_chat_query null + */ + protected abstract static class GeneratedCriteria { protected List criteria; protected GeneratedCriteria() { @@ -183,6 +248,66 @@ public class ChatQueryDOExample { return (Criteria) this; } + public Criteria andAgentIdIsNull() { + addCriterion("agent_id is null"); + return (Criteria) this; + } + + public Criteria andAgentIdIsNotNull() { + addCriterion("agent_id is not null"); + return (Criteria) this; + } + + public Criteria andAgentIdEqualTo(Integer value) { + addCriterion("agent_id =", value, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdNotEqualTo(Integer value) { + addCriterion("agent_id <>", value, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdGreaterThan(Integer value) { + addCriterion("agent_id >", value, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdGreaterThanOrEqualTo(Integer value) { + addCriterion("agent_id >=", value, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdLessThan(Integer value) { + addCriterion("agent_id <", value, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdLessThanOrEqualTo(Integer value) { + addCriterion("agent_id <=", value, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdIn(List values) { + addCriterion("agent_id in", values, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdNotIn(List values) { + addCriterion("agent_id not in", values, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdBetween(Integer value1, Integer value2) { + addCriterion("agent_id between", value1, value2, "agentId"); + return (Criteria) this; + } + + public Criteria andAgentIdNotBetween(Integer value1, Integer value2) { + addCriterion("agent_id not between", value1, value2, "agentId"); + return (Criteria) this; + } + public Criteria andCreateTimeIsNull() { addCriterion("create_time is null"); return (Criteria) this; @@ -564,6 +689,9 @@ public class ChatQueryDOExample { } } + /** + * s2_chat_query + */ public static class Criteria extends GeneratedCriteria { protected Criteria() { @@ -571,8 +699,10 @@ public class ChatQueryDOExample { } } + /** + * s2_chat_query null + */ public static class Criterion { - private String condition; private Object value; @@ -657,4 +787,4 @@ public class ChatQueryDOExample { return typeHandler; } } -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/CostType.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/CostType.java new file mode 100644 index 000000000..0e10f55bf --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/CostType.java @@ -0,0 +1,23 @@ +package com.tencent.supersonic.chat.persistence.dataobject; + +public enum CostType { + MAPPER(1, "mapper"), + PARSER(2, "parser"), + QUERY(3, "query"); + + private Integer type; + private String name; + + CostType(Integer type, String name) { + this.type = type; + this.name = name; + } + + public Integer getType() { + return type; + } + + public String getName() { + return name; + } +} 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 index b730f806b..f6b99f603 100644 --- 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 @@ -254,4 +254,4 @@ public class PluginDO { public void setComment(String comment) { this.comment = comment == null ? null : comment.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 index 8ee110998..6f25dc5e0 100644 --- 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 @@ -892,38 +892,6 @@ public class PluginDOExample { 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; @@ -959,5 +927,37 @@ public class PluginDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/StatisticsDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/StatisticsDO.java new file mode 100644 index 000000000..e69627fcd --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/dataobject/StatisticsDO.java @@ -0,0 +1,54 @@ +package com.tencent.supersonic.chat.persistence.dataobject; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.util.Date; + +@Data +@Builder +@NoArgsConstructor +@Getter +@AllArgsConstructor +public class StatisticsDO { + /** + * questionId + */ + private Long questionId; + + /** + * chatId + */ + private Long chatId; + + /** + * createTime + */ + private Date createTime; + + /** + * queryText + */ + private String queryText; + + /** + * userName + */ + private String userName; + + + /** + * interface + */ + private String interfaceName; + + /** + * cost + */ + private Integer cost; + + private Integer type; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatParseMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatParseMapper.java new file mode 100644 index 000000000..94be19489 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/ChatParseMapper.java @@ -0,0 +1,17 @@ +package com.tencent.supersonic.chat.persistence.mapper; + +import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + + +@Mapper +public interface ChatParseMapper { + + boolean batchSaveParseInfo(@Param("list") List list); + + ChatParseDO getParseInfo(Long questionId, String userName, int parseId); + +} 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 index aa4c19854..6dabf7e6c 100644 --- 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 @@ -14,4 +14,5 @@ public interface ChatQueryDOMapper { int updateByPrimaryKeyWithBLOBs(ChatQueryDO record); + Boolean deleteByPrimaryKey(Long questionId); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/StatisticsMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/StatisticsMapper.java new file mode 100644 index 000000000..f46042c27 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/StatisticsMapper.java @@ -0,0 +1,12 @@ +package com.tencent.supersonic.chat.persistence.mapper; + +import com.tencent.supersonic.chat.persistence.dataobject.StatisticsDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface StatisticsMapper { + boolean batchSaveStatistics(@Param("list") List list); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/custom/ShowCaseCustomMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/custom/ShowCaseCustomMapper.java new file mode 100644 index 000000000..fddb34594 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/mapper/custom/ShowCaseCustomMapper.java @@ -0,0 +1,12 @@ +package com.tencent.supersonic.chat.persistence.mapper.custom; + +import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import org.apache.ibatis.annotations.Mapper; +import java.util.List; + +@Mapper +public interface ShowCaseCustomMapper { + + List queryShowCase(int start, int limit, int agentId); + +} 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 index cce4aafd4..4ddafcefd 100644 --- 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 @@ -2,18 +2,37 @@ 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.PageQueryInfoReq; -import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.response.ParseResp; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO; import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; + +import java.util.List; public interface ChatQueryRepository { PageInfo getChatQuery(PageQueryInfoReq pageQueryInfoCommend, long chatId); + List queryShowCase(PageQueryInfoReq pageQueryInfoCommend, int agentId); + void createChatQuery(QueryResult queryResult, ChatContext chatCtx); ChatQueryDO getLastChatQuery(long chatId); int updateChatQuery(ChatQueryDO chatQueryDO); + + Long createChatParse(ParseResp parseResult, ChatContext chatCtx, QueryReq queryReq); + + Boolean batchSaveParseInfo(ChatContext chatCtx, QueryReq queryReq, + ParseResp parseResult, + List candidateParses, + List selectedParses); + + public ChatParseDO getParseInfo(Long questionId, String userName, int parseId); + + Boolean deleteChatQuery(Long questionId); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/StatisticsRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/StatisticsRepository.java new file mode 100644 index 000000000..e6b457754 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/StatisticsRepository.java @@ -0,0 +1,11 @@ +package com.tencent.supersonic.chat.persistence.repository; + + +import com.tencent.supersonic.chat.persistence.dataobject.StatisticsDO; + +import java.util.List; + +public interface StatisticsRepository { + + boolean batchSaveStatistics(List list); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatConfigRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatConfigRepositoryImpl.java index 5df0cce0e..6ba9121eb 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatConfigRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatConfigRepositoryImpl.java @@ -1,13 +1,14 @@ package com.tencent.supersonic.chat.persistence.repository.impl; -import com.tencent.supersonic.chat.api.pojo.request.ChatConfigFilter; -import com.tencent.supersonic.chat.api.pojo.response.ChatConfigResp; import com.tencent.supersonic.chat.config.ChatConfig; +import com.tencent.supersonic.chat.api.pojo.request.ChatConfigFilter; import com.tencent.supersonic.chat.config.ChatConfigFilterInternal; +import com.tencent.supersonic.chat.api.pojo.response.ChatConfigResp; import com.tencent.supersonic.chat.persistence.dataobject.ChatConfigDO; -import com.tencent.supersonic.chat.persistence.mapper.ChatConfigMapper; 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 org.springframework.beans.BeanUtils; @@ -23,7 +24,7 @@ public class ChatConfigRepositoryImpl implements ChatConfigRepository { private final ChatConfigMapper chatConfigMapper; public ChatConfigRepositoryImpl(ChatConfigHelper chatConfigHelper, - ChatConfigMapper chatConfigMapper) { + ChatConfigMapper chatConfigMapper) { this.chatConfigHelper = chatConfigHelper; this.chatConfigMapper = chatConfigMapper; } @@ -52,8 +53,8 @@ public class ChatConfigRepositoryImpl implements ChatConfigRepository { List chaConfigDOList = chatConfigMapper.search(filterInternal); if (!CollectionUtils.isEmpty(chaConfigDOList)) { chaConfigDOList.stream().forEach(chaConfigDO -> - chaConfigDescriptorList.add( - chatConfigHelper.chatConfigDO2Descriptor(chaConfigDO.getModelId(), chaConfigDO))); + chaConfigDescriptorList.add(chatConfigHelper + .chatConfigDO2Descriptor(chaConfigDO.getModelId(), chaConfigDO))); } return chaConfigDescriptorList; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatContextRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatContextRepositoryImpl.java index 627411496..cf82a2592 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatContextRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatContextRepositoryImpl.java @@ -52,8 +52,9 @@ public class ChatContextRepositoryImpl implements ChatContextRepository { chatContext.setUser(contextDO.getUser()); chatContext.setQueryText(contextDO.getQueryText()); if (contextDO.getSemanticParse() != null && !contextDO.getSemanticParse().isEmpty()) { - log.info("--->: {}",contextDO.getSemanticParse()); - SemanticParseInfo semanticParseInfo = JsonUtil.toObject(contextDO.getSemanticParse(), SemanticParseInfo.class); + log.info("--->: {}", contextDO.getSemanticParse()); + SemanticParseInfo semanticParseInfo = JsonUtil.toObject(contextDO.getSemanticParse(), + SemanticParseInfo.class); chatContext.setParseInfo(semanticParseInfo); } return chatContext; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatQueryRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatQueryRepositoryImpl.java index bfbe2f884..0d99937c2 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatQueryRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/ChatQueryRepositoryImpl.java @@ -3,20 +3,30 @@ 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.pojo.request.PageQueryInfoReq; -import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.response.ParseResp; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO; 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.QueryResp; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; +import com.tencent.supersonic.chat.persistence.mapper.ChatParseMapper; import com.tencent.supersonic.chat.persistence.mapper.ChatQueryDOMapper; +import com.tencent.supersonic.chat.persistence.mapper.custom.ShowCaseCustomMapper; 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.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Repository; @@ -29,8 +39,16 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { private final ChatQueryDOMapper chatQueryDOMapper; - public ChatQueryRepositoryImpl(ChatQueryDOMapper chatQueryDOMapper) { + private final ChatParseMapper chatParseMapper; + + private final ShowCaseCustomMapper showCaseCustomMapper; + + public ChatQueryRepositoryImpl(ChatQueryDOMapper chatQueryDOMapper, + ChatParseMapper chatParseMapper, + ShowCaseCustomMapper showCaseCustomMapper) { this.chatQueryDOMapper = chatQueryDOMapper; + this.chatParseMapper = chatParseMapper; + this.showCaseCustomMapper = showCaseCustomMapper; } @Override @@ -47,18 +65,27 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { PageInfo chatQueryVOPageInfo = PageUtils.pageInfo2PageInfoVo(pageInfo); chatQueryVOPageInfo.setList( - pageInfo.getList().stream().map(this::convertTo) + pageInfo.getList().stream().filter(o -> !StringUtils.isEmpty(o.getQueryResult())).map(this::convertTo) .sorted(Comparator.comparingInt(o -> o.getQuestionId().intValue())) .collect(Collectors.toList())); return chatQueryVOPageInfo; } + @Override + public List queryShowCase(PageQueryInfoReq pageQueryInfoCommend, int agentId) { + return showCaseCustomMapper.queryShowCase(pageQueryInfoCommend.getCurrent(), + pageQueryInfoCommend.getPageSize(), agentId).stream().map(this::convertTo) + .collect(Collectors.toList()); + } + private QueryResp convertTo(ChatQueryDO chatQueryDO) { QueryResp queryResponse = new QueryResp(); BeanUtils.copyProperties(chatQueryDO, queryResponse); QueryResult queryResult = JsonUtil.toObject(chatQueryDO.getQueryResult(), QueryResult.class); - queryResult.setQueryId(chatQueryDO.getQuestionId()); - queryResponse.setQueryResult(queryResult); + if (queryResult != null) { + queryResult.setQueryId(chatQueryDO.getQuestionId()); + queryResponse.setQueryResult(queryResult); + } return queryResponse; } @@ -71,12 +98,63 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { chatQueryDO.setQueryState(queryResult.getQueryState().ordinal()); chatQueryDO.setQueryText(chatCtx.getQueryText()); chatQueryDO.setQueryResult(JsonUtil.toString(queryResult)); + chatQueryDO.setAgentId(chatCtx.getAgentId()); chatQueryDOMapper.insert(chatQueryDO); ChatQueryDO lastChatQuery = getLastChatQuery(chatCtx.getChatId()); Long queryId = lastChatQuery.getQuestionId(); queryResult.setQueryId(queryId); } + public Long createChatParse(ParseResp parseResult, ChatContext chatCtx, QueryReq queryReq) { + ChatQueryDO chatQueryDO = new ChatQueryDO(); + chatQueryDO.setChatId(Long.valueOf(chatCtx.getChatId())); + chatQueryDO.setCreateTime(new java.util.Date()); + chatQueryDO.setUserName(queryReq.getUser().getName()); + chatQueryDO.setQueryText(queryReq.getQueryText()); + chatQueryDO.setAgentId(queryReq.getAgentId()); + chatQueryDO.setQueryResult(""); + try { + chatQueryDOMapper.insert(chatQueryDO); + } catch (Exception e) { + log.info("database insert has an exception:{}", e.toString()); + } + + ChatQueryDO lastChatQuery = getLastChatQuery(chatCtx.getChatId()); + Long queryId = lastChatQuery.getQuestionId(); + parseResult.setQueryId(queryId); + return queryId; + } + + public Boolean batchSaveParseInfo(ChatContext chatCtx, QueryReq queryReq, + ParseResp parseResult, + List candidateParses, + List selectedParses) { + Long queryId = createChatParse(parseResult, chatCtx, queryReq); + List chatParseDOList = new ArrayList<>(); + log.info("candidateParses size:{},selectedParses size:{}", candidateParses.size(), selectedParses.size()); + getChatParseDO(chatCtx, queryReq, queryId, 0, 1, candidateParses, chatParseDOList); + getChatParseDO(chatCtx, queryReq, queryId, candidateParses.size(), 0, selectedParses, chatParseDOList); + Boolean save = chatParseMapper.batchSaveParseInfo(chatParseDOList); + return save; + } + + public void getChatParseDO(ChatContext chatCtx, QueryReq queryReq, Long queryId, int base, int isCandidate, + List parses, List chatParseDOList) { + for (int i = 0; i < parses.size(); i++) { + ChatParseDO chatParseDO = new ChatParseDO(); + parses.get(i).setId(base + i + 1); + chatParseDO.setChatId(Long.valueOf(chatCtx.getChatId())); + chatParseDO.setQuestionId(queryId); + chatParseDO.setQueryText(queryReq.getQueryText()); + chatParseDO.setParseInfo(JsonUtil.toString(parses.get(i))); + chatParseDO.setIsCandidate(isCandidate); + chatParseDO.setParseId(base + i + 1); + chatParseDO.setCreateTime(new java.util.Date()); + chatParseDO.setUserName(queryReq.getUser().getName()); + chatParseDOList.add(chatParseDO); + } + } + @Override public ChatQueryDO getLastChatQuery(long chatId) { ChatQueryDOExample example = new ChatQueryDOExample(); @@ -96,4 +174,13 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { public int updateChatQuery(ChatQueryDO chatQueryDO) { return chatQueryDOMapper.updateByPrimaryKeyWithBLOBs(chatQueryDO); } + + public ChatParseDO getParseInfo(Long questionId, String userName, int parseId) { + return chatParseMapper.getParseInfo(questionId, userName, parseId); + } + + @Override + public Boolean deleteChatQuery(Long questionId) { + return chatQueryDOMapper.deleteByPrimaryKey(questionId); + } } 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 index 101c97609..1b66b5c90 100644 --- 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 @@ -5,13 +5,14 @@ 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; -import lombok.extern.slf4j.Slf4j; -import org.apache.logging.log4j.util.Strings; -import org.springframework.stereotype.Repository; @Repository @Slf4j diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/StatisticsRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/StatisticsRepositoryImpl.java new file mode 100644 index 000000000..7a8593944 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/persistence/repository/impl/StatisticsRepositoryImpl.java @@ -0,0 +1,29 @@ +package com.tencent.supersonic.chat.persistence.repository.impl; + +import com.tencent.supersonic.chat.persistence.dataobject.StatisticsDO; +import com.tencent.supersonic.chat.persistence.mapper.StatisticsMapper; +import com.tencent.supersonic.chat.persistence.repository.StatisticsRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Primary +@Slf4j +public class StatisticsRepositoryImpl implements StatisticsRepository { + + private final StatisticsMapper statisticsMapper; + + public StatisticsRepositoryImpl(StatisticsMapper statisticsMapper) { + this.statisticsMapper = statisticsMapper; + } + + public boolean batchSaveStatistics(List list) { + return statisticsMapper.batchSaveStatistics(list); + } + + ; + +} 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 index c1f1611ad..b8f1b329a 100644 --- 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 @@ -3,15 +3,17 @@ package com.tencent.supersonic.chat.plugin; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.tencent.supersonic.chat.agent.tool.DslTool; -import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.QueryContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; import com.tencent.supersonic.chat.agent.Agent; import com.tencent.supersonic.chat.agent.tool.AgentToolType; import com.tencent.supersonic.chat.agent.tool.PluginTool; -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.parser.plugin.embedding.EmbeddingConfig; +import com.tencent.supersonic.chat.parser.plugin.embedding.EmbeddingResp; +import com.tencent.supersonic.chat.parser.plugin.embedding.RecallRetrieval; import com.tencent.supersonic.chat.plugin.event.PluginAddEvent; import com.tencent.supersonic.chat.plugin.event.PluginUpdateEvent; import com.tencent.supersonic.chat.query.plugin.ParamOption; @@ -20,10 +22,16 @@ import com.tencent.supersonic.chat.service.AgentService; import com.tencent.supersonic.chat.service.PluginService; import com.tencent.supersonic.common.util.ContextUtils; import java.net.URI; -import java.util.*; +import java.util.List; +import java.util.Collection; +import java.util.Set; +import java.util.Optional; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Objects; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -31,7 +39,11 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.util.Strings; import org.springframework.context.event.EventListener; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.*; +import org.springframework.http.ResponseEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.HttpEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; @@ -149,9 +161,6 @@ public class PluginManager { } public void requestEmbeddingPluginAddALL(List plugins) { - plugins = plugins.stream() - .filter(plugin -> ParseMode.EMBEDDING_RECALL.equals(plugin.getParseMode())) - .collect(Collectors.toList()); requestEmbeddingPluginAdd(convert(plugins)); } @@ -229,11 +238,11 @@ public class PluginManager { } List paramOptions = getSemanticOption(plugin); if (CollectionUtils.isEmpty(paramOptions)) { - return Pair.of(true, Sets.newHashSet()); + return Pair.of(true, pluginMatchedModel); } Set matchedModel = Sets.newHashSet(); - Map> paramOptionMap = paramOptions.stream(). - collect(Collectors.groupingBy(ParamOption::getModelId)); + Map> paramOptionMap = paramOptions.stream() + .collect(Collectors.groupingBy(ParamOption::getModelId)); for (Long modelId : paramOptionMap.keySet()) { List params = paramOptionMap.get(modelId); if (CollectionUtils.isEmpty(params)) { @@ -268,8 +277,8 @@ public class PluginManager { return Sets.newHashSet(); } return schemaElementMatches.stream().filter(schemaElementMatch -> - SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType()) || - SchemaElementType.ID.equals(schemaElementMatch.getElement().getType())) + SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType()) + || SchemaElementType.ID.equals(schemaElementMatch.getElement().getType())) .map(SchemaElementMatch::getElement) .map(SchemaElement::getId) .collect(Collectors.toSet()); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginParseConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginParseConfig.java index d207e586a..5fabd1ce9 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginParseConfig.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/plugin/PluginParseConfig.java @@ -1,12 +1,13 @@ package com.tencent.supersonic.chat.plugin; -import com.tencent.supersonic.chat.parser.function.Parameters; -import java.io.Serializable; -import java.util.List; +import com.tencent.supersonic.chat.parser.plugin.function.Parameters; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; + +import java.io.Serializable; +import java.util.List; import lombok.NoArgsConstructor; import lombok.ToString; @@ -17,12 +18,12 @@ import lombok.ToString; @NoArgsConstructor public class PluginParseConfig implements Serializable { - private String name; - - private String description; - public Parameters parameters; public List examples; + private String name; + + private String description; + } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/HeuristicQuerySelector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/HeuristicQuerySelector.java index 7f14b46d0..eb3043ae2 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/HeuristicQuerySelector.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/HeuristicQuerySelector.java @@ -5,11 +5,13 @@ import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.query.rule.RuleSemanticQuery; + +import java.util.List; +import java.util.ArrayList; +import java.util.OptionalDouble; + import com.tencent.supersonic.chat.query.rule.metric.MetricEntityQuery; import com.tencent.supersonic.chat.query.rule.metric.MetricModelQuery; -import java.util.ArrayList; -import java.util.List; -import java.util.OptionalDouble; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -50,8 +52,8 @@ public class HeuristicQuerySelector implements QuerySelector { return true; } for (SemanticQuery candidateQuery : candidateQueries) { - if (candidateQuery.getQueryMode().equals(MetricEntityQuery.QUERY_MODE) && - semanticQuery.getParseInfo().getScore() == candidateQuery.getParseInfo().getScore()) { + if (candidateQuery.getQueryMode().equals(MetricEntityQuery.QUERY_MODE) + && semanticQuery.getParseInfo().getScore() == candidateQuery.getParseInfo().getScore()) { return false; } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FieldCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FieldCorrector.java deleted file mode 100644 index 1ff0f1ed2..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FieldCorrector.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; - -import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; -import com.tencent.supersonic.common.util.jsqlparser.CCJSqlParserUtils; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class FieldCorrector extends BaseDSLOptimizer { - - @Override - public CorrectionInfo rewriter(CorrectionInfo correctionInfo) { - String replaceFields = CCJSqlParserUtils.replaceFields(correctionInfo.getSql(), - getFieldToBizName(correctionInfo.getParseInfo().getModelId())); - correctionInfo.setSql(replaceFields); - return correctionInfo; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FunctionCorrector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FunctionCorrector.java deleted file mode 100644 index f5cf6af4c..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/optimizer/FunctionCorrector.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; - -import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; -import com.tencent.supersonic.common.util.jsqlparser.CCJSqlParserUtils; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class FunctionCorrector extends BaseDSLOptimizer { - - @Override - public CorrectionInfo rewriter(CorrectionInfo correctionInfo) { - String replaceFunction = CCJSqlParserUtils.replaceFunction(correctionInfo.getSql()); - correctionInfo.setSql(replaceFunction); - return correctionInfo; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/DSLQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/DslQuery.java similarity index 69% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/DSLQuery.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/DslQuery.java index 2971ddc97..64b97bbf0 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/DSLQuery.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/DslQuery.java @@ -1,15 +1,12 @@ -package com.tencent.supersonic.chat.query.dsl; +package com.tencent.supersonic.chat.query.llm.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.request.QueryReq; 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.parser.llm.dsl.DSLParseResult; import com.tencent.supersonic.chat.query.QueryManager; -import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; -import com.tencent.supersonic.chat.api.component.DSLOptimizer; import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; import com.tencent.supersonic.chat.service.SemanticService; import com.tencent.supersonic.chat.utils.ComponentFactory; @@ -29,12 +26,12 @@ import org.springframework.stereotype.Component; @Slf4j @Component -public class DSLQuery extends PluginSemanticQuery { +public class DslQuery extends PluginSemanticQuery { public static final String QUERY_MODE = "DSL"; protected SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - public DSLQuery() { + public DslQuery() { QueryManager.register(this); } @@ -48,31 +45,12 @@ public class DSLQuery extends PluginSemanticQuery { String json = JsonUtil.toString(parseInfo.getProperties().get(Constants.CONTEXT)); DSLParseResult dslParseResult = JsonUtil.toObject(json, DSLParseResult.class); LLMResp llmResp = dslParseResult.getLlmResp(); - QueryReq queryReq = dslParseResult.getRequest(); - - CorrectionInfo correctionInfo = CorrectionInfo.builder() - .queryFilters(queryReq.getQueryFilters()) - .sql(llmResp.getSqlOutput()) - .parseInfo(parseInfo) - .build(); - - List DSLCorrections = ComponentFactory.getSqlCorrections(); - - DSLCorrections.forEach(DSLCorrection -> { - try { - DSLCorrection.rewriter(correctionInfo); - log.info("sqlCorrection:{} sql:{}", DSLCorrection.getClass().getSimpleName(), correctionInfo.getSql()); - } catch (Exception e) { - log.error("sqlCorrection:{} execute error,correctionInfo:{}", DSLCorrection, correctionInfo, e); - } - }); - String querySql = correctionInfo.getSql(); long startTime = System.currentTimeMillis(); - QueryDslReq queryDslReq = QueryReqBuilder.buildDslReq(querySql, parseInfo.getModelId()); + QueryDslReq queryDslReq = QueryReqBuilder.buildDslReq(llmResp.getCorrectorSql(), parseInfo.getModelId()); QueryResultWithSchemaResp queryResp = semanticLayer.queryByDsl(queryDslReq, user); - log.info("queryByDsl cost:{},querySql:{}", System.currentTimeMillis() - startTime, querySql); + log.info("queryByDsl cost:{},querySql:{}", System.currentTimeMillis() - startTime, llmResp.getSqlOutput()); QueryResult queryResult = new QueryResult(); if (Objects.nonNull(queryResp)) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/LLMReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/LLMReq.java similarity index 90% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/LLMReq.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/LLMReq.java index acce57c7e..1dbebeb61 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/LLMReq.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/LLMReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.query.dsl; +package com.tencent.supersonic.chat.query.llm.dsl; import java.util.List; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/LLMResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/LLMResp.java similarity index 76% rename from chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/LLMResp.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/LLMResp.java index 6b1718ecd..a7ead1e87 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/dsl/LLMResp.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/llm/dsl/LLMResp.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.query.dsl; +package com.tencent.supersonic.chat.query.llm.dsl; import java.util.List; import lombok.Data; @@ -17,4 +17,6 @@ public class LLMResp { private String schemaLinkingOutput; private String schemaLinkStr; + + private String correctorSql; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerReq.java index bab24c6ca..6f996b587 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerReq.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerReq.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.query.metricInterpret; +package com.tencent.supersonic.chat.query.metricinterpret; import lombok.Data; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerResp.java index 32f4991ea..5ef6a8d27 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerResp.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/LLmAnswerResp.java @@ -1,11 +1,9 @@ -package com.tencent.supersonic.chat.query.metricInterpret; - +package com.tencent.supersonic.chat.query.metricinterpret; import lombok.Data; @Data public class LLmAnswerResp { - - private String assistant_message; + private String assistantMessage; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/MetricInterpretQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/MetricInterpretQuery.java index 2c48f1fe1..49f8b444e 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/MetricInterpretQuery.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/metricInterpret/MetricInterpretQuery.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.query.metricInterpret; +package com.tencent.supersonic.chat.query.metricinterpret; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; @@ -26,7 +26,11 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.*; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @Slf4j @@ -34,17 +38,17 @@ import java.util.stream.Collectors; public class MetricInterpretQuery extends PluginSemanticQuery { - public final static String QUERY_MODE = "METRIC_INTERPRET"; + public static final String QUERY_MODE = "METRIC_INTERPRET"; + + public MetricInterpretQuery() { + QueryManager.register(this); + } @Override public String getQueryMode() { return QUERY_MODE; } - public MetricInterpretQuery() { - QueryManager.register(this); - } - @Override public QueryResult execute(User user) throws SqlParseException { QueryStructReq queryStructReq = QueryReqBuilder.buildStructReq(parseInfo); @@ -55,10 +59,11 @@ public class MetricInterpretQuery extends PluginSemanticQuery { String text = generateTableText(queryResultWithSchemaResp); Map properties = parseInfo.getProperties(); Map replacedMap = new HashMap<>(); - String textReplaced = replaceText((String) properties.get("queryText"), parseInfo.getElementMatches(), replacedMap); + String textReplaced = replaceText((String) properties.get("queryText"), + parseInfo.getElementMatches(), replacedMap); String answer = replaceAnswer(fetchInterpret(textReplaced, text), replacedMap); QueryResult queryResult = new QueryResult(); - List queryColumns = Lists.newArrayList(new QueryColumn("结果","string","answer")); + List queryColumns = Lists.newArrayList(new QueryColumn("结果", "string", "answer")); Map result = new HashMap<>(); result.put("answer", answer); List> resultList = Lists.newArrayList(); @@ -70,7 +75,8 @@ public class MetricInterpretQuery extends PluginSemanticQuery { return queryResult; } - private String replaceText(String text, List schemaElementMatches, Map replacedMap) { + private String replaceText(String text, List schemaElementMatches, + Map replacedMap) { if (CollectionUtils.isEmpty(schemaElementMatches)) { return text; } @@ -134,10 +140,10 @@ public class MetricInterpretQuery extends PluginSemanticQuery { JSONObject.toJSONString(lLmAnswerReq)); LLmAnswerResp lLmAnswerResp = JSONObject.parseObject(responseEntity.getBody(), LLmAnswerResp.class); if (lLmAnswerResp != null) { - return lLmAnswerResp.getAssistant_message(); + return lLmAnswerResp.getAssistantMessage(); } return null; } -} \ No newline at end of file +} 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 index 82f51f705..29df82412 100644 --- 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 @@ -2,14 +2,15 @@ package com.tencent.supersonic.chat.query.plugin.webpage; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.pojo.ModelSchema; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +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.QueryFilters; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; 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.api.pojo.response.ChatConfigRichResp; import com.tencent.supersonic.chat.plugin.Plugin; import com.tencent.supersonic.chat.plugin.PluginParseResult; import com.tencent.supersonic.chat.query.QueryManager; @@ -17,7 +18,6 @@ import com.tencent.supersonic.chat.query.plugin.ParamOption; import com.tencent.supersonic.chat.query.plugin.PluginSemanticQuery; import com.tencent.supersonic.chat.query.plugin.WebBase; import com.tencent.supersonic.chat.query.plugin.WebBaseResult; -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; @@ -26,8 +26,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.*; -import java.util.stream.Collectors; +import java.util.List; +import java.util.Map; +import java.util.HashMap; @Slf4j @Component @@ -49,8 +50,8 @@ public class WebPageQuery extends PluginSemanticQuery { QueryResult queryResult = new QueryResult(); queryResult.setQueryMode(QUERY_MODE); Map properties = parseInfo.getProperties(); - PluginParseResult pluginParseResult = JsonUtil.toObject(JsonUtil.toString(properties.get(Constants.CONTEXT)) - , PluginParseResult.class); + PluginParseResult pluginParseResult = JsonUtil.toObject(JsonUtil.toString(properties.get(Constants.CONTEXT)), + PluginParseResult.class); WebPageResponse webPageResponse = buildResponse(pluginParseResult); queryResult.setResponse(webPageResponse); SemanticService semanticService = ContextUtils.getBean(SemanticService.class); @@ -111,10 +112,14 @@ public class WebPageQuery extends PluginSemanticQuery { Object queryFilterValue = filterValueMap.get(schemaElementMatch.getElement().getId()); if (queryFilterValue != null) { if (String.valueOf(queryFilterValue).equals(String.valueOf(schemaElementMatch.getWord()))) { - elementValueMap.put(String.valueOf(schemaElementMatch.getElement().getId()), schemaElementMatch.getWord()); + elementValueMap.put( + String.valueOf(schemaElementMatch.getElement().getId()), + schemaElementMatch.getWord()); } } else { - elementValueMap.computeIfAbsent(String.valueOf(schemaElementMatch.getElement().getId()), k -> schemaElementMatch.getWord()); + elementValueMap.computeIfAbsent( + String.valueOf(schemaElementMatch.getElement().getId()), + k -> schemaElementMatch.getWord()); } }); } 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 index 50c20832c..d03ae402b 100644 --- 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 @@ -11,10 +11,10 @@ import com.tencent.supersonic.chat.query.plugin.ParamOption; 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.util.ContextUtils; import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.common.util.ContextUtils; + import java.net.URI; -import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.extern.slf4j.Slf4j; @@ -28,6 +28,9 @@ import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; +import java.util.HashMap; + + @Slf4j @Component public class WebServiceQuery extends PluginSemanticQuery { @@ -50,8 +53,8 @@ public class WebServiceQuery extends PluginSemanticQuery { QueryResult queryResult = new QueryResult(); queryResult.setQueryMode(QUERY_MODE); Map properties = parseInfo.getProperties(); - PluginParseResult pluginParseResult = JsonUtil.toObject(JsonUtil.toString(properties.get(Constants.CONTEXT)), - PluginParseResult.class); + PluginParseResult pluginParseResult = JsonUtil.toObject( + JsonUtil.toString(properties.get(Constants.CONTEXT)), PluginParseResult.class); WebServiceResponse webServiceResponse = buildResponse(pluginParseResult); queryResult.setResponse(webServiceResponse); queryResult.setQueryState(QueryState.SUCCESS); 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 index c011866d3..bab6c3c7f 100644 --- 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 @@ -3,6 +3,7 @@ package com.tencent.supersonic.chat.query.plugin.webservice; import com.tencent.supersonic.chat.query.plugin.WebBase; import lombok.Data; + @Data public class WebServiceResponse { 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 index 873354b5f..2633c4c21 100644 --- 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 @@ -55,9 +55,9 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { parseInfo.setQueryMode(getQueryMode()); SemanticService schemaService = ContextUtils.getBean(SemanticService.class); - ModelSchema ModelSchema = schemaService.getModelSchema(modelId); + ModelSchema modelSchema = schemaService.getModelSchema(modelId); - fillSchemaElement(parseInfo, ModelSchema); + fillSchemaElement(parseInfo, modelSchema); fillScore(parseInfo); fillDateConf(parseInfo, chatContext.getParseInfo()); } @@ -83,8 +83,8 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { Map maxSimilarityMatch = new HashMap<>(); for (SchemaElementMatch match : parseInfo.getElementMatches()) { SchemaElementType type = match.getElement().getType(); - if (!maxSimilarityMatch.containsKey(type) || - match.getSimilarity() > maxSimilarityMatch.get(type).getSimilarity()) { + if (!maxSimilarityMatch.containsKey(type) + || match.getSimilarity() > maxSimilarityMatch.get(type).getSimilarity()) { maxSimilarityMatch.put(type, match); } } @@ -96,8 +96,8 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { parseInfo.setScore(parseInfo.getScore() + totalScore); } - private void fillSchemaElement(SemanticParseInfo parseInfo, ModelSchema ModelSchema) { - parseInfo.setModel(ModelSchema.getModel()); + private void fillSchemaElement(SemanticParseInfo parseInfo, ModelSchema modelSchema) { + parseInfo.setModel(modelSchema.getModel()); Map> dim2Values = new HashMap<>(); Map> id2Values = new HashMap<>(); @@ -106,7 +106,7 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { SchemaElement element = schemaMatch.getElement(); switch (element.getType()) { case ID: - SchemaElement entityElement = ModelSchema.getElement(SchemaElementType.ENTITY, element.getId()); + SchemaElement entityElement = modelSchema.getElement(SchemaElementType.ENTITY, element.getId()); if (entityElement != null) { if (id2Values.containsKey(element.getId())) { id2Values.get(element.getId()).add(schemaMatch); @@ -116,7 +116,7 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { } break; case VALUE: - SchemaElement dimElement = ModelSchema.getElement(SchemaElementType.DIMENSION, element.getId()); + SchemaElement dimElement = modelSchema.getElement(SchemaElementType.DIMENSION, element.getId()); if (dimElement != null) { if (dim2Values.containsKey(element.getId())) { dim2Values.get(element.getId()).add(schemaMatch); @@ -140,7 +140,7 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { if (!id2Values.isEmpty()) { for (Map.Entry> entry : id2Values.entrySet()) { - SchemaElement entity = ModelSchema.getElement(SchemaElementType.ENTITY, entry.getKey()); + SchemaElement entity = modelSchema.getElement(SchemaElementType.ENTITY, entry.getKey()); if (entry.getValue().size() == 1) { SchemaElementMatch schemaMatch = entry.getValue().get(0); @@ -151,7 +151,7 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { dimensionFilter.setOperator(FilterOperatorEnum.EQUALS); dimensionFilter.setElementID(schemaMatch.getElement().getId()); parseInfo.getDimensionFilters().add(dimensionFilter); - parseInfo.setEntity(ModelSchema.getEntity()); + parseInfo.setEntity(modelSchema.getEntity()); } else { QueryFilter dimensionFilter = new QueryFilter(); List vals = new ArrayList<>(); @@ -168,7 +168,7 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { if (!dim2Values.isEmpty()) { for (Map.Entry> entry : dim2Values.entrySet()) { - SchemaElement dimension = ModelSchema.getElement(SchemaElementType.DIMENSION, entry.getKey()); + SchemaElement dimension = modelSchema.getElement(SchemaElementType.DIMENSION, entry.getKey()); if (entry.getValue().size() == 1) { SchemaElementMatch schemaMatch = entry.getValue().get(0); @@ -179,7 +179,7 @@ public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { dimensionFilter.setOperator(FilterOperatorEnum.EQUALS); dimensionFilter.setElementID(schemaMatch.getElement().getId()); parseInfo.getDimensionFilters().add(dimensionFilter); - parseInfo.setEntity(ModelSchema.getEntity()); + parseInfo.setEntity(modelSchema.getEntity()); } else { QueryFilter dimensionFilter = new QueryFilter(); List vals = new ArrayList<>(); 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 index 83edfab1e..7c3d2ed1f 100644 --- 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 @@ -2,8 +2,8 @@ package com.tencent.supersonic.chat.query.rule.entity; import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.DIMENSION; import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ID; -import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; 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; 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 index bc88440c3..e5d1ec561 100644 --- 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 @@ -1,9 +1,8 @@ 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.OptionType.OPTIONAL; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; -import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.*; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; 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 index 2ee4bf18f..e1dce47ee 100644 --- 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 @@ -1,9 +1,9 @@ package com.tencent.supersonic.chat.query.rule.entity; +import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.QueryContext; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.ModelSchema; -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.api.pojo.response.ChatConfigRichResp; import com.tencent.supersonic.chat.api.pojo.response.ChatDefaultRichConfigResp; @@ -12,6 +12,7 @@ import com.tencent.supersonic.chat.service.SemanticService; 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.Objects; import java.util.Set; @@ -30,15 +31,15 @@ public abstract class EntityListQuery extends EntitySemanticQuery { ConfigService configService = ContextUtils.getBean(ConfigService.class); ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(parseInfo.getModelId()); SemanticService schemaService = ContextUtils.getBean(SemanticService.class); - ModelSchema ModelSchema = schemaService.getModelSchema(modelId); + ModelSchema modelSchema = schemaService.getModelSchema(modelId); if (chaConfigRichDesc != null && chaConfigRichDesc.getChatDetailRichConfig() != null - && Objects.nonNull(ModelSchema) && Objects.nonNull(ModelSchema.getEntity())) { + && Objects.nonNull(modelSchema) && Objects.nonNull(modelSchema.getEntity())) { Set dimensions = new LinkedHashSet(); Set metrics = new LinkedHashSet(); Set orders = new LinkedHashSet(); - ChatDefaultRichConfigResp chatDefaultConfig = chaConfigRichDesc.getChatDetailRichConfig() - .getChatDefaultConfig(); + ChatDefaultRichConfigResp chatDefaultConfig = chaConfigRichDesc + .getChatDetailRichConfig().getChatDefaultConfig(); if (chatDefaultConfig != null) { chatDefaultConfig.getMetrics().stream() .forEach(metric -> { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricEntityQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricEntityQuery.java index db9697259..f07749a93 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricEntityQuery.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/query/rule/metric/MetricEntityQuery.java @@ -1,23 +1,24 @@ package com.tencent.supersonic.chat.query.rule.metric; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; -import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ID; -import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; -import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; - import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; 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.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ID; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; @Slf4j @Component 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 index 23c987178..a125cabeb 100644 --- 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 @@ -1,12 +1,12 @@ package com.tencent.supersonic.chat.query.rule.metric; +import org.springframework.stereotype.Component; + 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.OptionType.REQUIRED; import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST; - -import org.springframework.stereotype.Component; +import static com.tencent.supersonic.chat.query.rule.QueryMatchOption.OptionType.REQUIRED; @Component public class MetricGroupByQuery extends MetricSemanticQuery { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/AgentController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/AgentController.java index 49c6c5474..79a41b5ab 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/rest/AgentController.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/AgentController.java @@ -4,13 +4,19 @@ import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; import com.tencent.supersonic.chat.agent.Agent; import com.tencent.supersonic.chat.service.AgentService; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; @RestController -@RequestMapping("/api/chat/agent") +@RequestMapping({"/api/chat/agent", "/openapi/chat/agent"}) public class AgentController { private AgentService agentService; 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 6f34d8dda..88612800a 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 @@ -9,7 +9,6 @@ import com.tencent.supersonic.chat.api.pojo.request.ChatConfigEditReqReq; import com.tencent.supersonic.chat.api.pojo.request.ChatConfigFilter; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigResp; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigRichResp; -import com.tencent.supersonic.chat.service.ConfigService; import com.tencent.supersonic.chat.utils.ComponentFactory; import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.PageDimensionReq; @@ -18,9 +17,12 @@ 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.ModelResp; +import com.tencent.supersonic.chat.service.ConfigService; + 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.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -44,16 +46,16 @@ public class ChatConfigController { @PostMapping public Long addChatConfig(@RequestBody ChatConfigBaseReq extendBaseCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return configService.addConfig(extendBaseCmd, user); } @PutMapping public Long editModelExtend(@RequestBody ChatConfigEditReqReq extendEditCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return configService.editConfig(extendEditCmd, user); } @@ -61,8 +63,8 @@ public class ChatConfigController { @PostMapping("/search") public List search(@RequestBody ChatConfigFilter filter, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return configService.search(filter, user); } @@ -80,44 +82,44 @@ public class ChatConfigController { @GetMapping("/modelList/{domainId}") public List getModelList(@PathVariable("domainId") Long domainId, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return semanticLayer.getModelList(AuthType.ADMIN, domainId, user); } - @GetMapping("/domainList") - public List getDomainList(HttpServletRequest request, - HttpServletResponse response) { - User user = UserHolder.findUser(request, response); - return semanticLayer.getDomainList(user); - } - @GetMapping("/modelList") public List getModelList(HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return semanticLayer.getModelList(AuthType.ADMIN, null, user); } + @GetMapping("/domainList") + public List getDomainList(HttpServletRequest request, + HttpServletResponse response) { + User user = UserHolder.findUser(request, response); + return semanticLayer.getDomainList(user); + } + @GetMapping("/modelList/view") public List getModelListVisible(HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return semanticLayer.getModelList(AuthType.VISIBLE, null, user); } @PostMapping("/dimension/page") public PageInfo getDimension(@RequestBody PageDimensionReq pageDimensionCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { return semanticLayer.getDimensionPage(pageDimensionCmd); } @PostMapping("/metric/page") public PageInfo getMetric(@RequestBody PageMetricReq pageMetrricCmd, - HttpServletRequest request, - HttpServletResponse response) { + 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 d836660eb..fd74ca0f1 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,9 +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.api.pojo.request.PageQueryInfoReq; -import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +import com.tencent.supersonic.chat.api.pojo.response.ShowCaseResp; import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +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; @@ -69,11 +70,17 @@ public class ChatController { @PostMapping("/pageQueryInfo") public PageInfo pageQueryInfo(@RequestBody PageQueryInfoReq pageQueryInfoCommand, - @RequestParam(value = "chatId") long chatId, - HttpServletRequest request, - HttpServletResponse response) { + @RequestParam(value = "chatId") long chatId, + HttpServletRequest request, + HttpServletResponse response) { pageQueryInfoCommand.setUserName(UserHolder.findUser(request, response).getName()); return chatService.queryInfo(pageQueryInfoCommand, chatId); } + @PostMapping("/queryShowCase") + public ShowCaseResp queryShowCase(@RequestBody PageQueryInfoReq pageQueryInfoCommand, + @RequestParam(value = "agentId") int agentId) { + return chatService.queryShowCase(pageQueryInfoCommand, agentId); + } + } 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 43702f9c1..45f0aecfc 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 @@ -3,8 +3,8 @@ package com.tencent.supersonic.chat.rest; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq; -import com.tencent.supersonic.chat.api.pojo.request.QueryDataReq; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.request.QueryDataReq; import com.tencent.supersonic.chat.service.QueryService; import com.tencent.supersonic.chat.service.SearchService; import javax.servlet.http.HttpServletRequest; @@ -33,7 +33,7 @@ public class ChatQueryController { @PostMapping("search") public Object search(@RequestBody QueryReq queryCtx, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) { queryCtx.setUser(UserHolder.findUser(request, response)); return searchService.search(queryCtx); } @@ -53,8 +53,8 @@ public class ChatQueryController { } @PostMapping("execute") - public Object execute(@RequestBody ExecuteQueryReq queryCtx, HttpServletRequest request, - HttpServletResponse response) + public Object execute(@RequestBody ExecuteQueryReq queryCtx, + HttpServletRequest request, HttpServletResponse response) throws Exception { queryCtx.setUser(UserHolder.findUser(request, response)); return queryService.performExecution(queryCtx); @@ -62,14 +62,14 @@ public class ChatQueryController { @PostMapping("queryContext") public Object queryContext(@RequestBody QueryReq queryCtx, HttpServletRequest request, - HttpServletResponse response) throws Exception { + HttpServletResponse response) throws Exception { queryCtx.setUser(UserHolder.findUser(request, response)); return queryService.queryContext(queryCtx); } @PostMapping("queryData") - public Object queryData(@RequestBody QueryDataReq queryData, HttpServletRequest request, - HttpServletResponse response) + public Object queryData(@RequestBody QueryDataReq 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/PluginController.java b/chat/core/src/main/java/com/tencent/supersonic/chat/rest/PluginController.java index 0202c7f98..32a1705ec 100644 --- 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 @@ -5,31 +5,29 @@ 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 java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +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; - } + @Autowired + protected PluginService pluginService; @PostMapping public boolean createPlugin(@RequestBody Plugin plugin, - HttpServletRequest httpServletRequest, - HttpServletResponse httpServletResponse) { + HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse) { User user = UserHolder.findUser(httpServletRequest, httpServletResponse); pluginService.createPlugin(plugin, user); return true; @@ -37,8 +35,8 @@ public class PluginController { @PutMapping public boolean updatePlugin(@RequestBody Plugin plugin, - HttpServletRequest httpServletRequest, - HttpServletResponse httpServletResponse) { + HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse) { User user = UserHolder.findUser(httpServletRequest, httpServletResponse); pluginService.updatePlugin(plugin, user); return true; @@ -57,8 +55,8 @@ public class PluginController { @PostMapping("/query") List query(@RequestBody PluginQueryReq pluginQueryReq, - HttpServletRequest httpServletRequest, - HttpServletResponse httpServletResponse) { + HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse) { User user = UserHolder.findUser(httpServletRequest, httpServletResponse); return pluginService.queryWithAuthCheck(pluginQueryReq, user); } 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 dbeb5a449..42021f944 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 @@ -5,15 +5,18 @@ import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.api.pojo.response.RecommendQuestionResp; import com.tencent.supersonic.chat.api.pojo.response.RecommendResp; import com.tencent.supersonic.chat.service.RecommendService; -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.RestController; +import org.springframework.web.bind.annotation.RequestMapping; 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.RequestParam; -import org.springframework.web.bind.annotation.RestController; + +import java.util.List; /** * recommend controller @@ -27,9 +30,9 @@ public class RecommendController { @GetMapping("recommend/{modelId}") public RecommendResp recommend(@PathVariable("modelId") Long modelId, - @RequestParam(value = "limit", required = false) Long limit, - HttpServletRequest request, - HttpServletResponse response) { + @RequestParam(value = "limit", required = false) Long limit, + HttpServletRequest request, + HttpServletResponse response) { QueryReq queryCtx = new QueryReq(); queryCtx.setUser(UserHolder.findUser(request, response)); queryCtx.setModelId(modelId); @@ -38,9 +41,9 @@ public class RecommendController { @GetMapping("recommend/metric/{modelId}") public RecommendResp recommendMetricMode(@PathVariable("modelId") Long modelId, - @RequestParam(value = "limit", required = false) Long limit, - HttpServletRequest request, - HttpServletResponse response) { + @RequestParam(value = "limit", required = false) Long limit, + HttpServletRequest request, + HttpServletResponse response) { QueryReq queryCtx = new QueryReq(); queryCtx.setUser(UserHolder.findUser(request, response)); queryCtx.setModelId(modelId); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/AgentService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/AgentService.java index 2d247f6ea..8ce2308d8 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/service/AgentService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/AgentService.java @@ -2,7 +2,10 @@ package com.tencent.supersonic.chat.service; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.agent.Agent; +import com.tencent.supersonic.chat.agent.tool.AgentToolType; +import com.tencent.supersonic.chat.agent.tool.DslTool; import java.util.List; +import java.util.Set; public interface AgentService { @@ -15,5 +18,9 @@ public interface AgentService { Agent getAgent(Integer id); void deleteAgent(Integer id); - + + List getDslTools(Integer agentId, AgentToolType agentToolType); + + Set getDslToolsModelIds(Integer agentId, AgentToolType agentToolType); + } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/ChatService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/ChatService.java index 56ba6c806..df2a81e81 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/service/ChatService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/ChatService.java @@ -3,11 +3,16 @@ 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.request.PageQueryInfoReq; -import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.response.ParseResp; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.ShowCaseResp; import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO; import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; import java.util.List; public interface ChatService { @@ -39,9 +44,22 @@ public interface ChatService { PageInfo queryInfo(PageQueryInfoReq pageQueryInfoCommend, long chatId); + ShowCaseResp queryShowCase(PageQueryInfoReq pageQueryInfoCommend, int agentId); + public void addQuery(QueryResult queryResult, ChatContext chatCtx); + public void batchAddParse(ChatContext chatCtx, QueryReq queryReq, + ParseResp parseResult, + List candidateParses, + List selectedParses); + public ChatQueryDO getLastQuery(long chatId); public int updateQuery(ChatQueryDO chatQueryDO); + + public Boolean updateQuery(Long questionId, QueryResult queryResult, ChatContext chatCtx); + + public ChatParseDO getParseInfo(Long questionId, String userName, int parseId); + + public Boolean deleteChatQuery(Long questionId); } 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 index af1a43bd4..275a0ddaf 100644 --- 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 @@ -81,17 +81,17 @@ public class SemanticService { private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); public ModelSchema getModelSchema(Long id) { - ModelSchema ModelSchema = schemaService.getModelSchema(id); - if (!Objects.isNull(ModelSchema) && !Objects.isNull(ModelSchema.getModel())) { + ModelSchema modelSchema = schemaService.getModelSchema(id); + if (!Objects.isNull(modelSchema) && !Objects.isNull(modelSchema.getModel())) { ChatConfigResp chaConfigInfo = - configService.fetchConfigByModelId(ModelSchema.getModel().getId()); + configService.fetchConfigByModelId(modelSchema.getModel().getId()); // filter dimensions in blacklist - filterBlackDim(ModelSchema, chaConfigInfo); + filterBlackDim(modelSchema, chaConfigInfo); // filter metrics in blacklist - filterBlackMetric(ModelSchema, chaConfigInfo); + filterBlackMetric(modelSchema, chaConfigInfo); } - return ModelSchema; + return modelSchema; } public EntityInfo getEntityInfo(SemanticParseInfo parseInfo, User user) { @@ -103,20 +103,20 @@ public class SemanticService { return entityInfo; } if (entityInfo.getModelInfo() != null && entityInfo.getModelInfo().getPrimaryEntityBizName() != null) { - String ModelInfoPrimaryName = entityInfo.getModelInfo().getPrimaryEntityBizName(); - String ModelInfoId = ""; + String modelInfoPrimaryName = entityInfo.getModelInfo().getPrimaryEntityBizName(); + String modelInfoId = ""; for (QueryFilter chatFilter : parseInfo.getDimensionFilters()) { if (chatFilter != null && chatFilter.getBizName() != null && chatFilter.getBizName() - .equals(ModelInfoPrimaryName)) { + .equals(modelInfoPrimaryName)) { if (chatFilter.getOperator().equals(FilterOperatorEnum.EQUALS)) { - ModelInfoId = chatFilter.getValue().toString(); + modelInfoId = chatFilter.getValue().toString(); } } } - if (!"".equals(ModelInfoId)) { + if (!"".equals(modelInfoId)) { try { setMainModel(entityInfo, parseInfo.getModelId(), - ModelInfoId, user); + modelInfoId, user); return entityInfo; } catch (Exception e) { @@ -128,8 +128,8 @@ public class SemanticService { return null; } - public EntityInfo getEntityInfo(Long Model) { - ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(Model); + public EntityInfo getEntityInfo(Long model) { + ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(model); if (Objects.isNull(chaConfigRichDesc) || Objects.isNull(chaConfigRichDesc.getChatDetailRichConfig())) { return new EntityInfo(); } @@ -142,20 +142,20 @@ public class SemanticService { Long modelId = chaConfigRichDesc.getModelId(); if (Objects.nonNull(chaConfigRichDesc) && Objects.nonNull(modelId)) { SemanticService schemaService = ContextUtils.getBean(SemanticService.class); - ModelSchema ModelSchema = schemaService.getModelSchema(modelId); - if (Objects.isNull(ModelSchema) || Objects.isNull(ModelSchema.getEntity())) { + ModelSchema modelSchema = schemaService.getModelSchema(modelId); + if (Objects.isNull(modelSchema) || Objects.isNull(modelSchema.getEntity())) { return entityInfo; } - ModelInfo ModelInfo = new ModelInfo(); - ModelInfo.setItemId(modelId.intValue()); - ModelInfo.setName(ModelSchema.getModel().getName()); - ModelInfo.setWords(ModelSchema.getModel().getAlias()); - ModelInfo.setBizName(ModelSchema.getModel().getBizName()); - if (Objects.nonNull(ModelSchema.getEntity())) { - ModelInfo.setPrimaryEntityBizName(ModelSchema.getEntity().getBizName()); + ModelInfo modelInfo = new ModelInfo(); + modelInfo.setItemId(modelId.intValue()); + modelInfo.setName(modelSchema.getModel().getName()); + modelInfo.setWords(modelSchema.getModel().getAlias()); + modelInfo.setBizName(modelSchema.getModel().getBizName()); + if (Objects.nonNull(modelSchema.getEntity())) { + modelInfo.setPrimaryEntityBizName(modelSchema.getEntity().getBizName()); } - entityInfo.setModelInfo(ModelInfo); + entityInfo.setModelInfo(modelInfo); List dimensions = new ArrayList<>(); List metrics = new ArrayList<>(); @@ -189,19 +189,19 @@ public class SemanticService { return entityInfo; } - public void setMainModel(EntityInfo ModelInfo, Long Model, String entity, User user) { - ModelSchema ModelSchema = schemaService.getModelSchema(Model); + public void setMainModel(EntityInfo modelInfo, Long model, String entity, User user) { + ModelSchema modelSchema = schemaService.getModelSchema(model); - ModelInfo.setEntityId(entity); + modelInfo.setEntityId(entity); SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); - semanticParseInfo.setModel(ModelSchema.getModel()); + semanticParseInfo.setModel(modelSchema.getModel()); semanticParseInfo.setNativeQuery(true); - semanticParseInfo.setMetrics(getMetrics(ModelInfo)); - semanticParseInfo.setDimensions(getDimensions(ModelInfo)); + semanticParseInfo.setMetrics(getMetrics(modelInfo)); + semanticParseInfo.setDimensions(getDimensions(modelInfo)); DateConf dateInfo = new DateConf(); int unit = 1; ChatConfigResp chatConfigInfo = - configService.fetchConfigByModelId(ModelSchema.getModel().getId()); + configService.fetchConfigByModelId(modelSchema.getModel().getId()); if (Objects.nonNull(chatConfigInfo) && Objects.nonNull(chatConfigInfo.getChatDetailConfig()) && Objects.nonNull(chatConfigInfo.getChatDetailConfig().getChatDefaultConfig())) { ChatDefaultConfigReq chatDefaultConfig = chatConfigInfo.getChatDetailConfig().getChatDefaultConfig(); @@ -220,7 +220,7 @@ public class SemanticService { QueryFilter chatFilter = new QueryFilter(); chatFilter.setValue(String.valueOf(entity)); chatFilter.setOperator(FilterOperatorEnum.EQUALS); - chatFilter.setBizName(getEntityPrimaryName(ModelInfo)); + chatFilter.setBizName(getEntityPrimaryName(modelInfo)); Set chatFilters = new LinkedHashSet(); chatFilters.add(chatFilter); semanticParseInfo.setDimensionFilters(chatFilters); @@ -242,18 +242,18 @@ public class SemanticService { if (entry.getValue() == null || entryKey == null) { continue; } - ModelInfo.getDimensions().stream().filter(i -> entryKey.equals(i.getBizName())) + modelInfo.getDimensions().stream().filter(i -> entryKey.equals(i.getBizName())) .forEach(i -> i.setValue(entry.getValue().toString())); - ModelInfo.getMetrics().stream().filter(i -> entryKey.equals(i.getBizName())) + modelInfo.getMetrics().stream().filter(i -> entryKey.equals(i.getBizName())) .forEach(i -> i.setValue(entry.getValue().toString())); } } } } - private Set getDimensions(EntityInfo ModelInfo) { + private Set getDimensions(EntityInfo modelInfo) { Set dimensions = new LinkedHashSet(); - for (DataInfo mainEntityDimension : ModelInfo.getDimensions()) { + for (DataInfo mainEntityDimension : modelInfo.getDimensions()) { SchemaElement dimension = new SchemaElement(); dimension.setBizName(mainEntityDimension.getBizName()); dimensions.add(dimension); @@ -270,9 +270,9 @@ public class SemanticService { return entryKey; } - private Set getMetrics(EntityInfo ModelInfo) { + private Set getMetrics(EntityInfo modelInfo) { Set metrics = new LinkedHashSet(); - for (DataInfo metricValue : ModelInfo.getMetrics()) { + for (DataInfo metricValue : modelInfo.getMetrics()) { SchemaElement metric = new SchemaElement(); BeanUtils.copyProperties(metricValue, metric); metrics.add(metric); @@ -280,31 +280,31 @@ public class SemanticService { return metrics; } - private String getEntityPrimaryName(EntityInfo ModelInfo) { - return ModelInfo.getModelInfo().getPrimaryEntityBizName(); + private String getEntityPrimaryName(EntityInfo modelInfo) { + return modelInfo.getModelInfo().getPrimaryEntityBizName(); } - private void filterBlackMetric(ModelSchema ModelSchema, ChatConfigResp chaConfigInfo) { + private void filterBlackMetric(ModelSchema modelSchema, ChatConfigResp chaConfigInfo) { ItemVisibility visibility = generateFinalVisibility(chaConfigInfo); if (Objects.nonNull(chaConfigInfo) && Objects.nonNull(visibility) && !CollectionUtils.isEmpty(visibility.getBlackMetricIdList()) - && !CollectionUtils.isEmpty(ModelSchema.getMetrics())) { - Set metric4Chat = ModelSchema.getMetrics().stream() + && !CollectionUtils.isEmpty(modelSchema.getMetrics())) { + Set metric4Chat = modelSchema.getMetrics().stream() .filter(metric -> !visibility.getBlackMetricIdList().contains(metric.getId())) .collect(Collectors.toSet()); - ModelSchema.setMetrics(metric4Chat); + modelSchema.setMetrics(metric4Chat); } } - private void filterBlackDim(ModelSchema ModelSchema, ChatConfigResp chatConfigInfo) { + private void filterBlackDim(ModelSchema modelSchema, ChatConfigResp chatConfigInfo) { ItemVisibility visibility = generateFinalVisibility(chatConfigInfo); if (Objects.nonNull(chatConfigInfo) && Objects.nonNull(visibility) && !CollectionUtils.isEmpty(visibility.getBlackDimIdList()) - && !CollectionUtils.isEmpty(ModelSchema.getDimensions())) { - Set dim4Chat = ModelSchema.getDimensions().stream() + && !CollectionUtils.isEmpty(modelSchema.getDimensions())) { + Set dim4Chat = modelSchema.getDimensions().stream() .filter(dim -> !visibility.getBlackDimIdList().contains(dim.getId())) .collect(Collectors.toSet()); - ModelSchema.setDimensions(dim4Chat); + modelSchema.setDimensions(dim4Chat); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/StatisticsService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/StatisticsService.java new file mode 100644 index 000000000..ce62d9e8b --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/StatisticsService.java @@ -0,0 +1,9 @@ +package com.tencent.supersonic.chat.service; + +import com.tencent.supersonic.chat.persistence.dataobject.StatisticsDO; + +import java.util.List; + +public interface StatisticsService { + boolean batchSaveStatistics(List list); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/AgentServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/AgentServiceImpl.java index b4aa7dc86..df1651f0c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/AgentServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/AgentServiceImpl.java @@ -1,16 +1,23 @@ package com.tencent.supersonic.chat.service.impl; import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.agent.Agent; +import com.tencent.supersonic.chat.agent.tool.AgentToolType; +import com.tencent.supersonic.chat.agent.tool.DslTool; import com.tencent.supersonic.chat.persistence.dataobject.AgentDO; import com.tencent.supersonic.chat.persistence.repository.AgentRepository; import com.tencent.supersonic.chat.service.AgentService; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; -import java.util.Date; -import java.util.List; -import java.util.stream.Collectors; +import org.springframework.util.CollectionUtils; @Service public class AgentServiceImpl implements AgentService { @@ -54,18 +61,18 @@ public class AgentServiceImpl implements AgentService { return agentRepository.getAgents(); } - private Agent convert(AgentDO agentDO){ - if (agentDO == null ) { + private Agent convert(AgentDO agentDO) { + if (agentDO == null) { return null; } Agent agent = new Agent(); - BeanUtils.copyProperties(agentDO,agent); + BeanUtils.copyProperties(agentDO, agent); agent.setAgentConfig(agentDO.getConfig()); agent.setExamples(JSONObject.parseArray(agentDO.getExamples(), String.class)); return agent; } - private AgentDO convert(Agent agent, User user){ + private AgentDO convert(Agent agent, User user) { AgentDO agentDO = new AgentDO(); BeanUtils.copyProperties(agent, agentDO); agentDO.setConfig(agent.getAgentConfig()); @@ -79,4 +86,27 @@ public class AgentServiceImpl implements AgentService { } return agentDO; } + + public List getDslTools(Integer agentId, AgentToolType agentToolType) { + Agent agent = getAgent(agentId); + if (agent == null) { + return Lists.newArrayList(); + } + List tools = agent.getTools(agentToolType); + if (CollectionUtils.isEmpty(tools)) { + return Lists.newArrayList(); + } + return tools.stream().map(tool -> JSONObject.parseObject(tool, DslTool.class)).collect(Collectors.toList()); + } + + public Set getDslToolsModelIds(Integer agentId, AgentToolType agentToolType) { + List dslTools = getDslTools(agentId, agentToolType); + if (CollectionUtils.isEmpty(dslTools)) { + return new HashSet<>(); + } + return dslTools.stream().map(DslTool::getModelIds) + .filter(modelIds -> !CollectionUtils.isEmpty(modelIds)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ChatServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ChatServiceImpl.java index 1919069e6..30bd0411a 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ChatServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ChatServiceImpl.java @@ -4,19 +4,28 @@ 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.SemanticParseInfo; -import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq; -import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.response.ParseResp; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.api.pojo.response.ShowCaseResp; import com.tencent.supersonic.chat.persistence.dataobject.ChatDO; +import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO; import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; import com.tencent.supersonic.chat.persistence.dataobject.QueryDO; +import com.tencent.supersonic.chat.api.pojo.response.QueryResp; +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 com.tencent.supersonic.chat.service.ChatService; + import java.text.SimpleDateFormat; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; + +import com.tencent.supersonic.chat.service.ChatService; +import com.tencent.supersonic.common.util.JsonUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; @@ -31,7 +40,7 @@ public class ChatServiceImpl implements ChatService { private ChatQueryRepository chatQueryRepository; public ChatServiceImpl(ChatContextRepository chatContextRepository, ChatRepository chatRepository, - ChatQueryRepository chatQueryRepository) { + ChatQueryRepository chatQueryRepository) { this.chatContextRepository = chatContextRepository; this.chatRepository = chatRepository; this.chatQueryRepository = chatQueryRepository; @@ -119,6 +128,18 @@ public class ChatServiceImpl implements ChatService { return chatQueryRepository.getChatQuery(pageQueryInfoCommend, chatId); } + @Override + public ShowCaseResp queryShowCase(PageQueryInfoReq pageQueryInfoCommend, int agentId) { + ShowCaseResp showCaseResp = new ShowCaseResp(); + List queryResps = chatQueryRepository.queryShowCase(pageQueryInfoCommend, agentId); + Map> showCaseMap = queryResps.stream() + .collect(Collectors.groupingBy(QueryResp::getChatId)); + showCaseResp.setShowCaseMap(showCaseMap); + showCaseResp.setCurrent(pageQueryInfoCommend.getCurrent()); + showCaseResp.setPageSize(pageQueryInfoCommend.getPageSize()); + return showCaseResp; + } + @Override public void addQuery(QueryResult queryResult, ChatContext chatCtx) { chatQueryRepository.createChatQuery(queryResult, chatCtx); @@ -127,8 +148,15 @@ public class ChatServiceImpl implements ChatService { } @Override - public ChatQueryDO getLastQuery(long chatId) { - return chatQueryRepository.getLastChatQuery(chatId); + public Boolean updateQuery(Long questionId, QueryResult queryResult, ChatContext chatCtx) { + ChatQueryDO chatQueryDO = new ChatQueryDO(); + chatQueryDO.setQuestionId(questionId); + chatQueryDO.setQueryResult(JsonUtil.toString(queryResult)); + chatQueryDO.setQueryState(1); + updateQuery(chatQueryDO); + chatRepository.updateLastQuestion(chatCtx.getChatId().longValue(), + chatCtx.getQueryText(), getCurrentTime()); + return true; } @Override @@ -136,9 +164,31 @@ public class ChatServiceImpl implements ChatService { return chatQueryRepository.updateChatQuery(chatQueryDO); } + @Override + public void batchAddParse(ChatContext chatCtx, QueryReq queryReq, + ParseResp parseResult, + List candidateParses, + List selectedParses) { + chatQueryRepository.batchSaveParseInfo(chatCtx, queryReq, parseResult, candidateParses, selectedParses); + + } + + @Override + public ChatQueryDO getLastQuery(long chatId) { + return chatQueryRepository.getLastChatQuery(chatId); + } + private String getCurrentTime() { SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return tempDate.format(new java.util.Date()); } + public ChatParseDO getParseInfo(Long questionId, String userName, int parseId) { + return chatQueryRepository.getParseInfo(questionId, userName, parseId); + } + + public Boolean deleteChatQuery(Long questionId) { + return chatQueryRepository.deleteChatQuery(questionId); + } + } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ConfigServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ConfigServiceImpl.java index db284e4f6..49a40f615 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ConfigServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/ConfigServiceImpl.java @@ -5,35 +5,37 @@ import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.chat.api.pojo.ModelSchema; import com.tencent.supersonic.chat.api.pojo.SchemaElement; +import com.tencent.supersonic.chat.api.pojo.request.ChatConfigEditReqReq; +import com.tencent.supersonic.chat.api.pojo.request.ItemVisibility; +import com.tencent.supersonic.chat.api.pojo.request.ChatDetailConfigReq; import com.tencent.supersonic.chat.api.pojo.request.ChatAggConfigReq; import com.tencent.supersonic.chat.api.pojo.request.ChatConfigBaseReq; -import com.tencent.supersonic.chat.api.pojo.request.ChatConfigEditReqReq; import com.tencent.supersonic.chat.api.pojo.request.ChatConfigFilter; -import com.tencent.supersonic.chat.api.pojo.request.ChatDefaultConfigReq; -import com.tencent.supersonic.chat.api.pojo.request.ChatDetailConfigReq; import com.tencent.supersonic.chat.api.pojo.request.Entity; -import com.tencent.supersonic.chat.api.pojo.request.ItemVisibility; +import com.tencent.supersonic.chat.api.pojo.request.ChatDefaultConfigReq; import com.tencent.supersonic.chat.api.pojo.request.KnowledgeInfoReq; -import com.tencent.supersonic.chat.api.pojo.response.ChatAggRichConfigResp; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigResp; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigRichResp; import com.tencent.supersonic.chat.api.pojo.response.ChatDefaultRichConfigResp; +import com.tencent.supersonic.chat.api.pojo.response.ChatAggRichConfigResp; import com.tencent.supersonic.chat.api.pojo.response.ChatDetailRichConfigResp; import com.tencent.supersonic.chat.api.pojo.response.EntityRichInfoResp; import com.tencent.supersonic.chat.api.pojo.response.ItemVisibilityInfo; import com.tencent.supersonic.chat.config.ChatConfig; -import com.tencent.supersonic.chat.persistence.repository.ChatConfigRepository; import com.tencent.supersonic.chat.service.ConfigService; import com.tencent.supersonic.chat.service.SemanticService; -import com.tencent.supersonic.chat.utils.ChatConfigHelper; import com.tencent.supersonic.chat.utils.ComponentFactory; +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; import java.util.Map; import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -54,7 +56,7 @@ public class ConfigServiceImpl implements ConfigService { public ConfigServiceImpl(ChatConfigRepository chatConfigRepository, - ChatConfigHelper chatConfigHelper) { + ChatConfigHelper chatConfigHelper) { this.chatConfigRepository = chatConfigRepository; this.chatConfigHelper = chatConfigHelper; } @@ -116,7 +118,7 @@ public class ConfigServiceImpl implements ConfigService { private ItemVisibilityInfo fetchVisibilityDescByConfig(ItemVisibility visibility, - ModelSchema modelSchema) { + ModelSchema modelSchema) { ItemVisibilityInfo itemVisibilityDesc = new ItemVisibilityInfo(); List dimIdAllList = chatConfigHelper.generateAllDimIdList(modelSchema); @@ -169,19 +171,20 @@ public class ConfigServiceImpl implements ConfigService { } private ChatDetailRichConfigResp fillChatDetailRichConfig(ModelSchema modelSchema, - ChatConfigRichResp chatConfigRich, ChatConfigResp chatConfigResp) { + ChatConfigRichResp chatConfigRich, + ChatConfigResp chatConfigResp) { if (Objects.isNull(chatConfigResp) || Objects.isNull(chatConfigResp.getChatDetailConfig())) { return null; } ChatDetailRichConfigResp detailRichConfig = new ChatDetailRichConfigResp(); ChatDetailConfigReq chatDetailConfig = chatConfigResp.getChatDetailConfig(); - ItemVisibilityInfo itemVisibilityInfo = fetchVisibilityDescByConfig(chatDetailConfig.getVisibility(), - modelSchema); + ItemVisibilityInfo itemVisibilityInfo = fetchVisibilityDescByConfig( + chatDetailConfig.getVisibility(), modelSchema); detailRichConfig.setVisibility(itemVisibilityInfo); detailRichConfig.setKnowledgeInfos(fillKnowledgeBizName(chatDetailConfig.getKnowledgeInfos(), modelSchema)); detailRichConfig.setGlobalKnowledgeConfig(chatDetailConfig.getGlobalKnowledgeConfig()); - detailRichConfig.setChatDefaultConfig( - fetchDefaultConfig(chatDetailConfig.getChatDefaultConfig(), modelSchema, itemVisibilityInfo)); + detailRichConfig.setChatDefaultConfig(fetchDefaultConfig(chatDetailConfig.getChatDefaultConfig(), + modelSchema, itemVisibilityInfo)); return detailRichConfig; } @@ -209,14 +212,15 @@ public class ConfigServiceImpl implements ConfigService { chatAggRichConfig.setVisibility(itemVisibilityInfo); chatAggRichConfig.setKnowledgeInfos(fillKnowledgeBizName(chatAggConfig.getKnowledgeInfos(), modelSchema)); chatAggRichConfig.setGlobalKnowledgeConfig(chatAggConfig.getGlobalKnowledgeConfig()); - chatAggRichConfig.setChatDefaultConfig( - fetchDefaultConfig(chatAggConfig.getChatDefaultConfig(), modelSchema, itemVisibilityInfo)); + chatAggRichConfig.setChatDefaultConfig(fetchDefaultConfig(chatAggConfig.getChatDefaultConfig(), + modelSchema, itemVisibilityInfo)); return chatAggRichConfig; } private ChatDefaultRichConfigResp fetchDefaultConfig(ChatDefaultConfigReq chatDefaultConfig, - ModelSchema modelSchema, ItemVisibilityInfo itemVisibilityInfo) { + ModelSchema modelSchema, + ItemVisibilityInfo itemVisibilityInfo) { ChatDefaultRichConfigResp defaultRichConfig = new ChatDefaultRichConfigResp(); if (Objects.isNull(chatDefaultConfig)) { return defaultRichConfig; @@ -232,8 +236,8 @@ public class ConfigServiceImpl implements ConfigService { List metrics = new ArrayList<>(); if (!CollectionUtils.isEmpty(chatDefaultConfig.getDimensionIds())) { chatDefaultConfig.getDimensionIds().stream() - .filter(dimId -> dimIdAndRespPair.containsKey(dimId) && itemVisibilityInfo.getWhiteDimIdList() - .contains(dimId)) + .filter(dimId -> dimIdAndRespPair.containsKey(dimId) + && itemVisibilityInfo.getWhiteDimIdList().contains(dimId)) .forEach(dimId -> { SchemaElement dimSchemaResp = dimIdAndRespPair.get(dimId); if (Objects.nonNull(dimSchemaResp)) { @@ -266,7 +270,7 @@ public class ConfigServiceImpl implements ConfigService { private List fillKnowledgeBizName(List knowledgeInfos, - ModelSchema modelSchema) { + ModelSchema modelSchema) { if (CollectionUtils.isEmpty(knowledgeInfos)) { return new ArrayList<>(); } 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 index 32ca44efb..601cc8e67 100644 --- 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 @@ -14,15 +14,17 @@ 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.common.pojo.enums.AuthType; import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.response.ModelResp; + import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; @@ -39,7 +41,7 @@ public class PluginServiceImpl implements PluginService { private ApplicationEventPublisher publisher; public PluginServiceImpl(PluginRepository pluginRepository, - ApplicationEventPublisher publisher) { + ApplicationEventPublisher publisher) { this.pluginRepository = pluginRepository; this.publisher = publisher; } @@ -115,8 +117,9 @@ public class PluginServiceImpl implements PluginService { 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()))) + pluginDO.getPattern().contains(pluginQueryReq.getPattern()) + || (pluginDO.getName() != null + && pluginDO.getName().contains(pluginQueryReq.getPattern()))) .collect(Collectors.toList()); } return convertList(pluginDOS); @@ -130,8 +133,8 @@ public class PluginServiceImpl implements PluginService { if (StringUtils.isBlank(plugin.getParseModeConfig())) { return false; } - PluginParseConfig functionCallConfig = JsonUtil.toObject(plugin.getParseModeConfig(), - PluginParseConfig.class); + PluginParseConfig functionCallConfig = JsonUtil.toObject( + plugin.getParseModeConfig(), PluginParseConfig.class); if (Objects.isNull(functionCallConfig) || StringUtils.isEmpty(functionCallConfig.getName())) { return false; } 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 index cedb2689c..4ea03f75c 100644 --- 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 @@ -2,29 +2,42 @@ 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.component.SchemaMapper; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +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.SemanticParseInfo; import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.response.EntityInfo; import com.tencent.supersonic.chat.api.pojo.response.ParseResp; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; import com.tencent.supersonic.chat.api.pojo.response.QueryState; +import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO; +import com.tencent.supersonic.chat.persistence.dataobject.CostType; +import com.tencent.supersonic.chat.persistence.dataobject.StatisticsDO; import com.tencent.supersonic.chat.query.QuerySelector; import com.tencent.supersonic.chat.api.pojo.request.QueryDataReq; 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.service.SemanticService; +import com.tencent.supersonic.chat.service.StatisticsService; import com.tencent.supersonic.chat.utils.ComponentFactory; + +import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; + +import com.tencent.supersonic.common.util.ContextUtils; 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.beans.factory.annotation.Value; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; @@ -37,6 +50,13 @@ public class QueryServiceImpl implements QueryService { @Autowired private ChatService chatService; + @Autowired + private StatisticsService statisticsService; + + private final String entity = "ENTITY"; + + @Value("${time.threshold: 100}") + private Integer timeThreshold; private List schemaMappers = ComponentFactory.getSchemaMappers(); private List semanticParsers = ComponentFactory.getSemanticParsers(); @@ -47,17 +67,25 @@ public class QueryServiceImpl implements QueryService { QueryContext queryCtx = new QueryContext(queryReq); // in order to support multi-turn conversation, chat context is needed ChatContext chatCtx = chatService.getOrCreateContext(queryReq.getChatId()); - + List timeCostDOList = new ArrayList<>(); schemaMappers.stream().forEach(mapper -> { + Long startTime = System.currentTimeMillis(); mapper.map(queryCtx); - log.info("{} result:{}", mapper.getClass().getSimpleName(), JsonUtil.toString(queryCtx)); + Long endTime = System.currentTimeMillis(); + String className = mapper.getClass().getSimpleName(); + timeCostDOList.add(StatisticsDO.builder().cost((int) (endTime - startTime)) + .interfaceName(className).type(CostType.MAPPER.getType()).build()); + log.info("{} result:{}", className, JsonUtil.toString(queryCtx)); }); - semanticParsers.stream().forEach(parser -> { + Long startTime = System.currentTimeMillis(); parser.parse(queryCtx, chatCtx); - log.info("{} result:{}", parser.getClass().getSimpleName(), JsonUtil.toString(queryCtx)); + Long endTime = System.currentTimeMillis(); + String className = parser.getClass().getSimpleName(); + timeCostDOList.add(StatisticsDO.builder().cost((int) (endTime - startTime)) + .interfaceName(className).type(CostType.PARSER.getType()).build()); + log.info("{} result:{}", className, JsonUtil.toString(queryCtx)); }); - ParseResp parseResult; if (queryCtx.getCandidateQueries().size() > 0) { log.debug("pick before [{}]", queryCtx.getCandidateQueries().stream().collect( @@ -70,9 +98,15 @@ public class QueryServiceImpl implements QueryService { .map(SemanticQuery::getParseInfo) .sorted(Comparator.comparingDouble(SemanticParseInfo::getScore).reversed()) .collect(Collectors.toList()); + selectedParses.forEach(parseInfo -> { + if (parseInfo.getQueryMode().contains(entity)) { + EntityInfo entityInfo = ContextUtils.getBean(SemanticService.class) + .getEntityInfo(parseInfo, queryReq.getUser()); + parseInfo.setEntityInfo(entityInfo); + } + }); List candidateParses = queryCtx.getCandidateQueries().stream() .map(SemanticQuery::getParseInfo).collect(Collectors.toList()); - parseResult = ParseResp.builder() .chatId(queryReq.getChatId()) .queryText(queryReq.getQueryText()) @@ -80,6 +114,9 @@ public class QueryServiceImpl implements QueryService { .selectedParses(selectedParses) .candidateParses(candidateParses) .build(); + chatService.batchAddParse(chatCtx, queryReq, parseResult, candidateParses, selectedParses); + saveInfo(timeCostDOList, queryReq.getQueryText(), parseResult.getQueryId(), + queryReq.getUser().getName(), queryReq.getChatId().longValue()); } else { parseResult = ParseResp.builder() .chatId(queryReq.getChatId()) @@ -87,13 +124,15 @@ public class QueryServiceImpl implements QueryService { .state(ParseResp.ParseState.FAILED) .build(); } - return parseResult; } @Override public QueryResult performExecution(ExecuteQueryReq queryReq) throws Exception { - SemanticParseInfo parseInfo = queryReq.getParseInfo(); + ChatParseDO chatParseDO = chatService.getParseInfo(queryReq.getQueryId(), + queryReq.getUser().getName(), queryReq.getParseId()); + List timeCostDOList = new ArrayList<>(); + SemanticParseInfo parseInfo = JsonUtil.toObject(chatParseDO.getParseInfo(), SemanticParseInfo.class); SemanticQuery semanticQuery = QueryManager.createQuery(parseInfo.getQueryMode()); if (semanticQuery == null) { return null; @@ -102,9 +141,15 @@ public class QueryServiceImpl implements QueryService { // in order to support multi-turn conversation, chat context is needed ChatContext chatCtx = chatService.getOrCreateContext(queryReq.getChatId()); - + chatCtx.setAgentId(queryReq.getAgentId()); + Long startTime = System.currentTimeMillis(); QueryResult queryResult = semanticQuery.execute(queryReq.getUser()); + Long endTime = System.currentTimeMillis(); if (queryResult != null) { + timeCostDOList.add(StatisticsDO.builder().cost((int) (endTime - startTime)) + .interfaceName(semanticQuery.getClass().getSimpleName()).type(CostType.QUERY.getType()).build()); + saveInfo(timeCostDOList, queryReq.getQueryText(), queryReq.getQueryId(), + queryReq.getUser().getName(), queryReq.getChatId().longValue()); queryResult.setChatContext(parseInfo); // update chat context after a successful semantic query if (queryReq.isSaveAnswer() && QueryState.SUCCESS.equals(queryResult.getQueryState())) { @@ -113,12 +158,33 @@ public class QueryServiceImpl implements QueryService { } chatCtx.setQueryText(queryReq.getQueryText()); chatCtx.setUser(queryReq.getUser().getName()); - chatService.addQuery(queryResult, chatCtx); + //chatService.addQuery(queryResult, chatCtx); + chatService.updateQuery(queryReq.getQueryId(), queryResult, chatCtx); + } else { + chatService.deleteChatQuery(queryReq.getQueryId()); } return queryResult; } + public void saveInfo(List timeCostDOList, + String queryText, Long queryId, + String userName, Long chatId) { + List list = timeCostDOList.stream() + .filter(o -> o.getCost() > timeThreshold).collect(Collectors.toList()); + list.forEach(o -> { + o.setQueryText(queryText); + o.setQuestionId(queryId); + o.setUserName(userName); + o.setChatId(chatId); + o.setCreateTime(new java.util.Date()); + }); + if (list.size() > 0) { + log.info("filterStatistics size:{},data:{}", list.size(), JsonUtil.toString(list)); + statisticsService.batchSaveStatistics(list); + } + } + @Override public QueryResult executeQuery(QueryReq queryReq) throws Exception { QueryContext queryCtx = new QueryContext(queryReq); 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 index d5e8380d9..704062d91 100644 --- 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 @@ -3,20 +3,22 @@ package com.tencent.supersonic.chat.service.impl; import com.tencent.supersonic.chat.api.pojo.ModelSchema; import com.tencent.supersonic.chat.api.pojo.SchemaElement; -import com.tencent.supersonic.chat.api.pojo.request.ChatConfigFilter; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.response.RecommendQuestionResp; +import com.tencent.supersonic.chat.api.pojo.request.ChatConfigFilter; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigResp; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigRichResp; -import com.tencent.supersonic.chat.api.pojo.response.RecommendQuestionResp; import com.tencent.supersonic.chat.api.pojo.response.RecommendResp; -import com.tencent.supersonic.chat.service.ConfigService; -import com.tencent.supersonic.chat.service.RecommendService; -import com.tencent.supersonic.chat.service.SemanticService; + 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; @@ -112,10 +114,11 @@ public class RecommendServiceImpl implements RecommendService { 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 RecommendQuestionResp(chatConfigResp.getModelId(), - chatConfigResp.getRecommendedQuestions())); + if (Objects.nonNull(chatConfigResp) + && !CollectionUtils.isEmpty(chatConfigResp.getRecommendedQuestions())) { + recommendQuestions.add( + new RecommendQuestionResp(chatConfigResp.getModelId(), + chatConfigResp.getRecommendedQuestions())); } }); return recommendQuestions; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/SearchServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/SearchServiceImpl.java index 599a14a5a..9828d2581 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/SearchServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/SearchServiceImpl.java @@ -10,17 +10,19 @@ 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.QueryReq; import com.tencent.supersonic.chat.api.pojo.response.SearchResult; -import com.tencent.supersonic.chat.mapper.MatchText; -import com.tencent.supersonic.chat.mapper.ModelInfoStat; +import com.tencent.supersonic.chat.mapper.MapperHelper; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.knowledge.dictionary.ModelInfoStat; import com.tencent.supersonic.chat.mapper.ModelWithSemanticType; +import com.tencent.supersonic.chat.mapper.MatchText; import com.tencent.supersonic.chat.mapper.SearchMatchStrategy; import com.tencent.supersonic.chat.service.AgentService; 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.utils.NatureHelper; import com.tencent.supersonic.knowledge.dictionary.DictWord; -import com.tencent.supersonic.knowledge.dictionary.DictWordType; 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; @@ -59,10 +61,10 @@ public class SearchServiceImpl implements SearchService { private AgentService agentService; @Override - public List search(QueryReq queryCtx) { + public List search(QueryReq queryReq) { // 1. check search enable - Integer agentId = queryCtx.getAgentId(); + Integer agentId = queryReq.getAgentId(); if (agentId != null) { Agent agent = agentService.getAgent(agentId); if (!agent.enableSearch()) { @@ -70,7 +72,7 @@ public class SearchServiceImpl implements SearchService { } } - String queryText = queryCtx.getQueryText(); + String queryText = queryReq.getQueryText(); // 2.get meta info SemanticSchema semanticSchemaDb = schemaService.getSemanticSchema(); List metricsDb = semanticSchemaDb.getMetrics(); @@ -78,8 +80,11 @@ public class SearchServiceImpl implements SearchService { // 3.detect by segment List originals = HanlpHelper.getTerms(queryText); - Map> regTextMap = searchMatchStrategy.match(queryText, originals, - queryCtx.getModelId()); + + MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); + Set detectModelIds = mapperHelper.getModelIds(queryReq); + + Map> regTextMap = searchMatchStrategy.match(queryReq, originals, detectModelIds); regTextMap.entrySet().stream().forEach(m -> HanlpHelper.transLetterOriginal(m.getValue())); // 4.get the most matching data @@ -96,12 +101,12 @@ public class SearchServiceImpl implements SearchService { return Lists.newArrayList(); } Map.Entry> searchTextEntry = mostSimilarSearchResult.get(); - log.info("searchTextEntry:{},queryCtx:{}", searchTextEntry, queryCtx); + log.info("searchTextEntry:{},queryReq:{}", searchTextEntry, queryReq); Set searchResults = new LinkedHashSet(); ModelInfoStat modelStat = NatureHelper.getModelStat(originals); - List possibleModels = getPossibleModels(queryCtx, originals, modelStat, queryCtx.getModelId()); + List possibleModels = getPossibleModels(queryReq, originals, modelStat, queryReq.getModelId()); // 5.1 priority dimension metric boolean existMetricAndDimension = searchMetricAndDimension(new HashSet<>(possibleModels), modelToName, @@ -116,7 +121,7 @@ public class SearchServiceImpl implements SearchService { Set searchResultSet = searchDimensionValue(metricsDb, modelToName, modelStat.getMetricModelCount(), existMetricAndDimension, - matchText, natureToNameMap, natureToNameEntry, queryCtx.getQueryFilters()); + matchText, natureToNameMap, natureToNameEntry, queryReq.getQueryFilters()); searchResults.addAll(searchResultSet); } @@ -265,7 +270,7 @@ public class SearchServiceImpl implements SearchService { posDO.setWord(entry.getName()); posDO.setNature(nature); return posDO; - } + } )).sorted(Comparator.comparingInt(a -> a.getWord().length())) .collect(Collectors.toMap(DictWord::getNature, DictWord::getWord, (value1, value2) -> value1, LinkedHashMap::new)); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/StatisticsServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/StatisticsServiceImpl.java new file mode 100644 index 000000000..9309152e4 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/service/impl/StatisticsServiceImpl.java @@ -0,0 +1,25 @@ +package com.tencent.supersonic.chat.service.impl; + +import com.tencent.supersonic.chat.persistence.dataobject.StatisticsDO; +import com.tencent.supersonic.chat.persistence.repository.StatisticsRepository; +import com.tencent.supersonic.chat.service.StatisticsService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service("statisticsService") +@Slf4j +public class StatisticsServiceImpl implements StatisticsService { + + private StatisticsRepository statisticsRepository; + + public StatisticsServiceImpl(StatisticsRepository statisticsRepository) { + this.statisticsRepository = statisticsRepository; + } + + @Override + public boolean batchSaveStatistics(List list) { + return statisticsRepository.batchSaveStatistics(list); + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ChatConfigHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ChatConfigHelper.java index 125279aef..6106a86e9 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ChatConfigHelper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ChatConfigHelper.java @@ -5,23 +5,25 @@ import static com.tencent.supersonic.common.pojo.Constants.ADMIN_LOWER; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.chat.api.pojo.ModelSchema; import com.tencent.supersonic.chat.api.pojo.SchemaElement; -import com.tencent.supersonic.chat.api.pojo.request.ChatAggConfigReq; import com.tencent.supersonic.chat.api.pojo.request.ChatConfigBaseReq; -import com.tencent.supersonic.chat.api.pojo.request.ChatConfigEditReqReq; +import com.tencent.supersonic.chat.api.pojo.request.ChatAggConfigReq; import com.tencent.supersonic.chat.api.pojo.request.ChatDetailConfigReq; +import com.tencent.supersonic.chat.api.pojo.request.ChatConfigEditReqReq; import com.tencent.supersonic.chat.api.pojo.request.ItemVisibility; import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestionReq; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigResp; import com.tencent.supersonic.chat.config.ChatConfig; import com.tencent.supersonic.chat.persistence.dataobject.ChatConfigDO; -import com.tencent.supersonic.common.pojo.RecordInfo; 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.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; @@ -120,6 +122,7 @@ public class ChatConfigHelper { chatConfigDescriptor.setUpdatedBy(chatConfigDO.getUpdatedBy()); chatConfigDescriptor.setUpdatedAt(chatConfigDO.getUpdatedAt()); + if (Strings.isEmpty(chatConfigDO.getChatAggConfig())) { chatConfigDescriptor.setChatAggConfig(generateEmptyChatAggConfigResp()); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ComponentFactory.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ComponentFactory.java index e32ebba1b..1277356fc 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ComponentFactory.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/ComponentFactory.java @@ -4,12 +4,12 @@ import com.tencent.supersonic.chat.api.component.SchemaMapper; import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.chat.api.component.SemanticParser; -import com.tencent.supersonic.chat.api.component.DSLOptimizer; +import com.tencent.supersonic.chat.api.component.SemanticCorrector; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import com.tencent.supersonic.chat.parser.function.ModelResolver; +import com.tencent.supersonic.chat.parser.plugin.function.ModelResolver; import com.tencent.supersonic.chat.query.QuerySelector; import org.apache.commons.collections.CollectionUtils; import org.springframework.core.io.support.SpringFactoriesLoader; @@ -19,7 +19,7 @@ public class ComponentFactory { private static List schemaMappers = new ArrayList<>(); private static List semanticParsers = new ArrayList<>(); - private static List dslCorrections = new ArrayList<>(); + private static List dslCorrections = new ArrayList<>(); private static SemanticLayer semanticLayer; private static QuerySelector querySelector; private static ModelResolver modelResolver; @@ -31,8 +31,8 @@ public class ComponentFactory { return CollectionUtils.isEmpty(semanticParsers) ? init(SemanticParser.class, semanticParsers) : semanticParsers; } - public static List getSqlCorrections() { - return CollectionUtils.isEmpty(dslCorrections) ? init(DSLOptimizer.class, dslCorrections) : dslCorrections; + public static List getSqlCorrections() { + return CollectionUtils.isEmpty(dslCorrections) ? init(SemanticCorrector.class, dslCorrections) : dslCorrections; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictMetaHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictMetaHelper.java index 310137955..87173e509 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictMetaHelper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/DictMetaHelper.java @@ -10,12 +10,13 @@ import com.tencent.supersonic.chat.api.pojo.request.KnowledgeAdvancedConfig; import com.tencent.supersonic.chat.api.pojo.request.KnowledgeInfoReq; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigRichResp; import com.tencent.supersonic.chat.api.pojo.response.ChatDefaultRichConfigResp; -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.config.DefaultMetric; 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; import java.util.HashSet; @@ -24,6 +25,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; + import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -126,16 +128,17 @@ public class DictMetaHelper { } private void fillDimValueDOList(List dimValueDOList, Long modelId, - Map dimIdAndDescPair) { + Map dimIdAndDescPair) { ChatConfigRichResp chaConfigRichDesc = configService.getConfigRichInfo(modelId); if (Objects.nonNull(chaConfigRichDesc) && Objects.nonNull(chaConfigRichDesc.getChatAggRichConfig())) { - ChatDefaultRichConfigResp chatDefaultConfig = chaConfigRichDesc.getChatAggRichConfig() - .getChatDefaultConfig(); - List knowledgeAggInfo = chaConfigRichDesc.getChatAggRichConfig().getKnowledgeInfos(); + ChatDefaultRichConfigResp chatDefaultConfig = + chaConfigRichDesc.getChatAggRichConfig().getChatDefaultConfig(); + List knowledgeAggInfo = + chaConfigRichDesc.getChatAggRichConfig().getKnowledgeInfos(); - List knowledgeDetailInfo = chaConfigRichDesc.getChatDetailRichConfig() - .getKnowledgeInfos(); + List knowledgeDetailInfo = + chaConfigRichDesc.getChatDetailRichConfig().getKnowledgeInfos(); fillKnowledgeDimValue(knowledgeDetailInfo, chatDefaultConfig, dimValueDOList, dimIdAndDescPair, modelId); fillKnowledgeDimValue(knowledgeAggInfo, chatDefaultConfig, dimValueDOList, dimIdAndDescPair, modelId); @@ -145,22 +148,23 @@ public class DictMetaHelper { } private void fillKnowledgeDimValue(List knowledgeInfos, - ChatDefaultRichConfigResp chatDefaultConfig, - List dimValueDOList, Map dimIdAndDescPair, Long modelId) { + ChatDefaultRichConfigResp chatDefaultConfig, + List dimValueDOList, + Map dimIdAndDescPair, Long modelId) { if (!CollectionUtils.isEmpty(knowledgeInfos)) { List dimensions = new ArrayList<>(); List defaultMetricDescList = new ArrayList<>(); knowledgeInfos.stream() - .filter(knowledgeInfo -> knowledgeInfo.getSearchEnable() && !CollectionUtils.isEmpty( - dimIdAndDescPair) + .filter(knowledgeInfo -> knowledgeInfo.getSearchEnable() + && !CollectionUtils.isEmpty(dimIdAndDescPair) && dimIdAndDescPair.containsKey(knowledgeInfo.getItemId())) .forEach(knowledgeInfo -> { if (dimIdAndDescPair.containsKey(knowledgeInfo.getItemId())) { SchemaElement dimensionDesc = dimIdAndDescPair.get(knowledgeInfo.getItemId()); //default cnt - if (Objects.isNull(chatDefaultConfig) || CollectionUtils.isEmpty( - chatDefaultConfig.getMetrics())) { + if (Objects.isNull(chatDefaultConfig) + || CollectionUtils.isEmpty(chatDefaultConfig.getMetrics())) { String datasourceBizName = dimensionDesc.getBizName(); if (Strings.isNotEmpty(datasourceBizName)) { String internalMetricName = @@ -169,9 +173,8 @@ public class DictMetaHelper { } } else { SchemaElement schemaItem = chatDefaultConfig.getMetrics().get(0); - defaultMetricDescList.add( - new DefaultMetric(schemaItem.getBizName(), chatDefaultConfig.getUnit(), - chatDefaultConfig.getPeriod())); + defaultMetricDescList.add(new DefaultMetric(schemaItem.getBizName(), + chatDefaultConfig.getUnit(), chatDefaultConfig.getPeriod())); } @@ -180,7 +183,8 @@ public class DictMetaHelper { dim4Dict.setDimId(knowledgeInfo.getItemId()); dim4Dict.setBizName(bizName); if (Objects.nonNull(knowledgeInfo.getKnowledgeAdvancedConfig())) { - KnowledgeAdvancedConfig knowledgeAdvancedConfig = knowledgeInfo.getKnowledgeAdvancedConfig(); + KnowledgeAdvancedConfig knowledgeAdvancedConfig + = knowledgeInfo.getKnowledgeAdvancedConfig(); BeanUtils.copyProperties(knowledgeAdvancedConfig, dim4Dict); } dimensions.add(dim4Dict); 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 index 380f80bb3..6b955b7ac 100644 --- 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 @@ -17,6 +17,7 @@ import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import java.time.LocalDate; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -81,7 +82,24 @@ public class QueryReqBuilder { BeanUtils.copyProperties(dateInfo, dateInfoNew); if (Objects.nonNull(dateInfo) && DateConf.DateMode.RECENT.equals(dateInfo.getDateMode())) { int unit = dateInfo.getUnit(); - String startDate = LocalDate.now().plusDays(-unit).toString(); + int days = 1; + switch (dateInfo.getPeriod()) { + case Constants.DAY: + days = 1; + break; + case Constants.WEEK: + days = 7; + break; + case Constants.MONTH: + days = 30; + break; + case Constants.YEAR: + days = 365; + break; + default: + break; + } + String startDate = LocalDate.now().plusDays(-(unit * days)).toString(); String endDate = LocalDate.now().plusDays(-1).toString(); dateInfoNew.setDateMode(DateConf.DateMode.BETWEEN); dateInfoNew.setStartDate(startDate); @@ -159,7 +177,13 @@ public class QueryReqBuilder { dimension.setBizName(dateField); if (QueryManager.isMetricQuery(queryMode)) { - parseInfo.getDimensions().add(dimension); + List timeDimensions = Arrays.asList(TimeDimensionEnum.DAY.getName(), + TimeDimensionEnum.WEEK.getName(), TimeDimensionEnum.MONTH.getName()); + Set dimensions = parseInfo.getDimensions().stream() + .filter(d -> !timeDimensions.contains(d.getBizName().toLowerCase())).collect( + Collectors.toSet()); + dimensions.add(dimension); + parseInfo.setDimensions(dimensions); } } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/SchemaMatchHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/SchemaMatchHelper.java index a9e684799..dfaeb6532 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/SchemaMatchHelper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/utils/SchemaMatchHelper.java @@ -38,7 +38,7 @@ public class SchemaMatchHelper { } private static boolean isMetricOrDimension(SchemaElementMatch elementMatch) { - return SchemaElementType.METRIC.equals(elementMatch.getElement().getType()) || - SchemaElementType.DIMENSION.equals(elementMatch.getElement().getType()); + return SchemaElementType.METRIC.equals(elementMatch.getElement().getType()) + || SchemaElementType.DIMENSION.equals(elementMatch.getElement().getType()); } } diff --git a/chat/core/src/main/python/bin/install.sh b/chat/core/src/main/python/bin/install.sh index 9e68a6fd2..df8800a19 100755 --- a/chat/core/src/main/python/bin/install.sh +++ b/chat/core/src/main/python/bin/install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash binDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$binDir/.." && pwd -P) +baseDir=$(readlink -f $binDir/../) echo $binDir source ${binDir}/env.sh diff --git a/chat/core/src/main/python/bin/run.sh b/chat/core/src/main/python/bin/run.sh index 8f7af2f23..8ed1a9d90 100755 --- a/chat/core/src/main/python/bin/run.sh +++ b/chat/core/src/main/python/bin/run.sh @@ -4,7 +4,7 @@ llm_host=$1 llm_port=$2 binDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$binDir/.." && pwd -P) +baseDir=$(readlink -f $binDir/../) source ${baseDir}/bin/env.sh diff --git a/chat/core/src/main/python/bin/service.sh b/chat/core/src/main/python/bin/service.sh index a1788b5fb..bd3ae8e0a 100755 --- a/chat/core/src/main/python/bin/service.sh +++ b/chat/core/src/main/python/bin/service.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash binDir=$(cd "$(dirname "$0")"; pwd) -baseDir=$(cd "$binDir/.." && pwd -P) +baseDir=$(readlink -f $binDir/../) source ${baseDir}/bin/env.sh command=$1 diff --git a/chat/core/src/main/python/llm/api_service.py b/chat/core/src/main/python/llm/api_service.py index c06748b74..a5bd975f2 100644 --- a/chat/core/src/main/python/llm/api_service.py +++ b/chat/core/src/main/python/llm/api_service.py @@ -25,31 +25,20 @@ app = FastAPI() @app.post("/query2sql/") async def din_query2sql(query_body: Mapping[str, Any]): - if 'queryText' not in query_body: - raise HTTPException(status_code=400, + if 'queryText' not in query_body: + raise HTTPException(status_code=400, detail="query_text is not in query_body") - else: - query_text = query_body['queryText'] + else: + query_text = query_body['queryText'] - if 'schema' not in query_body: - raise HTTPException(status_code=400, detail="schema is not in query_body") - else: - schema = query_body['schema'] + if 'schema' not in query_body: + raise HTTPException(status_code=400, detail="schema is not in query_body") + else: + schema = query_body['schema'] - if 'currentDate' not in query_body: - raise HTTPException(status_code=400, detail="currentDate is not in query_body") - else: - current_date = query_body['currentDate'] + resp = query2sql(query_text=query_text, schema=schema) - if 'linking' not in query_body: - linking = None - else: - linking = query_body['linking'] - - resp = query2sql(query_text=query_text, - schema=schema, current_date=current_date, linking=linking) - - return resp + return resp @app.post("/preset_query_retrival/") 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 63fad8222..000000000 --- a/chat/core/src/main/python/llm/few_shot_example/sql_exampler.py +++ /dev/null @@ -1,296 +0,0 @@ -examplars= [ - { "current_date":"2020-12-01", - "table_name":"内容库产品", - "fields_list":"""["部门", "模块", "用户名", "访问次数", "访问人数", "访问时长", "数据日期"]""", - "question":"比较jerryjzhang和lexluo在内容库的访问次数", - "prior_schema_links":"""['jerryjzhang'->用户名, 'lexluo'->用户名]""", - "analysis": """让我们一步一步地思考。在问题“比较jerryjzhang和lexluo在内容库的访问次数“中,我们被问: -“比较jerryjzhang和lexluo”,所以我们需要column=[用户名] -”内容库的访问次数“,所以我们需要column=[访问次数] -基于table和columns,可能的cell values 是 = ['jerryjzhang', 'lexluo']。""", - "schema_links":"""["用户名", "访问次数", "'jerryjzhang'", "'lexluo'"]""", - "sql":"""select 用户名, 访问次数 from 内容库产品 where 用户名 in ('jerryjzhang', 'lexluo') and 数据日期 = '2020-12-01' """ - }, - { "current_date":"2022-11-06", - "table_name":"内容库产品", - "fields_list":"""["部门", "模块", "用户名", "访问次数", "访问人数", "访问时长", "数据日期"]""", - "question":"内容库近12个月访问人数 按部门", - "prior_schema_links":"""[]""", - "analysis": """让我们一步一步地思考。在问题“内容库近12个月访问人数 按部门“中,我们被问: -”内容库近12个月“,所以我们需要column=[数据日期] -“访问人数”,所以我们需要column=[访问人数] -”按部门“,所以我们需要column=[部门] -基于table和columns,可能的cell values 是 = [12]。""", - "schema_links":"""["访问人数", "部门", "数据日期", 12]""", - "sql":"""select 部门, 数据日期, 访问人数 from 内容库产品 where datediff('month', 数据日期, '2022-11-06') <= 12 """ - }, - { "current_date":"2023-04-21", - "table_name":"内容库产品", - "fields_list":"""["部门", "模块", "用户名", "访问次数", "访问人数", "访问时长", "数据日期"]""", - "question":"内容库内容合作部、生态业务部的访问时长", - "prior_schema_links":"""['内容合作部'->部门, '生态业务部'->部门]""", - "analysis": """让我们一步一步地思考。在问题“内容库内容合作部、生态业务部的访问时长“中,我们被问: -“访问时长”,所以我们需要column=[访问时长] -”内容库内容合作部、生态业务部“,所以我们需要column=[部门] -基于table和columns,可能的cell values 是 = ['内容合作部', '生态业务部']。""", - "schema_links":"""["访问时长", "部门", "'内容合作部'", "'生态业务部'"]""", - "sql":"""select 部门, 访问时长 from 内容库产品 where 部门 in ('内容合作部', '生态业务部') and 数据日期 = '2023-04-21' """ - }, - { "current_date":"2023-08-21", - "table_name":"优选", - "fields_list":"""["优选版权归属系", "付费模式", "结算播放份额", "付费用户结算播放份额", "数据日期"]""", - "question":"近3天阔景系TME结算播放份额", - "prior_schema_links":"""['阔景系'->优选版权归属系]""", - "analysis": """让我们一步一步地思考。在问题“近3天阔景系TME结算播放份额“中,我们被问: -“TME结算播放份额”,所以我们需要column=[结算播放份额] -”阔景系“,所以我们需要column=[优选版权归属系] -”近3天“,所以我们需要column=[数据日期] -基于table和columns,可能的cell values 是 = ['阔景系', 3]。""", - "schema_links":"""["结算播放份额", "优选版权归属系", "数据日期", "'阔景系'", 3]""", - "sql":"""select 优选版权归属系, 结算播放份额 from 优选 where 优选版权归属系 = '阔景系' and datediff('day', 数据日期, '2023-08-21') <= 3 """ - }, - { "current_date":"2023-05-22", - "table_name":"歌曲库", - "fields_list":"""["是否音乐人歌曲", "Q音歌曲ID", "Q音歌曲MID", "歌曲名", "歌曲版本", "语种", "歌曲类型", "翻唱类型", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "结算播放量", "运营播放量", "付费用户结算播放量", "历史累计结算播放量", "运营搜播量", "结算搜播量", "运营完播量", "运营推播量", "近7日复播率", "日均搜播量", "数据日期"]""", - "question":"对比近7天翻唱版和纯音乐的歌曲播放量", - "prior_schema_links":"""['纯音乐'->语种, '翻唱版'->歌曲版本]""", - "analysis": """让我们一步一步地思考。在问题“对比近3天翻唱版和纯音乐的歌曲播放量“中,我们被问: -“歌曲播放量”,所以我们需要column=[结算播放量] -”翻唱版“,所以我们需要column=[歌曲版本] -”和纯音乐的歌曲“,所以我们需要column=[语种] -”近7天“,所以我们需要column=[数据日期] -基于table和columns,可能的cell values 是 = ['翻唱版', '纯音乐', 7]。""", - "schema_links":"""["结算播放量", "歌曲版本", "语种", "数据日期", "'翻唱版'", "'纯音乐'", 7]""", - "sql":"""select 歌曲版本, 语种, 结算播放量 from 歌曲库 where 歌曲版本 = '翻唱版' and 语种 = '纯音乐' and datediff('day', 数据日期, '2023-05-22') <= 7 """ - }, - { "current_date":"2023-05-31", - "table_name":"艺人库", - "fields_list":"""["上下架状态", "歌手名", "歌手等级", "歌手类型", "歌手来源", "TME音乐人等级", "活跃区域", "年龄", "歌手才能", "歌手风格", "粉丝数", "抖音粉丝数", "网易粉丝数", "微博粉丝数", "网易歌曲数", "在架歌曲数", "网易分享数", "独占歌曲数", "网易在架歌曲评论数", "有播放量歌曲数", "数据日期"]""", - "question":"对比一下陈卓璇、孟美岐、赖美云的粉丝数", - "prior_schema_links":"""['1527896'->TME歌手ID, '1565463'->TME歌手ID, '2141459'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“对比一下陈卓璇、孟美岐、赖美云的粉丝数“中,我们被问: -“粉丝数”,所以我们需要column=[粉丝数] -”陈卓璇、孟美岐、赖美云“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['陈卓璇', '孟美岐', '赖美云']。""", - "schema_links":"""["粉丝数", "歌手名", "'陈卓璇'", "'孟美岐'", "'赖美云'"]""", - "sql":"""select 歌手名, 粉丝数 from 艺人库 where 歌手名 in ('陈卓璇', '孟美岐', '赖美云') and 数据日期 = '2023-05-31' """ - }, - { "current_date":"2023-07-31", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "歌曲版本", "歌曲类型", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"播放量大于1万的歌曲有多少", - "prior_schema_links":"""[]""", - "analysis": """让我们一步一步地思考。在问题“播放量大于1万的歌曲有多少“中,我们被问: -“歌曲有多少”,所以我们需要column=[歌曲名] -”播放量大于1万的“,所以我们需要column=[结算播放量] -基于table和columns,可能的cell values 是 = [10000]。""", - "schema_links":"""["歌曲名", "结算播放量", 10000]""", - "sql":"""select 歌曲名 from 歌曲库 where 结算播放量 > 10000 and 数据日期 = '2023-07-31' """ - }, - { "current_date":"2023-07-31", - "table_name":"内容库产品", - "fields_list":"""["用户名", "部门", "模块", "访问时长", "访问次数", "访问人数", "数据日期"]""", - "question":"内容库访问时长小于1小时,且来自内容合作部的用户是哪些", - "prior_schema_links":"""['内容合作部'->部门]""", - "analysis": """让我们一步一步地思考。在问题“内容库访问时长小于1小时,且来自内容合作部的用户是哪些“中,我们被问: -“用户是哪些”,所以我们需要column=[用户名] -”内容合作部的“,所以我们需要column=[部门] -”访问时长小于1小时“,所以我们需要column=[访问时长] -基于table和columns,可能的cell values 是 = ['内容合作部', 1]。""", - "schema_links":"""["用户名", "部门", "访问时长", "'内容合作部'", 1]""", - "sql":"""select 用户名 from 内容库产品 where 部门 = '内容合作部' and 访问时长 < 1 and 数据日期 = '2023-07-31' """ - }, - { "current_date":"2023-08-31", - "table_name":"内容库产品", - "fields_list":"""["用户名", "部门", "模块", "访问时长", "访问次数", "访问人数", "数据日期"]""", - "question":"内容库pv最高的用户有哪些", - "prior_schema_links":"""[]""", - "analysis": """让我们一步一步地思考。在问题“内容库pv最高的用户有哪些“中,我们被问: -“用户有哪些”,所以我们需要column=[用户名] -”pv最高的“,所以我们需要column=[访问次数] -基于table和columns,可能的cell values 是 = []。""", - "schema_links":"""["用户名", "访问次数"]""", - "sql":"""select 用户名 from 内容库产品 where 数据日期 = '2023-08-31' order by 访问次数 desc limit 10 """ - }, - { "current_date":"2023-08-31", - "table_name":"艺人库", - "fields_list":"""["播放量层级", "播放量单调性", "播放量方差", "播放量突增类型", "播放量集中度", "歌手名", "歌手等级", "歌手类型", "歌手来源", "TME音乐人等级", "结算播放量", "运营播放量", "历史累计结算播放量", "有播放量歌曲数", "历史累计运营播放量", "付费用户结算播放量", "结算播放量占比", "运营播放份额", "免费用户结算播放占比", "完播量", "数据日期"]""", - "question":"近90天袁娅维播放量平均值是多少", - "prior_schema_links":"""['152789226'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“近90天袁娅维播放量平均值是多少“中,我们被问: -“播放量平均值是多少”,所以我们需要column=[结算播放量] -”袁娅维“,所以我们需要column=[歌手名] -”近90天“,所以我们需要column=[数据日期] -基于table和columns,可能的cell values 是 = ['袁娅维', 90]。""", - "schema_links":"""["结算播放量", "歌手名", "数据日期", "'袁娅维'", 90]""", - "sql":"""select avg(结算播放量) from 艺人库 where 歌手名 = '袁娅维' and datediff('day', 数据日期, '2023-08-31') <= 90 """ - }, - { "current_date":"2023-08-31", - "table_name":"艺人库", - "fields_list":"""["播放量层级", "播放量单调性", "播放量方差", "播放量突增类型", "播放量集中度", "歌手名", "歌手等级", "歌手类型", "歌手来源", "TME音乐人等级", "结算播放量", "运营播放量", "历史累计结算播放量", "有播放量歌曲数", "历史累计运营播放量", "付费用户结算播放量", "结算播放量占比", "运营播放份额", "免费用户结算播放占比", "完播量", "数据日期"]""", - "question":"周深近7天结算播放量总和是多少", - "prior_schema_links":"""['199509'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“周深近7天结算播放量总和是多少“中,我们被问: -“结算播放量总和是多少”,所以我们需要column=[结算播放量] -”周深“,所以我们需要column=[歌手名] -”近7天“,所以我们需要column=[数据日期] -基于table和columns,可能的cell values 是 = ['周深', 7]。""", - "schema_links":"""["结算播放量", "歌手名", "数据日期", "'周深'", 7]""", - "sql":"""select sum(结算播放量) from 艺人库 where 歌手名 = '周深' and datediff('day', 数据日期, '2023-08-31') <= 7 """ - }, - { "current_date":"2023-09-14", - "table_name":"内容库产品", - "fields_list":"""["部门", "模块", "用户名", "访问次数", "访问人数", "访问时长", "数据日期"]""", - "question":"内容库访问次数大于1k的部门是哪些", - "prior_schema_links":"""[]""", - "analysis": """让我们一步一步地思考。在问题“内容库访问次数大于1k的部门是哪些“中,我们被问: -“部门是哪些”,所以我们需要column=[部门] -”访问次数大于1k的“,所以我们需要column=[访问次数] -基于table和columns,可能的cell values 是 = [1000]。""", - "schema_links":"""["部门", "访问次数", 1000]""", - "sql":"""select 部门 from 内容库产品 where 访问次数 > 1000 and 数据日期 = '2023-09-14' """ - }, - { "current_date":"2023-09-18", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "TME歌手ID", "歌曲版本", "歌曲类型", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"陈奕迅唱的所有的播放量大于20k的孤勇者有哪些", - "prior_schema_links":"""['199509'->TME歌手ID, '1527123'->TME歌曲ID]""", - "analysis": """让我们一步一步地思考。在问题“陈奕迅唱的所有的播放量大于20k的孤勇者有哪些“中,我们被问: -“孤勇者有哪些”,所以我们需要column=[歌曲名] -”播放量大于20k的“,所以我们需要column=[结算播放量] -”陈奕迅唱的“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = [20000, '陈奕迅', '孤勇者']。""", - "schema_links":"""["歌曲名", "结算播放量", "歌手名", 20000, "'陈奕迅'", "'孤勇者'"]""", - "sql":"""select 歌曲名 from 歌曲库 where 结算播放量 > 20000 and 歌手名 = '陈奕迅' and 歌曲名 = '孤勇者' and 数据日期 = '2023-09-18' """ - }, - { "current_date":"2023-09-18", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "歌曲版本", "歌手名", "歌曲类型", "发布时间", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"周杰伦去年发布的歌曲有哪些", - "prior_schema_links":"""['23109'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“周杰伦去年发布的歌曲有哪些“中,我们被问: -“歌曲有哪些”,所以我们需要column=[歌曲名] -”去年发布的“,所以我们需要column=[发布时间] -”周杰伦“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['周杰伦', 1]。""", - "schema_links":"""["歌曲名", "发布时间", "歌手名", 1, "'周杰伦'"]""", - "sql":"""select 歌曲名 from 歌曲库 where datediff('year', 发布时间, '2023-09-18') <= 1 and 歌手名 = '周杰伦' and 数据日期 = '2023-09-18' """ - }, - { "current_date":"2023-09-11", - "table_name":"艺人库", - "fields_list":"""["播放量层级", "播放量单调性", "播放量方差", "播放量突增类型", "播放量集中度", "歌手名", "歌手等级", "歌手类型", "歌手来源", "签约日期", "TME音乐人等级", "结算播放量", "运营播放量", "历史累计结算播放量", "有播放量歌曲数", "历史累计运营播放量", "付费用户结算播放量", "结算播放量占比", "运营播放份额", "免费用户结算播放占比", "完播量", "数据日期"]""", - "question":"我想要近半年签约的播放量前十的歌手有哪些", - "prior_schema_links":"""[]""", - "analysis": """让我们一步一步地思考。在问题“我想要近半年签约的播放量前十的歌手“中,我们被问: -“歌手有哪些”,所以我们需要column=[歌手名] -”播放量前十的“,所以我们需要column=[结算播放量] -”近半年签约的“,所以我们需要column=[签约日期] -基于table和columns,可能的cell values 是 = [0.5, 10]。""", - "schema_links":"""["歌手名", "结算播放量", "签约日期", 0.5, 10]""", - "sql":"""select 歌手名 from 艺人库 where datediff('year', 签约日期, '2023-09-11') <= 0.5 and 数据日期 = '2023-09-11' order by 结算播放量 desc limit 10""" - }, - { "current_date":"2023-08-12", - "table_name":"歌曲库", - "fields_list": """["发行日期", "歌曲语言", "歌曲来源", "歌曲流派", "歌曲名", "歌曲版本", "歌曲类型", "发行时间", "数据日期"]""", - "question":"最近一年发行的歌曲中,有哪些在近7天播放超过一千万的", - "prior_schema_links":"""[]""", - "analysis": """让我们一步一步地思考。在问题“最近一年发行的歌曲中,有哪些在近7天播放超过一千万的“中,我们被问: -“发行的歌曲中,有哪些”,所以我们需要column=[歌曲名] -”最近一年发行的“,所以我们需要column=[发行日期] -”在近7天播放超过一千万的“,所以我们需要column=[数据日期, 结算播放量] -基于table和columns,可能的cell values 是 = [1, 10000000]""", - "schema_links":"""["歌曲名", "发行日期", "数据日期", "结算播放量", 1, 10000000]""", - "sql":"""select 歌曲名 from 歌曲库 where datediff('year', 发行日期, '2023-08-12') <= 1 and datediff('day', 数据日期, '2023-08-12') <= 7 and 结算播放量 > 10000000""" - }, - { "current_date":"2023-08-12", - "table_name":"歌曲库", - "fields_list": """["发行日期", "歌曲语言", "歌曲来源", "歌曲流派", "歌曲名", "歌曲版本", "歌曲类型", "发行时间", "数据日期"]""", - "question":"今年以来发行的歌曲中,有哪些在近7天播放超过一千万的", - "prior_schema_links":"""[]""", - "analysis": """让我们一步一步地思考。在问题“今年以来发行的歌曲中,有哪些在近7天播放超过一千万的“中,我们被问: -“发行的歌曲中,有哪些”,所以我们需要column=[歌曲名] -”今年以来发行的“,所以我们需要column=[发行日期] -”在近7天播放超过一千万的“,所以我们需要column=[数据日期, 结算播放量] -基于table和columns,可能的cell values 是 = [0, 7, 10000000]""", - "schema_links":"""["歌曲名", "发行日期", "数据日期", "结算播放量", 0, 7, 10000000]""", - "sql":"""select 歌曲名 from 歌曲库 where datediff('year', 发行日期, '2023-08-12') <= 0 and datediff('day', 数据日期, '2023-08-12') <= 7 and 结算播放量 > 10000000""" - }, - { "current_date":"2023-08-12", - "table_name":"歌曲库", - "fields_list": """["发行日期", "歌曲语言", "歌曲来源", "歌曲流派", "歌曲名", "歌曲版本", "歌曲类型", "发行时间", "数据日期"]""", - "question":"2023年以来发行的歌曲中,有哪些在近7天播放超过一千万的", - "prior_schema_links":"""['514129144'->TME歌曲ID]""", - "analysis": """让我们一步一步地思考。在问题“2023年以来发行的歌曲中,有哪些在近7天播放超过一千万的“中,我们被问: -“发行的歌曲中,有哪些”,所以我们需要column=[歌曲名] -”2023年以来发行的“,所以我们需要column=[发行日期] -”在近7天播放超过一千万的“,所以我们需要column=[数据日期, 结算播放量] -基于table和columns,可能的cell values 是 = [2023, 7, 10000000]""", - "schema_links":"""["歌曲名", "发行日期", "数据日期", "结算播放量", 2023, 7, 10000000]""", - "sql":"""select 歌曲名 from 歌曲库 where YEAR(发行日期) >= 2023 and datediff('day', 数据日期, '2023-08-12') <= 7 and 结算播放量 > 10000000""" - }, - { "current_date":"2023-08-01", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "歌曲版本", "歌手名", "歌曲类型", "发布时间", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"周杰伦2023年6月之后发布的歌曲有哪些", - "prior_schema_links":"""['23109'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“周杰伦2023年6月之后发布的歌曲有哪些“中,我们被问: -“歌曲有哪些”,所以我们需要column=[歌曲名] -”2023年6月之后发布的“,所以我们需要column=[发布时间] -”周杰伦“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['周杰伦', 2023, 6]。""", - "schema_links":"""["歌曲名", "发布时间", "歌手名", "周杰伦", 2023, 6]""", - "sql":"""select 歌曲名 from 歌曲库 where YEAR(发布时间) >= 2023 and MONTH(发布时间) >= 6 and 歌手名 = '周杰伦' and 数据日期 = '2023-08-01' """ - }, - { "current_date":"2023-08-01", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "歌曲版本", "歌手名", "歌曲类型", "发布时间", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"邓紫棋在2023年1月5日之后发布的歌曲中,有哪些播放量大于500W的?", - "prior_schema_links":"""['2312311'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“邓紫棋在2023年1月5日之后发布的歌曲中,有哪些播放量大于500W的?“中,我们被问: -“播放量大于500W的”,所以我们需要column=[结算播放量] -”邓紫棋在2023年1月5日之后发布的“,所以我们需要column=[发布时间] -”邓紫棋“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['邓紫棋', 2023, 1, 5, 5000000]。""", - "schema_links":"""["结算播放量", "发布时间", "歌手名", "邓紫棋", 2023, 1, 5, 5000000]""", - "sql":"""select 歌曲名 from 歌曲库 where YEAR(发布时间) >= 2023 and MONTH(发布时间) >= 1 and DAY(发布时间) >= 5 and 歌手名 = '邓紫棋' and 结算播放量 > 5000000 and 数据日期 = '2023-08-01'""" - }, - { "current_date":"2023-09-17", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "歌曲版本", "歌手名", "歌曲类型", "发布时间", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"2023年6月以后,张靓颖播放量大于200万的歌曲有哪些?", - "prior_schema_links":"""['45453'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“2023年6月以后,张靓颖播放量大于200万的歌曲有哪些?“中,我们被问: -“播放量大于200万的”,所以我们需要column=[结算播放量] -”2023年6月以后,张靓颖“,所以我们需要column=[数据日期, 歌手名] -”歌曲有哪些“,所以我们需要column=[歌曲名] -基于table和columns,可能的cell values 是 = ['张靓颖', 2023, 6, 2000000]。""", - "schema_links":"""["结算播放量", "数据日期", "歌手名", "张靓颖", 2023, 6, 2000000]""", - "sql":"""select 歌曲名 from 歌曲库 where YEAR(数据日期) >= 2023 and MONTH(数据日期) >= 6 and 歌手名 = '张靓颖' and 结算播放量 > 2000000 """ - }, - { "current_date":"2023-08-16", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "歌曲版本", "歌手名", "歌曲类型", "发布时间", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"2021年6月以后发布的李宇春的播放量大于20万的歌曲有哪些", - "prior_schema_links":"""['23109'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“2021年6月以后发布的李宇春的播放量大于20万的歌曲有哪些“中,我们被问: -“播放量大于20万的”,所以我们需要column=[结算播放量] -”2021年6月以后发布的“,所以我们需要column=[发布时间] -”李宇春“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['李宇春', 2021, 6, 200000]。""", - "schema_links":"""["结算播放量", "发布时间", "歌手名", "李宇春", 2021, 6, 200000]""", - "sql":"""select 歌曲名 from 歌曲库 where YEAR(发布时间) >= 2021 and MONTH(发布时间) >= 6 and 歌手名 = '李宇春' and 结算播放量 > 200000 and 数据日期 = '2023-08-16'""" - }, - { "current_date":"2023-08-16", - "table_name":"歌曲库", - "fields_list":"""["歌曲名", "歌曲版本", "歌手名", "歌曲类型", "发布时间", "TME歌曲ID", "是否优选窄口径歌曲", "是否优选宽口径歌曲", "是否音乐人歌曲", "网易歌曲ID", "Q音歌曲ID", "Q音歌曲MID", "结算播放量", "运营播放量", "分享量", "收藏量", "运营搜播量", "结算搜播量", "拉新用户数", "拉活用户数", "分享率", "结算播放份额", "数据日期"]""", - "question":"刘德华在1992年4月2日到2020年5月2日之间发布的播放量大于20万的歌曲有哪些", - "prior_schema_links":"""['4234234'->TME歌手ID]""", - "analysis": """让我们一步一步地思考。在问题“刘德华在1992年4月2日到2020年5月2日之间发布的播放量大于20万的歌曲有哪些“中,我们被问: -“播放量大于20万的”,所以我们需要column=[结算播放量] -”1992年4月2日到2020年5月2日之间发布的“,所以我们需要column=[发布时间] -”刘德华“,所以我们需要column=[歌手名] -基于table和columns,可能的cell values 是 = ['刘德华', 1992, 4, 2, 2020, 5, 2, 200000]。""", - "schema_links":"""["结算播放量", "发布时间", "歌手名", "刘德华", 1992, 4, 2, 2020, 5, 2, 200000]""", - "sql":"""select 歌曲名 from 歌曲库 where YEAR(发布时间) >= 1992 and MONTH(发布时间) >= 4 and DAY(发布时间) >= 2 and YEAR(发布时间) <= 2020 and MONTH(发布时间) <= 5 and DAY(发布时间) <= 2 and 歌手名 = '刘德华' and 结算播放量 > 200000 and 数据日期 = '2023-08-16'""" - } -] \ No newline at end of file diff --git a/chat/core/src/main/python/llm/preset_retrieval/run.py b/chat/core/src/main/python/llm/preset_retrieval/run.py index dc501b49c..9027253bf 100644 --- a/chat/core/src/main/python/llm/preset_retrieval/run.py +++ b/chat/core/src/main/python/llm/preset_retrieval/run.py @@ -8,7 +8,8 @@ from typing import Any, List, Mapping, Optional, Union sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.dirname(os.path.abspath(__file__))) - +import chromadb +from chromadb.config import Settings from chromadb.api import Collection, Documents, Embeddings from langchain.llms import OpenAI @@ -20,9 +21,13 @@ from preset_query_db import (get_ids, add2preset_query_collection, from util.text2vec import Text2VecEmbeddingFunction from run_config import CHROMA_DB_PERSIST_PATH, PRESET_QUERY_COLLECTION_NAME -from util.chromadb_instance import client +client = chromadb.Client(Settings( + chroma_db_impl="duckdb+parquet", + persist_directory=CHROMA_DB_PERSIST_PATH # Optional, defaults to .chromadb/ in the current directory +)) + emb_func = Text2VecEmbeddingFunction() collection = client.get_or_create_collection(name=PRESET_QUERY_COLLECTION_NAME, @@ -30,8 +35,6 @@ collection = client.get_or_create_collection(name=PRESET_QUERY_COLLECTION_NAME, metadata={"hnsw:space": "cosine"} ) # Get a collection object from an existing collection, by name. If it doesn't exist, create it. -print("init_preset_query_collection_size: ", preset_query_collection_size(collection)) - def preset_query_retrieval_run(collection:Collection, query_texts_list:List[str], n_results:int=5): retrieval_res = query2preset_query_collection(collection=collection, diff --git a/chat/core/src/main/python/llm/run_config.py b/chat/core/src/main/python/llm/run_config.py index e2b47b404..989b44e5a 100644 --- a/chat/core/src/main/python/llm/run_config.py +++ b/chat/core/src/main/python/llm/run_config.py @@ -9,7 +9,6 @@ TEMPERATURE = 0.0 CHROMA_DB_PERSIST_DIR = 'chm_db' PRESET_QUERY_COLLECTION_NAME = "preset_query_collection" -TEXT2DSL_COLLECTION_NAME = "text2dsl_collection" CHROMA_DB_PERSIST_PATH = os.path.join(PROJECT_DIR_PATH, CHROMA_DB_PERSIST_DIR) diff --git a/chat/core/src/main/python/llm/sql/constructor.py b/chat/core/src/main/python/llm/sql/constructor.py deleted file mode 100644 index c6f367492..000000000 --- a/chat/core/src/main/python/llm/sql/constructor.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding:utf-8 -*- -import os -import sys - -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -from langchain.prompts.few_shot import FewShotPromptTemplate -from langchain.prompts import PromptTemplate -from langchain.vectorstores import Chroma -from langchain.embeddings import OpenAIEmbeddings, HuggingFaceEmbeddings -from langchain.prompts.example_selector import SemanticSimilarityExampleSelector - -import chromadb -from chromadb.config import Settings - -from few_shot_example.sql_exampler import examplars as din_sql_examplars -from util.text2vec import Text2VecEmbeddingFunction, hg_embedding -from util.chromadb_instance import client as chromadb_client - - -from run_config import TEXT2DSL_COLLECTION_NAME - - -vectorstore = Chroma(collection_name=TEXT2DSL_COLLECTION_NAME, - embedding_function=hg_embedding, - client=chromadb_client) - -example_nums = 15 - -schema_linking_example_selector = SemanticSimilarityExampleSelector(vectorstore=vectorstore, k=example_nums, - input_keys=["question"], - example_keys=["table_name", "fields_list", "prior_schema_links", "question", "analysis", "schema_links"]) - -sql_example_selector = SemanticSimilarityExampleSelector(vectorstore=vectorstore, k=example_nums, - input_keys=["question"], - example_keys=["question", "current_date", "table_name", "schema_links", "sql"]) - -if vectorstore._collection.count() > 0: - print("examples already in din_sql_vectorstore") - print("init din_sql_vectorstore size:", vectorstore._collection.count()) - if vectorstore._collection.count() < len(din_sql_examplars): - print("din_sql_examplars size:", len(din_sql_examplars)) - vectorstore._collection.delete() - print("empty din_sql_vectorstore") - for example in din_sql_examplars: - schema_linking_example_selector.add_example(example) - print("added din_sql_vectorstore size:", vectorstore._collection.count()) -else: - for example in din_sql_examplars: - schema_linking_example_selector.add_example(example) - - print("added din_sql_vectorstore size:", vectorstore._collection.count()) diff --git a/chat/core/src/main/python/llm/sql/output_parser.py b/chat/core/src/main/python/llm/sql/output_parser.py index c90388850..64df5ba1f 100644 --- a/chat/core/src/main/python/llm/sql/output_parser.py +++ b/chat/core/src/main/python/llm/sql/output_parser.py @@ -1,13 +1,15 @@ # -*- coding:utf-8 -*- import re -def schema_link_parse(schema_link_output): - try: - schema_link_output = schema_link_output.strip() - pattern = r'Schema_links:(.*)' - schema_link_output = re.findall(pattern, schema_link_output, re.DOTALL)[0].strip() - except Exception as e: - print(e) - schema_link_output = None - return schema_link_output \ No newline at end of file +def schema_link_parse(schema_link_output): + try: + schema_link_output = schema_link_output.strip() + pattern = r'Schema_links:(.*)' + schema_link_output = re.findall(pattern, schema_link_output, re.DOTALL)[ + 0].strip() + except Exception as e: + print(e) + schema_link_output = None + + return schema_link_output diff --git a/chat/core/src/main/python/llm/sql/prompt_maker.py b/chat/core/src/main/python/llm/sql/prompt_maker.py index 0cfed83b1..6e05f95b3 100644 --- a/chat/core/src/main/python/llm/sql/prompt_maker.py +++ b/chat/core/src/main/python/llm/sql/prompt_maker.py @@ -1,5 +1,8 @@ # -*- coding:utf-8 -*- from typing import Any, List, Mapping, Optional, Union +import requests +import logging +import json import os import sys @@ -8,68 +11,78 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__))) from langchain.prompts import PromptTemplate from langchain.prompts.few_shot import FewShotPromptTemplate -from langchain.prompts.example_selector import SemanticSimilarityExampleSelector +from langchain.llms import OpenAI + +from few_shot_example.sql_exampler import examplars +from output_parser import schema_link_parse + + +def schema_linking_prompt_maker(user_query: str, model_name: str, + fields_list: List[str], + few_shots_example: str): + instruction = "# 根据数据库的表结构,找出为每个问题生成SQL查询语句的schema_links\n" + + schema_linking_prompt = "Table {table_name}, columns = {fields_list}\n问题:{user_query}\n分析: 让我们一步一步地思考。".format( + table_name=model_name, + fields_list=fields_list, + user_query=user_query) + + return instruction + few_shots_example + schema_linking_prompt def schema_linking_exampler(user_query: str, - domain_name: str, - fields_list: List[str], - prior_schema_links: Mapping[str,str], - example_selector: SemanticSimilarityExampleSelector, - ) -> str: + model_name: str, + fields_list: List[str] +) -> str: + example_prompt_template = PromptTemplate( + input_variables=["table_name", "fields_list", "question", "analysis", + "schema_links"], + template="Table {table_name}, columns = {fields_list}\n问题:{question}\n分析:{analysis} 所以Schema_links是:\nSchema_links:{schema_links}") - prior_schema_links_str = '['+ ','.join(["""'{}'->{}""".format(k,v) for k,v in prior_schema_links.items()]) + ']' + instruction = "# 根据数据库的表结构,找出为每个问题生成SQL查询语句的schema_links" - example_prompt_template = PromptTemplate(input_variables=["table_name", "fields_list", "prior_schema_links", "question", "analysis", "schema_links"], - template="Table {table_name}, columns = {fields_list}, prior_schema_links = {prior_schema_links}\n问题:{question}\n分析:{analysis} 所以Schema_links是:\nSchema_links:{schema_links}") + schema_linking_prompt = "Table {table_name}, columns = {fields_list}\n问题:{question}\n分析: 让我们一步一步地思考。" - instruction = "# 根据数据库的表结构,参考先验信息,找出为每个问题生成SQL查询语句的schema_links" + schema_linking_example_prompt_template = FewShotPromptTemplate( + examples=examplars, + example_prompt=example_prompt_template, + example_separator="\n\n", + prefix=instruction, + input_variables=["table_name", "fields_list", "question"], + suffix=schema_linking_prompt + ) - schema_linking_prompt = "Table {table_name}, columns = {fields_list}, prior_schema_links = {prior_schema_links}\n问题:{question}\n分析: 让我们一步一步地思考。" + schema_linking_example_prompt = schema_linking_example_prompt_template.format( + table_name=model_name, + fields_list=fields_list, + question=user_query) - schema_linking_example_prompt_template = FewShotPromptTemplate( - example_selector=example_selector, - example_prompt=example_prompt_template, - example_separator="\n\n", - prefix=instruction, - input_variables=["table_name", "fields_list", "prior_schema_links", "question"], - suffix=schema_linking_prompt - ) - - schema_linking_example_prompt = schema_linking_example_prompt_template.format(table_name=domain_name, - fields_list=fields_list, - prior_schema_links=prior_schema_links_str, - question=user_query) - - return schema_linking_example_prompt + return schema_linking_example_prompt def sql_exampler(user_query: str, - domain_name: str, - schema_link_str: str, - data_date: str, - example_selector: SemanticSimilarityExampleSelector, - ) -> str: - - instruction = "# 根据schema_links为每个问题生成SQL查询语句" + model_name: str, + schema_link_str: str +) -> str: + instruction = "# 根据schema_links为每个问题生成SQL查询语句" - sql_example_prompt_template = PromptTemplate(input_variables=["question", "current_date", "table_name", "schema_links", "sql"], - template="问题:{question}\nCurrent_date:{current_date}\nTable {table_name}\nSchema_links:{schema_links}\nSQL:{sql}") + sql_example_prompt_template = PromptTemplate( + input_variables=["question", "table_name", "schema_links", "sql"], + template="问题:{question}\nTable {table_name}\nSchema_links:{schema_links}\nSQL:{sql}") - sql_prompt = "问题:{question}\nCurrent_date:{current_date}\nTable {table_name}\nSchema_links:{schema_links}\nSQL:" + sql_prompt = "问题:{question}\nTable {table_name}\nSchema_links:{schema_links}\nSQL:" - sql_example_prompt_template = FewShotPromptTemplate( - example_selector=example_selector, - example_prompt=sql_example_prompt_template, - example_separator="\n\n", - prefix=instruction, - input_variables=["question", "current_date", "table_name", "schema_links"], - suffix=sql_prompt - ) + sql_example_prompt_template = FewShotPromptTemplate( + examples=examplars, + example_prompt=sql_example_prompt_template, + example_separator="\n\n", + prefix=instruction, + input_variables=["question", "table_name", "schema_links"], + suffix=sql_prompt + ) - sql_example_prompt = sql_example_prompt_template.format(question=user_query, - current_date=data_date, - table_name=domain_name, - schema_links=schema_link_str) + sql_example_prompt = sql_example_prompt_template.format(question=user_query, + table_name=model_name, + schema_links=schema_link_str) - return sql_example_prompt + return sql_example_prompt diff --git a/chat/core/src/main/python/llm/sql/run.py b/chat/core/src/main/python/llm/sql/run.py index 34919799b..ea60d7f36 100644 --- a/chat/core/src/main/python/llm/sql/run.py +++ b/chat/core/src/main/python/llm/sql/run.py @@ -1,4 +1,6 @@ -from typing import List, Union, Mapping +# -*- coding:utf-8 -*- + +from typing import List, Union import logging import json import os @@ -7,54 +9,33 @@ import sys sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.dirname(os.path.abspath(__file__))) -from sql.prompt_maker import schema_linking_exampler, sql_exampler -from sql.constructor import schema_linking_example_selector, sql_example_selector -from sql.output_parser import schema_link_parse +from sql.prompt_maker import schema_linking_exampler, schema_link_parse, \ + sql_exampler from util.llm_instance import llm +def query2sql(query_text: str, schema: dict): + print("schema: ", schema) -def query2sql(query_text: str, - schema : Union[dict, None] = None, - current_date: str = None, - linking: Union[List[Mapping[str, str]], None] = None - ): - - print("query_text: ", query_text) - print("schema: ", schema) - print("current_date: ", current_date) - print("prior_schema_links: ", linking) + model_name = schema['modelName'] + fields_list = schema['fieldNameList'] - if linking is not None: - prior_schema_links = {item['fieldValue']:item['fieldName'] for item in linking} - else: - prior_schema_links = {} + schema_linking_prompt = schema_linking_exampler(query_text, model_name, + fields_list) + schema_link_output = llm(schema_linking_prompt) + schema_link_str = schema_link_parse(schema_link_output) - model_name = schema['modelName'] - fields_list = schema['fieldNameList'] + sql_prompt = sql_exampler(query_text, model_name, schema_link_str) + sql_output = llm(sql_prompt) - schema_linking_prompt = schema_linking_exampler(query_text, model_name, fields_list, prior_schema_links, schema_linking_example_selector) - print("schema_linking_prompt->", schema_linking_prompt) - schema_link_output = llm(schema_linking_prompt) - schema_link_str = schema_link_parse(schema_link_output) - - sql_prompt = sql_exampler(query_text, model_name, schema_link_str, current_date, sql_example_selector) - print("sql_prompt->", sql_prompt) - sql_output = llm(sql_prompt) + resp = dict() + resp['query'] = query_text + resp['model'] = model_name + resp['fields'] = fields_list - resp = dict() - resp['query'] = query_text - resp['model'] = model_name - resp['fields'] = fields_list - resp['priorSchemaLinking'] = linking - resp['dataDate'] = current_date + resp['schemaLinkingOutput'] = schema_link_output + resp['schemaLinkStr'] = schema_link_str - resp['schemaLinkingOutput'] = schema_link_output - resp['schemaLinkStr'] = schema_link_str - - resp['sqlOutput'] = sql_output - - print("resp: ", resp) - - return resp + resp['sqlOutput'] = sql_output + return resp diff --git a/chat/core/src/main/python/llm/util/chromadb_instance.py b/chat/core/src/main/python/llm/util/chromadb_instance.py deleted file mode 100644 index f0fe6ce01..000000000 --- a/chat/core/src/main/python/llm/util/chromadb_instance.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding:utf-8 -*- -import chromadb -from chromadb.config import Settings - -from run_config import CHROMA_DB_PERSIST_PATH - -client = chromadb.Client(Settings( - chroma_db_impl="duckdb+parquet", - persist_directory=CHROMA_DB_PERSIST_PATH # Optional, defaults to .chromadb/ in the current directory -)) \ No newline at end of file diff --git a/chat/core/src/main/resources/mapper/ChatParseMapper.xml b/chat/core/src/main/resources/mapper/ChatParseMapper.xml new file mode 100644 index 000000000..cede70423 --- /dev/null +++ b/chat/core/src/main/resources/mapper/ChatParseMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + insert into s2_chat_parse + (question_id, chat_id, parse_id, create_time, query_text, user_name, parse_info,is_candidate) + values + + (#{item.questionId}, #{item.chatId}, #{item.parseId}, #{item.createTime}, #{item.queryText}, #{item.userName}, #{item.parseInfo}, #{item.isCandidate}) + + + + + + diff --git a/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml b/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml index 7de775067..72cbbc4b4 100644 --- a/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml +++ b/chat/core/src/main/resources/mapper/ChatQueryDOMapper.xml @@ -1,246 +1,244 @@ - + - - - - - - - - - - - - - - - - - - - - - - and ${criterion.condition} - - - and ${criterion.condition} #{criterion.value} - - - and ${criterion.condition} #{criterion.value} and - #{criterion.secondValue} - - - and ${criterion.condition} - - #{listItem} - - - - - - + + + + + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + - - - - question_id - , create_time, user_name, query_state, chat_id, score, feedback - - - query_text - , query_response - - - - - - 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}, - #{queryResult,jdbcType=LONGVARCHAR}) - - - insert into s2_chat_query - - - question_id, - - - create_time, - - - user_name, - - - query_state, - - - chat_id, - - - score, - - - feedback, - - - query_text, - - - query_response, - - - - - #{questionId,jdbcType=BIGINT}, - - - #{createTime,jdbcType=TIMESTAMP}, - - - #{userName,jdbcType=VARCHAR}, - - - #{queryState,jdbcType=INTEGER}, - - - #{chatId,jdbcType=BIGINT}, - - - #{score,jdbcType=INTEGER}, - - - #{feedback,jdbcType=VARCHAR}, - - - #{queryText,jdbcType=LONGVARCHAR}, - - - #{queryResult,jdbcType=LONGVARCHAR}, - - - - - - update s2_chat_query - - - create_time = #{createTime,jdbcType=TIMESTAMP}, - - - user_name = #{userName,jdbcType=VARCHAR}, - - - query_state = #{queryState,jdbcType=INTEGER}, - - - chat_id = #{chatId,jdbcType=BIGINT}, - - - score = #{score,jdbcType=INTEGER}, - - - feedback = #{feedback,jdbcType=VARCHAR}, - - - query_text = #{queryText,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}, - query_state = #{queryState,jdbcType=INTEGER}, - chat_id = #{chatId,jdbcType=BIGINT}, - score = #{score,jdbcType=INTEGER}, - feedback = #{feedback,jdbcType=VARCHAR}, - query_text = #{queryText,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}, - query_state = #{queryState,jdbcType=INTEGER}, - chat_id = #{chatId,jdbcType=BIGINT}, - score = #{score,jdbcType=INTEGER}, - feedback = #{feedback,jdbcType=VARCHAR} - where question_id = #{questionId,jdbcType=BIGINT} - - \ No newline at end of file + + + + + question_id, create_time, user_name, query_state, chat_id, score, feedback + + + query_text, query_result + + + + + + 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_result + ) + 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}, #{queryResult,jdbcType=LONGVARCHAR} + ) + + + insert into s2_chat_query + + + question_id, + + + create_time, + + + user_name, + + + query_state, + + + chat_id, + + + score, + + + feedback, + + + query_text, + + + query_result, + + + + + #{questionId,jdbcType=BIGINT}, + + + #{createTime,jdbcType=TIMESTAMP}, + + + #{userName,jdbcType=VARCHAR}, + + + #{queryState,jdbcType=INTEGER}, + + + #{chatId,jdbcType=BIGINT}, + + + #{score,jdbcType=INTEGER}, + + + #{feedback,jdbcType=VARCHAR}, + + + #{queryText,jdbcType=LONGVARCHAR}, + + + #{queryResult,jdbcType=LONGVARCHAR}, + + + + + + update s2_chat_query + + + create_time = #{createTime,jdbcType=TIMESTAMP}, + + + user_name = #{userName,jdbcType=VARCHAR}, + + + query_state = #{queryState,jdbcType=INTEGER}, + + + chat_id = #{chatId,jdbcType=BIGINT}, + + + score = #{score,jdbcType=INTEGER}, + + + feedback = #{feedback,jdbcType=VARCHAR}, + + + query_text = #{queryText,jdbcType=LONGVARCHAR}, + + + query_result = #{queryResult,jdbcType=LONGVARCHAR}, + + + where question_id = #{questionId,jdbcType=BIGINT} + + + update s2_chat_query + + + create_time = #{createTime,jdbcType=TIMESTAMP}, + + + user_name = #{userName,jdbcType=VARCHAR}, + + + query_state = #{queryState,jdbcType=INTEGER}, + + + chat_id = #{chatId,jdbcType=BIGINT}, + + + score = #{score,jdbcType=INTEGER}, + + + feedback = #{feedback,jdbcType=VARCHAR}, + + + query_text = #{queryText,jdbcType=LONGVARCHAR}, + + + query_result = #{queryResult,jdbcType=LONGVARCHAR}, + + + where question_id = #{questionId,jdbcType=BIGINT} + + + update s2_chat_query + set create_time = #{createTime,jdbcType=TIMESTAMP}, + user_name = #{userName,jdbcType=VARCHAR}, + query_state = #{queryState,jdbcType=INTEGER}, + chat_id = #{chatId,jdbcType=BIGINT}, + score = #{score,jdbcType=INTEGER}, + feedback = #{feedback,jdbcType=VARCHAR} + where question_id = #{questionId,jdbcType=BIGINT} + + diff --git a/chat/core/src/main/resources/mapper/StatisticsMapper.xml b/chat/core/src/main/resources/mapper/StatisticsMapper.xml new file mode 100644 index 000000000..2470c222d --- /dev/null +++ b/chat/core/src/main/resources/mapper/StatisticsMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + insert into s2_chat_statistics + (question_id,chat_id, user_name, query_text, interface_name,cost,type ,create_time) + values + + (#{item.questionId}, #{item.chatId}, #{item.userName}, #{item.queryText}, #{item.interfaceName}, #{item.cost}, #{item.type},#{item.createTime}) + + + + + + diff --git a/chat/core/src/main/resources/mapper/custom/ShowCaseCustomMapper.xml b/chat/core/src/main/resources/mapper/custom/ShowCaseCustomMapper.xml new file mode 100644 index 000000000..adaf36822 --- /dev/null +++ b/chat/core/src/main/resources/mapper/custom/ShowCaseCustomMapper.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and + #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + id, model_id, name, biz_name, description, type, created_at, created_by, updated_at, updated_by + + + typeParams + + + + + diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeRangeParserTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeRangeParserTest.java index 52d0ba795..f4e136a1c 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeRangeParserTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeRangeParserTest.java @@ -2,7 +2,6 @@ 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.pojo.request.QueryReq; import com.tencent.supersonic.chat.parser.rule.TimeRangeParser; import org.junit.jupiter.api.Test; @@ -10,35 +9,15 @@ import org.junit.jupiter.api.Test; class TimeRangeParserTest { -// private HeuristicQuerySelector voteStrategy = new HeuristicQuerySelector() { -// @Override -// public void init(List semanticParsers) { -// List queryMode = new ArrayList<>(Arrays.asList(EntityDetailQuery.QUERY_MODE)); -// for(SemanticParser semanticParser : semanticParsers) { -// if(semanticParser.getName().equals(TimeRangeParser.PARSER_MODE)) { -// semanticParser.getQueryModes().clear(); -// semanticParser.getQueryModes().addAll(queryMode); -// } -// } -// } -// }; - @Test void parse() { TimeRangeParser timeRangeParser = new TimeRangeParser(); QueryReq queryRequest = new QueryReq(); ChatContext chatCtx = new ChatContext(); - SchemaMapInfo schemaMap = new SchemaMapInfo(); queryRequest.setQueryText("supersonic最近30天访问次数"); - //voteStrategy.init(new ArrayList<>(Arrays.asList(timeRangeParser))); timeRangeParser.parse(new QueryContext(queryRequest), chatCtx); - //DateConf dateInfo = queryContext.getParseInfo(timeRangeParser.getQueryModes().get(0)) - // .getDateInfo(); - - //System.out.println(dateInfo); - } -} \ No newline at end of file +} diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/MapperHelperTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/LoadRemoveServiceTest.java similarity index 90% rename from chat/core/src/test/java/com/tencent/supersonic/chat/mapper/MapperHelperTest.java rename to chat/core/src/test/java/com/tencent/supersonic/chat/mapper/LoadRemoveServiceTest.java index 21909410e..bb3d028fd 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/MapperHelperTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/mapper/LoadRemoveServiceTest.java @@ -5,7 +5,7 @@ import com.hankcs.hanlp.algorithm.EditDistance; import org.junit.Assert; import org.junit.jupiter.api.Test; -class MapperHelperTest { +class LoadRemoveServiceTest { @Test @@ -13,4 +13,4 @@ class MapperHelperTest { int compute = EditDistance.compute("在", "在你的身边"); Assert.assertEquals(compute, 4); } -} \ No newline at end of file +} diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDslParserTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDslParserTest.java new file mode 100644 index 000000000..e6f269e71 --- /dev/null +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/parser/llm/dsl/LLMDslParserTest.java @@ -0,0 +1,12 @@ +package com.tencent.supersonic.chat.parser.llm.dsl; + +import org.junit.jupiter.api.Test; + +class LLMDslParserTest { + + + @Test + void getDimensionFilter() { + } + +} \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/query/dsl/optimizer/DateFieldCorrectorTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/DateFieldCorrectorTest.java similarity index 78% rename from chat/core/src/test/java/com/tencent/supersonic/chat/query/dsl/optimizer/DateFieldCorrectorTest.java rename to chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/DateFieldCorrectorTest.java index 51c08072b..4b530bbe7 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/query/dsl/optimizer/DateFieldCorrectorTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/DateFieldCorrectorTest.java @@ -1,8 +1,9 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; +package com.tencent.supersonic.chat.query.llm.dsl.corrector; import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; import com.tencent.supersonic.chat.api.pojo.SchemaElement; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.corrector.DateFieldCorrector; import org.junit.Assert; import org.junit.jupiter.api.Test; @@ -20,18 +21,18 @@ class DateFieldCorrectorTest { .parseInfo(parseInfo) .build(); - CorrectionInfo rewriter = dateFieldCorrector.rewriter(correctionInfo); + CorrectionInfo rewriter = dateFieldCorrector.corrector(correctionInfo); Assert.assertEquals("SELECT count(歌曲名) FROM 歌曲库 WHERE 数据日期 = '2023-08-14'", rewriter.getSql()); - correctionInfo = CorrectionInfo.builder() + correctionInfo = CorrectionInfo.builder() .sql("select count(歌曲名) from 歌曲库 where 数据日期 = '2023-08-14'") .parseInfo(parseInfo) .build(); - rewriter = dateFieldCorrector.rewriter(correctionInfo); + rewriter = dateFieldCorrector.corrector(correctionInfo); Assert.assertEquals("select count(歌曲名) from 歌曲库 where 数据日期 = '2023-08-14'", rewriter.getSql()); } -} \ No newline at end of file +} diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/FieldValueCorrectorTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/FieldValueCorrectorTest.java new file mode 100644 index 000000000..c5f34907f --- /dev/null +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/FieldValueCorrectorTest.java @@ -0,0 +1,66 @@ +package com.tencent.supersonic.chat.query.llm.dsl.corrector; + +import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.corrector.FieldValueCorrector; +import com.tencent.supersonic.chat.parser.llm.dsl.DSLParseResult; +import com.tencent.supersonic.chat.query.llm.dsl.LLMReq; +import com.tencent.supersonic.chat.query.llm.dsl.LLMReq.ElementValue; +import com.tencent.supersonic.common.pojo.Constants; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +class FieldValueCorrectorTest { + + @Test + void rewriter() { + + FieldValueCorrector corrector = new FieldValueCorrector(); + CorrectionInfo correctionInfo = CorrectionInfo.builder() + .sql("select 歌曲名 from 歌曲库 where 专辑照片 = '七里香' and 专辑名 = '流行' and 数据日期 = '2023-08-19'") + .build(); + + SemanticParseInfo parseInfo = new SemanticParseInfo(); + + DSLParseResult dslParseResult = new DSLParseResult(); + LLMReq llmReq = new LLMReq(); + List linking = new ArrayList<>(); + ElementValue elementValue = new ElementValue(); + elementValue.setFieldValue("流行"); + elementValue.setFieldName("歌曲风格"); + linking.add(elementValue); + + ElementValue elementValue2 = new ElementValue(); + elementValue2.setFieldValue("七里香"); + elementValue2.setFieldName("歌曲名"); + linking.add(elementValue2); + + ElementValue elementValue3 = new ElementValue(); + elementValue3.setFieldValue("周杰伦"); + elementValue3.setFieldName("歌手名"); + linking.add(elementValue3); + + ElementValue elementValue4 = new ElementValue(); + elementValue4.setFieldValue("流行"); + elementValue4.setFieldName("歌曲流派"); + linking.add(elementValue4); + + llmReq.setLinking(linking); + dslParseResult.setLlmReq(llmReq); + + Map properties = new HashMap<>(); + properties.put(Constants.CONTEXT, dslParseResult); + + parseInfo.setProperties(properties); + correctionInfo.setParseInfo(parseInfo); + + CorrectionInfo rewriter = corrector.corrector(correctionInfo); + + Assert.assertEquals("SELECT 歌曲名 FROM 歌曲库 WHERE 歌曲名 = '七里香' AND 歌曲流派 = '流行' AND 数据日期 = '2023-08-19'", + rewriter.getSql()); + } +} \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/query/dsl/optimizer/SelectFieldAppendCorrectorTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/SelectFieldAppendCorrectorTest.java similarity index 53% rename from chat/core/src/test/java/com/tencent/supersonic/chat/query/dsl/optimizer/SelectFieldAppendCorrectorTest.java rename to chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/SelectFieldAppendCorrectorTest.java index d796dd12d..176c0ac17 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/query/dsl/optimizer/SelectFieldAppendCorrectorTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/query/llm/dsl/corrector/SelectFieldAppendCorrectorTest.java @@ -1,8 +1,7 @@ -package com.tencent.supersonic.chat.query.dsl.optimizer; - -import static org.junit.jupiter.api.Assertions.*; +package com.tencent.supersonic.chat.query.llm.dsl.corrector; import com.tencent.supersonic.chat.api.pojo.CorrectionInfo; +import com.tencent.supersonic.chat.corrector.SelectFieldAppendCorrector; import org.junit.Assert; import org.junit.jupiter.api.Test; @@ -12,14 +11,16 @@ class SelectFieldAppendCorrectorTest { void rewriter() { SelectFieldAppendCorrector corrector = new SelectFieldAppendCorrector(); CorrectionInfo correctionInfo = CorrectionInfo.builder() - .sql("select 歌曲名 from 歌曲库 where datediff('day', 发布日期, '2023-08-09') <= 1 and 歌手名 = '邓紫棋' and sys_imp_date = '2023-08-09' and 歌曲发布时 = '2023-08-01' order by 播放量 desc limit 11") + .sql("select 歌曲名 from 歌曲库 where datediff('day', 发布日期, '2023-08-09') <= 1 and 歌手名 = '邓紫棋' " + + "and sys_imp_date = '2023-08-09' and 歌曲发布时 = '2023-08-01' order by 播放量 desc limit 11") .build(); - CorrectionInfo rewriter = corrector.rewriter(correctionInfo); + CorrectionInfo rewriter = corrector.corrector(correctionInfo); Assert.assertEquals( - "SELECT 歌曲名, 歌手名, 歌曲发布时, 发布日期 FROM 歌曲库 WHERE datediff('day', 发布日期, '2023-08-09') <= 1 AND 歌手名 = '邓紫棋' AND sys_imp_date = '2023-08-09' AND 歌曲发布时 = '2023-08-01' ORDER BY 播放量 DESC LIMIT 11", - rewriter.getSql()); + "SELECT 歌曲名, 歌手名, 歌曲发布时, 发布日期 FROM 歌曲库 WHERE datediff('day', 发布日期, '2023-08-09') <= 1 " + + "AND 歌手名 = '邓紫棋' AND sys_imp_date = '2023-08-09' " + + "AND 歌曲发布时 = '2023-08-01' ORDER BY 播放量 DESC LIMIT 11", rewriter.getSql()); } -} \ No newline at end of file +} diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/test/ChatBizLauncher.java b/chat/core/src/test/java/com/tencent/supersonic/chat/test/ChatBizLauncher.java index 7279ed301..fc996b200 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/test/ChatBizLauncher.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/test/ChatBizLauncher.java @@ -6,9 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; -@SpringBootApplication(scanBasePackages = {"com.tencent.supersonic.chat"} - // , exclude = {DataSourceAutoConfiguration.class} -) +@SpringBootApplication(scanBasePackages = {"com.tencent.supersonic.chat"}) @ComponentScan("com.tencent.supersonic.chat") @MapperScan("com.tencent.supersonic.chat") public class ChatBizLauncher { 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 700786744..39c24e53b 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 @@ -4,28 +4,26 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; -import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.chat.api.pojo.response.ChatConfigResp; -import com.tencent.supersonic.chat.api.pojo.response.ChatConfigRichResp; -import com.tencent.supersonic.chat.api.pojo.response.EntityRichInfoResp; import com.tencent.supersonic.chat.config.DefaultMetric; import com.tencent.supersonic.chat.config.DefaultMetricInfo; import com.tencent.supersonic.chat.config.EntityInternalDetail; -import com.tencent.supersonic.chat.persistence.mapper.ChatContextMapper; import com.tencent.supersonic.chat.persistence.repository.impl.ChatContextRepositoryImpl; -import com.tencent.supersonic.chat.service.ChatService; import com.tencent.supersonic.chat.service.QueryService; -import com.tencent.supersonic.chat.service.impl.ConfigServiceImpl; -import com.tencent.supersonic.common.pojo.Constants; 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.ModelSchemaResp; import com.tencent.supersonic.semantic.api.model.response.MetricResp; import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; -import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; +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.MetricService; import com.tencent.supersonic.semantic.model.domain.ModelService; +import com.tencent.supersonic.semantic.model.domain.MetricService; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -45,17 +43,13 @@ public class MockBeansConfiguration { public static void buildHttpSemanticServiceImpl(SemanticLayer httpSemanticLayer, List dimensionDescs, List metricDescs) { - ChatConfigRichResp chaConfigRichDesc = new ChatConfigRichResp(); DefaultMetric defaultMetricDesc = new DefaultMetric(); defaultMetricDesc.setUnit(3); defaultMetricDesc.setPeriod(Constants.DAY); -// chaConfigRichDesc.setDefaultMetrics(new ArrayList<>(Arrays.asList(defaultMetricDesc))); - EntityRichInfoResp entityDesc = new EntityRichInfoResp(); List dimensionDescs1 = new ArrayList<>(); DimSchemaResp dimensionDesc = new DimSchemaResp(); dimensionDesc.setId(162L); dimensionDescs1.add(dimensionDesc); -// entityDesc.setEntityIds(dimensionDescs1); DimSchemaResp dimensionDesc2 = new DimSchemaResp(); dimensionDesc2.setId(163L); @@ -69,14 +63,11 @@ public class MockBeansConfiguration { metricDesc.setBizName("js_play_cnt"); metricDesc.setName("结算播放量"); entityInternalDetailDesc.setMetricList(new ArrayList<>(Arrays.asList(metricDesc))); -// entityDesc.setEntityInternalDetailDesc(entityInternalDetailDesc); -// chaConfigRichDesc.setEntity(entityDesc); -// when(httpSemanticLayer.getChatConfigRichInfo(anyLong())).thenReturn(chaConfigRichDesc); ModelSchemaResp modelSchemaDesc = new ModelSchemaResp(); modelSchemaDesc.setDimensions(dimensionDescs); modelSchemaDesc.setMetrics(metricDescs); -// when(httpSemanticLayer.getModelSchemaInfo(anyLong())).thenReturn(modelSchemaDesc); + } public static void getModelExtendMock(ConfigServiceImpl configService) { @@ -87,7 +78,6 @@ public class MockBeansConfiguration { defaultMetricInfos.add(defaultMetricInfo); ChatConfigResp chaConfigDesc = new ChatConfigResp(); -// chaConfigDesc.setDefaultMetrics(defaultMetricInfos); when(configService.fetchConfigByModelId(anyLong())).thenReturn(chaConfigDesc); } 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 2f1a01f93..0996363ed 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 @@ -1,6 +1,8 @@ package com.hankcs.hanlp.collection.trie.bintrie; import com.hankcs.hanlp.corpus.io.ByteArray; +import com.tencent.supersonic.common.util.ContextUtils; +import com.tencent.supersonic.knowledge.service.LoadRemoveService; import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInput; @@ -8,9 +10,12 @@ import java.io.ObjectOutput; import java.util.AbstractMap; import java.util.ArrayDeque; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class BaseNode implements Comparable { @@ -19,6 +24,8 @@ public abstract class BaseNode implements Comparable { * 状态数组,方便读取的时候用 */ static final Status[] ARRAY_STATUS = Status.values(); + + private static final Logger logger = LoggerFactory.getLogger(BaseNode.class); /** * 子节点 */ @@ -279,10 +286,14 @@ public abstract class BaseNode implements Comparable { + '}'; } - public void walkNode(Set> entrySet) { + public void walkNode(Set> entrySet, Integer agentId, Set detectModelIds) { if (status == Status.WORD_MIDDLE_2 || status == Status.WORD_END_3) { + LoadRemoveService loadRemoveService = ContextUtils.getBean(LoadRemoveService.class); + logger.debug("agentId:{},detectModelIds:{},before:{}", agentId, detectModelIds, value.toString()); + List natures = loadRemoveService.removeNatures((List) value, agentId, detectModelIds); String name = this.prefix != null ? this.prefix + c : "" + c; - entrySet.add(new TrieEntry(name, value)); + logger.debug("name:{},after:{},natures:{}", name, (List) value, natures); + entrySet.add(new TrieEntry(name, (V) natures)); } } @@ -292,7 +303,8 @@ public abstract class BaseNode implements Comparable { * @param entrySet * @param limit */ - public void walkLimit(StringBuilder sb, Set> entrySet, int limit) { + public void walkLimit(StringBuilder sb, Set> entrySet, int limit, Integer agentId, + Set detectModelIds) { Queue queue = new ArrayDeque<>(); this.prefix = sb.toString(); queue.add(this); @@ -304,7 +316,7 @@ public abstract class BaseNode implements Comparable { if (root == null) { continue; } - root.walkNode(entrySet); + root.walkNode(entrySet, agentId, detectModelIds); if (root.child == null) { continue; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/ModelInfoStat.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/ModelInfoStat.java similarity index 86% rename from chat/core/src/main/java/com/tencent/supersonic/chat/mapper/ModelInfoStat.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/ModelInfoStat.java index c1f249fc6..1886e4856 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/mapper/ModelInfoStat.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/dictionary/ModelInfoStat.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.mapper; +package com.tencent.supersonic.knowledge.dictionary; import java.io.Serializable; import lombok.Builder; 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 index 50fddcace..e940a7fc5 100644 --- 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 @@ -23,4 +23,4 @@ public class WordBuilderFactory { 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/semantic/LocalSemanticLayer.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/LocalSemanticLayer.java index e42c21c0a..d11d05017 100644 --- 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 @@ -8,7 +8,12 @@ import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.ModelSchemaFilterReq; 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.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.ModelResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; 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; @@ -31,7 +36,7 @@ public class LocalSemanticLayer extends BaseSemanticLayer { @SneakyThrows @Override - public QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user){ + public QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user) { QueryService queryService = ContextUtils.getBean(QueryService.class); return queryService.queryByStructWithAuth(queryStructReq, user); } diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/ModelSchemaBuilder.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/ModelSchemaBuilder.java index 43a120325..02b415d05 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/ModelSchemaBuilder.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/ModelSchemaBuilder.java @@ -12,7 +12,13 @@ import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; import org.springframework.util.CollectionUtils; -import java.util.*; +import java.util.Set; +import java.util.HashSet; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Objects; +import java.util.Map; import java.util.stream.Collectors; public class ModelSchemaBuilder { diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/RemoteSemanticLayer.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/RemoteSemanticLayer.java index 944a485d7..1319d0e81 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/RemoteSemanticLayer.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/semantic/RemoteSemanticLayer.java @@ -1,43 +1,37 @@ package com.tencent.supersonic.knowledge.semantic; -import static com.tencent.supersonic.common.pojo.Constants.LIST_LOWER; -import static com.tencent.supersonic.common.pojo.Constants.PAGESIZE_LOWER; -import static com.tencent.supersonic.common.pojo.Constants.TOTAL_LOWER; -import static com.tencent.supersonic.common.pojo.Constants.TRUE_LOWER; - import com.alibaba.fastjson.JSON; import com.github.pagehelper.PageInfo; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; 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.common.pojo.ResultData; -import com.tencent.supersonic.common.pojo.ReturnCode; -import com.tencent.supersonic.common.pojo.enums.AuthType; -import com.tencent.supersonic.common.pojo.exception.CommonException; 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.common.util.JsonUtil; +import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.ModelSchemaFilterReq; 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.semantic.api.model.response.ModelResp; -import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.ModelResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; 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.pojo.exception.CommonException; +import com.tencent.supersonic.common.pojo.ResultData; +import com.tencent.supersonic.common.pojo.ReturnCode; + import java.net.URI; -import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; -import java.util.concurrent.TimeUnit; +import java.util.LinkedHashMap; + import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; @@ -50,6 +44,11 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; +import static com.tencent.supersonic.common.pojo.Constants.TRUE_LOWER; +import static com.tencent.supersonic.common.pojo.Constants.LIST_LOWER; +import static com.tencent.supersonic.common.pojo.Constants.TOTAL_LOWER; +import static com.tencent.supersonic.common.pojo.Constants.PAGESIZE_LOWER; + @Slf4j public class RemoteSemanticLayer extends BaseSemanticLayer { @@ -57,8 +56,6 @@ public class RemoteSemanticLayer extends BaseSemanticLayer { private AuthenticationConfig authenticationConfig; - private static final Cache> domainSchemaCache = - CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); private ParameterizedTypeReference> structTypeRef = new ParameterizedTypeReference>() { }; @@ -125,7 +122,7 @@ public class RemoteSemanticLayer extends BaseSemanticLayer { DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); URI requestUrl = UriComponentsBuilder.fromHttpUrl( - defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchModelSchemaPath()).build() + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchModelSchemaPath()).build() .encode().toUri(); ModelSchemaFilterReq filter = new ModelSchemaFilterReq(); filter.setModelIds(ids); @@ -155,8 +152,8 @@ public class RemoteSemanticLayer extends BaseSemanticLayer { public List getDomainList(User user) { DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); Object domainDescListObject = fetchHttpResult( - defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDomainListPath(), null, - HttpMethod.GET); + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDomainListPath(), + null, HttpMethod.GET); return JsonUtil.toList(JsonUtil.toString(domainDescListObject), DomainResp.class); } @@ -167,8 +164,8 @@ public class RemoteSemanticLayer extends BaseSemanticLayer { } DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); String url = String.format("%s?domainId=%s&authType=%s", - defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchModelListPath() - , domainId, authType.toString()); + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchModelListPath(), + domainId, authType.toString()); Object domainDescListObject = fetchHttpResult(url, null, HttpMethod.GET); return JsonUtil.toList(JsonUtil.toString(domainDescListObject), ModelResp.class); } @@ -218,8 +215,8 @@ public class RemoteSemanticLayer extends BaseSemanticLayer { DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); log.info("url:{}", defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchMetricPagePath()); Object dimensionListObject = fetchHttpResult( - defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchMetricPagePath(), body, - HttpMethod.POST); + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchMetricPagePath(), + body, HttpMethod.POST); LinkedHashMap map = (LinkedHashMap) dimensionListObject; PageInfo metricDescObjectPageInfo = generatePageInfo(map); PageInfo metricDescPageInfo = new PageInfo<>(); @@ -233,8 +230,8 @@ public class RemoteSemanticLayer extends BaseSemanticLayer { String body = JsonUtil.toString(pageDimensionCmd); DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); Object dimensionListObject = fetchHttpResult( - defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDimensionPagePath(), body, - HttpMethod.POST); + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDimensionPagePath(), + body, HttpMethod.POST); LinkedHashMap map = (LinkedHashMap) dimensionListObject; PageInfo dimensionDescObjectPageInfo = generatePageInfo(map); PageInfo dimensionDescPageInfo = new PageInfo<>(); diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/LoadRemoveService.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/LoadRemoveService.java new file mode 100644 index 000000000..c00ce9d7b --- /dev/null +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/LoadRemoveService.java @@ -0,0 +1,55 @@ +package com.tencent.supersonic.knowledge.service; + +import com.tencent.supersonic.knowledge.utils.NatureHelper; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Data +@Service +public class LoadRemoveService { + + @Value("${mapper.remove.agentId:}") + private Integer mapperRemoveAgentId; + + @Value("${mapper.remove.nature.prefix:}") + private String mapperRemoveNaturePrefix; + + + public List removeNatures(List value, Integer agentId, Set detectModelIds) { + if (CollectionUtils.isEmpty(value)) { + return value; + } + List resultList = new ArrayList<>(value); + if (!CollectionUtils.isEmpty(detectModelIds)) { + resultList.removeIf(nature -> { + if (Objects.isNull(nature)) { + return false; + } + Long modelId = NatureHelper.getModelId(nature); + if (Objects.nonNull(modelId)) { + return !detectModelIds.contains(modelId); + } + return false; + }); + } + if (Objects.nonNull(mapperRemoveAgentId) + && mapperRemoveAgentId.equals(agentId) + && StringUtils.isNotBlank(mapperRemoveNaturePrefix)) { + resultList.removeIf(nature -> { + if (Objects.isNull(nature)) { + return false; + } + return nature.startsWith(mapperRemoveNaturePrefix); + }); + } + return resultList; + } + +} \ 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 index 4113d4b60..60a02c91f 100644 --- 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 @@ -15,9 +15,9 @@ import org.springframework.stereotype.Service; @Slf4j public class SchemaService { - private static final Integer META_CACHE_TIME = 5; - public static final String ALL_CACHE = "all"; + public static final String ALL_CACHE = "all"; + private static final Integer META_CACHE_TIME = 5; private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); private LoadingCache cache = CacheBuilder.newBuilder() diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SearchService.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SearchService.java index 1c865f6a9..49c6c2159 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SearchService.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/service/SearchService.java @@ -27,7 +27,6 @@ public class SearchService { public static final int SEARCH_SIZE = 200; private static BinTrie> trie; private static BinTrie> suffixTrie; - private static String localFileCache = ""; static { trie = new BinTrie<>(); @@ -39,16 +38,13 @@ public class SearchService { * @param key * @return */ - public static List prefixSearch(String key) { - return prefixSearch(key, SEARCH_SIZE, trie); + public static List prefixSearch(String key, int limit, Integer agentId, Set detectModelIds) { + return prefixSearch(key, limit, agentId, trie, detectModelIds); } - public static List prefixSearch(String key, int limit) { - return prefixSearch(key, limit, trie); - } - - public static List prefixSearch(String key, int limit, BinTrie> binTrie) { - Set>> result = prefixSearchLimit(key, limit, binTrie); + public static List prefixSearch(String key, int limit, Integer agentId, BinTrie> binTrie, + Set detectModelIds) { + Set>> result = prefixSearchLimit(key, limit, binTrie, agentId, detectModelIds); return result.stream().map( entry -> { String name = entry.getKey().replace("#", " "); @@ -64,13 +60,14 @@ public class SearchService { * @param key * @return */ - public static List suffixSearch(String key, int limit) { + public static List suffixSearch(String key, int limit, Integer agentId, Set detectModelIds) { String reverseDetectSegment = StringUtils.reverse(key); - return suffixSearch(reverseDetectSegment, limit, suffixTrie); + return suffixSearch(reverseDetectSegment, limit, agentId, suffixTrie, detectModelIds); } - public static List suffixSearch(String key, int limit, BinTrie> binTrie) { - Set>> result = prefixSearchLimit(key, limit, binTrie); + public static List suffixSearch(String key, int limit, Integer agentId, BinTrie> binTrie, + Set detectModelIds) { + Set>> result = prefixSearchLimit(key, limit, binTrie, agentId, detectModelIds); return result.stream().map( entry -> { String name = entry.getKey().replace("#", " "); @@ -86,7 +83,7 @@ public class SearchService { } private static Set>> prefixSearchLimit(String key, int limit, - BinTrie> binTrie) { + BinTrie> binTrie, Integer agentId, Set detectModelIds) { key = key.toLowerCase(); Set>> entrySet = new TreeSet>>(); StringBuilder sb = new StringBuilder(key.substring(0, key.length() - 1)); @@ -102,7 +99,7 @@ public class SearchService { if (branch == null) { return entrySet; } - branch.walkLimit(sb, entrySet, limit); + branch.walkLimit(sb, entrySet, limit, agentId, detectModelIds); return entrySet; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/NatureHelper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/NatureHelper.java similarity index 98% rename from chat/core/src/main/java/com/tencent/supersonic/chat/utils/NatureHelper.java rename to chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/NatureHelper.java index bf9bd411f..4dd6db8d5 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/utils/NatureHelper.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/utils/NatureHelper.java @@ -1,10 +1,10 @@ -package com.tencent.supersonic.chat.utils; +package com.tencent.supersonic.knowledge.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.ModelInfoStat; import com.tencent.supersonic.knowledge.dictionary.DictWordType; +import com.tencent.supersonic.knowledge.dictionary.ModelInfoStat; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; 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 cc651ea98..93d69986c 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 @@ -53,11 +53,11 @@ public class DateConf { return false; } DateConf dateConf = (DateConf) o; - return dateMode == dateConf.dateMode && - Objects.equals(startDate, dateConf.startDate) && - Objects.equals(endDate, dateConf.endDate) && - Objects.equals(unit, dateConf.unit) && - Objects.equals(period, dateConf.period); + return dateMode == dateConf.dateMode + && Objects.equals(startDate, dateConf.startDate) + && Objects.equals(endDate, dateConf.endDate) + && Objects.equals(unit, dateConf.unit) + && Objects.equals(period, dateConf.period); } @Override diff --git a/common/src/main/java/com/tencent/supersonic/common/pojo/QueryAuthorization.java b/common/src/main/java/com/tencent/supersonic/common/pojo/QueryAuthorization.java index d4aa22df3..443b88b4e 100644 --- a/common/src/main/java/com/tencent/supersonic/common/pojo/QueryAuthorization.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/QueryAuthorization.java @@ -16,4 +16,8 @@ public class QueryAuthorization { private List dimensionFilters; private List dimensionFiltersDesc; private String message; + + public QueryAuthorization(String message) { + this.message = message; + } } \ No newline at end of file diff --git a/common/src/main/java/com/tencent/supersonic/common/util/ChatGptHelper.java b/common/src/main/java/com/tencent/supersonic/common/util/ChatGptHelper.java index 56f207540..4a5848957 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/ChatGptHelper.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/ChatGptHelper.java @@ -33,9 +33,9 @@ public class ChatGptHelper { private Integer proxyPort; - public ChatGPT getChatGPT(){ + public ChatGPT getChatGPT() { Proxy proxy = null; - if (!"default".equals(proxyIp)){ + if (!"default".equals(proxyIp)) { proxy = Proxys.http(proxyIp, proxyPort); } return ChatGPT.builder() @@ -47,8 +47,8 @@ public class ChatGptHelper { .init(); } - public Message getChatCompletion(Message system,Message message){ - ChatCompletion chatCompletion = ChatCompletion.builder() + public Message getChatCompletion(Message system, Message message) { + ChatCompletion chatCompletion = ChatCompletion.builder() .model(ChatCompletion.Model.GPT_3_5_TURBO_16K.getName()) .messages(Arrays.asList(system, message)) .maxTokens(10000) @@ -58,41 +58,61 @@ public class ChatGptHelper { return response.getChoices().get(0).getMessage(); } - public String inferredTime(String queryText){ + public String inferredTime(String queryText) { long nowTime = System.currentTimeMillis(); Date date = new Date(nowTime); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String formattedDate = sdf.format(date); - Message system = Message.ofSystem("现在时间 "+formattedDate+",你是一个专业的数据分析师,你的任务是基于数据,专业的解答用户的问题。" + - "你需要遵守以下规则:\n" + - "1.返回规范的数据格式,json,如: 输入:近 10 天的日活跃数,输出:{\"start\":\"2023-07-21\",\"end\":\"2023-07-31\"}" + - "2.你对时间数据要求规范,能从近 10 天,国庆节,端午节,获取到相应的时间,填写到 json 中。\n"+ - "3.你的数据时间,只有当前及之前时间即可,超过则回复去年\n" + - "4.只需要解析出时间,时间可以是时间月和年或日、日历采用公历\n"+ - "5.时间给出要是绝对正确,不能瞎编\n" + Message system = Message.ofSystem("现在时间 " + formattedDate + ",你是一个专业的数据分析师,你的任务是基于数据,专业的解答用户的问题。" + + "你需要遵守以下规则:\n" + + "1.返回规范的数据格式,json,如: 输入:近 10 天的日活跃数,输出:{\"start\":\"2023-07-21\",\"end\":\"2023-07-31\"}" + + "2.你对时间数据要求规范,能从近 10 天,国庆节,端午节,获取到相应的时间,填写到 json 中。\n" + + "3.你的数据时间,只有当前及之前时间即可,超过则回复去年\n" + + "4.只需要解析出时间,时间可以是时间月和年或日、日历采用公历\n" + + "5.时间给出要是绝对正确,不能瞎编\n" ); - Message message = Message.of("输入:"+queryText+",输出:"); + Message message = Message.of("输入:" + queryText + ",输出:"); Message res = getChatCompletion(system, message); return res.getContent(); } - public String mockAlias(String mockType,String name,String bizName,String table,String desc,Boolean isPercentage){ - String msg = "Assuming you are a professional data analyst specializing in indicators, you have a vast amount of data analysis indicator content. You are familiar with the basic format of the content,Now, Construct your answer Based on the following json-schema.\n" + - "{\n" + - "\"$schema\": \"http://json-schema.org/draft-07/schema#\",\n" + - "\"type\": \"array\",\n" + - "\"minItems\": 2,\n" + - "\"maxItems\": 4,\n" + - "\"items\": {\n" + - "\"type\": \"string\",\n" + - "\"description\": \"Assuming you are a data analyst and give a defined "+mockType+" name: " +name+","+ - "this "+mockType+" is from database and table: "+table+ ",This "+mockType+" calculates the field source: "+bizName+", The description of this indicator is: "+desc+", provide some aliases for this,please take chinese or english,but more chinese and Not repeating,\"\n" + - "},\n" + - "\"additionalProperties\":false}\n" + - "Please double-check whether the answer conforms to the format described in the JSON-schema.\n" + - "ANSWER JSON:"; - log.info("msg:{}",msg); + public String mockAlias(String mockType, + String name, + String bizName, + String table, + String desc, + Boolean isPercentage) { + String msg = "Assuming you are a professional data analyst specializing in indicators, " + + "you have a vast amount of data analysis indicator content. You are familiar with the basic" + + " format of the content,Now, Construct your answer Based on the following json-schema.\n" + + "{\n" + + "\"$schema\": \"http://json-schema.org/draft-07/schema#\",\n" + + "\"type\": \"array\",\n" + + "\"minItems\": 2,\n" + + "\"maxItems\": 4,\n" + + "\"items\": {\n" + + "\"type\": \"string\",\n" + + "\"description\": \"Assuming you are a data analyst and give a defined " + + mockType + + " name: " + + name + "," + + "this " + + mockType + + " is from database and table: " + + table + ",This " + + mockType + + " calculates the field source: " + + bizName + + ", The description of this indicator is: " + + desc + + ", provide some aliases for this,please take chinese or english," + + "but more chinese and Not repeating,\"\n" + + "},\n" + + "\"additionalProperties\":false}\n" + + "Please double-check whether the answer conforms to the format described in the JSON-schema.\n" + + "ANSWER JSON:"; + log.info("msg:{}", msg); Message system = Message.ofSystem(""); Message message = Message.of(msg); Message res = getChatCompletion(system, message); @@ -100,17 +120,19 @@ public class ChatGptHelper { } - - public String mockDimensionValueAlias(String json){ - String msg = "Assuming you are a professional data analyst specializing in indicators,for you a json list," + - "the required content to follow is as follows: " + - "1. The format of JSON," + - "2. Only return in JSON format," + - "3. the array item > 1 and < 5,more alias," + - "for example:input:[\"qq_music\",\"kugou_music\"],out:{\"tran\":[\"qq音乐\",\"酷狗音乐\"],\"alias\":{\"qq_music\":[\"q音\",\"qq音乐\"],\"kugou_music\":[\"kugou\",\"酷狗\"]}}," + - "now input: " + json + ","+ - "answer json:"; - log.info("msg:{}",msg); + public String mockDimensionValueAlias(String json) { + String msg = "Assuming you are a professional data analyst specializing in indicators,for you a json list," + + "the required content to follow is as follows: " + + "1. The format of JSON," + + "2. Only return in JSON format," + + "3. the array item > 1 and < 5,more alias," + + "for example:input:[\"qq_music\",\"kugou_music\"]," + + "out:{\"tran\":[\"qq音乐\",\"酷狗音乐\"],\"alias\":{\"qq_music\":[\"q音\",\"qq音乐\"]," + + "\"kugou_music\":[\"kugou\",\"酷狗\"]}}," + + "now input: " + + json + "," + + "answer json:"; + log.info("msg:{}", msg); Message system = Message.ofSystem(""); Message message = Message.of(msg); Message res = getChatCompletion(system, message); @@ -118,12 +140,9 @@ public class ChatGptHelper { } - - - public static void main(String[] args) { ChatGptHelper chatGptHelper = new ChatGptHelper(); - System.out.println(chatGptHelper.mockAlias("","","","","",false)); + System.out.println(chatGptHelper.mockAlias("", "", "", "", "", false)); } 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 index 5715b1df9..b743fc450 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/DateUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/DateUtils.java @@ -31,6 +31,7 @@ public class DateUtils { dateFormat.parse(date); return DateTimeFormatter.ofPattern(format); } catch (Exception e) { + log.info("date parse has a exception:{}", e.toString()); } } return DateTimeFormatter.ofPattern(formats[0]); @@ -44,6 +45,7 @@ public class DateUtils { LocalDateTime.parse(date, dateTimeFormatter); return dateTimeFormatter; } catch (Exception e) { + log.info("date parse has a exception:{}", e.toString()); } } return DateTimeFormatter.ofPattern(formats[0]); diff --git a/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FieldAndValueAcquireVisitor.java b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FieldAndValueAcquireVisitor.java new file mode 100644 index 000000000..112a78520 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FieldAndValueAcquireVisitor.java @@ -0,0 +1,84 @@ +package com.tencent.supersonic.common.util.jsqlparser; + +import java.util.Set; +import net.sf.jsqlparser.expression.DoubleValue; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.GreaterThan; +import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals; +import net.sf.jsqlparser.expression.operators.relational.MinorThan; +import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; +import net.sf.jsqlparser.schema.Column; + +public class FieldAndValueAcquireVisitor extends ExpressionVisitorAdapter { + + private Set filterExpressions; + + public FieldAndValueAcquireVisitor(Set filterExpressions) { + this.filterExpressions = filterExpressions; + } + + + @Override + public void visit(MinorThan expr) { + FilterExpression filterExpression = getFilterExpression(expr); + filterExpressions.add(filterExpression); + } + + @Override + public void visit(EqualsTo expr) { + FilterExpression filterExpression = getFilterExpression(expr); + filterExpressions.add(filterExpression); + } + + + @Override + public void visit(MinorThanEquals expr) { + FilterExpression filterExpression = getFilterExpression(expr); + filterExpressions.add(filterExpression); + } + + + @Override + public void visit(GreaterThan expr) { + FilterExpression filterExpression = getFilterExpression(expr); + filterExpressions.add(filterExpression); + } + + @Override + public void visit(GreaterThanEquals expr) { + FilterExpression filterExpression = getFilterExpression(expr); + filterExpressions.add(filterExpression); + } + + private FilterExpression getFilterExpression(ComparisonOperator expr) { + Expression leftExpression = expr.getLeftExpression(); + Expression rightExpression = expr.getRightExpression(); + + FilterExpression filterExpression = new FilterExpression(); + String columnName = null; + if (leftExpression instanceof Column) { + Column column = (Column) leftExpression; + columnName = column.getColumnName(); + filterExpression.setFieldName(columnName); + } + if (rightExpression instanceof StringValue) { + StringValue stringValue = (StringValue) rightExpression; + filterExpression.setFieldValue(stringValue.getValue()); + } + if (rightExpression instanceof DoubleValue) { + DoubleValue doubleValue = (DoubleValue) rightExpression; + filterExpression.setFieldValue(doubleValue.getValue()); + } + if (rightExpression instanceof LongValue) { + LongValue longValue = (LongValue) rightExpression; + filterExpression.setFieldValue(longValue.getValue()); + } + filterExpression.setOperator(expr.getStringExpression()); + return filterExpression; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FiledValueReplaceVisitor.java b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FiledValueReplaceVisitor.java new file mode 100644 index 000000000..884baa708 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FiledValueReplaceVisitor.java @@ -0,0 +1,46 @@ +package com.tencent.supersonic.common.util.jsqlparser; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.schema.Column; +import org.springframework.util.CollectionUtils; + +public class FiledValueReplaceVisitor extends ExpressionVisitorAdapter { + + private Map> fieldValueToFieldNames; + + public FiledValueReplaceVisitor(Map> fieldValueToFieldNames) { + this.fieldValueToFieldNames = fieldValueToFieldNames; + } + + @Override + public void visit(EqualsTo expr) { + Expression leftExpression = expr.getLeftExpression(); + Expression rightExpression = expr.getRightExpression(); + if (!(rightExpression instanceof StringValue)) { + return; + } + if (!(leftExpression instanceof Column)) { + return; + } + if (CollectionUtils.isEmpty(fieldValueToFieldNames)) { + return; + } + if (Objects.isNull(rightExpression) || Objects.isNull(leftExpression)) { + return; + } + Column leftColumnName = (Column) leftExpression; + StringValue rightStringValue = (StringValue) rightExpression; + + Set fieldNames = fieldValueToFieldNames.get(rightStringValue.getValue()); + if (!CollectionUtils.isEmpty(fieldNames) && !fieldNames.contains(leftColumnName.getColumnName())) { + leftColumnName.setColumnName(fieldNames.stream().findFirst().get()); + } + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FilterExpression.java b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FilterExpression.java new file mode 100644 index 000000000..b4c304d62 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/FilterExpression.java @@ -0,0 +1,14 @@ +package com.tencent.supersonic.common.util.jsqlparser; + +import lombok.Data; + +@Data +public class FilterExpression { + + private String operator; + + private String fieldName; + + private Object fieldValue; + +} \ No newline at end of file diff --git a/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/OrderByAcquireVisitor.java b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/OrderByAcquireVisitor.java new file mode 100644 index 000000000..c840207db --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/OrderByAcquireVisitor.java @@ -0,0 +1,25 @@ +package com.tencent.supersonic.common.util.jsqlparser; + +import java.util.Set; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.select.OrderByElement; +import net.sf.jsqlparser.statement.select.OrderByVisitorAdapter; + +public class OrderByAcquireVisitor extends OrderByVisitorAdapter { + + private Set fields; + + public OrderByAcquireVisitor(Set fields) { + this.fields = fields; + } + + @Override + public void visit(OrderByElement orderBy) { + Expression expression = orderBy.getExpression(); + if (expression instanceof Column) { + fields.add(((Column) expression).getColumnName()); + } + super.visit(orderBy); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelper.java b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelper.java new file mode 100644 index 000000000..d7e9a0df8 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelper.java @@ -0,0 +1,188 @@ +package com.tencent.supersonic.common.util.jsqlparser; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.GroupByElement; +import net.sf.jsqlparser.statement.select.OrderByElement; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectBody; +import net.sf.jsqlparser.statement.select.SelectItem; +import org.springframework.util.CollectionUtils; + +/** + * Sql Parser Select Helper + */ +@Slf4j +public class SqlParserSelectHelper { + public static List getFilterExpression(String sql) { + PlainSelect plainSelect = getPlainSelect(sql); + if (Objects.isNull(plainSelect)) { + return new ArrayList<>(); + } + Set result = new HashSet<>(); + Expression where = plainSelect.getWhere(); + if (Objects.nonNull(where)) { + where.accept(new FieldAndValueAcquireVisitor(result)); + } + return new ArrayList<>(result); + } + + public static List getWhereFields(String sql) { + PlainSelect plainSelect = getPlainSelect(sql); + if (Objects.isNull(plainSelect)) { + return new ArrayList<>(); + } + Set result = new HashSet<>(); + Expression where = plainSelect.getWhere(); + if (Objects.nonNull(where)) { + where.accept(new FieldAcquireVisitor(result)); + } + return new ArrayList<>(result); + } + + public static List getOrderByFields(String sql) { + PlainSelect plainSelect = getPlainSelect(sql); + if (Objects.isNull(plainSelect)) { + return new ArrayList<>(); + } + Set result = new HashSet<>(); + List orderByElements = plainSelect.getOrderByElements(); + if (!CollectionUtils.isEmpty(orderByElements)) { + for (OrderByElement orderByElement : orderByElements) { + orderByElement.accept(new OrderByAcquireVisitor(result)); + } + } + return new ArrayList<>(result); + } + + public static List getSelectFields(String sql) { + PlainSelect plainSelect = getPlainSelect(sql); + if (Objects.isNull(plainSelect)) { + return new ArrayList<>(); + } + return new ArrayList<>(getSelectFields(plainSelect)); + } + + public static Set getSelectFields(PlainSelect plainSelect) { + List selectItems = plainSelect.getSelectItems(); + Set result = new HashSet<>(); + for (SelectItem selectItem : selectItems) { + selectItem.accept(new FieldAcquireVisitor(result)); + } + return result; + } + + public static PlainSelect getPlainSelect(String sql) { + Select selectStatement = getSelect(sql); + if (selectStatement == null) { + return null; + } + SelectBody selectBody = selectStatement.getSelectBody(); + + if (!(selectBody instanceof PlainSelect)) { + return null; + } + return (PlainSelect) selectBody; + } + + public static Select getSelect(String sql) { + Statement statement = null; + try { + statement = CCJSqlParserUtil.parse(sql); + } catch (JSQLParserException e) { + log.error("parse error", e); + return null; + } + + if (!(statement instanceof Select)) { + return null; + } + return (Select) statement; + } + + + public static List getAllFields(String sql) { + + PlainSelect plainSelect = getPlainSelect(sql); + if (Objects.isNull(plainSelect)) { + return new ArrayList<>(); + } + Set result = getSelectFields(plainSelect); + + GroupByElement groupBy = plainSelect.getGroupBy(); + if (groupBy != null) { + List groupByExpressions = groupBy.getGroupByExpressions(); + for (Expression expression : groupByExpressions) { + if (expression instanceof Column) { + Column column = (Column) expression; + result.add(column.getColumnName()); + } + } + } + List orderByElements = plainSelect.getOrderByElements(); + if (orderByElements != null) { + for (OrderByElement orderByElement : orderByElements) { + Expression expression = orderByElement.getExpression(); + + if (expression instanceof Column) { + Column column = (Column) expression; + result.add(column.getColumnName()); + } + } + } + Expression where = plainSelect.getWhere(); + if (where != null) { + where.accept(new ExpressionVisitorAdapter() { + @Override + public void visit(Column column) { + result.add(column.getColumnName()); + } + }); + } + + return new ArrayList<>(result); + } + + public static String getTableName(String sql) { + Select selectStatement = getSelect(sql); + if (selectStatement == null) { + return null; + } + SelectBody selectBody = selectStatement.getSelectBody(); + PlainSelect plainSelect = (PlainSelect) selectBody; + + Table table = (Table) plainSelect.getFromItem(); + return table.getName(); + } + + + public static boolean hasAggregateFunction(String sql) { + Select selectStatement = getSelect(sql); + SelectBody selectBody = selectStatement.getSelectBody(); + + if (!(selectBody instanceof PlainSelect)) { + return false; + } + PlainSelect plainSelect = (PlainSelect) selectBody; + List selectItems = plainSelect.getSelectItems(); + AggregateFunctionVisitor visitor = new AggregateFunctionVisitor(); + for (SelectItem selectItem : selectItems) { + selectItem.accept(visitor); + } + return visitor.hasAggregateFunction(); + } + +} + diff --git a/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/CCJSqlParserUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserUpdateHelper.java similarity index 56% rename from common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/CCJSqlParserUtils.java rename to common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserUpdateHelper.java index da0e9cb1f..e25978fd5 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/CCJSqlParserUtils.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserUpdateHelper.java @@ -1,23 +1,17 @@ package com.tencent.supersonic.common.util.jsqlparser; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.expression.operators.relational.EqualsTo; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.GroupByElement; import net.sf.jsqlparser.statement.select.OrderByElement; import net.sf.jsqlparser.statement.select.PlainSelect; @@ -29,115 +23,30 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.util.CollectionUtils; /** - * CC JSql ParserUtils + * Sql Parser Update Helper */ @Slf4j -public class CCJSqlParserUtils { +public class SqlParserUpdateHelper { - public static List getWhereFields(String sql) { - PlainSelect plainSelect = getPlainSelect(sql); - if (Objects.isNull(plainSelect)) { - return new ArrayList<>(); - } - Set result = new HashSet<>(); - Expression where = plainSelect.getWhere(); - if (Objects.nonNull(where)) { - where.accept(new FieldAcquireVisitor(result)); - } - return new ArrayList<>(result); - } - - public static List getSelectFields(String sql) { - PlainSelect plainSelect = getPlainSelect(sql); - if (Objects.isNull(plainSelect)) { - return new ArrayList<>(); - } - return new ArrayList<>(getSelectFields(plainSelect)); - } - - private static Set getSelectFields(PlainSelect plainSelect) { - List selectItems = plainSelect.getSelectItems(); - Set result = new HashSet<>(); - for (SelectItem selectItem : selectItems) { - selectItem.accept(new FieldAcquireVisitor(result)); - } - return result; - } - - private static PlainSelect getPlainSelect(String sql) { - Select selectStatement = getSelect(sql); - if (selectStatement == null) { - return null; - } + public static String replaceValueFields(String sql, Map> fieldValueToFieldNames) { + Select selectStatement = SqlParserSelectHelper.getSelect(sql); SelectBody selectBody = selectStatement.getSelectBody(); - if (!(selectBody instanceof PlainSelect)) { - return null; - } - return (PlainSelect) selectBody; - } - - private static Select getSelect(String sql) { - Statement statement = null; - try { - statement = CCJSqlParserUtil.parse(sql); - } catch (JSQLParserException e) { - log.error("parse error", e); - return null; - } - - if (!(statement instanceof Select)) { - return null; - } - return (Select) statement; - } - - - public static List getAllFields(String sql) { - - PlainSelect plainSelect = getPlainSelect(sql); - if (Objects.isNull(plainSelect)) { - return new ArrayList<>(); - } - Set result = getSelectFields(plainSelect); - - GroupByElement groupBy = plainSelect.getGroupBy(); - if (groupBy != null) { - List groupByExpressions = groupBy.getGroupByExpressions(); - for (Expression expression : groupByExpressions) { - if (expression instanceof Column) { - Column column = (Column) expression; - result.add(column.getColumnName()); - } - } - } - List orderByElements = plainSelect.getOrderByElements(); - if (orderByElements != null) { - for (OrderByElement orderByElement : orderByElements) { - Expression expression = orderByElement.getExpression(); - - if (expression instanceof Column) { - Column column = (Column) expression; - result.add(column.getColumnName()); - } - } + return sql; } + PlainSelect plainSelect = (PlainSelect) selectBody; + //1. replace where fields Expression where = plainSelect.getWhere(); - if (where != null) { - where.accept(new ExpressionVisitorAdapter() { - @Override - public void visit(Column column) { - result.add(column.getColumnName()); - } - }); + FiledValueReplaceVisitor visitor = new FiledValueReplaceVisitor(fieldValueToFieldNames); + if (Objects.nonNull(where)) { + where.accept(visitor); } - - return new ArrayList<>(result); + return selectStatement.toString(); } public static String replaceFields(String sql, Map fieldToBizName) { - Select selectStatement = getSelect(sql); + Select selectStatement = SqlParserSelectHelper.getSelect(sql); SelectBody selectBody = selectStatement.getSelectBody(); if (!(selectBody instanceof PlainSelect)) { return sql; @@ -173,7 +82,7 @@ public class CCJSqlParserUtils { public static String replaceFunction(String sql) { - Select selectStatement = getSelect(sql); + Select selectStatement = SqlParserSelectHelper.getSelect(sql); SelectBody selectBody = selectStatement.getSelectBody(); if (!(selectBody instanceof PlainSelect)) { return sql; @@ -208,7 +117,7 @@ public class CCJSqlParserUtils { public static String addFieldsToSelect(String sql, List fields) { - Select selectStatement = getSelect(sql); + Select selectStatement = SqlParserSelectHelper.getSelect(sql); // add fields to select for (String field : fields) { SelectUtils.addExpression(selectStatement, new Column(field)); @@ -216,24 +125,11 @@ public class CCJSqlParserUtils { return selectStatement.toString(); } - - public static String getTableName(String sql) { - Select selectStatement = getSelect(sql); - if (selectStatement == null) { - return null; - } - SelectBody selectBody = selectStatement.getSelectBody(); - PlainSelect plainSelect = (PlainSelect) selectBody; - - Table table = (Table) plainSelect.getFromItem(); - return table.getName(); - } - public static String replaceTable(String sql, String tableName) { if (StringUtils.isEmpty(tableName)) { return sql; } - Select selectStatement = getSelect(sql); + Select selectStatement = SqlParserSelectHelper.getSelect(sql); SelectBody selectBody = selectStatement.getSelectBody(); PlainSelect plainSelect = (PlainSelect) selectBody; // replace table name @@ -247,7 +143,7 @@ public class CCJSqlParserUtils { if (StringUtils.isEmpty(column) || Objects.isNull(value)) { return sql; } - Select selectStatement = getSelect(sql); + Select selectStatement = SqlParserSelectHelper.getSelect(sql); SelectBody selectBody = selectStatement.getSelectBody(); if (!(selectBody instanceof PlainSelect)) { @@ -271,7 +167,7 @@ public class CCJSqlParserUtils { public static String addWhere(String sql, Expression expression) { - Select selectStatement = getSelect(sql); + Select selectStatement = SqlParserSelectHelper.getSelect(sql); SelectBody selectBody = selectStatement.getSelectBody(); if (!(selectBody instanceof PlainSelect)) { @@ -288,23 +184,5 @@ public class CCJSqlParserUtils { return selectStatement.toString(); } - - public static boolean hasAggregateFunction(String sql) { - Select selectStatement = getSelect(sql); - SelectBody selectBody = selectStatement.getSelectBody(); - - if (!(selectBody instanceof PlainSelect)) { - return false; - } - PlainSelect plainSelect = (PlainSelect) selectBody; - List selectItems = plainSelect.getSelectItems(); - AggregateFunctionVisitor visitor = new AggregateFunctionVisitor(); - for (SelectItem selectItem : selectItems) { - selectItem.accept(visitor); - } - return visitor.hasAggregateFunction(); - } - - } 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 0be459cf2..943aacf64 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 @@ -121,7 +121,8 @@ class SqlParseUtilsTest { 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 " + + " 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" ); @@ -129,4 +130,4 @@ class SqlParseUtilsTest { .collect(Collectors.toList()); Assert.assertTrue(collect.contains("user_id")); } -} \ No newline at end of file +} diff --git a/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/CCJSqlParserUtilsTest.java b/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/CCJSqlParserUtilsTest.java deleted file mode 100644 index 427c16471..000000000 --- a/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/CCJSqlParserUtilsTest.java +++ /dev/null @@ -1,244 +0,0 @@ -package com.tencent.supersonic.common.util.jsqlparser; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import org.junit.Assert; -import org.junit.jupiter.api.Test; - -/** - * CCJSqlParserUtils Test - */ -class CCJSqlParserUtilsTest { - - @Test - void replaceFields() { - - Map fieldToBizName = initParams(); - String replaceSql = "select 歌曲名 from 歌曲库 where datediff('day', 发布日期, '2023-08-09') <= 1 and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' and 歌曲发布时 = '2023-08-01' order by 播放量 desc limit 11"; - - replaceSql = CCJSqlParserUtils.replaceFields(replaceSql, fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-09' AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' AND song_publis_date = '2023-08-01' AND publish_date >= '2023-08-08' ORDER BY play_count DESC LIMIT 11" - , replaceSql); - - replaceSql = "select YEAR(发行日期), count(歌曲名) from 歌曲库 where YEAR(发行日期) in (2022, 2023) and 数据日期 = '2023-08-14' group by YEAR(发行日期)"; - - replaceSql = CCJSqlParserUtils.replaceFields(replaceSql, fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT YEAR(publish_date), count(song_name) FROM 歌曲库 WHERE YEAR(publish_date) IN (2022, 2023) AND sys_imp_date = '2023-08-14' GROUP BY YEAR(publish_date)", - replaceSql); - - replaceSql = "select YEAR(发行日期), count(歌曲名) from 歌曲库 where YEAR(发行日期) in (2022, 2023) and 数据日期 = '2023-08-14' group by 发行日期"; - - replaceSql = CCJSqlParserUtils.replaceFields(replaceSql, fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT YEAR(publish_date), count(song_name) FROM 歌曲库 WHERE YEAR(publish_date) IN (2022, 2023) AND sys_imp_date = '2023-08-14' GROUP BY publish_date", - replaceSql); - - replaceSql = CCJSqlParserUtils.replaceFields( - "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-11') <= 1 and 结算播放量 > 1000000 and datediff('day', 数据日期, '2023-08-11') <= 30", - fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-11' AND play_count > 1000000 AND sys_imp_date <= '2023-08-11' AND publish_date >= '2022-08-11' AND sys_imp_date >= '2023-07-12'" - , replaceSql); - - replaceSql = CCJSqlParserUtils.replaceFields( - "select 歌曲名 from 歌曲库 where datediff('day', 发布日期, '2023-08-09') <= 1 and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", - fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-09' AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' AND publish_date >= '2023-08-08' ORDER BY play_count DESC LIMIT 11" - , replaceSql); - - replaceSql = CCJSqlParserUtils.replaceFields( - "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-09') = 0 and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", - fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT song_name FROM 歌曲库 WHERE 1 = 1 AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' AND publish_date <= '2023-08-09' AND publish_date >= '2023-01-01' ORDER BY play_count DESC LIMIT 11" - , replaceSql); - - replaceSql = CCJSqlParserUtils.replaceFields( - "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-09') <= 0.5 and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", - fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-09' AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' AND publish_date >= '2023-02-09' ORDER BY play_count DESC LIMIT 11" - , replaceSql); - - replaceSql = CCJSqlParserUtils.replaceFields( - "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-09') >= 0.5 and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", - fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT song_name FROM 歌曲库 WHERE publish_date >= '2023-08-09' AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' AND publish_date <= '2023-02-09' ORDER BY play_count DESC LIMIT 11" - , replaceSql); - - replaceSql = CCJSqlParserUtils.replaceFields( - "select 部门,用户 from 超音数 where 数据日期 = '2023-08-08' and 用户 ='alice' and 发布日期 ='11' order by 访问次数 desc limit 1", - fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT department, user_id FROM 超音数 WHERE sys_imp_date = '2023-08-08' AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1" - , replaceSql); - - replaceSql = CCJSqlParserUtils.replaceTable(replaceSql, "s2"); - - replaceSql = CCJSqlParserUtils.addFieldsToSelect(replaceSql, Collections.singletonList("field_a")); - - replaceSql = CCJSqlParserUtils.replaceFields( - "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 ='alice' and 发布日期 ='11' group by 部门 limit 1", - fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT department, sum(pv) FROM 超音数 WHERE sys_imp_date = '2023-08-08' AND user_id = 'alice' AND publish_date = '11' GROUP BY department LIMIT 1", - replaceSql); - - replaceSql = "select sum(访问次数) from 超音数 where 数据日期 >= '2023-08-06' and 数据日期 <= '2023-08-06' and 部门 = 'hr'"; - replaceSql = CCJSqlParserUtils.replaceFields(replaceSql, fieldToBizName); - replaceSql = CCJSqlParserUtils.replaceFunction(replaceSql); - - Assert.assertEquals( - "SELECT sum(pv) FROM 超音数 WHERE sys_imp_date >= '2023-08-06' AND sys_imp_date <= '2023-08-06' AND department = 'hr'", - replaceSql); - } - - - @Test - void getAllFields() { - - List allFields = CCJSqlParserUtils.getAllFields( - "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08' AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); - - Assert.assertEquals(allFields.size(), 6); - - allFields = CCJSqlParserUtils.getAllFields( - "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date >= '2023-08-08' AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); - - Assert.assertEquals(allFields.size(), 6); - - allFields = CCJSqlParserUtils.getAllFields( - "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 = 'alice' and 发布日期 ='11' group by 部门 limit 1"); - - Assert.assertEquals(allFields.size(), 5); - } - - @Test - void replaceTable() { - - String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; - String replaceSql = CCJSqlParserUtils.replaceTable(sql, "s2"); - - Assert.assertEquals( - "SELECT 部门, sum(访问次数) FROM s2 WHERE 数据日期 = '2023-08-08' AND 用户 = alice AND 发布日期 = '11' GROUP BY 部门 LIMIT 1", - replaceSql); - } - - - @Test - void getSelectFields() { - - String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; - List selectFields = CCJSqlParserUtils.getSelectFields(sql); - - Assert.assertEquals(selectFields.contains("访问次数"), true); - Assert.assertEquals(selectFields.contains("部门"), true); - } - - @Test - void getWhereFields() { - - String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 = 'alice' and 发布日期 ='11' group by 部门 limit 1"; - List selectFields = CCJSqlParserUtils.getWhereFields(sql); - - Assert.assertEquals(selectFields.contains("发布日期"), true); - Assert.assertEquals(selectFields.contains("数据日期"), true); - Assert.assertEquals(selectFields.contains("用户"), true); - } - - - @Test - void addWhere() throws JSQLParserException { - - String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; - sql = CCJSqlParserUtils.addWhere(sql, "column_a", 123444555); - List selectFields = CCJSqlParserUtils.getAllFields(sql); - - Assert.assertEquals(selectFields.contains("column_a"), true); - - sql = CCJSqlParserUtils.addWhere(sql, "column_b", "123456666"); - selectFields = CCJSqlParserUtils.getAllFields(sql); - - Assert.assertEquals(selectFields.contains("column_b"), true); - - Expression expression = CCJSqlParserUtil.parseCondExpression(" ( column_c = 111 or column_d = 1111)"); - - sql = CCJSqlParserUtils.addWhere( - "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 =alice and 发布日期 ='11' group by 部门 limit 1", - expression); - - Assert.assertEquals(sql.contains("column_c = 111"), true); - - } - - - @Test - void hasAggregateFunction() throws JSQLParserException { - - String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; - boolean hasAggregateFunction = CCJSqlParserUtils.hasAggregateFunction(sql); - - Assert.assertEquals(hasAggregateFunction, true); - sql = "select 部门,count (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; - hasAggregateFunction = CCJSqlParserUtils.hasAggregateFunction(sql); - Assert.assertEquals(hasAggregateFunction, true); - - sql = "SELECT count(1) FROM s2 WHERE sys_imp_date = '2023-08-08' AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"; - hasAggregateFunction = CCJSqlParserUtils.hasAggregateFunction(sql); - Assert.assertEquals(hasAggregateFunction, true); - - sql = "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08' AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"; - hasAggregateFunction = CCJSqlParserUtils.hasAggregateFunction(sql); - Assert.assertEquals(hasAggregateFunction, false); - - sql = "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08' AND user_id = 'alice' AND publish_date = '11'"; - hasAggregateFunction = CCJSqlParserUtils.hasAggregateFunction(sql); - Assert.assertEquals(hasAggregateFunction, false); - - } - - private Map initParams() { - Map fieldToBizName = new HashMap<>(); - fieldToBizName.put("部门", "department"); - fieldToBizName.put("用户", "user_id"); - fieldToBizName.put("数据日期", "sys_imp_date"); - fieldToBizName.put("发布日期", "publish_date"); - fieldToBizName.put("访问次数", "pv"); - fieldToBizName.put("歌曲名", "song_name"); - fieldToBizName.put("歌手名", "singer_name"); - fieldToBizName.put("播放", "play_count"); - fieldToBizName.put("歌曲发布时间", "song_publis_date"); - fieldToBizName.put("歌曲发布年份", "song_publis_year"); - fieldToBizName.put("转3.0前后30天结算份额衰减", "fdafdfdsa_fdas"); - return fieldToBizName; - } -} \ No newline at end of file diff --git a/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelperTest.java b/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelperTest.java new file mode 100644 index 000000000..b34195ca8 --- /dev/null +++ b/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserSelectHelperTest.java @@ -0,0 +1,190 @@ +package com.tencent.supersonic.common.util.jsqlparser; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +/** + * SqlParserSelectHelper Test + */ +class SqlParserSelectHelperTest { + + + @Test + void getWhereFilterExpression() { + + List filterExpression = SqlParserSelectHelper.getFilterExpression( + "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08' " + + " AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); + + System.out.println(filterExpression); + + filterExpression = SqlParserSelectHelper.getFilterExpression( + "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08' " + + "AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); + + System.out.println(filterExpression); + + filterExpression = SqlParserSelectHelper.getFilterExpression( + "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08' " + + "AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); + + System.out.println(filterExpression); + + filterExpression = SqlParserSelectHelper.getFilterExpression( + "SELECT department, user_id, field_a FROM s2 WHERE " + + "user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); + + System.out.println(filterExpression); + + filterExpression = SqlParserSelectHelper.getFilterExpression( + "SELECT department, user_id, field_a FROM s2 WHERE " + + "user_id = 'alice' AND publish_date > 10000 ORDER BY pv DESC LIMIT 1"); + + System.out.println(filterExpression); + } + + + @Test + void getAllFields() { + + List allFields = SqlParserSelectHelper.getAllFields( + "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08'" + + " AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); + + Assert.assertEquals(allFields.size(), 6); + + allFields = SqlParserSelectHelper.getAllFields( + "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date >= '2023-08-08'" + + " AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"); + + Assert.assertEquals(allFields.size(), 6); + + allFields = SqlParserSelectHelper.getAllFields( + "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' and 用户 = 'alice'" + + " and 发布日期 ='11' group by 部门 limit 1"); + + Assert.assertEquals(allFields.size(), 5); + } + + + @Test + void getSelectFields() { + + String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; + List selectFields = SqlParserSelectHelper.getSelectFields(sql); + + Assert.assertEquals(selectFields.contains("访问次数"), true); + Assert.assertEquals(selectFields.contains("部门"), true); + } + + @Test + void getWhereFields() { + + String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08'" + + " and 用户 = 'alice' and 发布日期 ='11' group by 部门 limit 1"; + List selectFields = SqlParserSelectHelper.getWhereFields(sql); + + Assert.assertEquals(selectFields.contains("发布日期"), true); + Assert.assertEquals(selectFields.contains("数据日期"), true); + Assert.assertEquals(selectFields.contains("用户"), true); + + sql = "select 部门,用户 from 超音数 where 数据日期 = '2023-08-08'" + + " and 用户 = 'alice' and 发布日期 ='11' order by 访问次数 limit 1"; + selectFields = SqlParserSelectHelper.getWhereFields(sql); + + Assert.assertEquals(selectFields.contains("发布日期"), true); + Assert.assertEquals(selectFields.contains("数据日期"), true); + Assert.assertEquals(selectFields.contains("用户"), true); + } + + @Test + void getOrderByFields() { + + String sql = "select 部门,用户 from 超音数 where 数据日期 = '2023-08-08'" + + " and 用户 = 'alice' and 发布日期 ='11' order by 访问次数 limit 1"; + List selectFields = SqlParserSelectHelper.getOrderByFields(sql); + + Assert.assertEquals(selectFields.contains("访问次数"), true); + } + + + @Test + void addWhere() throws JSQLParserException { + + String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; + sql = SqlParserUpdateHelper.addWhere(sql, "column_a", 123444555); + List selectFields = SqlParserSelectHelper.getAllFields(sql); + + Assert.assertEquals(selectFields.contains("column_a"), true); + + sql = SqlParserUpdateHelper.addWhere(sql, "column_b", "123456666"); + selectFields = SqlParserSelectHelper.getAllFields(sql); + + Assert.assertEquals(selectFields.contains("column_b"), true); + + Expression expression = CCJSqlParserUtil.parseCondExpression(" ( column_c = 111 or column_d = 1111)"); + + sql = SqlParserUpdateHelper.addWhere( + "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1", + expression); + + Assert.assertEquals(sql.contains("column_c = 111"), true); + + } + + + @Test + void hasAggregateFunction() throws JSQLParserException { + + String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; + boolean hasAggregateFunction = SqlParserSelectHelper.hasAggregateFunction(sql); + + Assert.assertEquals(hasAggregateFunction, true); + sql = "select 部门,count (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; + hasAggregateFunction = SqlParserSelectHelper.hasAggregateFunction(sql); + Assert.assertEquals(hasAggregateFunction, true); + + sql = "SELECT count(1) FROM s2 WHERE sys_imp_date = '2023-08-08' AND user_id = 'alice'" + + " AND publish_date = '11' ORDER BY pv DESC LIMIT 1"; + hasAggregateFunction = SqlParserSelectHelper.hasAggregateFunction(sql); + Assert.assertEquals(hasAggregateFunction, true); + + sql = "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08' " + + "AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1"; + hasAggregateFunction = SqlParserSelectHelper.hasAggregateFunction(sql); + Assert.assertEquals(hasAggregateFunction, false); + + sql = "SELECT department, user_id, field_a FROM s2 WHERE sys_imp_date = '2023-08-08'" + + " AND user_id = 'alice' AND publish_date = '11'"; + hasAggregateFunction = SqlParserSelectHelper.hasAggregateFunction(sql); + Assert.assertEquals(hasAggregateFunction, false); + + } + + private Map initParams() { + Map fieldToBizName = new HashMap<>(); + fieldToBizName.put("部门", "department"); + fieldToBizName.put("用户", "user_id"); + fieldToBizName.put("数据日期", "sys_imp_date"); + fieldToBizName.put("发布日期", "publish_date"); + fieldToBizName.put("访问次数", "pv"); + fieldToBizName.put("歌曲名", "song_name"); + fieldToBizName.put("歌手名", "singer_name"); + fieldToBizName.put("播放", "play_count"); + fieldToBizName.put("歌曲发布时间", "song_publis_date"); + fieldToBizName.put("歌曲发布年份", "song_publis_year"); + fieldToBizName.put("转3.0前后30天结算份额衰减", "fdafdfdsa_fdas"); + return fieldToBizName; + } +} diff --git a/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserUpdateHelperTest.java b/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserUpdateHelperTest.java new file mode 100644 index 000000000..33740931b --- /dev/null +++ b/common/src/test/java/com/tencent/supersonic/common/util/jsqlparser/SqlParserUpdateHelperTest.java @@ -0,0 +1,198 @@ +package com.tencent.supersonic.common.util.jsqlparser; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +/** + * SqlParserUpdateHelper Test + */ +class SqlParserUpdateHelperTest { + + @Test + void replaceFields() { + + Map fieldToBizName = initParams(); + String replaceSql = "select 歌曲名 from 歌曲库 where datediff('day', 发布日期, '2023-08-09') <= 1 " + + "and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' and 歌曲发布时 = '2023-08-01'" + + " order by 播放量 desc limit 11"; + + replaceSql = SqlParserUpdateHelper.replaceFields(replaceSql, fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-09' " + + "AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' AND " + + "song_publis_date = '2023-08-01' AND publish_date >= '2023-08-08' " + + "ORDER BY play_count DESC LIMIT 11", replaceSql); + + replaceSql = "select YEAR(发行日期), count(歌曲名) from 歌曲库 where YEAR(发行日期) " + + "in (2022, 2023) and 数据日期 = '2023-08-14' group by YEAR(发行日期)"; + + replaceSql = SqlParserUpdateHelper.replaceFields(replaceSql, fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT YEAR(publish_date), count(song_name) FROM 歌曲库 " + + "WHERE YEAR(publish_date) IN (2022, 2023) AND sys_imp_date = '2023-08-14' " + + "GROUP BY YEAR(publish_date)", + replaceSql); + + replaceSql = "select YEAR(发行日期), count(歌曲名) from 歌曲库 " + + "where YEAR(发行日期) in (2022, 2023) and 数据日期 = '2023-08-14' " + + "group by 发行日期"; + + replaceSql = SqlParserUpdateHelper.replaceFields(replaceSql, fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT YEAR(publish_date), count(song_name) FROM 歌曲库 " + + "WHERE YEAR(publish_date) IN (2022, 2023) AND sys_imp_date = '2023-08-14'" + + " GROUP BY publish_date", + replaceSql); + + replaceSql = SqlParserUpdateHelper.replaceFields( + "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-11') <= 1 " + + "and 结算播放量 > 1000000 and datediff('day', 数据日期, '2023-08-11') <= 30", + fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-11' " + + "AND play_count > 1000000 AND sys_imp_date <= '2023-08-11' AND " + + "publish_date >= '2022-08-11' AND sys_imp_date >= '2023-07-12'", replaceSql); + + replaceSql = SqlParserUpdateHelper.replaceFields( + "select 歌曲名 from 歌曲库 where datediff('day', 发布日期, '2023-08-09') <= 1 " + + "and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", + fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-09' " + + "AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' " + + "AND publish_date >= '2023-08-08' ORDER BY play_count DESC LIMIT 11", replaceSql); + + replaceSql = SqlParserUpdateHelper.replaceFields( + "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-09') = 0 " + + "and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT song_name FROM 歌曲库 WHERE 1 = 1 AND singer_name = '邓紫棋'" + + " AND sys_imp_date = '2023-08-09' AND publish_date <= '2023-08-09' " + + "AND publish_date >= '2023-01-01' ORDER BY play_count DESC LIMIT 11", replaceSql); + + replaceSql = SqlParserUpdateHelper.replaceFields( + "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-09') <= 0.5 " + + "and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT song_name FROM 歌曲库 WHERE publish_date <= '2023-08-09' " + + "AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' " + + "AND publish_date >= '2023-02-09' ORDER BY play_count DESC LIMIT 11", replaceSql); + + replaceSql = SqlParserUpdateHelper.replaceFields( + "select 歌曲名 from 歌曲库 where datediff('year', 发布日期, '2023-08-09') >= 0.5 " + + "and 歌手名 = '邓紫棋' and 数据日期 = '2023-08-09' order by 播放量 desc limit 11", fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT song_name FROM 歌曲库 WHERE publish_date >= '2023-08-09' " + + "AND singer_name = '邓紫棋' AND sys_imp_date = '2023-08-09' " + + "AND publish_date <= '2023-02-09' ORDER BY play_count DESC LIMIT 11", replaceSql); + + replaceSql = SqlParserUpdateHelper.replaceFields( + "select 部门,用户 from 超音数 where 数据日期 = '2023-08-08' and 用户 ='alice'" + + " and 发布日期 ='11' order by 访问次数 desc limit 1", fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT department, user_id FROM 超音数 WHERE sys_imp_date = '2023-08-08'" + + " AND user_id = 'alice' AND publish_date = '11' ORDER BY pv DESC LIMIT 1", replaceSql); + + replaceSql = SqlParserUpdateHelper.replaceTable(replaceSql, "s2"); + + replaceSql = SqlParserUpdateHelper.addFieldsToSelect(replaceSql, Collections.singletonList("field_a")); + + replaceSql = SqlParserUpdateHelper.replaceFields( + "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 ='alice' and 发布日期 ='11' group by 部门 limit 1", fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT department, sum(pv) FROM 超音数 WHERE sys_imp_date = '2023-08-08'" + + " AND user_id = 'alice' AND publish_date = '11' GROUP BY department LIMIT 1", replaceSql); + + replaceSql = "select sum(访问次数) from 超音数 where 数据日期 >= '2023-08-06' " + + "and 数据日期 <= '2023-08-06' and 部门 = 'hr'"; + replaceSql = SqlParserUpdateHelper.replaceFields(replaceSql, fieldToBizName); + replaceSql = SqlParserUpdateHelper.replaceFunction(replaceSql); + + Assert.assertEquals( + "SELECT sum(pv) FROM 超音数 WHERE sys_imp_date >= '2023-08-06' " + + "AND sys_imp_date <= '2023-08-06' AND department = 'hr'", replaceSql); + } + + + @Test + void replaceTable() { + + String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; + String replaceSql = SqlParserUpdateHelper.replaceTable(sql, "s2"); + + Assert.assertEquals( + "SELECT 部门, sum(访问次数) FROM s2 WHERE 数据日期 = '2023-08-08' " + + "AND 用户 = alice AND 发布日期 = '11' GROUP BY 部门 LIMIT 1", replaceSql); + } + + @Test + void addWhere() throws JSQLParserException { + + String sql = "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1"; + sql = SqlParserUpdateHelper.addWhere(sql, "column_a", 123444555); + List selectFields = SqlParserSelectHelper.getAllFields(sql); + + Assert.assertEquals(selectFields.contains("column_a"), true); + + sql = SqlParserUpdateHelper.addWhere(sql, "column_b", "123456666"); + selectFields = SqlParserSelectHelper.getAllFields(sql); + + Assert.assertEquals(selectFields.contains("column_b"), true); + + Expression expression = CCJSqlParserUtil.parseCondExpression(" ( column_c = 111 or column_d = 1111)"); + + sql = SqlParserUpdateHelper.addWhere( + "select 部门,sum (访问次数) from 超音数 where 数据日期 = '2023-08-08' " + + "and 用户 =alice and 发布日期 ='11' group by 部门 limit 1", + expression); + + Assert.assertEquals(sql.contains("column_c = 111"), true); + + } + + private Map initParams() { + Map fieldToBizName = new HashMap<>(); + fieldToBizName.put("部门", "department"); + fieldToBizName.put("用户", "user_id"); + fieldToBizName.put("数据日期", "sys_imp_date"); + fieldToBizName.put("发布日期", "publish_date"); + fieldToBizName.put("访问次数", "pv"); + fieldToBizName.put("歌曲名", "song_name"); + fieldToBizName.put("歌手名", "singer_name"); + fieldToBizName.put("播放", "play_count"); + fieldToBizName.put("歌曲发布时间", "song_publis_date"); + fieldToBizName.put("歌曲发布年份", "song_publis_year"); + fieldToBizName.put("转3.0前后30天结算份额衰减", "fdafdfdsa_fdas"); + return fieldToBizName; + } +} diff --git a/docs/images/supersonic_components.png b/docs/images/supersonic_components.png index 07ebe188d1c8657aec180614afe4fd5c6009ee36..4db266accee5b24ce32a2d01a3d76ddc807f268e 100644 GIT binary patch literal 280901 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

rIeO?;p(^ZTY;!iiOS?#a9zgf% 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

W~LMp8CqsU#-Wt<0lp=3V+}#ArQpcA98lAww)~ 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 QAb>9k5!vsRLi&OK3(gKHod5s; diff --git a/docs/images/wechat_contact.jpeg b/docs/images/wechat_contact.jpeg deleted file mode 100644 index 1d913ecc08614fb9797b00c32d64c1699d58becf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 124959 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%0A(StcL{-CfNxnraQl$`8N4MJvB6is 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 { - + private User user = User.getFakeUser(); @Qualifier("chatQueryService") @Autowired private QueryService queryService; @Autowired private ChatService chatService; @Autowired - protected ConfigService configService; + private ConfigService configService; @Autowired private PluginService pluginService; @Autowired private AgentService agentService; - private User user = User.getFakeUser(); - private void parseAndExecute(int chatId, String queryText) throws Exception { QueryReq queryRequest = new QueryReq(); queryRequest.setQueryText(queryText); queryRequest.setChatId(chatId); + queryRequest.setAgentId(1); queryRequest.setUser(User.getFakeUser()); ParseResp parseResp = queryService.performParsing(queryRequest); ExecuteQueryReq executeReq = new ExecuteQueryReq(); + executeReq.setQueryId(parseResp.getQueryId()); + executeReq.setParseId(parseResp.getSelectedParses().get(0).getId()); executeReq.setQueryText(queryRequest.getQueryText()); executeReq.setParseInfo(parseResp.getSelectedParses().get(0)); executeReq.setChatId(parseResp.getChatId()); executeReq.setUser(queryRequest.getUser()); + executeReq.setAgentId(1); queryService.performExecution(executeReq); } @@ -87,38 +92,39 @@ public class ConfigureDemo implements ApplicationListener ChatDetailConfigReq chatDetailConfig = new ChatDetailConfigReq(); ChatDefaultConfigReq chatDefaultConfigDetail = new ChatDefaultConfigReq(); - List dimensionIds_0 = Arrays.asList(1L, 2L); - List metricIds_0 = Arrays.asList(1L); - chatDefaultConfigDetail.setDimensionIds(dimensionIds_0); - chatDefaultConfigDetail.setMetricIds(metricIds_0); + List dimensionIds0 = Arrays.asList(1L, 2L); + List metricIds0 = Arrays.asList(1L); + chatDefaultConfigDetail.setDimensionIds(dimensionIds0); + chatDefaultConfigDetail.setMetricIds(metricIds0); chatDefaultConfigDetail.setUnit(7); chatDefaultConfigDetail.setPeriod("DAY"); chatDetailConfig.setChatDefaultConfig(chatDefaultConfigDetail); - ItemVisibility visibility_0 = new ItemVisibility(); - chatDetailConfig.setVisibility(visibility_0); + ItemVisibility visibility0 = new ItemVisibility(); + chatDetailConfig.setVisibility(visibility0); chatConfigBaseReq.setChatDetailConfig(chatDetailConfig); + ChatAggConfigReq chatAggConfig = new ChatAggConfigReq(); ChatDefaultConfigReq chatDefaultConfigAgg = new ChatDefaultConfigReq(); - List dimensionIds_1 = Arrays.asList(1L, 2L); - List metricIds_1 = Arrays.asList(1L); - chatDefaultConfigAgg.setDimensionIds(dimensionIds_1); - chatDefaultConfigAgg.setMetricIds(metricIds_1); + List dimensionIds1 = Arrays.asList(1L, 2L); + List metricIds1 = Arrays.asList(1L); + chatDefaultConfigAgg.setDimensionIds(dimensionIds1); + chatDefaultConfigAgg.setMetricIds(metricIds1); chatDefaultConfigAgg.setUnit(7); chatDefaultConfigAgg.setPeriod("DAY"); chatDefaultConfigAgg.setTimeMode(ChatDefaultConfigReq.TimeMode.RECENT); chatAggConfig.setChatDefaultConfig(chatDefaultConfigAgg); - ItemVisibility visibility_1 = new ItemVisibility(); - chatAggConfig.setVisibility(visibility_1); + ItemVisibility visibility1 = new ItemVisibility(); + chatAggConfig.setVisibility(visibility1); chatConfigBaseReq.setChatAggConfig(chatAggConfig); List recommendedQuestions = new ArrayList<>(); - RecommendedQuestionReq recommendedQuestionReq_0 = new RecommendedQuestionReq("超音数访问次数"); - RecommendedQuestionReq recommendedQuestionReq_1 = new RecommendedQuestionReq("超音数访问人数"); - RecommendedQuestionReq recommendedQuestionReq_2 = new RecommendedQuestionReq("超音数按部门访问次数"); - recommendedQuestions.add(recommendedQuestionReq_0); - recommendedQuestions.add(recommendedQuestionReq_1); - recommendedQuestions.add(recommendedQuestionReq_2); + RecommendedQuestionReq recommendedQuestionReq0 = new RecommendedQuestionReq("超音数访问次数"); + RecommendedQuestionReq recommendedQuestionReq1 = new RecommendedQuestionReq("超音数访问人数"); + RecommendedQuestionReq recommendedQuestionReq2 = new RecommendedQuestionReq("超音数按部门访问次数"); + recommendedQuestions.add(recommendedQuestionReq0); + recommendedQuestions.add(recommendedQuestionReq1); + recommendedQuestions.add(recommendedQuestionReq2); chatConfigBaseReq.setRecommendedQuestions(recommendedQuestions); configService.addConfig(chatConfigBaseReq, user); @@ -130,29 +136,30 @@ public class ConfigureDemo implements ApplicationListener ChatDetailConfigReq chatDetailConfig = new ChatDetailConfigReq(); ChatDefaultConfigReq chatDefaultConfigDetail = new ChatDefaultConfigReq(); - List dimensionIds_0 = Arrays.asList(4L, 5L, 6L, 7L); - List metricIds_0 = Arrays.asList(4L); - chatDefaultConfigDetail.setDimensionIds(dimensionIds_0); - chatDefaultConfigDetail.setMetricIds(metricIds_0); + List dimensionIds0 = Arrays.asList(4L, 5L, 6L, 7L); + List metricIds0 = Arrays.asList(4L); + chatDefaultConfigDetail.setDimensionIds(dimensionIds0); + chatDefaultConfigDetail.setMetricIds(metricIds0); chatDefaultConfigDetail.setUnit(7); chatDefaultConfigDetail.setPeriod("DAY"); chatDetailConfig.setChatDefaultConfig(chatDefaultConfigDetail); - ItemVisibility visibility_0 = new ItemVisibility(); - chatDetailConfig.setVisibility(visibility_0); + ItemVisibility visibility0 = new ItemVisibility(); + chatDetailConfig.setVisibility(visibility0); chatConfigBaseReq.setChatDetailConfig(chatDetailConfig); + ChatAggConfigReq chatAggConfig = new ChatAggConfigReq(); ChatDefaultConfigReq chatDefaultConfigAgg = new ChatDefaultConfigReq(); - List dimensionIds_1 = Arrays.asList(4L, 5L, 6L, 7L); - List metricIds_1 = Arrays.asList(4L); - chatDefaultConfigAgg.setDimensionIds(dimensionIds_1); - chatDefaultConfigAgg.setMetricIds(metricIds_1); + List dimensionIds1 = Arrays.asList(4L, 5L, 6L, 7L); + List metricIds1 = Arrays.asList(4L); + chatDefaultConfigAgg.setDimensionIds(dimensionIds1); + chatDefaultConfigAgg.setMetricIds(metricIds1); chatDefaultConfigAgg.setUnit(7); chatDefaultConfigAgg.setPeriod("DAY"); chatDefaultConfigAgg.setTimeMode(ChatDefaultConfigReq.TimeMode.RECENT); chatAggConfig.setChatDefaultConfig(chatDefaultConfigAgg); - ItemVisibility visibility_1 = new ItemVisibility(); - chatAggConfig.setVisibility(visibility_1); + ItemVisibility visibility1 = new ItemVisibility(); + chatAggConfig.setVisibility(visibility1); chatConfigBaseReq.setChatAggConfig(chatAggConfig); List recommendedQuestions = new ArrayList<>(); @@ -162,12 +169,12 @@ public class ConfigureDemo implements ApplicationListener } private void addPlugin_1() { - Plugin plugin_1 = new Plugin(); - plugin_1.setType("WEB_PAGE"); - plugin_1.setModelList(Arrays.asList(1L)); - plugin_1.setPattern("访问情况"); - plugin_1.setParseModeConfig(null); - plugin_1.setName("访问情况"); + Plugin plugin1 = new Plugin(); + plugin1.setType("WEB_PAGE"); + plugin1.setModelList(Arrays.asList(1L)); + plugin1.setPattern("访问情况"); + plugin1.setParseModeConfig(null); + plugin1.setName("访问情况"); WebBase webBase = new WebBase(); webBase.setUrl("www.test.com"); ParamOption paramOption = new ParamOption(); @@ -177,23 +184,23 @@ public class ConfigureDemo implements ApplicationListener paramOption.setModelId(1L); List paramOptions = Arrays.asList(paramOption); webBase.setParamOptions(paramOptions); - plugin_1.setConfig(JsonUtil.toString(webBase)); + plugin1.setConfig(JsonUtil.toString(webBase)); - pluginService.createPlugin(plugin_1, user); + pluginService.createPlugin(plugin1, user); } - private void addAgent() { Agent agent = new Agent(); agent.setId(1); - agent.setName("查信息"); - agent.setDescription("查信息"); + agent.setName("查指标"); + agent.setDescription("查指标"); agent.setStatus(1); agent.setEnableSearch(1); agent.setExamples(Lists.newArrayList("超音数访问次数", "超音数访问人数", "alice 停留时长")); AgentConfig agentConfig = new AgentConfig(); RuleQueryTool ruleQueryTool = new RuleQueryTool(); ruleQueryTool.setType(AgentToolType.RULE); + ruleQueryTool.setModelIds(Lists.newArrayList(1L, 2L)); ruleQueryTool.setQueryModes(Lists.newArrayList( "ENTITY_DETAIL", "ENTITY_LIST_FILTER", "ENTITY_ID", "METRIC_ENTITY", "METRIC_FILTER", "METRIC_GROUPBY", "METRIC_MODEL", "METRIC_ORDERBY" diff --git a/launchers/standalone/src/main/resources/META-INF/spring.factories b/launchers/standalone/src/main/resources/META-INF/spring.factories index 67aecd08c..2305f851b 100644 --- a/launchers/standalone/src/main/resources/META-INF/spring.factories +++ b/launchers/standalone/src/main/resources/META-INF/spring.factories @@ -3,30 +3,38 @@ com.tencent.supersonic.chat.api.component.SchemaMapper=\ com.tencent.supersonic.chat.mapper.FuzzyNameMapper, \ com.tencent.supersonic.chat.mapper.QueryFilterMapper, \ com.tencent.supersonic.chat.mapper.EntityMapper + com.tencent.supersonic.chat.api.component.SemanticParser=\ com.tencent.supersonic.chat.parser.rule.QueryModeParser, \ com.tencent.supersonic.chat.parser.rule.ContextInheritParser, \ com.tencent.supersonic.chat.parser.rule.AgentCheckParser, \ com.tencent.supersonic.chat.parser.rule.TimeRangeParser, \ com.tencent.supersonic.chat.parser.rule.AggregateTypeParser, \ - com.tencent.supersonic.chat.parser.llm.dsl.LLMDSLParser, \ - com.tencent.supersonic.chat.parser.embedding.EmbeddingBasedParser, \ - com.tencent.supersonic.chat.parser.function.FunctionBasedParser + com.tencent.supersonic.chat.parser.llm.dsl.LLMDslParser, \ + com.tencent.supersonic.chat.parser.plugin.embedding.EmbeddingBasedParser, \ + com.tencent.supersonic.chat.parser.plugin.function.FunctionBasedParser + + com.tencent.supersonic.chat.api.component.SemanticLayer=\ com.tencent.supersonic.knowledge.semantic.LocalSemanticLayer + com.tencent.supersonic.chat.query.QuerySelector=\ com.tencent.supersonic.chat.query.HeuristicQuerySelector -com.tencent.supersonic.chat.parser.function.ModelResolver=\ - com.tencent.supersonic.chat.parser.function.HeuristicModelResolver + +com.tencent.supersonic.chat.parser.plugin.function.ModelResolver=\ + com.tencent.supersonic.chat.parser.plugin.function.HeuristicModelResolver + com.tencent.supersonic.auth.authentication.interceptor.AuthenticationInterceptor=\ com.tencent.supersonic.auth.authentication.interceptor.DefaultAuthenticationInterceptor + com.tencent.supersonic.auth.api.authentication.adaptor.UserAdaptor=\ com.tencent.supersonic.auth.authentication.adaptor.DefaultUserAdaptor -com.tencent.supersonic.chat.api.component.DSLOptimizer=\ - com.tencent.supersonic.chat.query.dsl.optimizer.DateFieldCorrector, \ - com.tencent.supersonic.chat.query.dsl.optimizer.FieldCorrector, \ - com.tencent.supersonic.chat.query.dsl.optimizer.FunctionCorrector, \ - com.tencent.supersonic.chat.query.dsl.optimizer.TableNameCorrector, \ - com.tencent.supersonic.chat.query.dsl.optimizer.QueryFilterAppend, \ - com.tencent.supersonic.chat.query.dsl.optimizer.SelectFieldAppendCorrector \ No newline at end of file +com.tencent.supersonic.chat.api.component.SemanticCorrector=\ + com.tencent.supersonic.chat.corrector.DateFieldCorrector, \ + com.tencent.supersonic.chat.corrector.FieldValueCorrector, \ + com.tencent.supersonic.chat.corrector.FieldCorrector, \ + com.tencent.supersonic.chat.corrector.FunctionCorrector, \ + com.tencent.supersonic.chat.corrector.TableNameCorrector, \ + com.tencent.supersonic.chat.corrector.QueryFilterAppend, \ + com.tencent.supersonic.chat.corrector.SelectFieldAppendCorrector diff --git a/launchers/standalone/src/main/resources/application-local.yaml b/launchers/standalone/src/main/resources/application-local.yaml index 5a73d5b34..52649ba71 100644 --- a/launchers/standalone/src/main/resources/application-local.yaml +++ b/launchers/standalone/src/main/resources/application-local.yaml @@ -28,5 +28,8 @@ semantic: url: prefix: http://127.0.0.1:9081 +time: + threshold: 100 + mybatis: mapper-locations=classpath:mappers/custom/*.xml,classpath*:/mappers/*.xml diff --git a/launchers/standalone/src/main/resources/db/data-h2.sql b/launchers/standalone/src/main/resources/db/data-h2.sql index 921952ecb..f8e1030a3 100644 --- a/launchers/standalone/src/main/resources/db/data-h2.sql +++ b/launchers/standalone/src/main/resources/db/data-h2.sql @@ -1,2316 +1,1117 @@ -- 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_user (id, `name`, password, display_name, email) -values (5, 'alice', '123456', 'alice', 'alice@xx.com'); +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_user (id, `name`, password, display_name, email) values (5, 'alice','123456','alice','alice@xx.com'); -- sample models -insert into s2_domain (id, `name`, biz_name, parent_id, status, created_at, created_by, updated_at, - updated_by, `admin`, admin_org, viewer, view_org) -VALUES (1, '超音数', 'supersonic', 0, 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', - 'admin', 'admin', '', 'admin,tom,jack', 'admin'); -insert into s2_model (id, `name`, biz_name, domain_id, created_at, created_by, updated_at, - updated_by, `admin`, admin_org, is_open, viewer, view_org, entity) -VALUES (1, '超音数', 'supersonic', 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', - 'admin', '', 0, 'admin,tom,jack', 'admin', ''); -insert into s2_model (id, `name`, biz_name, domain_id, created_at, created_by, updated_at, - updated_by, `admin`, admin_org, is_open, viewer, view_org, entity) -VALUES (2, '艺人库', 'singer', 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', - 'admin', '', 0, 'admin,tom,jack', 'admin', '{"entityId": 7, "names": ["歌手", "艺人"]}'); -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_datasource (id, model_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'); -insert into s2_datasource (id, model_id, `name`, biz_name, description, database_id, - datasource_detail, created_at, created_by, updated_at, updated_by) -VALUES (2, 1, 'PVUV统计', 's2_pv_uv_statis', 'PVUV统计', 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_pv_uv_statis_pv","expr":"pv","isCreateMetric":1,"name":"访问次数"},{"agg":"count_distinct","bizName":"s2_pv_uv_statis_uv","expr":"uv","isCreateMetric":1,"name":"访问人数"}],"queryType":"sql_query","sqlQuery":"SELECT imp_date, user_name,page,1 as pv, user_name as uv FROM s2_pv_uv_statis"}', - '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); -insert into s2_datasource (id, model_id, `name`, biz_name, description, database_id, - datasource_detail, created_at, created_by, updated_at, updated_by) -VALUES (3, 1, '用户部门', 'user_department', '用户部门', 1, - '{"dimensions":[{"bizName":"department","dateFormat":"yyyy-MM-dd","expr":"department","isCreateDimension":1,"name":"部门","type":"categorical"}],"identifiers":[{"bizName":"user_name","name":"用户名","type":"primary"}],"measures":[],"queryType":"sql_query","sqlQuery":"SELECT user_name,department FROM s2_user_department"}', - '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); -insert into s2_datasource (id, model_id, `name`, biz_name, description, database_id, - datasource_detail, created_at, created_by, updated_at, updated_by) -VALUES (4, 2, '艺人库', 'singer', '艺人库', 1, - '{"dimensions":[{"bizName":"imp_date","dateFormat":"yyyy-MM-dd","expr":"imp_date","isCreateDimension":0,"type":"time","typeParams":{"isPrimary":"true","timeGranularity":"day"}},{"bizName":"act_area","dateFormat":"yyyy-MM-dd","expr":"act_area","isCreateDimension":1,"name":"活跃区域","type":"categorical"},{"bizName":"song_name","dateFormat":"yyyy-MM-dd","expr":"song_name","isCreateDimension":1,"name":"代表作","type":"categorical"},{"bizName":"genre","dateFormat":"yyyy-MM-dd","expr":"genre","isCreateDimension":1,"name":"风格","type":"categorical"}],"identifiers":[{"bizName":"singer_name","name":"歌手名","type":"primary"}],"measures":[{"agg":"sum","bizName":"music_down_cnt","expr":"down_cnt","isCreateMetric":1,"name":"下载量"},{"agg":"sum","bizName":"music_js_play_cnt","expr":"js_play_cnt","isCreateMetric":1,"name":"播放量"},{"agg":"sum","bizName":"music_favor_cnt","expr":"favor_cnt","isCreateMetric":1,"name":"收藏量"}],"queryType":"sql_query","sqlQuery":"SELECT imp_date,singer_name,act_area,song_name,genre,js_play_cnt,down_cnt,favor_cnt FROM singer "}', - '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); -insert into s2_datasource_rela (id, model_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, model_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, model_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, model_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, model_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, model_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, model_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'); -insert into s2_dimension (id, model_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 (5, 2, 4, '代表作', 'song_name', '代表作', 1, 2, 'categorical', NULL, 'song_name', - '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); -insert into s2_dimension (id, model_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 (6, 2, 4, '风格', 'genre', '风格', 1, 2, 'categorical', NULL, 'genre', '2023-05-24 00:00:00', - 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); -insert into s2_dimension (id, model_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_metric (id, model_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, model_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, model_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, model_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, model_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, model_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_domain (id, `name`, biz_name, parent_id, status, created_at, created_by, updated_at, updated_by, `admin`, admin_org, viewer, view_org) VALUES(1, '超音数', 'supersonic', 0, 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', 'admin', '', 'admin,tom,jack', 'admin' ); +insert into s2_model (id, `name`, biz_name, domain_id, created_at, created_by, updated_at, updated_by, `admin`, admin_org, is_open, viewer, view_org, entity) VALUES(1, '超音数', 'supersonic', 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', 'admin', '', 0, 'admin,tom,jack', 'admin','' ); +insert into s2_model (id, `name`, biz_name, domain_id, created_at, created_by, updated_at, updated_by, `admin`, admin_org, is_open, viewer, view_org, entity) VALUES(2, '艺人库', 'singer', 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', 'admin', '', 0, 'admin,tom,jack', 'admin','{"entityId": 7, "names": ["歌手", "艺人"]}' ); +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_datasource (id , model_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'); +insert into s2_datasource (id , model_id, `name`, biz_name, description, database_id ,datasource_detail, created_at, created_by, updated_at, updated_by ) VALUES(2, 1, 'PVUV统计', 's2_pv_uv_statis', 'PVUV统计', 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_pv_uv_statis_pv","expr":"pv","isCreateMetric":1,"name":"访问次数"},{"agg":"count_distinct","bizName":"s2_pv_uv_statis_uv","expr":"uv","isCreateMetric":1,"name":"访问人数"}],"queryType":"sql_query","sqlQuery":"SELECT imp_date, user_name,page,1 as pv, user_name as uv FROM s2_pv_uv_statis"}', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource (id , model_id, `name`, biz_name, description, database_id ,datasource_detail, created_at, created_by, updated_at, updated_by ) VALUES(3, 1, '用户部门', 'user_department', '用户部门', 1, '{"dimensions":[{"bizName":"department","dateFormat":"yyyy-MM-dd","expr":"department","isCreateDimension":1,"name":"部门","type":"categorical"}],"identifiers":[{"bizName":"user_name","name":"用户名","type":"primary"}],"measures":[],"queryType":"sql_query","sqlQuery":"SELECT user_name,department FROM s2_user_department"}', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource (id , model_id, `name`, biz_name, description, database_id ,datasource_detail, created_at, created_by, updated_at, updated_by ) VALUES(4, 2, '艺人库', 'singer', '艺人库', 1, '{"dimensions":[{"bizName":"imp_date","dateFormat":"yyyy-MM-dd","expr":"imp_date","isCreateDimension":0,"type":"time","typeParams":{"isPrimary":"true","timeGranularity":"day"}},{"bizName":"act_area","dateFormat":"yyyy-MM-dd","expr":"act_area","isCreateDimension":1,"name":"活跃区域","type":"categorical"},{"bizName":"song_name","dateFormat":"yyyy-MM-dd","expr":"song_name","isCreateDimension":1,"name":"代表作","type":"categorical"},{"bizName":"genre","dateFormat":"yyyy-MM-dd","expr":"genre","isCreateDimension":1,"name":"风格","type":"categorical"}],"identifiers":[{"bizName":"singer_name","name":"歌手名","type":"primary"}],"measures":[{"agg":"sum","bizName":"music_down_cnt","expr":"down_cnt","isCreateMetric":1,"name":"下载量"},{"agg":"sum","bizName":"music_js_play_cnt","expr":"js_play_cnt","isCreateMetric":1,"name":"播放量"},{"agg":"sum","bizName":"music_favor_cnt","expr":"favor_cnt","isCreateMetric":1,"name":"收藏量"}],"queryType":"sql_query","sqlQuery":"SELECT imp_date,singer_name,act_area,song_name,genre,js_play_cnt,down_cnt,favor_cnt FROM singer "}', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource_rela (id , model_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 , model_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 , model_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 , model_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 , model_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 , model_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 , model_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'); +insert into s2_dimension (id , model_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(5, 2, 4, '代表作', 'song_name', '代表作', 1, 2, 'categorical', NULL, 'song_name', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_dimension (id , model_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(6, 2, 4, '风格', 'genre', '风格', 1, 2, 'categorical', NULL, 'genre', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_dimension (id , model_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_metric (id, model_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, model_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, model_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, model_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, model_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, model_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'); -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 (2, 'dimension', 'yyyy-MM-dd', DATEADD('DAY', -28, CURRENT_DATE()), - DATEADD('DAY', -1, CURRENT_DATE()), '[]', '2023-06-01', 'admin', '2023-06-01', 'admin'); -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 (3, 'dimension', 'yyyy-MM-dd', DATEADD('DAY', -28, CURRENT_DATE()), - DATEADD('DAY', -1, CURRENT_DATE()), '[]', '2023-06-01', 'admin', '2023-06-01', 'admin'); +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'); +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 (2, 'dimension', 'yyyy-MM-dd', DATEADD('DAY', -28, CURRENT_DATE()), DATEADD('DAY', -1, CURRENT_DATE()), '[]', '2023-06-01', 'admin', '2023-06-01', 'admin'); +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 (3, 'dimension', 'yyyy-MM-dd', DATEADD('DAY', -28, CURRENT_DATE()), DATEADD('DAY', -1, CURRENT_DATE()), '[]', '2023-06-01', 'admin', '2023-06-01', 'admin'); insert into s2_auth_groups (group_id, config) -values (1, - '{"modelId":"1","name":"admin-permission","groupId":1,"authRules":[{"metrics":["stay_hours"],"dimensions":["page"]}],"dimensionFilters":[""],"dimensionFilterDescription":"授权admin 页面和停留时长权限","authorizedUsers":["admin"],"authorizedDepartmentIds":[]}'); +values (1, '{"modelId":"1","name":"admin-permission","groupId":1,"authRules":[{"metrics":["stay_hours"],"dimensions":["page"]}],"dimensionFilters":[""],"dimensionFilterDescription":"授权admin 页面和停留时长权限","authorizedUsers":["admin"],"authorizedDepartmentIds":[]}'); insert into s2_auth_groups (group_id, config) -values (2, - '{"modelId":"1","name":"tom_sales_permission","groupId":2,"authRules":[{"metrics":["stay_hours"],"dimensions":["page"]}],"dimensionFilters":["department in (''sales'')"],"dimensionFilterDescription":"开通 tom sales部门权限", "authorizedUsers":["tom"],"authorizedDepartmentIds":[]}'); +values (2, '{"modelId":"1","name":"tom_sales_permission","groupId":2,"authRules":[{"metrics":["stay_hours"],"dimensions":["page"]}],"dimensionFilters":["department in (''sales'')"],"dimensionFilterDescription":"部门 in [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); -INSERT INTO singer (imp_date, singer_name, act_area, song_name, genre, js_play_cnt, down_cnt, - favor_cnt) -VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); +INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); -INSERT INTO singer (imp_date, singer_name, act_area, song_name, genre, js_play_cnt, down_cnt, - favor_cnt) -VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); +INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); -INSERT INTO singer (imp_date, singer_name, act_area, song_name, genre, js_play_cnt, down_cnt, - favor_cnt) -VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); +INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); -INSERT INTO singer (imp_date, singer_name, act_area, song_name, genre, js_play_cnt, down_cnt, - favor_cnt) -VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); +INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); -INSERT INTO singer (imp_date, singer_name, act_area, song_name, genre, js_play_cnt, down_cnt, - favor_cnt) -VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -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); +INSERT INTO singer (imp_date,singer_name,act_area, song_name,genre,js_play_cnt,down_cnt,favor_cnt) VALUES (DATEADD('DAY', -3, 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', -2, 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', -6, 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', -7, 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', -1, CURRENT_DATE()), 'Taylor Swift -', '欧美', 'Love Story', '爱情', 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()), 'Taylor Swift -', '欧美', 'Love Story', '爱情', 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()), 'Taylor Swift -', '欧美', 'Love Story', '爱情', 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', -3, CURRENT_DATE()), 'Taylor Swift -', '欧美', 'Love Story', '爱情', 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', -2, CURRENT_DATE()), 'Taylor Swift -', '欧美', 'Love Story', '爱情', 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', -6, CURRENT_DATE()), 'Taylor Swift -', '欧美', 'Love Story', '爱情', 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', -7, CURRENT_DATE()), 'Taylor Swift -', '欧美', 'Love Story', '爱情', 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', -1, CURRENT_DATE()), 'Taylor Swift +', '欧美','Love Story','爱情',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()), 'Taylor Swift +', '欧美','Love Story','爱情',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()), 'Taylor Swift +', '欧美','Love Story','爱情',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', -3, CURRENT_DATE()), 'Taylor Swift +', '欧美','Love Story','爱情',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', -2, CURRENT_DATE()), 'Taylor Swift +', '欧美','Love Story','爱情',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', -6, CURRENT_DATE()), 'Taylor Swift +', '欧美','Love Story','爱情',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', -7, CURRENT_DATE()), 'Taylor Swift +', '欧美','Love Story','爱情',1000000,1000000,1000000); ---demo data for semantic and chat -insert into s2_user_department (user_name, department) -values ('jack', 'HR'); +insert into s2_user_department (user_name, department) values ('jack','HR'); -insert into s2_user_department (user_name, department) -values ('jack', 'HR'); -insert into s2_user_department (user_name, department) -values ('tom', 'sales'); -insert into s2_user_department (user_name, department) -values ('lucy', 'marketing'); -insert into s2_user_department (user_name, department) -values ('john', 'strategy'); -insert into s2_user_department (user_name, department) -values ('alice', 'sales'); -insert into s2_user_department (user_name, department) -values ('dean', 'marketing'); +insert into s2_user_department (user_name, department) values ('jack','HR'); +insert into s2_user_department (user_name, department) values ('tom','sales'); +insert into s2_user_department (user_name, department) values ('lucy','marketing'); +insert into s2_user_department (user_name, department) values ('john','strategy'); +insert into s2_user_department (user_name, department) values ('alice','sales'); +insert into s2_user_department (user_name, department) values ('dean','marketing'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -5, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'alice', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p2'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p1'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p3'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p5'); -INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -5, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'alice', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'jack', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', 'p2'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', 'p1'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', 'p3'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', 'p4'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', 'p5'); +INSERT INTO s2_pv_uv_statis (imp_date, user_name, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.7636857512911863', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', '0.17663327393462436', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.38943688941552057', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', '0.2715819955225307', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.9358210273119568', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.9364586435510802', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.9707723036513162', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', '0.8497763866782723', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.15504417761372413', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.9507563118298399', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.9746364180572994', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', '0.12869214941133378', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.3024970533288409', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.6639702099980812', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'lucy', '0.4929901454858626', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.06853040276026445', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.8488086078299616', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', '0.8589111177125592', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', '0.5576357066482228', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.8047888670006846', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.766944548494366', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.5280072184505449', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.9693343356046343', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', '0.12805203958456424', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', '0.16963603387027637', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.5901202956521101', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.12710364646712236', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.6346530909156196', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', '0.12461289103639872', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', '0.9863947334662437', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', '0.48899961064192987', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'alice', '0.5382796792688207', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', '0.3506568687014143', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.8633072449771709', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.13999135315363687', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', '0.07258740493845894', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', '0.5244413940436958', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.13258670732966138', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.6015982054464575', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', '0.05513158944480323', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.6707121735296985', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', '0.9330440339006469', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', '0.5630674323371607', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', '0.8720647566229917', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.8331899070546519', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', '0.6712876436249856', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', '0.6694409980332703', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', '0.3703307480606334', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.775368688472696', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.9151205443267096', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.09543108823305857', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', '0.7893992120771057', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', '0.5119923080070498', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', '0.49906724167974936', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.046258282700961884', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'dean', '0.44843595680103954', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', '0.7743935471689718', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.5855299615656824', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', '0.9412963512379853', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.8383247587082538', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', '0.14517876867236124', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.9327229861441061', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.19042326582894153', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.6029067818254513', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.21715964747214422', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', '0.34259842721045974', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.7064419016593382', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', '0.5725636566517865', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', '0.22332539583809208', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.8049036189055911', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', '0.6029674758974956', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.11884976360561716', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', '0.7124916829130662', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.5893693718556829', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.602073304496253', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.10491061160039927', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', '0.9006548872378379', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.8545144244288455', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', '0.16915384987875726', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.2271640700690446', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', '0.7807518577160636', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.8919859648888653', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', '0.1564450687270359', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.5840549187653847', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', '0.2213255596777869', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', '0.07868261880306426', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.07710010861455818', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.5131249730162654', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.5035035055368601', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.8996978291173905', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.057442290722216294', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.6443079066865616', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', '0.7398098480748726', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', '0.9835694815034591', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', '0.9879213445635557', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.4020136688147111', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', '0.6698797170128024', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.17325132416789113', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', '0.5784229486763606', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.9185978183932058', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.5474783153973963', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.9730731954700215', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', '0.5390873359288765', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', '0.20522241320887713', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', '0.4088233242325021', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.7608047695853417', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.2749731221085713', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.06154055374702494', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.460668002022406', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.4474746325306228', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.5761666885467472', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'dean', '0.33233441360339655', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', '0.7426534909874778', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', '0.5841437875889118', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.2818296500094526', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', '0.8670888843915217', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', '0.5249294365740248', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.5483356748008438', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', '0.7278566847412673', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.6779976902157362', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.09995341651736978', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', '0.4528538159233879', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.5870756885301056', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.9842091927290255', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.04580936015706816', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.8814678270145769', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', '0.06517379256096412', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.8769832364187129', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', '0.584562279025023', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.8102404090621375', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.11481653429176686', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.43422888918962554', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'lucy', '0.0684414272594508', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.976546463969412', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.617906858141431', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'jack', '0.08663740247579998', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', '0.7124944606691416', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'alice', '0.1321700521239627', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'jack', '0.3078946609431664', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.6149442855237194', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'alice', '0.5963801306980994', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', '0.6999542038973406', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.4599112653446624', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', '0.20300901401048832', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.39989705958717037', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.2486378364940327', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', '0.16880398079144077', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.73927288385526', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.8645283506689198', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', '0.3266940826759587', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.9195490073037541', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.9452523036658287', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.21269683438120535', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.7377502855387184', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.38981597634408716', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.7001799391999863', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.6616720024008785', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'dean', '0.497721735058096', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'jack', '0.22255613760959603', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.05247640233319417', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', '0.27237572107833363', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', '0.9529452406380252', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.28243045060463157', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', '0.17880444250082506', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.035050038002381156', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', '0.840803223728221', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.5318457377361356', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.9280332892460665', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', '0.752354382202208', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', '0.1866528331789219', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', '0.7016165545791373', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.4191547989960899', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', '0.7025516699007639', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.6160127317884274', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', '0.91223094958137', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.4383056089013998', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', '0.595750781166582', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'lucy', '0.9472349338730268', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', '0.0519104588842193', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.48043983034526205', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.14754707786497478', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', '0.36124288370035695', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', '0.21777919493494613', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.22637666702475057', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.9378215576942598', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.3309229261144562', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.7602880453727515', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.9470462487873785', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.6770215935547629', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.1586074803669385', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'lucy', '0.2754855564794071', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', '0.8355347738454384', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.7251813505573811', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'jack', '0.006606625589642534', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', '0.304832277753024', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.026368662837989554', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', '0.6855977520602776', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'tom', '0.8193746826441749', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.021179295102459972', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.1533849522536005', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.18893553542301778', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.39870999343833624', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.9985665103520182', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.6961441157700171', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.9861933923851885', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', '0.993076500099477', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.4320547269058953', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', '0.18441071030375877', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.1501504986117118', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.252021845734527', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', '0.24442701577183745', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.07563738855797564', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', '0.34247820646440985', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.9456979276862031', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.19494357263973816', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.9371493867882469', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.6136241316589367', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', '0.8922330760877784', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', '0.9001986074661864', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.4889702884422866', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.2689551234431401', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.5223573993758465', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', '0.05042295556527243', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', '0.2717147121880483', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', '0.7397093309370814', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', '0.157064341631733', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', '0.7213399784998017', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', '0.764081440588005', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.7514070600074144', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.611647412825278', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.6600796877195596', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', '0.8942204153751679', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.07398121085929721', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', '0.1652506990439564', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.5849759516111703', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.1672502732600889', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.7836135556233219', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', '0.26181269644936356', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', '0.6577275876355586', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.3067293364197956', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.8608288543866495', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.814283434116926', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'jack', '0.33993584425872936', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'john', '0.010812798859160089', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.5156558224263926', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'jack', '0.46320035330198406', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', '0.2651020283994786', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.42467241545664147', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.3695905136678498', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', '0.15269122123348644', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.6755688670583248', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'jack', '0.39064306179528907', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', '0.36479296691952023', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'lucy', '0.5069249157662691', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.4785315495532231', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', '0.7582526218052175', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.42064109605717914', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', '0.5587757581237022', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', '0.3561686564964428', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.7101688305173135', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.6518061375522985', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.7564485884156583', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.36531347293134464', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', '0.5201689359070235', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', '0.7138792929290383', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.9751003716333827', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.5281906318027629', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.6291356541485003', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', '0.1938712974807698', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', '0.6267850210775459', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.4469970592043767', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', '0.7690659124175409', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'jack', '0.13335067838090386', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'jack', '0.2966621725922035', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.5740481445089863', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.838028890036331', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', '0.8094354537628714', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', '0.5552924586108698', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.49150373927678315', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.7264346889377966', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.9292830287297702', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.3905616258240767', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.15912349648571666', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', '0.6030082006630102', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', '0.8712354035243679', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.7685306377211826', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.2869913942171415', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.7142615166855639', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.5625978475154423', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.13611601734791123', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.6977333962685311', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', '0.35140477709778295', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.8805119222967716', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.7014124236538637', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', '0.12759538003439375', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.7515403792213445', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', '0.03700239289885987', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', '0.31674618364630946', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.4491378834800146', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', '0.6742764131652571', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'lucy', '0.5286362221140248', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.007890326473113496', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', '0.8046560540950831', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.7198364371127147', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.7400546712169153', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.16859870460868698', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.8462852684569557', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.010211452005474353', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', '0.8617802368201087', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.21667479046797633', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.8667689615468714', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', '0.16140709875863557', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.16713368182304666', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'lucy', '0.8957484629768053', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'tom', '0.457835758220534', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.9435170960198477', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', '0.9699253608913104', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.2309897429566834', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.7879705066452681', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.20795869239817255', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', '0.4110352469382019', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', '0.4979592772533561', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', '0.18810865430947044', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'tom', '0.5001240246982048', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'jack', '0.08341934160029707', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.04812784841651041', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.4655982693269717', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', '0.8539357978460663', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.9649541785823592', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', '0.8243635648047365', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.929949719929735', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.055983276861168996', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.07845430274829746', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.28257674222099116', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.1578419214960578', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', '0.7853118484860825', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', '0.20790127125904156', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.8650538395535204', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.902116091225815', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', '0.48542770770171373', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.16725337150113984', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'lucy', '0.3157444453259486', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.565727220131555', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', '0.2531688065358064', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', '0.9191434620980499', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.9224628853942058', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', '0.3256288410730337', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.9709152566761661', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.9794173893522709', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.16582064407977237', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', '0.2652519246960059', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'alice', '0.04092489871261762', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.3020444893927522', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.4655412764350543', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', '0.9226436424888846', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.4707663393012884', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.3277970119243966', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', '0.4730675479071551', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', '0.10261940477901954', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', '0.4148892373198616', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.2877219827348403', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.16212409974675845', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.9567425121214822', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'lucy', '0.19795350030679149', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.6954199597749198', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', '0.32884293488801164', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', '0.4789917995407148', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', '0.0698927593996298', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.3352267723792438', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', '0.8085116661598726', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.17515060210353794', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.6006963088370202', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.8794167536704468', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.04091469320757368', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', '0.6709116812690366', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', '0.4850646101328463', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.547488212623346', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', '0.6301717145008927', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', '0.06123370093612068', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.2545600223228257', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', '0.28355287519210803', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.3231348374147818', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.4585172495754063', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.7893945285152268', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.6810596014794181', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.7136031244915907', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'jack', '0.259734039051829', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.7759518703827996', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.06288891046833589', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', '0.8242980461154241', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.36590300307021595', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.20254092528445444', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.5427356081880325', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.1467846603517391', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.8975527268892767', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', '0.3483541520806722', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.6922544855316723', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.3690185253006011', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.7564541265683148', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', '0.3634152133342695', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.33740378933701987', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.7942640738315301', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.7894896778233523', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.7153281477198108', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'tom', '0.5546359859065261', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', '0.7727157385809087', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.8707097754747494', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.3873936520764878', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.7590305068820566', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.512826935863365', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', '0.19120284727846926', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', '0.5382693105670825', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.826241649014955', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', '0.6133080470571559', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.6452862617544055', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', '0.3025772179023586', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '4.709864550322962E-4', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.024816355013726588', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', '0.8407500495605565', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.8420879584266481', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', '0.2719224735814776', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.8939712577294938', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', '0.8086189323362379', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', '0.6063415085381448', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.39783242658234674', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.6085577206028068', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.5154289424127074', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', '0.878436600887031', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.5577906295015223', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', '0.1143260282925247', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', '0.312756557275364', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.05548807854726956', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', '0.12140791431139175', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.23897628700410234', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.22223137342481392', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.12379891645900953', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', '0.33729146112854247', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.8816768640060831', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', '0.6301700633426532', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', '0.4566295223861714', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', '0.1777378523933678', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.8163769471165477', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.4380805149704541', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', '0.2987018822475964', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.6726495645391617', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.8394327461109705', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'dean', '0.820512945501936', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.1580105370757261', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.9961450897279505', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.6574891890500061', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.5201205570085158', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', '0.2445069633928285', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', '0.3155229654901067', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.3665971881269575', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.5544977915912215', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.15978771803015113', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.038128748344929186', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.49026304025118594', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.5166802080526571', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.22568230066042194', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.9888634109849955', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', '0.21022365182102054', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'john', '0.47052993358031114', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.25686122383263454', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.18929054223320718', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.7925339862375451', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', '0.12613308249498645', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.7381524971311578', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.08639585437319919', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.9519897106846164', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.33446548574801926', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.40667134603483324', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.17100718420628735', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.4445585525686886', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.47372916928883013', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.19826861093848824', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.13679268112019338', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.9805515708224516', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'dean', '0.4738376165601095', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.5739441073158964', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'alice', '0.8428505498030564', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', '0.32655416551155336', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.7055736367780644', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', '0.9621355090189875', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.9665339161730553', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.44309781869697995', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', '0.8651220802537761', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.6451892308277741', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.056797307451316725', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.6847604118085596', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.13428051757364667', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.9814797176951834', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', '0.7386074051153445', 'p3'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.4825297824657663', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', '0.06608870508231235', 'p5'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'lucy', '0.6278253028988848', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'alice', '0.6705580511822682', 'p1'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', '0.8131712486302015', 'p2'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.8124302447925607', 'p4'); -INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) -VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', '0.039935860913407284', 'p2'); + + +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.7636857512911863', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', '0.17663327393462436', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.38943688941552057', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', '0.2715819955225307', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.9358210273119568', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.9364586435510802', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.9707723036513162', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', '0.8497763866782723', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.15504417761372413', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.9507563118298399', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.9746364180572994', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', '0.12869214941133378', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.3024970533288409', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.6639702099980812', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'lucy', '0.4929901454858626', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.06853040276026445', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.8488086078299616', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', '0.8589111177125592', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', '0.5576357066482228', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.8047888670006846', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.766944548494366', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.5280072184505449', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.9693343356046343', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', '0.12805203958456424', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', '0.16963603387027637', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.5901202956521101', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.12710364646712236', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.6346530909156196', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', '0.12461289103639872', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', '0.9863947334662437', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', '0.48899961064192987', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'alice', '0.5382796792688207', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'dean', '0.3506568687014143', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.8633072449771709', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.13999135315363687', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', '0.07258740493845894', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', '0.5244413940436958', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.13258670732966138', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.6015982054464575', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', '0.05513158944480323', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'alice', '0.6707121735296985', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', '0.9330440339006469', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', '0.5630674323371607', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', '0.8720647566229917', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.8331899070546519', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', '0.6712876436249856', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', '0.6694409980332703', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', '0.3703307480606334', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.775368688472696', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.9151205443267096', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.09543108823305857', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'dean', '0.7893992120771057', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', '0.5119923080070498', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', '0.49906724167974936', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.046258282700961884', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'dean', '0.44843595680103954', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', '0.7743935471689718', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.5855299615656824', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', '0.9412963512379853', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.8383247587082538', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'lucy', '0.14517876867236124', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.9327229861441061', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.19042326582894153', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.6029067818254513', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.21715964747214422', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', '0.34259842721045974', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.7064419016593382', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'lucy', '0.5725636566517865', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', '0.22332539583809208', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.8049036189055911', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', '0.6029674758974956', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.11884976360561716', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'alice', '0.7124916829130662', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.5893693718556829', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.602073304496253', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.10491061160039927', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', '0.9006548872378379', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.8545144244288455', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', '0.16915384987875726', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.2271640700690446', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', '0.7807518577160636', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.8919859648888653', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', '0.1564450687270359', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.5840549187653847', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', '0.2213255596777869', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', '0.07868261880306426', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.07710010861455818', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.5131249730162654', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.5035035055368601', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.8996978291173905', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.057442290722216294', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.6443079066865616', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', '0.7398098480748726', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'dean', '0.9835694815034591', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'john', '0.9879213445635557', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.4020136688147111', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', '0.6698797170128024', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.17325132416789113', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'lucy', '0.5784229486763606', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.9185978183932058', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.5474783153973963', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.9730731954700215', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', '0.5390873359288765', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'alice', '0.20522241320887713', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', '0.4088233242325021', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.7608047695853417', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.2749731221085713', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.06154055374702494', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.460668002022406', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.4474746325306228', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.5761666885467472', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'dean', '0.33233441360339655', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', '0.7426534909874778', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', '0.5841437875889118', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.2818296500094526', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', '0.8670888843915217', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'alice', '0.5249294365740248', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.5483356748008438', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', '0.7278566847412673', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.6779976902157362', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.09995341651736978', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', '0.4528538159233879', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.5870756885301056', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.9842091927290255', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.04580936015706816', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.8814678270145769', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', '0.06517379256096412', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.8769832364187129', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', '0.584562279025023', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.8102404090621375', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.11481653429176686', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.43422888918962554', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'lucy', '0.0684414272594508', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.976546463969412', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.617906858141431', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'jack', '0.08663740247579998', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', '0.7124944606691416', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'alice', '0.1321700521239627', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'jack', '0.3078946609431664', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.6149442855237194', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'alice', '0.5963801306980994', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', '0.6999542038973406', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.4599112653446624', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', '0.20300901401048832', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.39989705958717037', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.2486378364940327', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', '0.16880398079144077', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.73927288385526', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.8645283506689198', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', '0.3266940826759587', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.9195490073037541', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.9452523036658287', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.21269683438120535', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.7377502855387184', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.38981597634408716', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.7001799391999863', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.6616720024008785', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'dean', '0.497721735058096', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'jack', '0.22255613760959603', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.05247640233319417', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'dean', '0.27237572107833363', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'alice', '0.9529452406380252', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.28243045060463157', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'lucy', '0.17880444250082506', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.035050038002381156', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', '0.840803223728221', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.5318457377361356', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.9280332892460665', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', '0.752354382202208', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'dean', '0.1866528331789219', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', '0.7016165545791373', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.4191547989960899', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', '0.7025516699007639', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.6160127317884274', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'alice', '0.91223094958137', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.4383056089013998', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'jack', '0.595750781166582', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'lucy', '0.9472349338730268', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'jack', '0.0519104588842193', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.48043983034526205', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.14754707786497478', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', '0.36124288370035695', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'dean', '0.21777919493494613', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.22637666702475057', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.9378215576942598', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.3309229261144562', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.7602880453727515', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.9470462487873785', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.6770215935547629', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.1586074803669385', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'lucy', '0.2754855564794071', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', '0.8355347738454384', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.7251813505573811', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'jack', '0.006606625589642534', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', '0.304832277753024', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.026368662837989554', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'tom', '0.6855977520602776', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'tom', '0.8193746826441749', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.021179295102459972', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.1533849522536005', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.18893553542301778', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.39870999343833624', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.9985665103520182', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.6961441157700171', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.9861933923851885', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', '0.993076500099477', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.4320547269058953', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', '0.18441071030375877', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.1501504986117118', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.252021845734527', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'lucy', '0.24442701577183745', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.07563738855797564', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', '0.34247820646440985', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.9456979276862031', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.19494357263973816', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.9371493867882469', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.6136241316589367', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', '0.8922330760877784', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'dean', '0.9001986074661864', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.4889702884422866', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.2689551234431401', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.5223573993758465', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'tom', '0.05042295556527243', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', '0.2717147121880483', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', '0.7397093309370814', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', '0.157064341631733', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'lucy', '0.7213399784998017', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'tom', '0.764081440588005', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.7514070600074144', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.611647412825278', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.6600796877195596', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', '0.8942204153751679', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.07398121085929721', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', '0.1652506990439564', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.5849759516111703', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.1672502732600889', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.7836135556233219', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'dean', '0.26181269644936356', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', '0.6577275876355586', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.3067293364197956', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.8608288543866495', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.814283434116926', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'jack', '0.33993584425872936', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'john', '0.010812798859160089', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.5156558224263926', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'jack', '0.46320035330198406', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', '0.2651020283994786', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.42467241545664147', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.3695905136678498', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'tom', '0.15269122123348644', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.6755688670583248', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'jack', '0.39064306179528907', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', '0.36479296691952023', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'lucy', '0.5069249157662691', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.4785315495532231', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', '0.7582526218052175', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.42064109605717914', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'dean', '0.5587757581237022', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'lucy', '0.3561686564964428', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.7101688305173135', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.6518061375522985', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.7564485884156583', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.36531347293134464', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'jack', '0.5201689359070235', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'john', '0.7138792929290383', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.9751003716333827', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.5281906318027629', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.6291356541485003', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', '0.1938712974807698', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'john', '0.6267850210775459', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.4469970592043767', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', '0.7690659124175409', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'jack', '0.13335067838090386', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'jack', '0.2966621725922035', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.5740481445089863', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'alice', '0.838028890036331', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', '0.8094354537628714', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'alice', '0.5552924586108698', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.49150373927678315', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.7264346889377966', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.9292830287297702', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.3905616258240767', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.15912349648571666', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'alice', '0.6030082006630102', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'lucy', '0.8712354035243679', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.7685306377211826', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.2869913942171415', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.7142615166855639', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.5625978475154423', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.13611601734791123', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'alice', '0.6977333962685311', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', '0.35140477709778295', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.8805119222967716', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.7014124236538637', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', '0.12759538003439375', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.7515403792213445', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'lucy', '0.03700239289885987', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', '0.31674618364630946', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.4491378834800146', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', '0.6742764131652571', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'lucy', '0.5286362221140248', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.007890326473113496', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', '0.8046560540950831', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.7198364371127147', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.7400546712169153', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.16859870460868698', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.8462852684569557', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.010211452005474353', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'alice', '0.8617802368201087', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.21667479046797633', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.8667689615468714', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', '0.16140709875863557', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.16713368182304666', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'lucy', '0.8957484629768053', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'tom', '0.457835758220534', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.9435170960198477', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'jack', '0.9699253608913104', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.2309897429566834', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.7879705066452681', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.20795869239817255', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', '0.4110352469382019', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'jack', '0.4979592772533561', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', '0.18810865430947044', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'tom', '0.5001240246982048', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'jack', '0.08341934160029707', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.04812784841651041', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.4655982693269717', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'dean', '0.8539357978460663', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'john', '0.9649541785823592', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', '0.8243635648047365', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.929949719929735', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.055983276861168996', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'tom', '0.07845430274829746', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'alice', '0.28257674222099116', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.1578419214960578', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', '0.7853118484860825', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', '0.20790127125904156', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.8650538395535204', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.902116091225815', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'lucy', '0.48542770770171373', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.16725337150113984', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'lucy', '0.3157444453259486', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.565727220131555', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', '0.2531688065358064', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', '0.9191434620980499', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.9224628853942058', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'jack', '0.3256288410730337', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'jack', '0.9709152566761661', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.9794173893522709', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'alice', '0.16582064407977237', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', '0.2652519246960059', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'alice', '0.04092489871261762', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.3020444893927522', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'john', '0.4655412764350543', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'dean', '0.9226436424888846', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.4707663393012884', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.3277970119243966', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'tom', '0.4730675479071551', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'jack', '0.10261940477901954', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'alice', '0.4148892373198616', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.2877219827348403', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.16212409974675845', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.9567425121214822', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'lucy', '0.19795350030679149', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.6954199597749198', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'alice', '0.32884293488801164', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'john', '0.4789917995407148', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'lucy', '0.0698927593996298', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.3352267723792438', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', '0.8085116661598726', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.17515060210353794', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.6006963088370202', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.8794167536704468', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.04091469320757368', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'tom', '0.6709116812690366', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', '0.4850646101328463', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'tom', '0.547488212623346', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'dean', '0.6301717145008927', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'lucy', '0.06123370093612068', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'alice', '0.2545600223228257', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'john', '0.28355287519210803', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.3231348374147818', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.4585172495754063', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.7893945285152268', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'john', '0.6810596014794181', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'john', '0.7136031244915907', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'jack', '0.259734039051829', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.7759518703827996', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'john', '0.06288891046833589', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'dean', '0.8242980461154241', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.36590300307021595', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'lucy', '0.20254092528445444', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.5427356081880325', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.1467846603517391', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.8975527268892767', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'dean', '0.3483541520806722', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.6922544855316723', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.3690185253006011', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'tom', '0.7564541265683148', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', '0.3634152133342695', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.33740378933701987', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.7942640738315301', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.7894896778233523', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'jack', '0.7153281477198108', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'tom', '0.5546359859065261', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'john', '0.7727157385809087', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'dean', '0.8707097754747494', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'john', '0.3873936520764878', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.7590305068820566', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'john', '0.512826935863365', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'john', '0.19120284727846926', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'dean', '0.5382693105670825', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'john', '0.826241649014955', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', '0.6133080470571559', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'jack', '0.6452862617544055', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'lucy', '0.3025772179023586', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '4.709864550322962E-4', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.024816355013726588', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -6, CURRENT_DATE()), 'alice', '0.8407500495605565', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'alice', '0.8420879584266481', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'lucy', '0.2719224735814776', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'tom', '0.8939712577294938', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'dean', '0.8086189323362379', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'tom', '0.6063415085381448', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'tom', '0.39783242658234674', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.6085577206028068', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'tom', '0.5154289424127074', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'john', '0.878436600887031', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.5577906295015223', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'lucy', '0.1143260282925247', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', '0.312756557275364', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.05548807854726956', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'tom', '0.12140791431139175', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.23897628700410234', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.22223137342481392', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.12379891645900953', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'john', '0.33729146112854247', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.8816768640060831', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -21, CURRENT_DATE()), 'jack', '0.6301700633426532', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -3, CURRENT_DATE()), 'alice', '0.4566295223861714', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', '0.1777378523933678', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.8163769471165477', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'tom', '0.4380805149704541', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', '0.2987018822475964', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'dean', '0.6726495645391617', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.8394327461109705', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'dean', '0.820512945501936', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'tom', '0.1580105370757261', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -20, CURRENT_DATE()), 'jack', '0.9961450897279505', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -7, CURRENT_DATE()), 'john', '0.6574891890500061', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'john', '0.5201205570085158', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'alice', '0.2445069633928285', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -17, CURRENT_DATE()), 'john', '0.3155229654901067', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'jack', '0.3665971881269575', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'john', '0.5544977915912215', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.15978771803015113', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'lucy', '0.038128748344929186', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'tom', '0.49026304025118594', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.5166802080526571', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.22568230066042194', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -28, CURRENT_DATE()), 'john', '0.9888634109849955', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'jack', '0.21022365182102054', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'john', '0.47052993358031114', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.25686122383263454', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.18929054223320718', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'jack', '0.7925339862375451', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -12, CURRENT_DATE()), 'john', '0.12613308249498645', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.7381524971311578', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -4, CURRENT_DATE()), 'alice', '0.08639585437319919', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -27, CURRENT_DATE()), 'tom', '0.9519897106846164', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.33446548574801926', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'jack', '0.40667134603483324', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -10, CURRENT_DATE()), 'jack', '0.17100718420628735', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -26, CURRENT_DATE()), 'lucy', '0.4445585525686886', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'tom', '0.47372916928883013', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'john', '0.19826861093848824', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -13, CURRENT_DATE()), 'john', '0.13679268112019338', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -24, CURRENT_DATE()), 'tom', '0.9805515708224516', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'dean', '0.4738376165601095', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'dean', '0.5739441073158964', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'alice', '0.8428505498030564', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'lucy', '0.32655416551155336', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -14, CURRENT_DATE()), 'tom', '0.7055736367780644', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -2, CURRENT_DATE()), 'tom', '0.9621355090189875', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -9, CURRENT_DATE()), 'jack', '0.9665339161730553', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'dean', '0.44309781869697995', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -18, CURRENT_DATE()), 'tom', '0.8651220802537761', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.6451892308277741', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -16, CURRENT_DATE()), 'dean', '0.056797307451316725', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.6847604118085596', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -23, CURRENT_DATE()), 'jack', '0.13428051757364667', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -29, CURRENT_DATE()), 'lucy', '0.9814797176951834', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -11, CURRENT_DATE()), 'tom', '0.7386074051153445', 'p3'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -25, CURRENT_DATE()), 'alice', '0.4825297824657663', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', '0.06608870508231235', 'p5'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -22, CURRENT_DATE()), 'lucy', '0.6278253028988848', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -1, CURRENT_DATE()), 'alice', '0.6705580511822682', 'p1'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -19, CURRENT_DATE()), 'alice', '0.8131712486302015', 'p2'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -15, CURRENT_DATE()), 'lucy', '0.8124302447925607', 'p4'); +INSERT INTO s2_stay_time_statis (imp_date, user_name, stay_hours, page) VALUES (DATEADD('DAY', -8, CURRENT_DATE()), 'lucy', '0.039935860913407284', 'p2'); diff --git a/launchers/standalone/src/main/resources/db/schema-h2.sql b/launchers/standalone/src/main/resources/db/schema-h2.sql index 9fa1ec519..e0e6bc25d 100644 --- a/launchers/standalone/src/main/resources/db/schema-h2.sql +++ b/launchers/standalone/src/main/resources/db/schema-h2.sql @@ -1,652 +1,343 @@ -- chat tables CREATE TABLE IF NOT EXISTS `s2_chat_context` ( - `chat_id` - BIGINT - NOT - NULL, -- context chat id - `modified_at` - TIMESTAMP - NOT - NULL - DEFAULT - CURRENT_TIMESTAMP - ON - UPDATE - CURRENT_TIMESTAMP, -- row modify time - `user` - varchar -( - 64 -) DEFAULT NULL , -- row modify user - `query_text` LONGVARCHAR DEFAULT NULL , -- query text + `chat_id` BIGINT NOT NULL , -- context chat id + `modified_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , -- row modify time + `user` varchar(64) DEFAULT NULL , -- row modify user + `query_text` LONGVARCHAR DEFAULT NULL , -- query text `semantic_parse` LONGVARCHAR DEFAULT NULL , -- parse data - `ext_data` LONGVARCHAR DEFAULT NULL , -- extend data - PRIMARY KEY -( - `chat_id` -) + `ext_data` LONGVARCHAR DEFAULT NULL , -- extend data + PRIMARY KEY (`chat_id`) ); CREATE TABLE IF NOT EXISTS `s2_chat` ( - `chat_id` - BIGINT - auto_increment,-- AUTO_INCREMENT, - `chat_name` - varchar -( - 100 -) DEFAULT NULL, - `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , - `last_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP - ON UPDATE CURRENT_TIMESTAMP , - `creator` varchar -( - 30 -) DEFAULT NULL, - `last_question` varchar -( - 200 -) DEFAULT NULL, - `is_delete` INT DEFAULT '0' COMMENT 'is deleted', - `is_top` INT DEFAULT '0' COMMENT 'is top', - PRIMARY KEY -( - `chat_id` -) - ); + `chat_id` BIGINT auto_increment ,-- AUTO_INCREMENT, + `chat_name` varchar(100) DEFAULT NULL, + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `last_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `creator` varchar(30) DEFAULT NULL, + `last_question` varchar(200) DEFAULT NULL, + `is_delete` INT DEFAULT '0' COMMENT 'is deleted', + `is_top` INT DEFAULT '0' COMMENT 'is top', + PRIMARY KEY (`chat_id`) + ) ; CREATE TABLE `s2_chat_query` ( - `question_id` BIGINT NOT NULL AUTO_INCREMENT, - `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `query_text` mediumtext, - `user_name` varchar(150) DEFAULT NULL COMMENT '', - `query_state` int(1) DEFAULT NULL, - `chat_id` BIGINT NOT NULL, -- context chat id - `query_response` mediumtext NOT NULL, - `score` int DEFAULT '0', - `feedback` varchar(1024) DEFAULT '', + `question_id` BIGINT NOT NULL AUTO_INCREMENT, + `agent_id` INT NULL, + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `query_text` mediumtext, + `user_name` varchar(150) DEFAULT NULL COMMENT '', + `query_state` int(1) DEFAULT NULL, + `chat_id` BIGINT NOT NULL , -- context chat id + `query_result` mediumtext NOT NULL , + `score` int DEFAULT '0', + `feedback` varchar(1024) DEFAULT '', PRIMARY KEY (`question_id`) ); +CREATE TABLE `s2_chat_parse` +( + `question_id` BIGINT NOT NULL, + `chat_id` BIGINT NOT NULL , + `parse_id` INT NOT NULL , + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `query_text` varchar(500), + `user_name` varchar(150) DEFAULT NULL COMMENT '', + `parse_info` mediumtext NOT NULL , + `is_candidate` INT DEFAULT 1 COMMENT '1是candidate,0是selected' +); -CREATE TABLE IF NOT EXISTS `s2_chat_config` +CREATE TABLE `s2_chat_statistics` ( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_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 , - `updated_by` varchar -( - 100 -) NOT NULL , - `status` INT NOT NULL DEFAULT '0' , -- domain extension information status : 0 is normal, 1 is off the shelf, 2 is deleted - PRIMARY KEY -( - `id` -) - ); -COMMENT -ON TABLE s2_chat_config IS 'chat config information table '; + `question_id` BIGINT NOT NULL, + `chat_id` BIGINT NOT NULL , + `user_name` varchar(150) DEFAULT NULL COMMENT '', + `query_text` varchar(200), + `interface_name` varchar(100) DEFAULT NULL COMMENT '', + `cost` INT(6) NOT NULL , + `type` INT NOT NULL , + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS `s2_chat_config` ( + `id` INT NOT NULL AUTO_INCREMENT, + `model_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 , + `updated_by` varchar(100) NOT NULL , + `status` INT NOT NULL DEFAULT '0' , -- domain extension information status : 0 is normal, 1 is off the shelf, 2 is deleted + PRIMARY KEY (`id`) + ) ; +COMMENT ON TABLE s2_chat_config IS 'chat config information table '; create table s2_user ( - id INT AUTO_INCREMENT, - name varchar(100) not null, + id INT AUTO_INCREMENT, + name varchar(100) not null, display_name varchar(100) null, - password varchar(100) null, - email varchar(100) null, + password varchar(100) null, + email varchar(100) null, PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_user IS 'user information table'; +COMMENT ON TABLE s2_user IS 'user information table'; -- semantic tables -CREATE TABLE IF NOT EXISTS `s2_domain` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `name` - varchar -( - 255 -) DEFAULT NULL , -- domain name - `biz_name` varchar -( - 255 -) DEFAULT NULL , -- internal name - `parent_id` INT DEFAULT '0' , -- parent domain ID - `status` INT NOT NULL , - `created_at` TIMESTAMP DEFAULT NULL , - `created_by` varchar -( - 100 -) DEFAULT NULL , - `updated_at` TIMESTAMP DEFAULT NULL , - `updated_by` varchar -( - 100 -) DEFAULT NULL , - `admin` varchar -( - 3000 -) DEFAULT NULL , -- domain administrator - `admin_org` varchar -( - 3000 -) DEFAULT NULL , -- domain administrators organization - `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 - PRIMARY KEY -( - `id` -) - ); -COMMENT -ON TABLE s2_domain IS 'domain basic information'; - -CREATE TABLE IF NOT EXISTS `s2_model` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `name` - varchar -( - 255 -) DEFAULT NULL , -- domain name - `biz_name` varchar -( - 255 -) DEFAULT NULL , -- internal name - `domain_id` INT DEFAULT '0' , -- parent domain ID - `created_at` TIMESTAMP DEFAULT NULL , - `created_by` varchar -( - 100 -) DEFAULT NULL , - `updated_at` TIMESTAMP DEFAULT NULL , - `updated_by` varchar -( - 100 -) DEFAULT NULL , - `admin` varchar -( - 3000 -) DEFAULT NULL , -- domain administrator - `admin_org` varchar -( - 3000 -) DEFAULT NULL , -- domain administrators organization - `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_model IS 'model information'; - - -CREATE TABLE `s2_database` -( - `id` INT NOT NULL AUTO_INCREMENT, - `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, - `created_by` varchar(100) NOT NULL, - `updated_at` TIMESTAMP NOT NULL, - `updated_by` varchar(100) NOT NULL, +CREATE TABLE IF NOT EXISTS `s2_domain` ( + `id` INT NOT NULL AUTO_INCREMENT , + `name` varchar(255) DEFAULT NULL , -- domain name + `biz_name` varchar(255) DEFAULT NULL , -- internal name + `parent_id` INT DEFAULT '0' , -- parent domain ID + `status` INT NOT NULL , + `created_at` TIMESTAMP DEFAULT NULL , + `created_by` varchar(100) DEFAULT NULL , + `updated_at` TIMESTAMP DEFAULT NULL , + `updated_by` varchar(100) DEFAULT NULL , + `admin` varchar(3000) DEFAULT NULL , -- domain administrator + `admin_org` varchar(3000) DEFAULT NULL , -- domain administrators organization + `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 PRIMARY KEY (`id`) -); -COMMENT -ON TABLE s2_database IS 'database instance table'; - -CREATE TABLE IF NOT EXISTS `s2_datasource` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_id` - INT - NOT - NULL, - `name` - varchar -( - 255 -) NOT NULL , - `biz_name` varchar -( - 255 -) NOT NULL , - `description` varchar -( - 500 -) DEFAULT NULL , - `database_id` INT NOT NULL , - `datasource_detail` LONGVARCHAR NOT NULL , - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , - `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL, - PRIMARY KEY -( - `id` -) ); -COMMENT -ON TABLE s2_datasource IS 'datasource table'; +COMMENT ON TABLE s2_domain IS 'domain basic information'; + +CREATE TABLE IF NOT EXISTS `s2_model` ( + `id` INT NOT NULL AUTO_INCREMENT , + `name` varchar(255) DEFAULT NULL , -- domain name + `biz_name` varchar(255) DEFAULT NULL , -- internal name + `domain_id` INT DEFAULT '0' , -- parent domain ID + `created_at` TIMESTAMP DEFAULT NULL , + `created_by` varchar(100) DEFAULT NULL , + `updated_at` TIMESTAMP DEFAULT NULL , + `updated_by` varchar(100) DEFAULT NULL , + `admin` varchar(3000) DEFAULT NULL , -- domain administrator + `admin_org` varchar(3000) DEFAULT NULL , -- domain administrators organization + `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_model IS 'model information'; + + +CREATE TABLE `s2_database` ( + `id` INT NOT NULL AUTO_INCREMENT, + `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 , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL, + PRIMARY KEY (`id`) +); +COMMENT ON TABLE s2_database IS 'database instance table'; + +CREATE TABLE IF NOT EXISTS `s2_datasource` ( + `id` INT NOT NULL AUTO_INCREMENT, + `model_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `biz_name` varchar(255) NOT NULL , + `description` varchar(500) DEFAULT NULL , + `database_id` INT NOT NULL , + `datasource_detail` LONGVARCHAR NOT NULL , + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL, + PRIMARY KEY (`id`) + ); +COMMENT ON TABLE s2_datasource IS 'datasource table'; create table s2_auth_groups ( group_id INT, - config varchar(2048), + config varchar(2048), PRIMARY KEY (`group_id`) ); -CREATE TABLE IF NOT EXISTS `s2_metric` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_id` - INT - NOT - NULL, - `name` - varchar -( - 255 -) NOT NULL , - `biz_name` varchar -( - 255 -) NOT NULL , - `description` varchar -( - 500 -) DEFAULT NULL , - `status` INT NOT NULL , -- status, 0 is normal, 1 is off the shelf, 2 is deleted +CREATE TABLE IF NOT EXISTS `s2_metric` ( + `id` INT NOT NULL AUTO_INCREMENT, + `model_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `biz_name` varchar(255) NOT NULL , + `description` varchar(500) DEFAULT NULL , + `status` INT NOT NULL , -- status, 0 is normal, 1 is off the shelf, 2 is deleted `sensitive_level` INT NOT NULL , - `type` varchar -( - 50 -) NOT NULL , -- type proxy,expr - `type_params` LONGVARCHAR DEFAULT NULL , + `type` varchar(50) NOT NULL , -- type proxy,expr + `type_params` LONGVARCHAR DEFAULT NULL , `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , + `created_by` varchar(100) NOT NULL , `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL , - `data_format_type` varchar -( - 50 -) DEFAULT NULL , - `data_format` varchar -( - 500 -) DEFAULT NULL, - `alias` varchar -( - 500 -) DEFAULT NULL, - PRIMARY KEY -( - `id` -) + `updated_by` varchar(100) NOT NULL , + `data_format_type` varchar(50) DEFAULT NULL , + `data_format` varchar(500) DEFAULT NULL, + `alias` varchar(500) DEFAULT NULL, + PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_metric IS 'metric information table'; +COMMENT ON TABLE s2_metric IS 'metric information table'; -CREATE TABLE IF NOT EXISTS `s2_dimension` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_id` - INT - NOT - NULL, - `datasource_id` - INT - NOT - NULL, - `name` - varchar -( - 255 -) NOT NULL , - `biz_name` varchar -( - 255 -) NOT NULL , - `description` varchar -( - 500 -) NOT NULL , +CREATE TABLE IF NOT EXISTS `s2_dimension` ( + `id` INT NOT NULL AUTO_INCREMENT , + `model_id` INT NOT NULL , + `datasource_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `biz_name` varchar(255) NOT NULL , + `description` varchar(500) NOT NULL , `status` INT NOT NULL , -- status, 0 is normal, 1 is off the shelf, 2 is deleted `sensitive_level` INT DEFAULT NULL , - `type` varchar -( - 50 -) NOT NULL , -- type categorical,time - `type_params` LONGVARCHAR DEFAULT NULL , + `type` varchar(50) NOT NULL , -- type categorical,time + `type_params` LONGVARCHAR DEFAULT NULL , `expr` LONGVARCHAR NOT NULL , -- expression - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , - `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL , - `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` -) + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL , + `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'; +COMMENT ON TABLE s2_dimension IS 'dimension information table'; create table s2_datasource_rela ( id INT AUTO_INCREMENT, - model_id INT null, - datasource_from INT null, - datasource_to INT null, + model_id INT null, + datasource_from INT null, + datasource_to INT null, join_key varchar(100) null, - created_at TIMESTAMP null, + created_at TIMESTAMP null, created_by varchar(100) null, - updated_at TIMESTAMP null, + updated_at TIMESTAMP null, updated_by varchar(100) null, PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_datasource_rela IS 'data source association table'; +COMMENT ON TABLE s2_datasource_rela IS 'data source association table'; create table s2_view_info ( id INT auto_increment, - model_id INT null, - type varchar(20) null comment 'datasource、dimension、metric', - config LONGVARCHAR null comment 'config detail', - created_at TIMESTAMP null, + model_id INT null, + type varchar(20) null comment 'datasource、dimension、metric', + config LONGVARCHAR null comment 'config detail', + created_at TIMESTAMP null, created_by varchar(100) null, - updated_at TIMESTAMP null, + updated_at TIMESTAMP null, updated_by varchar(100) not null ); -COMMENT -ON TABLE s2_view_info IS 'view information table'; +COMMENT ON TABLE s2_view_info IS 'view information table'; -CREATE TABLE `s2_query_stat_info` -( - `id` INT NOT NULL AUTO_INCREMENT, - `trace_id` varchar(200) DEFAULT NULL, -- query unique identifier - `model_id` INT DEFAULT NULL, - `user` varchar(200) DEFAULT NULL, - `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - `query_type` varchar(200) DEFAULT NULL, -- the corresponding scene - `query_type_back` INT DEFAULT '0', -- query type, 0-normal query, 1-pre-refresh type - `query_sql_cmd` LONGVARCHAR, -- sql type request parameter - `sql_cmd_md5` varchar(200) DEFAULT NULL, -- sql type request parameter md5 - `query_struct_cmd` LONGVARCHAR, -- struct type request parameter - `struct_cmd_md5` varchar(200) DEFAULT NULL, -- struct type request parameter md5值 - `sql` LONGVARCHAR, - `sql_md5` varchar(200) DEFAULT NULL, -- sql md5 - `query_engine` varchar(20) DEFAULT NULL, - `elapsed_ms` bigINT DEFAULT NULL, - `query_state` varchar(20) DEFAULT NULL, - `native_query` INT DEFAULT NULL, -- 1-detail query, 0-aggregation query - `start_date` varchar(50) DEFAULT NULL, - `end_date` varchar(50) DEFAULT NULL, - `dimensions` LONGVARCHAR, -- dimensions involved in sql - `metrics` LONGVARCHAR, -- metric involved in sql - `select_cols` LONGVARCHAR, - `agg_cols` LONGVARCHAR, - `filter_cols` LONGVARCHAR, - `group_by_cols` LONGVARCHAR, - `order_by_cols` LONGVARCHAR, - `use_result_cache` TINYINT DEFAULT '-1', -- whether to hit the result cache - `use_sql_cache` TINYINT DEFAULT '-1', -- whether to hit the sql cache - `sql_cache_key` LONGVARCHAR, -- sql cache key - `result_cache_key` LONGVARCHAR, -- result cache key - PRIMARY KEY (`id`) -); -COMMENT -ON TABLE s2_query_stat_info IS 'query statistics table'; +CREATE TABLE `s2_query_stat_info` ( + `id` INT NOT NULL AUTO_INCREMENT, + `trace_id` varchar(200) DEFAULT NULL, -- query unique identifier + `model_id` INT DEFAULT NULL, + `user` varchar(200) DEFAULT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP , + `query_type` varchar(200) DEFAULT NULL, -- the corresponding scene + `query_type_back` INT DEFAULT '0' , -- query type, 0-normal query, 1-pre-refresh type + `query_sql_cmd`LONGVARCHAR , -- sql type request parameter + `sql_cmd_md5` varchar(200) DEFAULT NULL, -- sql type request parameter md5 + `query_struct_cmd`LONGVARCHAR , -- struct type request parameter + `struct_cmd_md5` varchar(200) DEFAULT NULL, -- struct type request parameter md5值 + `sql`LONGVARCHAR , + `sql_md5` varchar(200) DEFAULT NULL, -- sql md5 + `query_engine` varchar(20) DEFAULT NULL, + `elapsed_ms` bigINT DEFAULT NULL, + `query_state` varchar(20) DEFAULT NULL, + `native_query` INT DEFAULT NULL, -- 1-detail query, 0-aggregation query + `start_date` varchar(50) DEFAULT NULL, + `end_date` varchar(50) DEFAULT NULL, + `dimensions`LONGVARCHAR , -- dimensions involved in sql + `metrics`LONGVARCHAR , -- metric involved in sql + `select_cols`LONGVARCHAR , + `agg_cols`LONGVARCHAR , + `filter_cols`LONGVARCHAR , + `group_by_cols`LONGVARCHAR , + `order_by_cols`LONGVARCHAR , + `use_result_cache` TINYINT DEFAULT '-1' , -- whether to hit the result cache + `use_sql_cache` TINYINT DEFAULT '-1' , -- whether to hit the sql cache + `sql_cache_key`LONGVARCHAR , -- sql cache key + `result_cache_key`LONGVARCHAR , -- result cache key + PRIMARY KEY (`id`) +) ; +COMMENT ON TABLE s2_query_stat_info IS 'query statistics table'; -CREATE TABLE IF NOT EXISTS `s2_semantic_pasre_info` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `trace_id` - varchar -( - 200 -) NOT NULL , - `model_id` INT NOT NULL , - `dimensions` LONGVARCHAR , - `metrics` LONGVARCHAR , - `orders` LONGVARCHAR , - `filters` LONGVARCHAR , - `date_info` LONGVARCHAR , +CREATE TABLE IF NOT EXISTS `s2_semantic_pasre_info` ( + `id` INT NOT NULL AUTO_INCREMENT, + `trace_id` varchar(200) NOT NULL , + `model_id` INT NOT NULL , + `dimensions`LONGVARCHAR , + `metrics`LONGVARCHAR , + `orders`LONGVARCHAR , + `filters`LONGVARCHAR , + `date_info`LONGVARCHAR , `limit` INT NOT NULL , `native_query` TINYINT NOT NULL DEFAULT '0' , - `sql` LONGVARCHAR , - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , + `sql`LONGVARCHAR , + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , `status` INT NOT NULL , `elapsed_ms` bigINT DEFAULT NULL , - PRIMARY KEY -( - `id` -) + PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_semantic_pasre_info IS 'semantic layer sql parsing information table'; +COMMENT ON TABLE s2_semantic_pasre_info IS 'semantic layer sql parsing information table'; -CREATE TABLE IF NOT EXISTS `s2_available_date_info` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `item_id` - INT - NOT - NULL, - `type` - varchar -( - 255 -) NOT NULL , - `date_format` varchar -( - 64 -) NOT NULL , - `start_date` varchar -( - 64 -) , - `end_date` varchar -( - 64 -) , - `unavailable_date` LONGVARCHAR DEFAULT NULL , - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , - `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL , - `date_period` varchar -( - 100 -) DEFAULT NULL , - `status` INT DEFAULT '0', -- 1-in use 0 is normal, 1 is off the shelf, 2 is deleted - PRIMARY KEY -( - `id` -) +CREATE TABLE IF NOT EXISTS `s2_available_date_info` ( + `id` INT NOT NULL AUTO_INCREMENT , + `item_id` INT NOT NULL , + `type` varchar(255) NOT NULL , + `date_format` varchar(64) NOT NULL , + `start_date` varchar(64) , + `end_date` varchar(64) , + `unavailable_date` LONGVARCHAR DEFAULT NULL , + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL , + `date_period` varchar(100) DEFAULT NULL , + `status` INT DEFAULT '0', -- 1-in use 0 is normal, 1 is off the shelf, 2 is deleted + PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_dimension IS 'dimension information table'; +COMMENT ON TABLE s2_dimension IS 'dimension information table'; CREATE TABLE IF NOT EXISTS `s2_plugin` ( - `id` - INT - AUTO_INCREMENT, - `type` - varchar -( - 50 -) NULL, - `model` varchar -( - 100 -) NULL, - `pattern` varchar -( - 500 -) NULL, - `parse_mode` varchar -( - 100 -) NULL, - `parse_mode_config` LONGVARCHAR 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, - `comment` LONGVARCHAR NULL, - PRIMARY KEY -( - `id` -) - ); -COMMENT -ON TABLE s2_plugin IS 'plugin information table'; + `id` INT AUTO_INCREMENT, + `type` varchar(50) NULL, + `model` varchar(100) NULL, + `pattern` varchar(500) NULL, + `parse_mode` varchar(100) NULL, + `parse_mode_config` LONGVARCHAR 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, + `comment` LONGVARCHAR NULL, + PRIMARY KEY (`id`) +); COMMENT ON TABLE s2_plugin IS 'plugin information table'; CREATE TABLE IF NOT EXISTS s2_agent ( @@ -660,91 +351,44 @@ CREATE TABLE IF NOT EXISTS s2_agent created_at TIMESTAMP null, updated_by varchar(100) null, updated_at TIMESTAMP null, - enable_search int null, + enable_search int null, PRIMARY KEY (`id`) -); COMMENT ON TABLE s2_agent IS 'assistant information table'; +); COMMENT ON TABLE s2_agent IS 'agent information table'; -------demo for semantic and chat -CREATE TABLE IF NOT EXISTS `s2_user_department` -( - `user_name` varchar -( - 200 -) NOT NULL, - `department` varchar -( - 200 -) NOT NULL -- department of user +CREATE TABLE IF NOT EXISTS `s2_user_department` ( + `user_name` varchar(200) NOT NULL, + `department` varchar(200) NOT NULL -- department of user ); -COMMENT -ON TABLE s2_user_department IS 'user_department_info'; +COMMENT ON TABLE s2_user_department IS 'user_department_info'; -CREATE TABLE IF NOT EXISTS `s2_pv_uv_statis` -( - `imp_date` varchar -( - 200 -) NOT NULL, - `user_name` varchar -( - 200 -) NOT NULL, - `page` varchar -( - 200 -) NOT NULL +CREATE TABLE IF NOT EXISTS `s2_pv_uv_statis` ( + `imp_date` varchar(200) NOT NULL, + `user_name` varchar(200) NOT NULL, + `page` varchar(200) NOT NULL ); -COMMENT -ON TABLE s2_pv_uv_statis IS 's2_pv_uv_statis'; +COMMENT ON TABLE s2_pv_uv_statis IS 's2_pv_uv_statis'; -CREATE TABLE IF NOT EXISTS `s2_stay_time_statis` -( - `imp_date` varchar -( - 200 -) NOT NULL, - `user_name` varchar -( - 200 -) NOT NULL, +CREATE TABLE IF NOT EXISTS `s2_stay_time_statis` ( + `imp_date` varchar(200) NOT NULL, + `user_name` varchar(200) NOT NULL, `stay_hours` DOUBLE NOT NULL, - `page` varchar -( - 200 -) NOT NULL + `page` varchar(200) NOT NULL ); -COMMENT -ON TABLE s2_stay_time_statis IS 's2_stay_time_statis_info'; +COMMENT ON TABLE s2_stay_time_statis IS 's2_stay_time_statis_info'; -CREATE TABLE IF NOT EXISTS `singer` -( - `imp_date` varchar -( - 200 -) NOT NULL, - `singer_name` varchar -( - 200 -) NOT NULL, - `act_area` varchar -( - 200 -) NOT NULL, - `song_name` varchar -( - 200 -) NOT NULL, - `genre` varchar -( - 200 -) NOT NULL, +CREATE TABLE IF NOT EXISTS `singer` ( + `imp_date` varchar(200) NOT NULL, + `singer_name` varchar(200) NOT NULL, + `act_area` varchar(200) NOT NULL, + `song_name` varchar(200) NOT NULL, + `genre` varchar(200) NOT NULL, `js_play_cnt` bigINT DEFAULT NULL, `down_cnt` bigINT DEFAULT NULL, `favor_cnt` bigINT DEFAULT NULL ); -COMMENT -ON TABLE singer IS 'singer_info'; +COMMENT ON TABLE singer IS 'singer_info'; diff --git a/launchers/standalone/src/main/resources/db/sql-update.sql b/launchers/standalone/src/main/resources/db/sql-update.sql index 096dd6692..bfaed7f1c 100644 --- a/launchers/standalone/src/main/resources/db/sql-update.sql +++ b/launchers/standalone/src/main/resources/db/sql-update.sql @@ -1,5 +1,4 @@ -alter table s2_domain - add column `entity` varchar(500) DEFAULT NULL COMMENT '主题域实体信息'; +alter table s2_domain add column `entity`varchar(500) DEFAULT NULL COMMENT '主题域实体信息'; --20230808 @@ -9,19 +8,19 @@ create table s2_model ( id bigint auto_increment primary key, - name varchar(100) null, + name varchar(100) null, biz_name varchar(100) null, - domain_id bigint null, + domain_id bigint null, viewer varchar(500) null, - view_org varchar(500) null, + view_org varchar(500) null, admin varchar(500) null, - admin_org varchar(500) null, - is_open int null, + admin_org varchar(500) null, + is_open int null, created_by varchar(100) null, - created_at datetime null, - updated_by varchar(100) null, - updated_at datetime null, - entity text null + created_at datetime null, + updated_by varchar(100) null, + updated_at datetime null, + entity text null ) collate = utf8_unicode_ci; alter table s2_datasource change column domain_id model_id bigint; @@ -31,8 +30,11 @@ alter table s2_datasource_rela change column domain_id model_id bigint; alter table s2_view_info change column domain_id model_id bigint; alter table s2_domain_extend change column domain_id model_id bigint; alter table s2_chat_config change column domain_id model_id bigint; -alter table s2_plugin change column domain model varchar (100); +alter table s2_plugin change column domain model varchar(100); alter table s2_query_stat_info change column domain_id model_id bigint; -update s2_plugin -set config = replace(config, 'domain', 'model'); \ No newline at end of file +update s2_plugin set config = replace(config, 'domain', 'model'); + +--20230823 +alter table s2_chat_query add column agent_id int after question_id; +alter table s2_chat_query change column query_response query_result mediumtext; 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 index 7b8d5f49b..028500289 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/BaseQueryTest.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/BaseQueryTest.java @@ -51,6 +51,8 @@ public class BaseQueryTest { ParseResp parseResp = submitParse(queryText); ExecuteQueryReq request = new ExecuteQueryReq(); + request.setQueryId(parseResp.getQueryId()); + request.setParseId(parseResp.getSelectedParses().get(0).getId()); request.setChatId(parseResp.getChatId()); request.setQueryText(parseResp.getQueryText()); request.setUser(DataUtils.getUser()); @@ -63,6 +65,8 @@ public class BaseQueryTest { ParseResp parseResp = submitParse(queryText); ExecuteQueryReq request = new ExecuteQueryReq(); + request.setQueryId(parseResp.getQueryId()); + request.setParseId(parseResp.getSelectedParses().get(0).getId()); request.setChatId(parseResp.getChatId()); request.setQueryText(parseResp.getQueryText()); request.setUser(DataUtils.getUser()); 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 index abf7fd7fd..50c39e51e 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/EntityQueryTest.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/EntityQueryTest.java @@ -18,7 +18,7 @@ import org.junit.Test; public class EntityQueryTest extends BaseQueryTest { @Test - public void queryTest_METRIC_ENTITY_QUERY() throws Exception { + public void queryTest_metric_entity_query() throws Exception { QueryResult actualResult = submitNewChat("艺人周杰伦的播放量"); QueryResult expectedResult = new QueryResult(); @@ -41,7 +41,7 @@ public class EntityQueryTest extends BaseQueryTest { } @Test - public void queryTest_ENTITY_LIST_FILTER() throws Exception { + public void queryTest_entity_list_filter() throws Exception { QueryResult actualResult = submitNewChat("爱情、流行类型的艺人"); QueryResult expectedResult = new QueryResult(); diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricInterpretTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricInterpretTest.java index a1da76abd..8645896be 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricInterpretTest.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricInterpretTest.java @@ -4,9 +4,9 @@ import com.alibaba.fastjson.JSONObject; import com.tencent.supersonic.StandaloneLauncher; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; -import com.tencent.supersonic.chat.parser.embedding.EmbeddingConfig; +import com.tencent.supersonic.chat.parser.plugin.embedding.EmbeddingConfig; import com.tencent.supersonic.chat.plugin.PluginManager; -import com.tencent.supersonic.chat.query.metricInterpret.LLmAnswerResp; +import com.tencent.supersonic.chat.query.metricinterpret.LLmAnswerResp; import com.tencent.supersonic.chat.service.AgentService; import com.tencent.supersonic.chat.service.QueryService; import com.tencent.supersonic.util.DataUtils; @@ -44,13 +44,13 @@ public class MetricInterpretTest { MockConfiguration.mockAgent(agentService); MockConfiguration.mockEmbeddingUrl(embeddingConfig); LLmAnswerResp lLmAnswerResp = new LLmAnswerResp(); - lLmAnswerResp.setAssistant_message("alice最近在超音数的访问情况有增多"); + lLmAnswerResp.setAssistantMessage("alice最近在超音数的访问情况有增多"); MockConfiguration.mockPluginManagerDoRequest(pluginManager, "answer_with_plugin_call", ResponseEntity.ok(JSONObject.toJSONString(lLmAnswerResp))); QueryReq queryReq = DataUtils.getQueryReqWithAgent(1000, "能不能帮我解读分析下最近alice在超音数的访问情况", DataUtils.getAgent().getId()); QueryResult queryResult = queryService.executeQuery(queryReq); - Assert.assertEquals(queryResult.getQueryResults().get(0).get("answer"), lLmAnswerResp.getAssistant_message()); + Assert.assertEquals(queryResult.getQueryResults().get(0).get("answer"), lLmAnswerResp.getAssistantMessage()); } } 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 index f34309d93..4a980967d 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricQueryTest.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MetricQueryTest.java @@ -21,16 +21,18 @@ import org.springframework.beans.BeanUtils; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; import java.util.stream.Collectors; - -import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.*; +import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.SUM; +import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.NONE; public class MetricQueryTest extends BaseQueryTest { @Test - public void queryTest_METRIC_FILTER() throws Exception { + public void queryTest_metric_filter() throws Exception { QueryResult actualResult = submitNewChat("alice的访问次数"); QueryResult expectedResult = new QueryResult(); @@ -52,7 +54,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_FILTER_with_agent() { + public void queryTest_metric_filter_with_agent() { //agent only support METRIC_ENTITY, METRIC_FILTER MockConfiguration.mockAgent(agentService); ParseResp parseResp = submitParseWithAgent("alice的访问次数", DataUtils.getAgent().getId()); @@ -63,7 +65,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_DOMAIN() throws Exception { + public void queryTest_metric_domain() throws Exception { QueryResult actualResult = submitNewChat("超音数的访问次数"); QueryResult expectedResult = new QueryResult(); @@ -82,7 +84,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_MODEL_with_agent() { + public void queryTest_metric_model_with_agent() { //agent only support METRIC_ENTITY, METRIC_FILTER MockConfiguration.mockAgent(agentService); ParseResp parseResp = submitParseWithAgent("超音数的访问次数", DataUtils.getAgent().getId()); @@ -92,7 +94,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_GROUPBY() throws Exception { + public void queryTest_metric_groupby() throws Exception { QueryResult actualResult = submitNewChat("超音数各部门的访问次数"); QueryResult expectedResult = new QueryResult(); @@ -112,7 +114,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_FILTER_COMPARE() throws Exception { + public void queryTest_metric_filter_compare() throws Exception { QueryResult actualResult = submitNewChat("对比alice和lucy的访问次数"); QueryResult expectedResult = new QueryResult(); @@ -137,7 +139,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_TOPN() throws Exception { + public void queryTest_metric_topn() throws Exception { QueryResult actualResult = submitNewChat("近3天访问次数最多的用户"); QueryResult expectedResult = new QueryResult(); @@ -157,7 +159,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_GROUPBY_SUM() throws Exception { + public void queryTest_metric_groupby_sum() throws Exception { QueryResult actualResult = submitNewChat("超音数各部门的访问次数总和"); QueryResult expectedResult = new QueryResult(); SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); @@ -176,7 +178,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_METRIC_FILTER_TIME() throws Exception { + 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)); @@ -202,7 +204,7 @@ public class MetricQueryTest extends BaseQueryTest { } @Test - public void queryTest_CONFIG_VISIBILITY() throws Exception { + public void queryTest_config_visibility() throws Exception { // 1. round_1 use blacklist ChatConfigResp chatConfig = configService.fetchConfigByModelId(1L); ChatConfigEditReqReq extendEditCmd = new ChatConfigEditReqReq(); diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MockConfiguration.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MockConfiguration.java index fb95fe332..79ba8b6d8 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MockConfiguration.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/MockConfiguration.java @@ -2,9 +2,9 @@ package com.tencent.supersonic.integration; 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.parser.plugin.embedding.EmbeddingConfig; +import com.tencent.supersonic.chat.parser.plugin.embedding.EmbeddingResp; +import com.tencent.supersonic.chat.parser.plugin.embedding.RecallRetrieval; import com.tencent.supersonic.chat.plugin.PluginManager; import com.tencent.supersonic.chat.service.AgentService; import com.tencent.supersonic.util.DataUtils; @@ -34,7 +34,8 @@ public class MockConfiguration { when(embeddingConfig.getUrl()).thenReturn("test"); } - public static void mockPluginManagerDoRequest(PluginManager pluginManager, String path, ResponseEntity responseEntity) { + public static void mockPluginManagerDoRequest(PluginManager pluginManager, String path, + ResponseEntity responseEntity) { when(pluginManager.doRequest(eq(path), notNull(String.class))).thenReturn(responseEntity); } diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/llm/LLMDslParserTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/llm/LLMDslParserTest.java new file mode 100644 index 000000000..8d77ac2c6 --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/llm/LLMDslParserTest.java @@ -0,0 +1,43 @@ +package com.tencent.supersonic.integration.llm; + +import static org.mockito.Mockito.when; + +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.request.QueryReq; +import com.tencent.supersonic.chat.config.LLMConfig; +import com.tencent.supersonic.chat.parser.llm.dsl.LLMDslParser; +import com.tencent.supersonic.chat.utils.ComponentFactory; +import com.tencent.supersonic.integration.BaseQueryTest; +import com.tencent.supersonic.util.DataUtils; +import org.junit.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +public class LLMDslParserTest extends BaseQueryTest { + + @MockBean + protected LLMConfig llmConfig; + + @Test + public void parse() throws Exception { + String queryText = "周杰伦专辑十一月的萧邦有哪些歌曲"; + QueryReq queryReq = DataUtils.getQueryContextReq(10, queryText); + QueryContext queryContext = new QueryContext(); + queryContext.setRequest(queryReq); + SemanticParser dslParser = ComponentFactory.getSemanticParsers().stream().filter(parser -> { + if (parser instanceof LLMDslParser) { + return true; + } else { + return false; + } + } + ).findFirst().get(); + + when(llmConfig.getUrl()).thenReturn("llmUrl"); + + ChatContext chatCtx = new ChatContext(); + dslParser.parse(queryContext, chatCtx); + } + +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/integration/mapper/MapperTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/mapper/MapperTest.java new file mode 100644 index 000000000..b0aeefc35 --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/integration/mapper/MapperTest.java @@ -0,0 +1,46 @@ +package com.tencent.supersonic.integration.mapper; + +import static com.tencent.supersonic.common.pojo.enums.AggregateTypeEnum.NONE; + +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.request.QueryReq; +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.query.rule.metric.MetricEntityQuery; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.integration.BaseQueryTest; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import com.tencent.supersonic.util.DataUtils; +import org.junit.Test; + +public class MapperTest extends BaseQueryTest { + + @Test + public void hanlp() throws Exception { + + QueryReq queryContextReq = DataUtils.getQueryContextReq(10, "艺人周杰伦的播放量"); + queryContextReq.setAgentId(1); + + QueryResult actualResult = submitNewChat("艺人周杰伦的播放量"); + + QueryResult expectedResult = new QueryResult(); + SemanticParseInfo expectedParseInfo = new SemanticParseInfo(); + expectedResult.setChatContext(expectedParseInfo); + + expectedResult.setQueryMode(MetricEntityQuery.QUERY_MODE); + expectedParseInfo.setAggType(NONE); + + QueryFilter dimensionFilter = DataUtils.getFilter("singer_name", FilterOperatorEnum.EQUALS, "周杰伦", "歌手名", 7L); + expectedParseInfo.getDimensionFilters().add(dimensionFilter); + + SchemaElement metric = SchemaElement.builder().name("播放量").build(); + expectedParseInfo.getMetrics().add(metric); + + expectedParseInfo.setDateInfo(DataUtils.getDateConf(DateConf.DateMode.RECENT, 7, period, startDay, endDay)); + expectedParseInfo.setNativeQuery(false); + + assertQueryResult(expectedResult, actualResult); + } + +} 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 index 08b19eb3e..2341b81ec 100644 --- 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 @@ -29,4 +29,4 @@ public class BasePluginTest { Assert.assertEquals("alice", webPage.getParams().get(0).getValue()); } -} \ No newline at end of file +} 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 index 56836c7a1..2bc35dec8 100644 --- 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 @@ -5,7 +5,7 @@ import com.tencent.supersonic.chat.api.pojo.request.QueryFilters; import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.api.pojo.response.ParseResp; import com.tencent.supersonic.chat.api.pojo.response.QueryResult; -import com.tencent.supersonic.chat.parser.embedding.EmbeddingConfig; +import com.tencent.supersonic.chat.parser.plugin.embedding.EmbeddingConfig; import com.tencent.supersonic.chat.plugin.PluginManager; import com.tencent.supersonic.chat.service.AgentService; import com.tencent.supersonic.chat.service.QueryService; @@ -17,16 +17,16 @@ 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; +public class PluginRecognizeTest extends BasePluginTest { @MockBean protected PluginManager pluginManager; @MockBean - protected AgentService agentService; + private EmbeddingConfig embeddingConfig; + + @MockBean + private AgentService agentService; @Autowired @Qualifier("chatQueryService") @@ -34,7 +34,7 @@ public class PluginRecognizeTest extends BasePluginTest{ @Test public void webPageRecognize() throws Exception { - MockConfiguration.mockEmbeddingRecognize(pluginManager, "alice最近的访问情况怎么样","1"); + MockConfiguration.mockEmbeddingRecognize(pluginManager, "alice最近的访问情况怎么样", "1"); MockConfiguration.mockEmbeddingUrl(embeddingConfig); QueryReq queryContextReq = DataUtils.getQueryContextReq(1000, "alice最近的访问情况怎么样"); QueryResult queryResult = queryService.executeQuery(queryContextReq); @@ -43,7 +43,7 @@ public class PluginRecognizeTest extends BasePluginTest{ @Test public void webPageRecognizeWithQueryFilter() throws Exception { - MockConfiguration.mockEmbeddingRecognize(pluginManager, "在超音数最近的情况怎么样","1"); + MockConfiguration.mockEmbeddingRecognize(pluginManager, "在超音数最近的情况怎么样", "1"); MockConfiguration.mockEmbeddingUrl(embeddingConfig); QueryReq queryRequest = DataUtils.getQueryContextReq(1000, "在超音数最近的情况怎么样"); QueryFilters queryFilters = new QueryFilters(); @@ -59,7 +59,7 @@ public class PluginRecognizeTest extends BasePluginTest{ @Test public void pluginRecognizeWithAgent() { - MockConfiguration.mockEmbeddingRecognize(pluginManager, "alice最近的访问情况怎么样","1"); + MockConfiguration.mockEmbeddingRecognize(pluginManager, "alice最近的访问情况怎么样", "1"); MockConfiguration.mockEmbeddingUrl(embeddingConfig); MockConfiguration.mockAgent(agentService); QueryReq queryContextReq = DataUtils.getQueryReqWithAgent(1000, "alice最近的访问情况怎么样", 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 d478b531d..21923514f 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 @@ -31,7 +31,7 @@ public class DataUtils { public static QueryReq getQueryContextReq(Integer id, String query) { QueryReq queryContextReq = new QueryReq(); - queryContextReq.setQueryText(query);//"alice的访问次数" + queryContextReq.setQueryText(query); queryContextReq.setChatId(id); queryContextReq.setUser(user_test); return queryContextReq; @@ -39,7 +39,7 @@ public class DataUtils { public static QueryReq getQueryReqWithAgent(Integer id, String query, Integer agentId) { QueryReq queryReq = new QueryReq(); - queryReq.setQueryText(query);//"alice的访问次数" + queryReq.setQueryText(query); queryReq.setChatId(id); queryReq.setUser(user_test); queryReq.setAgentId(agentId); @@ -74,8 +74,8 @@ public class DataUtils { .build(); } - public static QueryFilter getFilter(String bizName, FilterOperatorEnum filterOperatorEnum, Object value, String name, - Long elementId) { + public static QueryFilter getFilter(String bizName, FilterOperatorEnum filterOperatorEnum, + Object value, String name, Long elementId) { QueryFilter filter = new QueryFilter(); filter.setBizName(bizName); filter.setOperator(filterOperatorEnum); @@ -95,7 +95,8 @@ public class DataUtils { return dateInfo; } - public static DateConf getDateConf(DateConf.DateMode dateMode, Integer unit, String period, String startDate, String endDate) { + public static DateConf getDateConf(DateConf.DateMode dateMode, Integer unit, + String period, String startDate, String endDate) { DateConf dateInfo = new DateConf(); dateInfo.setUnit(unit); dateInfo.setDateMode(dateMode); @@ -114,9 +115,9 @@ public class DataUtils { } public static Boolean compareDate(DateConf dateInfo1, DateConf dateInfo2) { - Boolean timeFilterExist = dateInfo1.getUnit().equals(dateInfo2.getUnit()) && - dateInfo1.getDateMode().equals(dateInfo2.getDateMode()) && - dateInfo1.getPeriod().equals(dateInfo2.getPeriod()); + Boolean timeFilterExist = dateInfo1.getUnit().equals(dateInfo2.getUnit()) + && dateInfo1.getDateMode().equals(dateInfo2.getDateMode()) + && dateInfo1.getPeriod().equals(dateInfo2.getPeriod()); return timeFilterExist; } @@ -135,11 +136,11 @@ public class DataUtils { public static Boolean compareDimensionFilter(Set dimensionFilters, QueryFilter dimensionFilter) { Boolean dimensionFilterExist = false; for (QueryFilter filter : dimensionFilters) { - if (filter.getBizName().equals(dimensionFilter.getBizName()) && - filter.getOperator().equals(dimensionFilter.getOperator()) && - filter.getValue().toString().equals(dimensionFilter.getValue().toString()) && - filter.getElementID().equals(dimensionFilter.getElementID()) && - filter.getName().equals(dimensionFilter.getName())) { + if (filter.getBizName().equals(dimensionFilter.getBizName()) + && filter.getOperator().equals(dimensionFilter.getOperator()) + && filter.getValue().toString().equals(dimensionFilter.getValue().toString()) + && filter.getElementID().equals(dimensionFilter.getElementID()) + && filter.getName().equals(dimensionFilter.getName())) { dimensionFilterExist = true; } } @@ -163,6 +164,7 @@ public class DataUtils { private static RuleQueryTool getRuleQueryTool() { RuleQueryTool ruleQueryTool = new RuleQueryTool(); ruleQueryTool.setType(AgentToolType.RULE); + ruleQueryTool.setModelIds(Lists.newArrayList(1L, 2L)); ruleQueryTool.setQueryModes(Lists.newArrayList("METRIC_ENTITY", "METRIC_FILTER", "METRIC_MODEL")); return ruleQueryTool; } diff --git a/launchers/standalone/src/test/resources/application-local.yaml b/launchers/standalone/src/test/resources/application-local.yaml index 4c029c184..ef0671022 100644 --- a/launchers/standalone/src/test/resources/application-local.yaml +++ b/launchers/standalone/src/test/resources/application-local.yaml @@ -24,5 +24,8 @@ semantic: url: prefix: http://127.0.0.1:9081 +time: + threshold: 100 + mybatis: mapper-locations=classpath:mappers/custom/*.xml,classpath*:/mappers/*.xml diff --git a/launchers/standalone/src/test/resources/db/schema-h2.sql b/launchers/standalone/src/test/resources/db/schema-h2.sql index 03f9e50f2..7cba53bc2 100644 --- a/launchers/standalone/src/test/resources/db/schema-h2.sql +++ b/launchers/standalone/src/test/resources/db/schema-h2.sql @@ -1,734 +1,393 @@ -- chat tables CREATE TABLE IF NOT EXISTS `s2_chat_context` ( - `chat_id` - BIGINT - NOT - NULL, -- context chat id - `modified_at` - TIMESTAMP - NOT - NULL - DEFAULT - CURRENT_TIMESTAMP - ON - UPDATE - CURRENT_TIMESTAMP, -- row modify time - `user` - varchar -( - 64 -) DEFAULT NULL , -- row modify user - `query_text` LONGVARCHAR DEFAULT NULL , -- query text + `chat_id` BIGINT NOT NULL , -- context chat id + `modified_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , -- row modify time + `user` varchar(64) DEFAULT NULL , -- row modify user + `query_text` LONGVARCHAR DEFAULT NULL , -- query text `semantic_parse` LONGVARCHAR DEFAULT NULL , -- parse data - `ext_data` LONGVARCHAR DEFAULT NULL , -- extend data - PRIMARY KEY -( - `chat_id` -) + `ext_data` LONGVARCHAR DEFAULT NULL , -- extend data + PRIMARY KEY (`chat_id`) ); CREATE TABLE IF NOT EXISTS `s2_chat` ( - `chat_id` - BIGINT - auto_increment,-- AUTO_INCREMENT, - `chat_name` - varchar -( - 100 -) DEFAULT NULL, - `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , - `last_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP - ON UPDATE CURRENT_TIMESTAMP , - `creator` varchar -( - 30 -) DEFAULT NULL, - `last_question` varchar -( - 200 -) DEFAULT NULL, - `is_delete` INT DEFAULT '0' COMMENT 'is deleted', - `is_top` INT DEFAULT '0' COMMENT 'is top', - PRIMARY KEY -( - `chat_id` -) - ); + `chat_id` BIGINT auto_increment ,-- AUTO_INCREMENT, + `chat_name` varchar(100) DEFAULT NULL, + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `last_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `creator` varchar(30) DEFAULT NULL, + `last_question` varchar(200) DEFAULT NULL, + `is_delete` INT DEFAULT '0' COMMENT 'is deleted', + `is_top` INT DEFAULT '0' COMMENT 'is top', + PRIMARY KEY (`chat_id`) + ) ; CREATE TABLE `s2_chat_query` ( - `question_id` BIGINT NOT NULL AUTO_INCREMENT, - `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `query_text` mediumtext, - `user_name` varchar(150) DEFAULT NULL COMMENT '', - `query_state` int(1) DEFAULT NULL, - `chat_id` BIGINT NOT NULL, -- context chat id - `query_response` mediumtext NOT NULL, - `score` int DEFAULT '0', - `feedback` varchar(1024) DEFAULT '', + `question_id` BIGINT NOT NULL AUTO_INCREMENT, + `agent_id` INT NULL, + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `query_text` mediumtext, + `user_name` varchar(150) DEFAULT NULL COMMENT '', + `query_state` int(1) DEFAULT NULL, + `chat_id` BIGINT NOT NULL , -- context chat id + `query_result` mediumtext NOT NULL , + `score` int DEFAULT '0', + `feedback` varchar(1024) DEFAULT '', PRIMARY KEY (`question_id`) ); +CREATE TABLE `s2_chat_parse` +( + `question_id` BIGINT NOT NULL, + `chat_id` BIGINT NOT NULL , + `parse_id` INT NOT NULL , + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `query_text` varchar(500), + `user_name` varchar(150) DEFAULT NULL COMMENT '', + `parse_info` mediumtext NOT NULL , + `is_candidate` INT DEFAULT 1 COMMENT '1是candidate,0是selected' +); -CREATE TABLE IF NOT EXISTS `s2_chat_config` +CREATE TABLE `s2_chat_statistics` ( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_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 , - `updated_by` varchar -( - 100 -) NOT NULL , - `status` INT NOT NULL DEFAULT '0' , -- domain extension information status : 0 is normal, 1 is off the shelf, 2 is deleted - PRIMARY KEY -( - `id` -) - ); -COMMENT -ON TABLE s2_chat_config IS 'chat config information table '; + `question_id` BIGINT NOT NULL, + `chat_id` BIGINT NOT NULL , + `user_name` varchar(150) DEFAULT NULL COMMENT '', + `query_text` varchar(200), + `interface_name` varchar(100) DEFAULT NULL COMMENT '', + `cost` INT(6) NOT NULL , + `type` INT NOT NULL , + `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); +CREATE TABLE IF NOT EXISTS `s2_chat_config` ( + `id` INT NOT NULL AUTO_INCREMENT, + `model_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 , + `updated_by` varchar(100) NOT NULL , + `status` INT NOT NULL DEFAULT '0' , -- domain extension information status : 0 is normal, 1 is off the shelf, 2 is deleted + PRIMARY KEY (`id`) + ) ; +COMMENT ON TABLE s2_chat_config IS 'chat config information table '; + +CREATE TABLE IF NOT EXISTS s2_agent +( + id int AUTO_INCREMENT, + name varchar(100) null, + description varchar(500) null, + status int null, + examples varchar(500) null, + config varchar(2000) null, + created_by varchar(100) null, + created_at TIMESTAMP null, + updated_by varchar(100) null, + updated_at TIMESTAMP null, + enable_search int null, + PRIMARY KEY (`id`) + ); COMMENT ON TABLE s2_agent IS 'agent information table'; create table s2_user ( - id INT AUTO_INCREMENT, - name varchar(100) not null, + id INT AUTO_INCREMENT, + name varchar(100) not null, display_name varchar(100) null, - password varchar(100) null, - email varchar(100) null, + password varchar(100) null, + email varchar(100) null, PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_user IS 'user information table'; +COMMENT ON TABLE s2_user IS 'user information table'; -- semantic tables -CREATE TABLE IF NOT EXISTS `s2_domain` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `name` - varchar -( - 255 -) DEFAULT NULL , -- domain name - `biz_name` varchar -( - 255 -) DEFAULT NULL , -- internal name - `parent_id` INT DEFAULT '0' , -- parent domain ID - `status` INT NOT NULL , - `created_at` TIMESTAMP DEFAULT NULL , - `created_by` varchar -( - 100 -) DEFAULT NULL , - `updated_at` TIMESTAMP DEFAULT NULL , - `updated_by` varchar -( - 100 -) DEFAULT NULL , - `admin` varchar -( - 3000 -) DEFAULT NULL , -- domain administrator - `admin_org` varchar -( - 3000 -) DEFAULT NULL , -- domain administrators organization - `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 - PRIMARY KEY -( - `id` -) - ); -COMMENT -ON TABLE s2_domain IS 'domain basic information'; - -CREATE TABLE IF NOT EXISTS `s2_model` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `name` - varchar -( - 255 -) DEFAULT NULL , -- domain name - `biz_name` varchar -( - 255 -) DEFAULT NULL , -- internal name - `domain_id` INT DEFAULT '0' , -- parent domain ID - `created_at` TIMESTAMP DEFAULT NULL , - `created_by` varchar -( - 100 -) DEFAULT NULL , - `updated_at` TIMESTAMP DEFAULT NULL , - `updated_by` varchar -( - 100 -) DEFAULT NULL , - `admin` varchar -( - 3000 -) DEFAULT NULL , -- domain administrator - `admin_org` varchar -( - 3000 -) DEFAULT NULL , -- domain administrators organization - `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_model IS 'model information'; - - -CREATE TABLE `s2_database` -( - `id` INT NOT NULL AUTO_INCREMENT, - `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, - `created_by` varchar(100) NOT NULL, - `updated_at` TIMESTAMP NOT NULL, - `updated_by` varchar(100) NOT NULL, +CREATE TABLE IF NOT EXISTS `s2_domain` ( + `id` INT NOT NULL AUTO_INCREMENT , + `name` varchar(255) DEFAULT NULL , -- domain name + `biz_name` varchar(255) DEFAULT NULL , -- internal name + `parent_id` INT DEFAULT '0' , -- parent domain ID + `status` INT NOT NULL , + `created_at` TIMESTAMP DEFAULT NULL , + `created_by` varchar(100) DEFAULT NULL , + `updated_at` TIMESTAMP DEFAULT NULL , + `updated_by` varchar(100) DEFAULT NULL , + `admin` varchar(3000) DEFAULT NULL , -- domain administrator + `admin_org` varchar(3000) DEFAULT NULL , -- domain administrators organization + `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 PRIMARY KEY (`id`) -); -COMMENT -ON TABLE s2_database IS 'database instance table'; - -CREATE TABLE IF NOT EXISTS `s2_datasource` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_id` - INT - NOT - NULL, - `name` - varchar -( - 255 -) NOT NULL , - `biz_name` varchar -( - 255 -) NOT NULL , - `description` varchar -( - 500 -) DEFAULT NULL , - `database_id` INT NOT NULL , - `datasource_detail` LONGVARCHAR NOT NULL , - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , - `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL, - PRIMARY KEY -( - `id` -) ); -COMMENT -ON TABLE s2_datasource IS 'datasource table'; +COMMENT ON TABLE s2_domain IS 'domain basic information'; + +CREATE TABLE IF NOT EXISTS `s2_model` ( + `id` INT NOT NULL AUTO_INCREMENT , + `name` varchar(255) DEFAULT NULL , -- domain name + `biz_name` varchar(255) DEFAULT NULL , -- internal name + `domain_id` INT DEFAULT '0' , -- parent domain ID + `created_at` TIMESTAMP DEFAULT NULL , + `created_by` varchar(100) DEFAULT NULL , + `updated_at` TIMESTAMP DEFAULT NULL , + `updated_by` varchar(100) DEFAULT NULL , + `admin` varchar(3000) DEFAULT NULL , -- domain administrator + `admin_org` varchar(3000) DEFAULT NULL , -- domain administrators organization + `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_model IS 'model information'; + + +CREATE TABLE `s2_database` ( + `id` INT NOT NULL AUTO_INCREMENT, + `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 , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL, + PRIMARY KEY (`id`) +); +COMMENT ON TABLE s2_database IS 'database instance table'; + +CREATE TABLE IF NOT EXISTS `s2_datasource` ( + `id` INT NOT NULL AUTO_INCREMENT, + `model_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `biz_name` varchar(255) NOT NULL , + `description` varchar(500) DEFAULT NULL , + `database_id` INT NOT NULL , + `datasource_detail` LONGVARCHAR NOT NULL , + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL, + PRIMARY KEY (`id`) + ); +COMMENT ON TABLE s2_datasource IS 'datasource table'; create table s2_auth_groups ( group_id INT, - config varchar(2048), + config varchar(2048), PRIMARY KEY (`group_id`) ); -CREATE TABLE IF NOT EXISTS `s2_metric` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_id` - INT - NOT - NULL, - `name` - varchar -( - 255 -) NOT NULL , - `biz_name` varchar -( - 255 -) NOT NULL , - `description` varchar -( - 500 -) DEFAULT NULL , - `status` INT NOT NULL , -- status, 0 is normal, 1 is off the shelf, 2 is deleted +CREATE TABLE IF NOT EXISTS `s2_metric` ( + `id` INT NOT NULL AUTO_INCREMENT, + `model_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `biz_name` varchar(255) NOT NULL , + `description` varchar(500) DEFAULT NULL , + `status` INT NOT NULL , -- status, 0 is normal, 1 is off the shelf, 2 is deleted `sensitive_level` INT NOT NULL , - `type` varchar -( - 50 -) NOT NULL , -- type proxy,expr - `type_params` LONGVARCHAR DEFAULT NULL , + `type` varchar(50) NOT NULL , -- type proxy,expr + `type_params` LONGVARCHAR DEFAULT NULL , `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , + `created_by` varchar(100) NOT NULL , `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL , - `data_format_type` varchar -( - 50 -) DEFAULT NULL , - `data_format` varchar -( - 500 -) DEFAULT NULL, - `alias` varchar -( - 500 -) DEFAULT NULL, - PRIMARY KEY -( - `id` -) + `updated_by` varchar(100) NOT NULL , + `data_format_type` varchar(50) DEFAULT NULL , + `data_format` varchar(500) DEFAULT NULL, + `alias` varchar(500) DEFAULT NULL, + PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_metric IS 'metric information table'; +COMMENT ON TABLE s2_metric IS 'metric information table'; -CREATE TABLE IF NOT EXISTS `s2_dimension` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `model_id` - INT - NOT - NULL, - `datasource_id` - INT - NOT - NULL, - `name` - varchar -( - 255 -) NOT NULL , - `biz_name` varchar -( - 255 -) NOT NULL , - `description` varchar -( - 500 -) NOT NULL , +CREATE TABLE IF NOT EXISTS `s2_dimension` ( + `id` INT NOT NULL AUTO_INCREMENT , + `model_id` INT NOT NULL , + `datasource_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `biz_name` varchar(255) NOT NULL , + `description` varchar(500) NOT NULL , `status` INT NOT NULL , -- status, 0 is normal, 1 is off the shelf, 2 is deleted `sensitive_level` INT DEFAULT NULL , - `type` varchar -( - 50 -) NOT NULL , -- type categorical,time - `type_params` LONGVARCHAR DEFAULT NULL , + `type` varchar(50) NOT NULL , -- type categorical,time + `type_params` LONGVARCHAR DEFAULT NULL , `expr` LONGVARCHAR NOT NULL , -- expression - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , - `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL , - `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` -) + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL , + `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'; +COMMENT ON TABLE s2_dimension IS 'dimension information table'; create table s2_datasource_rela ( id INT AUTO_INCREMENT, - model_id INT null, - datasource_from INT null, - datasource_to INT null, + model_id INT null, + datasource_from INT null, + datasource_to INT null, join_key varchar(100) null, - created_at TIMESTAMP null, + created_at TIMESTAMP null, created_by varchar(100) null, - updated_at TIMESTAMP null, + updated_at TIMESTAMP null, updated_by varchar(100) null, PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_datasource_rela IS 'data source association table'; +COMMENT ON TABLE s2_datasource_rela IS 'data source association table'; create table s2_view_info ( id INT auto_increment, - model_id INT null, - type varchar(20) null comment 'datasource、dimension、metric', - config LONGVARCHAR null comment 'config detail', - created_at TIMESTAMP null, + model_id INT null, + type varchar(20) null comment 'datasource、dimension、metric', + config LONGVARCHAR null comment 'config detail', + created_at TIMESTAMP null, created_by varchar(100) null, - updated_at TIMESTAMP null, + updated_at TIMESTAMP null, updated_by varchar(100) not null ); -COMMENT -ON TABLE s2_view_info IS 'view information table'; +COMMENT ON TABLE s2_view_info IS 'view information table'; -CREATE TABLE `s2_query_stat_info` -( - `id` INT NOT NULL AUTO_INCREMENT, - `trace_id` varchar(200) DEFAULT NULL, -- query unique identifier - `model_id` INT DEFAULT NULL, - `user` varchar(200) DEFAULT NULL, - `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - `query_type` varchar(200) DEFAULT NULL, -- the corresponding scene - `query_type_back` INT DEFAULT '0', -- query type, 0-normal query, 1-pre-refresh type - `query_sql_cmd` LONGVARCHAR, -- sql type request parameter - `sql_cmd_md5` varchar(200) DEFAULT NULL, -- sql type request parameter md5 - `query_struct_cmd` LONGVARCHAR, -- struct type request parameter - `struct_cmd_md5` varchar(200) DEFAULT NULL, -- struct type request parameter md5值 - `sql` LONGVARCHAR, - `sql_md5` varchar(200) DEFAULT NULL, -- sql md5 - `query_engine` varchar(20) DEFAULT NULL, - `elapsed_ms` bigINT DEFAULT NULL, - `query_state` varchar(20) DEFAULT NULL, - `native_query` INT DEFAULT NULL, -- 1-detail query, 0-aggregation query - `start_date` varchar(50) DEFAULT NULL, - `end_date` varchar(50) DEFAULT NULL, - `dimensions` LONGVARCHAR, -- dimensions involved in sql - `metrics` LONGVARCHAR, -- metric involved in sql - `select_cols` LONGVARCHAR, - `agg_cols` LONGVARCHAR, - `filter_cols` LONGVARCHAR, - `group_by_cols` LONGVARCHAR, - `order_by_cols` LONGVARCHAR, - `use_result_cache` TINYINT DEFAULT '-1', -- whether to hit the result cache - `use_sql_cache` TINYINT DEFAULT '-1', -- whether to hit the sql cache - `sql_cache_key` LONGVARCHAR, -- sql cache key - `result_cache_key` LONGVARCHAR, -- result cache key - PRIMARY KEY (`id`) -); -COMMENT -ON TABLE s2_query_stat_info IS 'query statistics table'; +CREATE TABLE `s2_query_stat_info` ( + `id` INT NOT NULL AUTO_INCREMENT, + `trace_id` varchar(200) DEFAULT NULL, -- query unique identifier + `model_id` INT DEFAULT NULL, + `user` varchar(200) DEFAULT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP , + `query_type` varchar(200) DEFAULT NULL, -- the corresponding scene + `query_type_back` INT DEFAULT '0' , -- query type, 0-normal query, 1-pre-refresh type + `query_sql_cmd`LONGVARCHAR , -- sql type request parameter + `sql_cmd_md5` varchar(200) DEFAULT NULL, -- sql type request parameter md5 + `query_struct_cmd`LONGVARCHAR , -- struct type request parameter + `struct_cmd_md5` varchar(200) DEFAULT NULL, -- struct type request parameter md5值 + `sql`LONGVARCHAR , + `sql_md5` varchar(200) DEFAULT NULL, -- sql md5 + `query_engine` varchar(20) DEFAULT NULL, + `elapsed_ms` bigINT DEFAULT NULL, + `query_state` varchar(20) DEFAULT NULL, + `native_query` INT DEFAULT NULL, -- 1-detail query, 0-aggregation query + `start_date` varchar(50) DEFAULT NULL, + `end_date` varchar(50) DEFAULT NULL, + `dimensions`LONGVARCHAR , -- dimensions involved in sql + `metrics`LONGVARCHAR , -- metric involved in sql + `select_cols`LONGVARCHAR , + `agg_cols`LONGVARCHAR , + `filter_cols`LONGVARCHAR , + `group_by_cols`LONGVARCHAR , + `order_by_cols`LONGVARCHAR , + `use_result_cache` TINYINT DEFAULT '-1' , -- whether to hit the result cache + `use_sql_cache` TINYINT DEFAULT '-1' , -- whether to hit the sql cache + `sql_cache_key`LONGVARCHAR , -- sql cache key + `result_cache_key`LONGVARCHAR , -- result cache key + PRIMARY KEY (`id`) +) ; +COMMENT ON TABLE s2_query_stat_info IS 'query statistics table'; -CREATE TABLE IF NOT EXISTS `s2_semantic_pasre_info` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `trace_id` - varchar -( - 200 -) NOT NULL , - `model_id` INT NOT NULL , - `dimensions` LONGVARCHAR , - `metrics` LONGVARCHAR , - `orders` LONGVARCHAR , - `filters` LONGVARCHAR , - `date_info` LONGVARCHAR , +CREATE TABLE IF NOT EXISTS `s2_semantic_pasre_info` ( + `id` INT NOT NULL AUTO_INCREMENT, + `trace_id` varchar(200) NOT NULL , + `model_id` INT NOT NULL , + `dimensions`LONGVARCHAR , + `metrics`LONGVARCHAR , + `orders`LONGVARCHAR , + `filters`LONGVARCHAR , + `date_info`LONGVARCHAR , `limit` INT NOT NULL , `native_query` TINYINT NOT NULL DEFAULT '0' , - `sql` LONGVARCHAR , - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , + `sql`LONGVARCHAR , + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , `status` INT NOT NULL , `elapsed_ms` bigINT DEFAULT NULL , - PRIMARY KEY -( - `id` -) + PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_semantic_pasre_info IS 'semantic layer sql parsing information table'; +COMMENT ON TABLE s2_semantic_pasre_info IS 'semantic layer sql parsing information table'; -CREATE TABLE IF NOT EXISTS `s2_available_date_info` -( - `id` - INT - NOT - NULL - AUTO_INCREMENT, - `item_id` - INT - NOT - NULL, - `type` - varchar -( - 255 -) NOT NULL , - `date_format` varchar -( - 64 -) NOT NULL , - `start_date` varchar -( - 64 -) , - `end_date` varchar -( - 64 -) , - `unavailable_date` LONGVARCHAR DEFAULT NULL , - `created_at` TIMESTAMP NOT NULL , - `created_by` varchar -( - 100 -) NOT NULL , - `updated_at` TIMESTAMP NOT NULL , - `updated_by` varchar -( - 100 -) NOT NULL , - `date_period` varchar -( - 100 -) DEFAULT NULL , - `status` INT DEFAULT '0', -- 1-in use 0 is normal, 1 is off the shelf, 2 is deleted - PRIMARY KEY -( - `id` -) +CREATE TABLE IF NOT EXISTS `s2_available_date_info` ( + `id` INT NOT NULL AUTO_INCREMENT , + `item_id` INT NOT NULL , + `type` varchar(255) NOT NULL , + `date_format` varchar(64) NOT NULL , + `start_date` varchar(64) , + `end_date` varchar(64) , + `unavailable_date` LONGVARCHAR DEFAULT NULL , + `created_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `updated_by` varchar(100) NOT NULL , + `date_period` varchar(100) DEFAULT NULL , + `status` INT DEFAULT '0', -- 1-in use 0 is normal, 1 is off the shelf, 2 is deleted + PRIMARY KEY (`id`) ); -COMMENT -ON TABLE s2_dimension IS 'dimension information table'; +COMMENT ON TABLE s2_dimension IS 'dimension information table'; CREATE TABLE IF NOT EXISTS `s2_plugin` ( - `id` - INT - AUTO_INCREMENT, - `type` - varchar -( - 50 -) NULL, - `model` varchar -( - 100 -) NULL, - `pattern` varchar -( - 500 -) NULL, - `parse_mode` varchar -( - 100 -) NULL, - `parse_mode_config` LONGVARCHAR 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, - `comment` LONGVARCHAR NULL, - PRIMARY KEY -( - `id` -) - ); -COMMENT -ON TABLE s2_plugin IS 'plugin information table'; + `id` INT AUTO_INCREMENT, + `type` varchar(50) NULL, + `model` varchar(100) NULL, + `pattern` varchar(500) NULL, + `parse_mode` varchar(100) NULL, + `parse_mode_config` LONGVARCHAR 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, + `comment` 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, - `department` varchar -( - 200 -) NOT NULL -- department of user +CREATE TABLE IF NOT EXISTS `s2_user_department` ( + `user_name` varchar(200) NOT NULL, + `department` varchar(200) NOT NULL -- department of user ); -COMMENT -ON TABLE s2_user_department IS 'user_department_info'; +COMMENT ON TABLE s2_user_department IS 'user_department_info'; -CREATE TABLE IF NOT EXISTS `s2_pv_uv_statis` -( - `imp_date` varchar -( - 200 -) NOT NULL, - `user_name` varchar -( - 200 -) NOT NULL, - `page` varchar -( - 200 -) NOT NULL +CREATE TABLE IF NOT EXISTS `s2_pv_uv_statis` ( + `imp_date` varchar(200) NOT NULL, + `user_name` varchar(200) NOT NULL, + `page` varchar(200) NOT NULL ); -COMMENT -ON TABLE s2_pv_uv_statis IS 's2_pv_uv_statis'; +COMMENT ON TABLE s2_pv_uv_statis IS 's2_pv_uv_statis'; -CREATE TABLE IF NOT EXISTS `s2_stay_time_statis` -( - `imp_date` varchar -( - 200 -) NOT NULL, - `user_name` varchar -( - 200 -) NOT NULL, +CREATE TABLE IF NOT EXISTS `s2_stay_time_statis` ( + `imp_date` varchar(200) NOT NULL, + `user_name` varchar(200) NOT NULL, `stay_hours` DOUBLE NOT NULL, - `page` varchar -( - 200 -) NOT NULL + `page` varchar(200) NOT NULL ); -COMMENT -ON TABLE s2_stay_time_statis IS 's2_stay_time_statis_info'; +COMMENT ON TABLE s2_stay_time_statis IS 's2_stay_time_statis_info'; -CREATE TABLE IF NOT EXISTS `singer` -( - `imp_date` varchar -( - 200 -) NOT NULL, - `singer_name` varchar -( - 200 -) NOT NULL, - `act_area` varchar -( - 200 -) NOT NULL, - `song_name` varchar -( - 200 -) NOT NULL, - `genre` varchar -( - 200 -) NOT NULL, +CREATE TABLE IF NOT EXISTS `singer` ( + `imp_date` varchar(200) NOT NULL, + `singer_name` varchar(200) NOT NULL, + `act_area` varchar(200) NOT NULL, + `song_name` varchar(200) NOT NULL, + `genre` varchar(200) NOT NULL, `js_play_cnt` bigINT DEFAULT NULL, `down_cnt` bigINT DEFAULT NULL, `favor_cnt` bigINT DEFAULT NULL ); -COMMENT -ON TABLE singer IS 'singer_info'; +COMMENT ON TABLE singer IS 'singer_info'; 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 index 3a4d262a4..c02409cd2 100644 --- 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 @@ -4,11 +4,6 @@ import java.util.ArrayList; import java.util.List; import lombok.Data; -/** - * @author: kanedai - * @date: 2023/7/24 - */ - @Data public class DimValueMap { diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/request/DomainReq.java index b57f342a6..f4aed6263 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/model/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.model.request; + import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; + import java.util.ArrayList; import java.util.List; + import lombok.Data; diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/CatalogImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/CatalogImpl.java index 1971a2c7d..52ac857fe 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/CatalogImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/CatalogImpl.java @@ -1,11 +1,21 @@ package com.tencent.supersonic.semantic.model.application; import com.tencent.supersonic.semantic.api.model.pojo.ItemDateFilter; -import com.tencent.supersonic.semantic.api.model.response.*; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.DatabaseResp; +import com.tencent.supersonic.semantic.api.model.response.ModelResp; +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.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.model.domain.*; +import com.tencent.supersonic.semantic.model.domain.DatabaseService; +import com.tencent.supersonic.semantic.model.domain.ModelService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.model.domain.Catalog; import java.util.List; import java.util.Map; import java.util.Set; diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatabaseServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatabaseServiceImpl.java index fd943ab4c..136fad907 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatabaseServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DatabaseServiceImpl.java @@ -2,22 +2,22 @@ package com.tencent.supersonic.semantic.model.application; import com.tencent.supersonic.auth.api.authentication.pojo.User; 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.DomainResp; import com.tencent.supersonic.semantic.api.model.response.ModelResp; -import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; import com.tencent.supersonic.semantic.api.model.response.SqlParserResp; -import com.tencent.supersonic.semantic.model.domain.DatabaseService; +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.DomainService; import com.tencent.supersonic.semantic.model.domain.ModelService; 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.pojo.Database; 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.Map; import java.util.Optional; @@ -38,9 +38,9 @@ public class DatabaseServiceImpl implements DatabaseService { private ModelService modelService; public DatabaseServiceImpl(DatabaseRepository databaseRepository, - SqlUtils sqlUtils, - DomainService domainService, - ModelService modelService) { + SqlUtils sqlUtils, + DomainService domainService, + ModelService modelService) { this.databaseRepository = databaseRepository; this.sqlUtils = sqlUtils; this.modelService = modelService; diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DimensionServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DimensionServiceImpl.java index 0e8046f23..9bc49594f 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DimensionServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DimensionServiceImpl.java @@ -7,7 +7,6 @@ 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.common.pojo.QueryColumn; import com.tencent.supersonic.common.util.ChatGptHelper; import com.tencent.supersonic.semantic.api.model.pojo.DatasourceDetail; import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; @@ -28,9 +27,11 @@ 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.*; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.HashMap; import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; @@ -55,14 +56,14 @@ public class DimensionServiceImpl implements DimensionService { public DimensionServiceImpl(DimensionRepository dimensionRepository, - DomainService domainService, - DatasourceService datasourceService, + DomainService domainService, + DatasourceService datasourceService, ChatGptHelper chatGptHelper, DatabaseService databaseService) { this.domainService = domainService; this.dimensionRepository = dimensionRepository; this.datasourceService = datasourceService; - this.chatGptHelper = chatGptHelper; + this.chatGptHelper = chatGptHelper; this.databaseService = databaseService; } @@ -181,7 +182,7 @@ public class DimensionServiceImpl implements DimensionService { } private List convertList(List dimensionDOS, - Map datasourceRespMap) { + Map datasourceRespMap) { List dimensionResps = Lists.newArrayList(); Map fullDomainPathMap = domainService.getDomainFullPath(); if (!CollectionUtils.isEmpty(dimensionDOS)) { @@ -259,17 +260,20 @@ public class DimensionServiceImpl implements DimensionService { @Override public List mockAlias(DimensionReq dimensionReq, String mockType, User user) { - String mockAlias = chatGptHelper.mockAlias(mockType,dimensionReq.getName(), dimensionReq.getBizName(), "", dimensionReq.getDescription() ,false); - return JSONObject.parseObject(mockAlias, new TypeReference>() {}); + String mockAlias = chatGptHelper.mockAlias(mockType, dimensionReq.getName(), dimensionReq.getBizName(), + "", dimensionReq.getDescription(), false); + return JSONObject.parseObject(mockAlias, new TypeReference>() { + }); } @Override public List mockDimensionValueAlias(DimensionReq dimensionReq, User user) { List datasourceList = datasourceService.getDatasourceList(); - List collect = datasourceList.stream().filter(datasourceResp -> datasourceResp.getId().equals(dimensionReq.getDatasourceId())).collect(Collectors.toList()); + List collect = datasourceList.stream().filter(datasourceResp -> + datasourceResp.getId().equals(dimensionReq.getDatasourceId())).collect(Collectors.toList()); - if (collect.isEmpty()){ + if (collect.isEmpty()) { return null; } DatasourceResp datasourceResp = collect.get(0); @@ -278,7 +282,8 @@ public class DimensionServiceImpl implements DimensionService { DatabaseResp database = databaseService.getDatabase(datasourceResp.getDatabaseId()); - String sql = "select ai_talk."+dimensionReq.getBizName()+" from ("+sqlQuery +") as ai_talk group by ai_talk."+dimensionReq.getBizName(); + String sql = "select ai_talk." + dimensionReq.getBizName() + " from (" + sqlQuery + + ") as ai_talk group by ai_talk." + dimensionReq.getBizName(); QueryResultWithSchemaResp queryResultWithSchemaResp = databaseService.executeSql(sql, database); List> resultList = queryResultWithSchemaResp.getResultList(); List valueList = new ArrayList<>(); @@ -287,7 +292,7 @@ public class DimensionServiceImpl implements DimensionService { valueList.add(value); } String json = chatGptHelper.mockDimensionValueAlias(JSON.toJSONString(valueList)); - log.info("return llm res is :{}",json); + log.info("return llm res is :{}", json); JSONObject jsonObject = JSON.parseObject(json); @@ -297,9 +302,10 @@ public class DimensionServiceImpl implements DimensionService { DimValueMap dimValueMap = new DimValueMap(); dimValueMap.setTechName((String) stringObjectMap.get(dimensionReq.getBizName())); dimValueMap.setBizName(jsonObject.getJSONArray("tran").getString(i)); - dimValueMap. setAlias(jsonObject.getJSONObject("alias").getJSONArray((String) stringObjectMap.get(dimensionReq.getBizName())).toJavaList(String.class)); + dimValueMap.setAlias(jsonObject.getJSONObject("alias").getJSONArray( + (String) stringObjectMap.get(dimensionReq.getBizName())).toJavaList(String.class)); dimValueMapsResp.add(dimValueMap); - i ++ ; + i++; } return dimValueMapsResp; } diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DomainServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DomainServiceImpl.java index af7ed3d6d..d874cf492 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DomainServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/DomainServiceImpl.java @@ -4,20 +4,29 @@ import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.service.UserService; -import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.common.util.BeanMapper; +import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.DomainReq; 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.ModelResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; import com.tencent.supersonic.semantic.model.domain.DomainService; import com.tencent.supersonic.semantic.model.domain.ModelService; 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.*; +import java.util.List; +import java.util.Date; +import java.util.Set; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; +import java.util.Queue; +import java.util.LinkedList; +import java.util.Objects; +import java.util.Comparator; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.assertj.core.util.Sets; @@ -36,8 +45,8 @@ public class DomainServiceImpl implements DomainService { public DomainServiceImpl(DomainRepository domainRepository, - @Lazy ModelService modelService, - UserService userService) { + @Lazy ModelService modelService, + UserService userService) { this.domainRepository = domainRepository; this.modelService = modelService; this.userService = userService; diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/MetricServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/MetricServiceImpl.java index 50de1b114..3cb2e9982 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/MetricServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/MetricServiceImpl.java @@ -5,7 +5,6 @@ import com.alibaba.fastjson.TypeReference; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.google.common.collect.Lists; -import com.plexpt.chatgpt.ChatGPT; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.common.util.ChatGptHelper; import com.tencent.supersonic.semantic.api.model.pojo.Measure; @@ -81,7 +80,7 @@ public class MetricServiceImpl implements MetricService { log.info("[insert metric] object:{}", JSONObject.toJSONString(metricToInsert)); saveMetricBatch(metricToInsert, user); } - + @Override public List getMetrics(Long modelId) { return convertList(metricRepository.getMetricList(modelId)); @@ -209,10 +208,12 @@ public class MetricServiceImpl implements MetricService { } @Override - public List mockAlias(MetricReq metricReq,String mockType,User user) { + public List mockAlias(MetricReq metricReq, String mockType, User user) { - String mockAlias = chatGptHelper.mockAlias(mockType,metricReq.getName(), metricReq.getBizName(), "", metricReq.getDescription() ,!"".equals(metricReq.getDataFormatType())); - return JSONObject.parseObject(mockAlias, new TypeReference>() {}); + String mockAlias = chatGptHelper.mockAlias(mockType, metricReq.getName(), metricReq.getBizName(), "", + metricReq.getDescription(), !"".equals(metricReq.getDataFormatType())); + return JSONObject.parseObject(mockAlias, new TypeReference>() { + }); } diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/ModelServiceImpl.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/ModelServiceImpl.java index b62dedcf2..54b3c2b97 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/ModelServiceImpl.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/application/ModelServiceImpl.java @@ -4,41 +4,42 @@ import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.service.UserService; -import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.common.util.BeanMapper; import com.tencent.supersonic.common.util.JsonUtil; +import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.ModelReq; import com.tencent.supersonic.semantic.api.model.request.ModelSchemaFilterReq; -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.MetricResp; -import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; import com.tencent.supersonic.semantic.api.model.response.ModelResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +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.DimSchemaResp; import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; -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.api.model.response.MetricSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DatasourceResp; import com.tencent.supersonic.semantic.model.domain.ModelService; +import com.tencent.supersonic.semantic.model.domain.DomainService; +import com.tencent.supersonic.semantic.model.domain.DimensionService; +import com.tencent.supersonic.semantic.model.domain.MetricService; +import com.tencent.supersonic.semantic.model.domain.DatasourceService; + import com.tencent.supersonic.semantic.model.domain.dataobject.ModelDO; import com.tencent.supersonic.semantic.model.domain.pojo.Model; import com.tencent.supersonic.semantic.model.domain.repository.ModelRepository; import com.tencent.supersonic.semantic.model.domain.utils.ModelConvert; -import java.util.ArrayList; -import java.util.Date; -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.beans.BeanUtils; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import java.util.List; +import java.util.Objects; +import java.util.Date; +import java.util.Set; +import java.util.Map; +import java.util.HashSet; +import java.util.ArrayList; +import java.util.stream.Collectors; @Slf4j @Service @@ -52,8 +53,8 @@ public class ModelServiceImpl implements ModelService { private final UserService userService; public ModelServiceImpl(ModelRepository modelRepository, @Lazy MetricService metricService, - @Lazy DimensionService dimensionService, @Lazy DatasourceService datasourceService, - @Lazy DomainService domainService, UserService userService) { + @Lazy DimensionService dimensionService, @Lazy DatasourceService datasourceService, + @Lazy DomainService domainService, UserService userService) { this.modelRepository = modelRepository; this.metricService = metricService; this.dimensionService = dimensionService; @@ -161,7 +162,7 @@ public class ModelServiceImpl implements ModelService { @Override public ModelResp getModel(Long id) { Map domainRespMap = domainService.getDomainList().stream() - .collect(Collectors.toMap(DomainResp::getId, d -> d)); + .collect(Collectors.toMap(DomainResp::getId, d -> d)); return ModelConvert.convert(getModelDO(id), domainRespMap); } @@ -186,8 +187,8 @@ public class ModelServiceImpl implements ModelService { if (CollectionUtils.isEmpty(modelDOS)) { return modelResps; } - Map domainRespMap = domainService.getDomainList().stream() - .collect(Collectors.toMap(DomainResp::getId, d -> d)); + Map domainRespMap = domainService.getDomainList() + .stream().collect(Collectors.toMap(DomainResp::getId, d -> d)); return modelDOS.stream() .map(modelDO -> ModelConvert.convert(modelDO, domainRespMap)) .collect(Collectors.toList()); @@ -216,8 +217,29 @@ public class ModelServiceImpl implements ModelService { @Override public Map getModelFullPathMap() { - return getModelList().stream() - .collect(Collectors.toMap(ModelResp::getId, ModelResp::getFullPath, (k1, k2) -> k1)); + return getModelList().stream().collect(Collectors.toMap(ModelResp::getId, + ModelResp::getFullPath, (k1, k2) -> k1)); + } + + @Override + public List getModelAdmin(Long id) { + ModelResp modelResp = getModel(id); + if (modelResp == null) { + return Lists.newArrayList(); + } + if (!CollectionUtils.isEmpty(modelResp.getAdmins())) { + return modelResp.getAdmins(); + } + Long domainId = modelResp.getDomainId(); + DomainResp domainResp = domainService.getDomain(domainId); + while (domainResp != null) { + if (!CollectionUtils.isEmpty(domainResp.getAdmins())) { + return domainResp.getAdmins(); + } + domainId = domainResp.getParentId(); + domainResp = domainService.getDomain(domainId); + } + return Lists.newArrayList(); } protected ModelDO getModelDO(Long id) { diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatabaseService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatabaseService.java index 5dbd2903e..020d6e2a6 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatabaseService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DatabaseService.java @@ -11,10 +11,10 @@ public interface DatabaseService { QueryResultWithSchemaResp executeSql(String sql, DatabaseResp databaseResp); - DatabaseResp getDatabaseByModelId(Long modelId); - QueryResultWithSchemaResp executeSql(String sql, Long domainId); + DatabaseResp getDatabaseByModelId(Long modelId); + boolean testConnect(DatabaseReq databaseReq, User user); DatabaseResp createOrUpdateDatabase(DatabaseReq databaseReq, User user); diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DimensionService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DimensionService.java index 10e6a46ea..3e80331c0 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DimensionService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/DimensionService.java @@ -4,7 +4,6 @@ import com.github.pagehelper.PageInfo; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; 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.request.PageDimensionReq; import com.tencent.supersonic.semantic.api.model.response.DimensionResp; import java.util.List; diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/MetricService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/MetricService.java index 8f674fa19..1b28e8e64 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/MetricService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/MetricService.java @@ -5,6 +5,7 @@ import com.tencent.supersonic.auth.api.authentication.pojo.User; 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 { @@ -33,5 +34,5 @@ public interface MetricService { void deleteMetric(Long id) throws Exception; - List mockAlias(MetricReq metricReq,String mockType,User user); + List mockAlias(MetricReq metricReq, String mockType, User user); } diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/ModelService.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/ModelService.java index ffea84c25..9bfad94f8 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/ModelService.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/ModelService.java @@ -33,6 +33,8 @@ public interface ModelService { Map getModelFullPathMap(); + List getModelAdmin(Long id); + ModelSchemaResp fetchSingleModelSchema(Long modelId); List fetchModelSchema(ModelSchemaFilterReq modelSchemaFilterReq); 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 index 52a29b7c7..20dce0613 100644 --- 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 @@ -29,8 +29,8 @@ public class H2Adaptor extends EngineAdaptor { @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'"; + return "SELECT COLUMN_NAME AS name, DATA_TYPE AS dataType\n" + + "FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ='%s' AND TABLE_NAME = '%s'"; } @Override @@ -40,6 +40,7 @@ public class H2Adaptor extends EngineAdaptor { @Override public String getTableMetaQueryTpl() { - return "SELECT TABLE_NAME as name FROM INFORMATION_SCHEMA.TABLES WHERE STORAGE_TYPE = 'MEMORY' AND TABLE_SCHEMA = '%s'"; + return "SELECT TABLE_NAME as name FROM INFORMATION_SCHEMA.TABLES " + + "WHERE STORAGE_TYPE = 'MEMORY' AND TABLE_SCHEMA = '%s'"; } } diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/MysqlAdaptor.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/MysqlAdaptor.java index dfbbde0d6..3759ecf2c 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/MysqlAdaptor.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/adaptor/engineadapter/MysqlAdaptor.java @@ -35,7 +35,8 @@ public class MysqlAdaptor extends EngineAdaptor { @Override public String getDbMetaQueryTpl() { - return "select distinct TABLE_SCHEMA as name 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 @@ -45,8 +46,8 @@ public class MysqlAdaptor extends EngineAdaptor { @Override public String getColumnMetaQueryTpl() { - return "SELECT COLUMN_NAME as name, DATA_TYPE as dataType, COLUMN_COMMENT as comment " + - "FROM information_schema.columns WHERE table_schema ='%s' AND table_name = '%s'"; + return "SELECT COLUMN_NAME as name, DATA_TYPE as dataType, COLUMN_COMMENT as comment " + + "FROM information_schema.columns WHERE table_schema ='%s' AND table_name = '%s'"; } diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDO.java index 925e20281..58074d9ec 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDO.java @@ -248,4 +248,4 @@ public class DatabaseDO { public void setConfig(String config) { this.config = config == null ? null : config.trim(); } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDOExample.java index b75151d07..70e40e882 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatabaseDOExample.java @@ -882,38 +882,6 @@ public class DatabaseDOExample { 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; @@ -949,5 +917,37 @@ public class DatabaseDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDO.java index 96f0a940a..9c6db09cb 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDO.java @@ -252,4 +252,4 @@ public class DatasourceDO { public void setDatasourceDetail(String datasourceDetail) { this.datasourceDetail = datasourceDetail == null ? null : datasourceDetail.trim(); } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDOExample.java index ce8fdf4f6..961e622af 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceDOExample.java @@ -872,38 +872,6 @@ public class DatasourceDOExample { 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; @@ -939,5 +907,37 @@ public class DatasourceDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDO.java index 4beb5e7a6..45d25af7f 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDO.java @@ -174,4 +174,4 @@ public class DatasourceRelaDO { public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy == null ? null : updatedBy.trim(); } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDOExample.java index e63d0fae7..aceb27da4 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DatasourceRelaDOExample.java @@ -792,38 +792,6 @@ public class DatasourceRelaDOExample { 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; @@ -859,5 +827,37 @@ public class DatasourceRelaDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDO.java index c080f0e59..403f5ef86 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDO.java @@ -432,4 +432,4 @@ public class DimensionDO { public void setExpr(String expr) { this.expr = expr == null ? null : expr.trim(); } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOExample.java index ac78e595c..67a7bb84c 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DimensionDOExample.java @@ -1342,38 +1342,6 @@ public class DimensionDOExample { 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; @@ -1409,5 +1377,37 @@ public class DimensionDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDOExample.java index b72c33737..397f44785 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/DomainDOExample.java @@ -1142,38 +1142,6 @@ public class DomainDOExample { 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; @@ -1209,5 +1177,37 @@ public class DomainDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDO.java index 040bb2e55..ceb2fad56 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDO.java @@ -4,265 +4,121 @@ import java.util.Date; public class MetricDO { - /** - * - */ private Long id; - /** - * 主体域ID - */ private Long modelId; - /** - * 指标名称 - */ private String name; - /** - * 字段名称 - */ private String bizName; - /** - * 描述 - */ private String description; - /** - * 指标状态,0正常,1下架,2删除 - */ private Integer status; - /** - * 敏感级别 - */ private Integer sensitiveLevel; - /** - * 指标类型 proxy,expr - */ private String type; - /** - * 创建时间 - */ private Date createdAt; - /** - * 创建人 - */ private String createdBy; - /** - * 更新时间 - */ private Date updatedAt; - /** - * 更新人 - */ private String updatedBy; - /** - * 数值类型 - */ private String dataFormatType; - /** - * 数值类型参数 - */ private String dataFormat; - /** - * - */ private String alias; - /** - * 类型参数 - */ private String typeParams; - /** - * @return id - */ + public Long getId() { return id; } - /** - * @param id - */ public void setId(Long id) { this.id = id; } - /** - * 主体域ID - * - * @return model_id 主体域ID - */ public Long getModelId() { return modelId; } - /** - * 主体域ID - * - * @param modelId 主体域ID - */ public void setModelId(Long modelId) { this.modelId = modelId; } - /** - * 指标名称 - * - * @return name 指标名称 - */ public String getName() { return name; } - /** - * 指标名称 - * - * @param name 指标名称 - */ public void setName(String name) { this.name = name == null ? null : name.trim(); } - /** - * 字段名称 - * - * @return biz_name 字段名称 - */ public String getBizName() { return bizName; } - /** - * 字段名称 - * - * @param bizName 字段名称 - */ public void setBizName(String bizName) { this.bizName = bizName == null ? null : bizName.trim(); } - /** - * 描述 - * - * @return description 描述 - */ public String getDescription() { return description; } - /** - * 描述 - * - * @param description 描述 - */ public void setDescription(String description) { this.description = description == null ? null : description.trim(); } - /** - * 指标状态,0正常,1下架,2删除 - * - * @return status 指标状态,0正常,1下架,2删除 - */ public Integer getStatus() { return status; } - /** - * 指标状态,0正常,1下架,2删除 - * - * @param status 指标状态,0正常,1下架,2删除 - */ public void setStatus(Integer status) { this.status = status; } - /** - * 敏感级别 - * - * @return sensitive_level 敏感级别 - */ public Integer getSensitiveLevel() { return sensitiveLevel; } - /** - * 敏感级别 - * - * @param sensitiveLevel 敏感级别 - */ public void setSensitiveLevel(Integer sensitiveLevel) { this.sensitiveLevel = sensitiveLevel; } - /** - * 指标类型 proxy,expr - * - * @return type 指标类型 proxy,expr - */ public String getType() { return type; } - /** - * 指标类型 proxy,expr - * - * @param type 指标类型 proxy,expr - */ public void setType(String type) { this.type = type == null ? null : type.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() { @@ -271,7 +127,6 @@ public class MetricDO { /** * 更新时间 - * * @param updatedAt 更新时间 */ public void setUpdatedAt(Date updatedAt) { @@ -280,7 +135,6 @@ public class MetricDO { /** * 更新人 - * * @return updated_by 更新人 */ public String getUpdatedBy() { @@ -289,7 +143,6 @@ public class MetricDO { /** * 更新人 - * * @param updatedBy 更新人 */ public void setUpdatedBy(String updatedBy) { @@ -298,7 +151,6 @@ public class MetricDO { /** * 数值类型 - * * @return data_format_type 数值类型 */ public String getDataFormatType() { @@ -307,7 +159,6 @@ public class MetricDO { /** * 数值类型 - * * @param dataFormatType 数值类型 */ public void setDataFormatType(String dataFormatType) { @@ -316,7 +167,6 @@ public class MetricDO { /** * 数值类型参数 - * * @return data_format 数值类型参数 */ public String getDataFormat() { @@ -325,7 +175,6 @@ public class MetricDO { /** * 数值类型参数 - * * @param dataFormat 数值类型参数 */ public void setDataFormat(String dataFormat) { @@ -333,6 +182,7 @@ public class MetricDO { } /** + * * @return alias */ public String getAlias() { @@ -340,6 +190,7 @@ public class MetricDO { } /** + * * @param alias */ public void setAlias(String alias) { @@ -348,7 +199,6 @@ public class MetricDO { /** * 类型参数 - * * @return type_params 类型参数 */ public String getTypeParams() { @@ -357,10 +207,9 @@ public class MetricDO { /** * 类型参数 - * * @param typeParams 类型参数 */ public void setTypeParams(String typeParams) { this.typeParams = typeParams == null ? null : typeParams.trim(); } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDOExample.java index 98d32eddf..3e75f81d2 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/MetricDOExample.java @@ -1212,38 +1212,6 @@ public class MetricDOExample { 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; @@ -1279,5 +1247,37 @@ public class MetricDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDO.java index c16bf1852..baa07e3db 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDO.java @@ -4,269 +4,143 @@ import java.util.Date; public class ModelDO { - /** - * - */ private Long id; - /** - * - */ private String name; - /** - * - */ private String bizName; - /** - * - */ private Long domainId; - /** - * - */ private String viewer; - /** - * - */ private String viewOrg; - /** - * - */ private String admin; - /** - * - */ private String adminOrg; - /** - * - */ private Integer isOpen; - /** - * - */ private String createdBy; - /** - * - */ private Date createdAt; - /** - * - */ private String updatedBy; - /** - * - */ private Date updatedAt; - /** - * - */ private String entity; - /** - * @return id - */ public Long getId() { return id; } - /** - * @param id - */ public void setId(Long id) { this.id = id; } - /** - * @return name - */ public String getName() { return name; } - /** - * @param name - */ public void setName(String name) { this.name = name == null ? null : name.trim(); } - /** - * @return biz_name - */ public String getBizName() { return bizName; } - /** - * @param bizName - */ public void setBizName(String bizName) { this.bizName = bizName == null ? null : bizName.trim(); } - /** - * @return domain_id - */ public Long getDomainId() { return domainId; } - /** - * @param domainId - */ public void setDomainId(Long domainId) { this.domainId = domainId; } - /** - * @return viewer - */ public String getViewer() { return viewer; } - /** - * @param viewer - */ public void setViewer(String viewer) { this.viewer = viewer == null ? null : viewer.trim(); } - /** - * @return view_org - */ public String getViewOrg() { return viewOrg; } - /** - * @param viewOrg - */ public void setViewOrg(String viewOrg) { this.viewOrg = viewOrg == null ? null : viewOrg.trim(); } - /** - * @return admin - */ public String getAdmin() { return admin; } - /** - * @param admin - */ public void setAdmin(String admin) { this.admin = admin == null ? null : admin.trim(); } - /** - * @return admin_org - */ public String getAdminOrg() { return adminOrg; } - /** - * @param adminOrg - */ public void setAdminOrg(String adminOrg) { this.adminOrg = adminOrg == null ? null : adminOrg.trim(); } - /** - * @return is_open - */ public Integer getIsOpen() { return isOpen; } - /** - * @param isOpen - */ public void setIsOpen(Integer isOpen) { this.isOpen = isOpen; } - /** - * @return created_by - */ public String getCreatedBy() { return createdBy; } - /** - * @param createdBy - */ public void setCreatedBy(String createdBy) { this.createdBy = createdBy == null ? null : createdBy.trim(); } - /** - * @return created_at - */ public Date getCreatedAt() { return createdAt; } - /** - * @param createdAt - */ public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } - /** - * @return updated_by - */ public String getUpdatedBy() { return updatedBy; } - /** - * @param updatedBy - */ public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy == null ? null : updatedBy.trim(); } - /** - * @return updated_at - */ public Date getUpdatedAt() { return updatedAt; } - /** - * @param updatedAt - */ public void setUpdatedAt(Date updatedAt) { this.updatedAt = updatedAt; } - /** - * @return entity - */ public String getEntity() { return entity; } - /** - * @param entity - */ public void setEntity(String entity) { this.entity = entity == null ? null : entity.trim(); } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDOExample.java index 7721ae42f..147839739 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ModelDOExample.java @@ -1082,38 +1082,6 @@ public class ModelDOExample { 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; @@ -1149,5 +1117,37 @@ public class ModelDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDO.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDO.java index df10e714a..f33f463db 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDO.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDO.java @@ -3,14 +3,11 @@ package com.tencent.supersonic.semantic.model.domain.dataobject; import java.util.Date; public class ViewInfoDO { - /** - * */ private Long id; /** - * */ private Long modelId; @@ -20,22 +17,18 @@ public class ViewInfoDO { private String type; /** - * */ private Date createdAt; /** - * */ private String createdBy; /** - * */ private Date updatedAt; /** - * */ private String updatedBy; @@ -74,7 +67,6 @@ public class ViewInfoDO { /** * datasource、dimension、metric - * * @return type datasource、dimension、metric */ public String getType() { @@ -83,7 +75,6 @@ public class ViewInfoDO { /** * datasource、dimension、metric - * * @param type datasource、dimension、metric */ public void setType(String type) { @@ -148,7 +139,6 @@ public class ViewInfoDO { /** * config detail - * * @return config config detail */ public String getConfig() { @@ -157,10 +147,9 @@ public class ViewInfoDO { /** * config detail - * * @param config config detail */ public void setConfig(String config) { this.config = config == null ? null : config.trim(); } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDOExample.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDOExample.java index 912796161..e00972682 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDOExample.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/dataobject/ViewInfoDOExample.java @@ -672,38 +672,6 @@ public class ViewInfoDOExample { 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; @@ -739,5 +707,37 @@ public class ViewInfoDOExample { protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } + + 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; + } } -} \ No newline at end of file +} diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DomainConvert.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DomainConvert.java index 81a81743a..e453e5f6e 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DomainConvert.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/DomainConvert.java @@ -3,17 +3,19 @@ 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.common.pojo.enums.StatusEnum; 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; @@ -56,7 +58,8 @@ public class DomainConvert { } 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/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/MetricConverter.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/MetricConverter.java index 8ea77d952..9b6513d3a 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/MetricConverter.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/domain/utils/MetricConverter.java @@ -3,21 +3,22 @@ package com.tencent.supersonic.semantic.model.domain.utils; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.common.pojo.DataFormat; -import com.tencent.supersonic.common.util.BeanMapper; 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.response.MetricResp; import com.tencent.supersonic.semantic.api.model.response.ModelResp; 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.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; import java.util.stream.Collectors; + import org.springframework.beans.BeanUtils; public class MetricConverter { diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DimensionController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DimensionController.java index a4dc762f4..4e3e851a2 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DimensionController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/DimensionController.java @@ -5,15 +5,14 @@ import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; import com.tencent.supersonic.semantic.api.model.pojo.DimValueMap; 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.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; -import com.tencent.supersonic.semantic.model.domain.MetricService; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -27,14 +26,9 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/api/semantic/dimension") public class DimensionController { - private DimensionService dimensionService; - - private MetricService metricService; - - public DimensionController(DimensionService dimensionService,MetricService metricService) { - this.metricService = metricService; + public DimensionController(DimensionService dimensionService) { this.dimensionService = dimensionService; } @@ -46,8 +40,8 @@ public class DimensionController { */ @PostMapping("/createDimension") public Boolean createDimension(@RequestBody DimensionReq dimensionReq, - HttpServletRequest request, - HttpServletResponse response) throws Exception { + HttpServletRequest request, + HttpServletResponse response) throws Exception { User user = UserHolder.findUser(request, response); dimensionService.createDimension(dimensionReq, user); return true; @@ -56,8 +50,8 @@ public class DimensionController { @PostMapping("/updateDimension") public Boolean updateDimension(@RequestBody DimensionReq dimensionReq, - HttpServletRequest request, - HttpServletResponse response) throws Exception { + HttpServletRequest request, + HttpServletResponse response) throws Exception { User user = UserHolder.findUser(request, response); dimensionService.updateDimension(dimensionReq, user); return true; @@ -66,18 +60,18 @@ public class DimensionController { @PostMapping("/mockDimensionAlias") public List mockMetricAlias(@RequestBody DimensionReq dimensionReq, HttpServletRequest request, - HttpServletResponse response){ + HttpServletResponse response) { User user = UserHolder.findUser(request, response); - return dimensionService.mockAlias(dimensionReq,"dimension",user); + return dimensionService.mockAlias(dimensionReq, "dimension", user); } @PostMapping("/mockDimensionValuesAlias") public List mockDimensionValuesAlias(@RequestBody DimensionReq dimensionReq, HttpServletRequest request, - HttpServletResponse response){ + HttpServletResponse response) { User user = UserHolder.findUser(request, response); - return dimensionService.mockDimensionValueAlias(dimensionReq,user); + return dimensionService.mockDimensionValueAlias(dimensionReq, user); } @GetMapping("/getDimensionList/{modelId}") @@ -88,7 +82,7 @@ public class DimensionController { @GetMapping("/{modelId}/{dimensionName}") public DimensionResp getDimensionDescByNameAndId(@PathVariable("modelId") Long modelId, - @PathVariable("dimensionName") String dimensionBizName) { + @PathVariable("dimensionName") String dimensionBizName) { return dimensionService.getDimension(dimensionBizName, modelId); } diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/MetricController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/MetricController.java index 7173ea637..99a164695 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/MetricController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/MetricController.java @@ -12,8 +12,13 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.DeleteMapping; @RestController @@ -51,9 +56,9 @@ public class MetricController { @PostMapping("/mockMetricAlias") public List mockMetricAlias(@RequestBody MetricReq metricReq, HttpServletRequest request, - HttpServletResponse response){ + HttpServletResponse response) { User user = UserHolder.findUser(request, response); - return metricService.mockAlias(metricReq,"indicator",user); + return metricService.mockAlias(metricReq, "indicator", user); } @GetMapping("/getMetricList/{modelId}") diff --git a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/ModelController.java b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/ModelController.java index 1e9fa8d84..70089dd80 100644 --- a/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/ModelController.java +++ b/semantic/model/src/main/java/com/tencent/supersonic/semantic/model/rest/ModelController.java @@ -6,18 +6,18 @@ import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.ModelReq; import com.tencent.supersonic.semantic.api.model.response.ModelResp; import com.tencent.supersonic.semantic.model.domain.ModelService; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.GetMapping; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; @RestController @@ -32,8 +32,8 @@ public class ModelController { @PostMapping("/createModel") public Boolean createModel(@RequestBody ModelReq modelReq, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); modelService.createModel(modelReq, user); return true; @@ -41,8 +41,8 @@ public class ModelController { @PostMapping("/updateModel") public Boolean updateModel(@RequestBody ModelReq modelReq, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); modelService.updateModel(modelReq, user); return true; @@ -56,8 +56,8 @@ public class ModelController { @GetMapping("/getModelList/{domainId}") public List getModelList(@PathVariable("domainId") Long domainId, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return modelService.getModelListWithAuth(user.getName(), domainId, AuthType.ADMIN); } diff --git a/semantic/model/src/main/resources/mapper/custom/MetricDOCustomMapper.xml b/semantic/model/src/main/resources/mapper/custom/MetricDOCustomMapper.xml index ac2c20e72..c13927100 100644 --- a/semantic/model/src/main/resources/mapper/custom/MetricDOCustomMapper.xml +++ b/semantic/model/src/main/resources/mapper/custom/MetricDOCustomMapper.xml @@ -119,7 +119,7 @@ and biz_name like CONCAT('%',#{bizName , jdbcType=VARCHAR},'%') - + and sensitive_level = #{sensitiveLevel} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Renderer.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Renderer.java index 53698e782..32cc7839d 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Renderer.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/Renderer.java @@ -79,7 +79,6 @@ public abstract class Renderer { if (measure.get().getConstraint() != null && !measure.get().getConstraint().isEmpty()) { metricNode.getMeasureFilter() .put(measure.get().getName(), SemanticNode.parse(measure.get().getConstraint(), scope)); - ; } } return metricNode; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DataSourceNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DataSourceNode.java index 58e61ed7a..95ac6ed6b 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DataSourceNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/calcite/sql/node/DataSourceNode.java @@ -7,6 +7,7 @@ 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; @@ -17,6 +18,7 @@ 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.SqlNode; import org.apache.calcite.sql.parser.SqlParser; @@ -50,7 +52,7 @@ public class DataSourceNode extends SemanticNode { } public static void getQueryDimensionMeasure(SemanticSchema schema, MetricReq metricCommand, - Set queryDimension, List measures) { + Set queryDimension, List measures) { queryDimension.addAll(metricCommand.getDimensions().stream() .map(d -> d.contains(Constants.DIMENSION_IDENTIFY) ? d.split(Constants.DIMENSION_IDENTIFY)[1] : d) .collect(Collectors.toSet())); @@ -62,17 +64,18 @@ public class DataSourceNode extends SemanticNode { } public static void mergeQueryFilterDimensionMeasure(SemanticSchema schema, MetricReq metricCommand, - Set queryDimension, List measures, SqlValidatorScope scope) throws Exception { + 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()); + 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() + schema.getMetrics().stream().filter(m -> m.getName().equalsIgnoreCase(filterCondition)) + .forEach(m -> m.getMetricTypeParams().getMeasures().stream() .forEach(mm -> queryMeasures.add(mm.getName()))); continue; } @@ -84,14 +87,13 @@ public class DataSourceNode extends SemanticNode { } public static List getMatchDataSources(SqlValidatorScope scope, SemanticSchema schema, - MetricReq metricCommand) throws Exception { + MetricReq metricCommand) throws Exception { List dataSources = new ArrayList<>(); // check by metric List measures = new ArrayList<>(); Set queryDimension = new HashSet<>(); getQueryDimensionMeasure(schema, metricCommand, queryDimension, measures); - String sourceName = ""; DataSource baseDataSource = null; // one , match measure count Map dataSourceMeasures = new HashMap<>(); @@ -148,8 +150,12 @@ public class DataSourceNode extends SemanticNode { return dataSources; } - private static boolean checkMatch(Set sourceMeasure, Set queryDimension, List measures, - Set dimension, MetricReq metricCommand, SqlValidatorScope scope) throws Exception { + private static boolean checkMatch(Set sourceMeasure, + Set queryDimension, + List measures, + Set dimension, + MetricReq metricCommand, + SqlValidatorScope scope) throws Exception { boolean isAllMatch = true; sourceMeasure.retainAll(measures); if (sourceMeasure.size() < measures.size()) { @@ -173,8 +179,11 @@ public class DataSourceNode extends SemanticNode { return isAllMatch; } - private static List getLinkDataSources(Set baseIdentifiers, Set queryDimension, - List measures, DataSource baseDataSource, SemanticSchema schema) { + private static List getLinkDataSources(Set baseIdentifiers, + Set queryDimension, + List measures, + DataSource baseDataSource, + SemanticSchema schema) { Set linkDataSourceName = new HashSet<>(); List linkDataSources = new ArrayList<>(); for (Map.Entry entry : schema.getDatasource().entrySet()) { @@ -200,7 +209,6 @@ public class DataSourceNode extends SemanticNode { linkMeasure.retainAll(measures); if (!linkMeasure.isEmpty()) { isMatch = true; - ; } } if (isMatch) { 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 index e8739721d..1c6552578 100644 --- 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 @@ -21,7 +21,6 @@ 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; @@ -106,10 +105,7 @@ public class CalculateAggConverter implements SemanticConverter { if (CollectionUtils.isEmpty(queryStructCmd.getAggregators())) { return false; } - //todo ck类型暂不拼with语句 - if (queryStructCmd.getModelId().equals(34L)) { - return false; - } + int nonSumFunction = 0; for (Aggregator agg : queryStructCmd.getAggregators()) { if (agg.getFunc() == null || "".equals(agg.getFunc())) { @@ -118,9 +114,7 @@ public class CalculateAggConverter implements SemanticConverter { if (agg.getFunc().equals(AggOperatorEnum.UNKNOWN)) { return false; } - if (agg.getFunc() != null - // && !agg.getFunc().equalsIgnoreCase(MetricAggDefault) - ) { + if (agg.getFunc() != null) { nonSumFunction++; } } @@ -129,7 +123,7 @@ public class CalculateAggConverter implements SemanticConverter { @Override public void converter(Catalog catalog, QueryStructReq queryStructCmd, ParseSqlReq sqlCommend, - MetricReq metricCommand) throws Exception { + MetricReq metricCommand) throws Exception { DatabaseResp databaseResp = catalog.getDatabaseByModelId(queryStructCmd.getModelId()); ParseSqlReq parseSqlReq = generateSqlCommend(queryStructCmd, EngineTypeEnum.valueOf(databaseResp.getType().toUpperCase()), databaseResp.getVersion()); @@ -156,7 +150,7 @@ public class CalculateAggConverter implements SemanticConverter { } public ParseSqlReq generateRatioSqlCommand(QueryStructReq queryStructCmd, EngineTypeEnum engineTypeEnum, - String version) + String version) throws Exception { check(queryStructCmd); ParseSqlReq sqlCommand = new ParseSqlReq(); @@ -178,15 +172,17 @@ public class CalculateAggConverter implements SemanticConverter { 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); + if (engineTypeEnum.equals(EngineTypeEnum.MYSQL) && Objects.nonNull(version) && version.startsWith( + mysqlLowVersion)) { + sqlCommand.setSupportWith(false); + sql = new MysqlEngineSql().sql(queryStructCmd, isOver, metricTableName); + } else { + sql = new CkEngineSql().sql(queryStructCmd, isOver, metricTableName); + } break; + default: } sqlCommand.setSql(sql); return sqlCommand; @@ -275,7 +271,7 @@ public class CalculateAggConverter implements SemanticConverter { 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) ", + 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) { @@ -302,7 +298,8 @@ public class CalculateAggConverter implements SemanticConverter { @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 ", + ",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."), @@ -330,8 +327,6 @@ public class CalculateAggConverter implements SemanticConverter { } 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( @@ -460,9 +455,6 @@ public class CalculateAggConverter implements SemanticConverter { } 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() diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/DefaultDimValueConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/DefaultDimValueConverter.java index d6de703ad..b362306d1 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/DefaultDimValueConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/DefaultDimValueConverter.java @@ -8,11 +8,11 @@ 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.query.parser.SemanticConverter; -import java.util.List; -import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.List; +import java.util.stream.Collectors; @Slf4j @Component("DefaultDimValueConverter") @@ -24,8 +24,8 @@ public class DefaultDimValueConverter implements SemanticConverter { } @Override - public void converter(Catalog catalog, QueryStructReq queryStructCmd, ParseSqlReq sqlCommend, - MetricReq metricCommand) throws Exception { + public void converter(Catalog catalog, QueryStructReq queryStructCmd, + ParseSqlReq sqlCommend, MetricReq metricCommand) throws Exception { List dimensionResps = catalog.getDimensions(queryStructCmd.getModelId()); //dimension which has default values dimensionResps = dimensionResps.stream() diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/MultiSourceJoin.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/MultiSourceJoin.java index 08ac6e0cc..5cb1039c3 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/MultiSourceJoin.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/MultiSourceJoin.java @@ -132,6 +132,4 @@ public class MultiSourceJoin implements SemanticConverter { MetricReq metricCommand) throws Exception { buildJoinPrefix(queryStructCmd); } - - } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/ParserDefaultConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/ParserDefaultConverter.java index e2f44efec..3329d7847 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/ParserDefaultConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/parser/convert/ParserDefaultConverter.java @@ -1,9 +1,6 @@ package com.tencent.supersonic.semantic.query.parser.convert; -import static com.tencent.supersonic.common.pojo.Constants.UNDERLINE; - import com.tencent.supersonic.common.pojo.ColumnOrder; -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; @@ -13,9 +10,7 @@ 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; import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -68,7 +63,8 @@ public class ParserDefaultConverter implements SemanticConverter { // todo tmp delete // support detail query if (queryStructCmd.getNativeQuery() && CollectionUtils.isEmpty(sqlCommend.getMetrics())) { - String internalMetricName = queryStructUtils.generateInternalMetricName(queryStructCmd.getModelId(), queryStructCmd.getGroups()); + String internalMetricName = queryStructUtils.generateInternalMetricName( + queryStructCmd.getModelId(), queryStructCmd.getGroups()); sqlCommend.getMetrics().add(internalMetricName); } 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 faf5adb5d..2a124c05f 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 @@ -3,15 +3,15 @@ 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.model.response.SqlParserResp; -import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; -import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; 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.ParseSqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; +import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; -import com.tencent.supersonic.semantic.query.persistence.pojo.QueryStatement; -import com.tencent.supersonic.semantic.query.service.QueryService; 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; @@ -57,7 +57,6 @@ public class QueryController { public SqlParserResp parseByStruct(@RequestBody ParseSqlReq parseSqlReq, HttpServletRequest request, HttpServletResponse response) throws Exception { - User user = UserHolder.findUser(request, response); QueryStatement queryStatement = semanticQueryEngine.physicalSql(parseSqlReq); SqlParserResp sqlParserResp = new SqlParserResp(); BeanUtils.copyProperties(queryStatement, sqlParserResp); 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 d3d3951fd..7c10021aa 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 @@ -7,22 +7,22 @@ import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.ModelSchemaFilterReq; 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.semantic.api.model.response.ModelResp; import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.ModelResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +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; 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.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; @RestController @RequestMapping("/api/semantic/schema") @@ -33,24 +33,24 @@ public class SchemaController { @PostMapping public List fetchModelSchema(@RequestBody ModelSchemaFilterReq filter, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return schemaService.fetchModelSchema(filter, user); } @GetMapping("/domain/list") public List getDomainList(HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return schemaService.getDomainList(user); } @GetMapping("/model/list") public List getModelList(@RequestParam("domainId") Long domainId, - @RequestParam("authType") String authType, - HttpServletRequest request, - HttpServletResponse response) { + @RequestParam("authType") String authType, + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return schemaService.getModelList(user, AuthType.valueOf(authType), domainId); } @@ -71,4 +71,4 @@ public class SchemaController { return schemaService.queryMetric(pageMetricCmd, user); } -} \ No newline at end of file +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryServiceImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryServiceImpl.java index 414fb7d6d..aa47d6bbc 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryServiceImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/QueryServiceImpl.java @@ -2,9 +2,8 @@ package com.tencent.supersonic.semantic.query.service; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; -import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.cache.CacheUtils; -import com.tencent.supersonic.semantic.api.model.pojo.QueryStat; +import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.semantic.api.model.request.ModelSchemaFilterReq; import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; 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 index ccf903e41..69610380b 100644 --- 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 @@ -6,11 +6,12 @@ import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.semantic.api.model.request.ModelSchemaFilterReq; 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.semantic.api.model.response.ModelResp; import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; +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.DomainResp; +import com.tencent.supersonic.semantic.api.model.response.ModelResp; + import java.util.List; public interface SchemaService { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaServiceImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaServiceImpl.java index 7f105efd9..68058404b 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaServiceImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/service/SchemaServiceImpl.java @@ -5,23 +5,23 @@ 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.common.pojo.enums.AuthType; -import com.tencent.supersonic.common.pojo.enums.TypeEnums; import com.tencent.supersonic.semantic.api.model.request.ModelSchemaFilterReq; 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.MetricResp; -import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; -import com.tencent.supersonic.semantic.api.model.response.ModelResp; import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricResp; +import com.tencent.supersonic.semantic.api.model.response.ModelResp; +import com.tencent.supersonic.semantic.api.model.response.DimensionResp; +import com.tencent.supersonic.semantic.api.model.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.MetricSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.DomainResp; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; +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 com.tencent.supersonic.semantic.model.domain.ModelService; +import com.tencent.supersonic.semantic.model.domain.MetricService; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -40,10 +40,10 @@ public class SchemaServiceImpl implements SchemaService { private final DomainService domainService; public SchemaServiceImpl(QueryService queryService, - ModelService modelService, - DimensionService dimensionService, - MetricService metricService, - DomainService domainService) { + ModelService modelService, + DimensionService dimensionService, + MetricService metricService, + DomainService domainService) { this.queryService = queryService; this.modelService = modelService; this.dimensionService = dimensionService; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DataPermissionAOP.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DataPermissionAOP.java index d7f5cfd49..986275e74 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DataPermissionAOP.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DataPermissionAOP.java @@ -12,23 +12,20 @@ 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.common.pojo.Constants; import com.tencent.supersonic.common.pojo.QueryAuthorization; import com.tencent.supersonic.common.pojo.QueryColumn; import com.tencent.supersonic.common.pojo.enums.AuthType; -import com.tencent.supersonic.common.pojo.exception.InvalidArgumentException; -import com.tencent.supersonic.common.pojo.exception.InvalidPermissionException; import com.tencent.supersonic.semantic.api.model.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.model.response.ModelResp; 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.ModelResp; -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.semantic.model.domain.DimensionService; -import com.tencent.supersonic.semantic.model.domain.MetricService; -import com.tencent.supersonic.semantic.model.domain.ModelService; +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,13 +36,16 @@ import java.util.Objects; 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.MetricService; +import com.tencent.supersonic.semantic.model.domain.ModelService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; +import org.assertj.core.util.Sets; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -133,14 +133,14 @@ public class DataPermissionAOP { .collect(Collectors.toSet()); QueryResultWithSchemaResp queryResultAfterDesensitization = desensitizationData(queryResultWithColumns, need2Apply); - addPromptInfoInfo(modelId, queryResultAfterDesensitization, authorizedResource); + addPromptInfoInfo(modelId, queryResultAfterDesensitization, authorizedResource, need2Apply); return queryResultAfterDesensitization; } - private boolean doModelAdmin(User user, QueryStructReq queryStructCmd) { - Long modelId = queryStructCmd.getModelId(); + private boolean doModelAdmin(User user, QueryStructReq queryStructReq) { + Long modelId = queryStructReq.getModelId(); List modelListAdmin = modelService.getModelListWithAuth(user.getName(), null, AuthType.ADMIN); if (CollectionUtils.isEmpty(modelListAdmin)) { return false; @@ -151,69 +151,60 @@ public class DataPermissionAOP { } } - private void doModelVisible(User user, QueryStructReq queryStructCmd) { + private void doModelVisible(User user, QueryStructReq queryStructReq) { Boolean visible = true; - Long domainId = queryStructCmd.getModelId(); + Long modelId = queryStructReq.getModelId(); List modelListVisible = modelService.getModelListWithAuth(user.getName(), null, AuthType.VISIBLE); if (CollectionUtils.isEmpty(modelListVisible)) { visible = false; } else { Map> id2domainDesc = modelListVisible.stream() .collect(Collectors.groupingBy(SchemaItem::getId)); - if (!CollectionUtils.isEmpty(id2domainDesc) && !id2domainDesc.containsKey(domainId)) { + if (!CollectionUtils.isEmpty(id2domainDesc) && !id2domainDesc.containsKey(modelId)) { visible = false; } } - if (!visible) { - List modelIds = new ArrayList<>(); - modelIds.add(domainId); - List modelInfos = modelService.getModelList(modelIds); - if (CollectionUtils.isEmpty(modelInfos)) { - throw new InvalidArgumentException( - "invalid domainId:" + domainId + ", please contact admin for details"); - } - String domainName = modelInfos.get(0).getName(); - throw new InvalidPermissionException( - "You do not have domain:" + domainName + " permission, please contact admin for details"); - + ModelResp modelResp = modelService.getModel(modelId); + String modelName = modelResp.getName(); + List admins = modelService.getModelAdmin(modelResp.getId()); + String message = String.format("您没有主题域[%s]权限,请联系管理员%s开通", modelName, admins); + throw new InvalidArgumentException(message); } } private QueryResultWithSchemaResp getQueryResultWithColumns(QueryResultWithSchemaResp resultWithColumns, Long domainId, AuthorizedResourceResp authResource) { - addPromptInfoInfo(domainId, resultWithColumns, authResource); + addPromptInfoInfo(domainId, resultWithColumns, authResource, Sets.newHashSet()); return resultWithColumns; } - private void addPromptInfoInfo(Long domainId, QueryResultWithSchemaResp queryResultWithColumns, - AuthorizedResourceResp authorizedResource) { + private void addPromptInfoInfo(Long modelId, QueryResultWithSchemaResp queryResultWithColumns, + AuthorizedResourceResp authorizedResource, Set need2Apply) { List filters = authorizedResource.getFilters(); + if (CollectionUtils.isEmpty(need2Apply) && CollectionUtils.isEmpty(filters)) { + return; + } + List admins = modelService.getModelAdmin(modelId); + if (!CollectionUtils.isEmpty(need2Apply)) { + String promptInfo = String.format("当前结果已经过脱敏处理, 申请权限请联系管理员%s", admins); + queryResultWithColumns.setQueryAuthorization(new QueryAuthorization(promptInfo)); + } if (!CollectionUtils.isEmpty(filters)) { log.debug("dimensionFilters:{}", filters); - - List modelIds = new ArrayList<>(); - modelIds.add(domainId); - List modelInfos = modelService.getModelList(modelIds); - String modelNameCn = ""; - if (!CollectionUtils.isEmpty(modelInfos)) { - modelNameCn = modelInfos.get(0).getName(); - } - + ModelResp modelResp = modelService.getModel(modelId); List exprList = new ArrayList<>(); List descList = new ArrayList<>(); filters.stream().forEach(filter -> { descList.add(filter.getDescription()); exprList.add(filter.getExpressions().toString()); }); - - String promptInfo = "the current data has been controlled by permissions," - + " related information:%s, please contact admin for details"; - String message = String.format(promptInfo, CollectionUtils.isEmpty(descList) ? exprList : descList); + String promptInfo = "当前结果已经过行权限过滤,详细过滤条件如下:%s, 申请权限请联系管理员%s"; + String message = String.format(promptInfo, CollectionUtils.isEmpty(descList) ? exprList : descList, admins); queryResultWithColumns.setQueryAuthorization( - new QueryAuthorization(modelNameCn, exprList, descList, message)); + new QueryAuthorization(modelResp.getName(), exprList, descList, message)); log.info("queryResultWithColumns:{}", queryResultWithColumns); } } @@ -292,7 +283,7 @@ public class DataPermissionAOP { return highSensitiveCols; } - private void doRowPermission(QueryStructReq queryStructCmd, AuthorizedResourceResp authorizedResource) { + private void doRowPermission(QueryStructReq queryStructReq, AuthorizedResourceResp authorizedResource) { log.debug("start doRowPermission logic"); StringJoiner joiner = new StringJoiner(" OR "); List dimensionFilters = new ArrayList<>(); @@ -313,13 +304,13 @@ public class DataPermissionAOP { }); if (StringUtils.isNotEmpty(joiner.toString())) { - log.info("before doRowPermission, queryStructCmd:{}", queryStructCmd); + log.info("before doRowPermission, queryStructReq:{}", queryStructReq); Filter filter = new Filter("", FilterOperatorEnum.SQL_PART, joiner.toString()); - List filters = Objects.isNull(queryStructCmd.getOriginalFilter()) ? new ArrayList<>() - : queryStructCmd.getOriginalFilter(); + List filters = Objects.isNull(queryStructReq.getOriginalFilter()) ? new ArrayList<>() + : queryStructReq.getOriginalFilter(); filters.add(filter); - queryStructCmd.setDimensionFilters(filters); - log.info("after doRowPermission, queryStructCmd:{}", queryStructCmd); + queryStructReq.setDimensionFilters(filters); + log.info("after doRowPermission, queryStructReq:{}", queryStructReq); } } @@ -348,7 +339,7 @@ public class DataPermissionAOP { try { queryResultWithColumns = deepCopyResult(raw); } catch (Exception e) { - log.warn("deepCopyResult, e:{}", e); + log.warn("deepCopyResult: ", e); } addAuthorizedSchemaInfo(queryResultWithColumns.getColumns(), need2Apply); desensitizationInternal(queryResultWithColumns.getResultList(), need2Apply); @@ -382,30 +373,32 @@ public class DataPermissionAOP { } } - private void doFilterCheckLogic(QueryStructReq queryStructCmd, Set resAuthName, + private void doFilterCheckLogic(QueryStructReq queryStructReq, Set resAuthName, Set sensitiveResReq) { - Set resFilterSet = queryStructUtils.getFilterResNameEnExceptInternalCol(queryStructCmd); + Set resFilterSet = queryStructUtils.getFilterResNameEnExceptInternalCol(queryStructReq); Set need2Apply = resFilterSet.stream() .filter(res -> !resAuthName.contains(res) && sensitiveResReq.contains(res)).collect(Collectors.toSet()); Set nameCnSet = new HashSet<>(); List modelIds = new ArrayList<>(); - modelIds.add(queryStructCmd.getModelId()); + modelIds.add(queryStructReq.getModelId()); List modelInfos = modelService.getModelList(modelIds); String modelNameCn = Constants.EMPTY; if (!CollectionUtils.isEmpty(modelInfos)) { modelNameCn = modelInfos.get(0).getName(); } - List dimensionDescList = dimensionService.getDimensions(queryStructCmd.getModelId()); + List dimensionDescList = dimensionService.getDimensions(queryStructReq.getModelId()); String finalDomainNameCn = modelNameCn; dimensionDescList.stream().filter(dim -> need2Apply.contains(dim.getBizName())) .forEach(dim -> nameCnSet.add(finalDomainNameCn + MINUS + dim.getName())); if (!CollectionUtils.isEmpty(need2Apply)) { - log.warn("in doFilterLogic, need2Apply:{}", need2Apply); - throw new InvalidPermissionException( - "you do not have data permission:" + nameCnSet + ", please contact admin for details"); + ModelResp modelResp = modelInfos.get(0); + List admins = modelService.getModelAdmin(modelResp.getId()); + log.info("in doFilterLogic, need2Apply:{}", need2Apply); + String message = String.format("您没有以下维度%s权限, 请联系管理员%s开通", nameCnSet, admins); + throw new InvalidPermissionException(message); } } @@ -415,4 +408,4 @@ public class DataPermissionAOP { return authService.queryAuthorizedResources(queryAuthResReq, user); } -} \ No newline at end of file +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DateUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DateUtils.java index 308f671b5..a7c0d53cd 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DateUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/DateUtils.java @@ -202,6 +202,19 @@ public class DateUtils { * @return */ public String betweenDateStr(ItemDateResp dateDate, DateConf dateInfo) { + if (MONTH.equalsIgnoreCase(dateInfo.getPeriod())) { + LocalDate endData = LocalDate.parse(dateInfo.getEndDate(), + DateTimeFormatter.ofPattern(DAY_FORMAT)); + LocalDate startData = LocalDate.parse(dateInfo.getStartDate(), + DateTimeFormatter.ofPattern(DAY_FORMAT)); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(MONTH_FORMAT); + return String.format("%s >= '%s' and %s <= '%s'", + sysDateMonthCol, startData.format(formatter), sysDateMonthCol, endData.format(formatter)); + } + if (WEEK.equalsIgnoreCase(dateInfo.getPeriod())) { + return String.format("%s >= '%s' and %s <= '%s'", + sysDateWeekCol, dateInfo.getStartDate(), sysDateWeekCol, dateInfo.getEndDate()); + } return String.format("%s >= '%s' and %s <= '%s'", sysDateCol, dateInfo.getStartDate(), sysDateCol, dateInfo.getEndDate()); } 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 index a37c2a704..e3f363a90 100644 --- 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 @@ -7,12 +7,6 @@ import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaR 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 java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.aspectj.lang.ProceedingJoinPoint; @@ -23,6 +17,13 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + @Aspect @Component @Slf4j @@ -34,9 +35,9 @@ public class DimValueAspect { @Autowired private DimensionService dimensionService; - @Around("execution(* com.tencent.supersonic.semantic.query.rest.QueryController.queryByStruct(..))" + - " || execution(* com.tencent.supersonic.semantic.query.service.QueryService.queryByStruct(..))" + - " || execution(* com.tencent.supersonic.semantic.query.service.QueryService.queryByStructWithAuth(..))") + @Around("execution(* com.tencent.supersonic.semantic.query.rest.QueryController.queryByStruct(..))" + + " || execution(* com.tencent.supersonic.semantic.query.service.QueryService.queryByStruct(..))" + + " || execution(* com.tencent.supersonic.semantic.query.service.QueryService.queryByStructWithAuth(..))") public Object handleDimValue(ProceedingJoinPoint joinPoint) throws Throwable { if (!dimensionValueMapEnable) { @@ -65,15 +66,15 @@ public class DimValueAspect { } private void rewriteDimValue(QueryResultWithSchemaResp queryResultWithColumns, - Map> dimAndTechNameAndBizNamePair) { + 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)) { + if (dimAndTechNameAndBizNamePair.containsKey(bizName) && Objects.nonNull(line.get(bizName))) { + String techName = line.get(bizName).toString(); Map techAndBizPair = dimAndTechNameAndBizNamePair.get(bizName); if (!CollectionUtils.isEmpty(techAndBizPair) && techAndBizPair.containsKey(techName)) { String bizValueName = techAndBizPair.get(techName); @@ -86,10 +87,10 @@ public class DimValueAspect { } } - private boolean selectDimValueMap(List columns, - Map> dimAndTechNameAndBizNamePair) { - if (CollectionUtils.isEmpty(dimAndTechNameAndBizNamePair) || CollectionUtils.isEmpty( - dimAndTechNameAndBizNamePair)) { + private boolean selectDimValueMap(List columns, Map> dimAndTechNameAndBizNamePair) { + if (CollectionUtils.isEmpty(dimAndTechNameAndBizNamePair) + || CollectionUtils.isEmpty(dimAndTechNameAndBizNamePair)) { return false; } @@ -118,9 +119,11 @@ public class DimValueAspect { 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); + if (aliasPair.containsKey(valueSingle)) { + valuesNew.add(aliasPair.get(valueSingle)); + } else { + valuesNew.add(valueSingle); + } } filter.setValue(valuesNew); } @@ -138,9 +141,9 @@ public class DimValueAspect { } } - private void generateAliasAndTechNamePair(List dimensions - , Map> dimAndAliasAndTechNamePair - , Map> dimAndTechNameAndBizNamePair) { + private void generateAliasAndTechNamePair(List dimensions, + Map> dimAndAliasAndTechNamePair, + Map> dimAndTechNameAndBizNamePair) { if (CollectionUtils.isEmpty(dimensions)) { return; } @@ -184,4 +187,4 @@ public class DimValueAspect { }); } -} \ No newline at end of file +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryReqConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryReqConverter.java index 6bcb6738c..d04a33110 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryReqConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryReqConverter.java @@ -1,6 +1,6 @@ package com.tencent.supersonic.semantic.query.utils; -import com.tencent.supersonic.common.util.jsqlparser.CCJSqlParserUtils; +import com.tencent.supersonic.common.util.jsqlparser.SqlParserSelectHelper; import com.tencent.supersonic.semantic.api.model.request.SqlExecuteReq; import com.tencent.supersonic.semantic.api.model.response.ModelSchemaResp; import com.tencent.supersonic.semantic.api.query.pojo.MetricTable; @@ -38,8 +38,8 @@ public class QueryReqConverter { MetricTable metricTable = new MetricTable(); String sql = databaseReq.getSql(); - List allFields = CCJSqlParserUtils.getAllFields(sql); - String tableName = CCJSqlParserUtils.getTableName(sql); + List allFields = SqlParserSelectHelper.getAllFields(sql); + String tableName = SqlParserSelectHelper.getTableName(sql); if (CollectionUtils.isEmpty(domainSchemas) || StringUtils.isEmpty(tableName)) { return new QueryStatement(); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryStructUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryStructUtils.java index 4c1ede9f8..a13a2907d 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryStructUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryStructUtils.java @@ -33,17 +33,14 @@ import org.springframework.util.CollectionUtils; @Slf4j @Component public class QueryStructUtils { - + public static Set internalCols = new HashSet<>( + Arrays.asList("dayno", "plat_sys_var", "sys_imp_date", "sys_imp_week", "sys_imp_month")); private final DateUtils dateUtils; private final SqlFilterUtils sqlFilterUtils; private final Catalog catalog; - @Value("${internal.metric.cnt.suffix:internal_cnt}") private String internalMetricNameSuffix; - public static Set internalCols = new HashSet<>( - Arrays.asList("dayno", "plat_sys_var", "sys_imp_date", "sys_imp_week", "sys_imp_month")); - public QueryStructUtils( DateUtils dateUtils, SqlFilterUtils sqlFilterUtils, Catalog catalog) { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryUtils.java index 2fd4d5bab..7c45ae91c 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/utils/QueryUtils.java @@ -40,16 +40,6 @@ public class QueryUtils { @Value("${query.cache.enable:true}") private Boolean cacheEnable; - @PostConstruct - public void fillPattern() { - Set aggFunctions = new HashSet<>(Arrays.asList("MAX", "MIN", "SUM", "AVG")); - String patternStr = "\\s*(%s\\((.*)\\)) AS"; - for (String agg : aggFunctions) { - patterns.add(Pattern.compile(String.format(patternStr, agg))); - } - } - - private final CacheUtils cacheUtils; private final StatUtils statUtils; @@ -63,12 +53,20 @@ public class QueryUtils { this.catalog = catalog; } + @PostConstruct + public void fillPattern() { + Set aggFunctions = new HashSet<>(Arrays.asList("MAX", "MIN", "SUM", "AVG")); + String patternStr = "\\s*(%s\\((.*)\\)) AS"; + for (String agg : aggFunctions) { + patterns.add(Pattern.compile(String.format(patternStr, agg))); + } + } public void fillItemNameInfo(QueryResultWithSchemaResp queryResultWithColumns, Long modelId) { List metricDescList = catalog.getMetrics(modelId); List dimensionDescList = catalog.getDimensions(modelId); - Map metricRespMap = - metricDescList.stream().collect(Collectors.toMap(MetricResp::getBizName, a -> a,(k1, k2)->k1)); + Map metricRespMap = + metricDescList.stream().collect(Collectors.toMap(MetricResp::getBizName, a -> a, (k1, k2) -> k1)); Map namePair = new HashMap<>(); Map nameTypePair = new HashMap<>(); addSysTimeDimension(namePair, nameTypePair); @@ -95,24 +93,13 @@ public class QueryUtils { if (!nameTypePair.containsKey(nameEn) && isNumberType(column.getType())) { column.setShowType("NUMBER"); } - if(metricRespMap.containsKey(nameEn)){ + if (metricRespMap.containsKey(nameEn)) { column.setDataFormatType(metricRespMap.get(nameEn).getDataFormatType()); column.setDataFormat(metricRespMap.get(nameEn).getDataFormat()); } }); } - private boolean isNumberType(String type) { - if (StringUtils.isBlank(type)) { - return false; - } - if (type.equalsIgnoreCase("int") || type.equalsIgnoreCase("bigint") - || type.equalsIgnoreCase("float") || type.equalsIgnoreCase("double")) { - return true; - } - return false; - } - public void fillItemNameInfo(QueryResultWithSchemaResp queryResultWithColumns, QueryMultiStructReq queryMultiStructCmd) { List aggregators = queryMultiStructCmd.getQueryStructReqs().stream() @@ -152,6 +139,17 @@ public class QueryUtils { }); } + private boolean isNumberType(String type) { + if (StringUtils.isBlank(type)) { + return false; + } + if (type.equalsIgnoreCase("int") || type.equalsIgnoreCase("bigint") + || type.equalsIgnoreCase("float") || type.equalsIgnoreCase("double")) { + return true; + } + return false; + } + private Map getMetricNameFromAgg(List aggregators) { Map map = new HashMap<>(); if (CollectionUtils.isEmpty(aggregators)) {