diff --git a/assembly/bin/build-standalone.sh b/assembly/bin/build-standalone.sh new file mode 100755 index 000000000..efa2324e8 --- /dev/null +++ b/assembly/bin/build-standalone.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +sbinDir=$(cd "$(dirname "$0")"; pwd) +baseDir=$(readlink -f $sbinDir/../) +runtimeDir=$baseDir/runtime +buildDir=$baseDir/build + +cd $baseDir + +#1. build semantic chat service +rm -fr ${buildDir}/*.tar.gz +rm -fr dist + +mvn -f $baseDir/../ clean package -DskipTests + +#2. move package to build +cp $baseDir/../launchers/standalone/target/*.tar.gz ${buildDir}/supersonic.tar.gz + +#3. build webapp +chmod +x $baseDir/../webapp/start-fe-prod.sh +cd ../webapp +sh ./start-fe-prod.sh +cp -fr ./supersonic-webapp.tar.gz ${buildDir}/ diff --git a/assembly/bin/start-all.sh b/assembly/bin/start-all.sh index 534c0094b..dc7c5abb5 100755 --- a/assembly/bin/start-all.sh +++ b/assembly/bin/start-all.sh @@ -2,7 +2,7 @@ sbinDir=$(cd "$(dirname "$0")"; pwd) baseDir=$(readlink -f $sbinDir/../) -runtimeDir=$baseDir/runtime +runtimeDir=$baseDir/../runtime buildDir=$baseDir/build cd $baseDir diff --git a/assembly/bin/start-standalone.sh b/assembly/bin/start-standalone.sh new file mode 100755 index 000000000..e0a180eda --- /dev/null +++ b/assembly/bin/start-standalone.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +sbinDir=$(cd "$(dirname "$0")"; pwd) +baseDir=$(readlink -f $sbinDir/../) +runtimeDir=$baseDir/../runtime +buildDir=$baseDir/build + +cd $baseDir + +#1. clear file +mkdir -p ${runtimeDir} +rm -fr ${runtimeDir}/* + +#2. package lib + +tar -zxvf ${buildDir}/supersonic.tar.gz -C ${runtimeDir} + +mv ${runtimeDir}/launchers-standalone-* ${runtimeDir}/supersonic-standalone + +tar -zxvf ${buildDir}/supersonic-webapp.tar.gz -C ${buildDir} + +mkdir -p ${runtimeDir}/supersonic-standalone/webapp + +cp -fr ${buildDir}/supersonic-webapp/* ${runtimeDir}/supersonic-standalone/webapp + +rm -fr ${buildDir}/supersonic-webapp + +#3. start service +sh ${runtimeDir}/supersonic-standalone/bin/service.sh restart + diff --git a/auth/api/pom.xml b/auth/api/pom.xml index 11a8f9f79..c3f97fb87 100644 --- a/auth/api/pom.xml +++ b/auth/api/pom.xml @@ -1,6 +1,6 @@ - com.tencent.supersonic diff --git a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/domain/pojo/AuthGroup.java b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/pojo/AuthGroup.java similarity index 89% rename from auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/domain/pojo/AuthGroup.java rename to auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/pojo/AuthGroup.java index c6aa819cd..2a9a053c1 100644 --- a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/domain/pojo/AuthGroup.java +++ b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/pojo/AuthGroup.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.auth.authorization.domain.pojo; +package com.tencent.supersonic.auth.api.authorization.pojo; import java.util.List; import lombok.Data; diff --git a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/domain/pojo/AuthRule.java b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/pojo/AuthRule.java similarity index 89% rename from auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/domain/pojo/AuthRule.java rename to auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/pojo/AuthRule.java index 735e73c4a..b5adafa67 100644 --- a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/domain/pojo/AuthRule.java +++ b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/pojo/AuthRule.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.auth.authorization.domain.pojo; +package com.tencent.supersonic.auth.api.authorization.pojo; import java.beans.Transient; import java.util.ArrayList; diff --git a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryAuthResReq.java b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryAuthResReq.java index dc1f6c6da..bf77f2e0d 100644 --- a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryAuthResReq.java +++ b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authorization/request/QueryAuthResReq.java @@ -1,6 +1,7 @@ package com.tencent.supersonic.auth.api.authorization.request; import com.tencent.supersonic.auth.api.authorization.pojo.AuthRes; +import java.util.ArrayList; import java.util.List; import lombok.Data; @@ -11,6 +12,10 @@ import lombok.ToString; public class QueryAuthResReq { private String user; + + private List departmentIds = new ArrayList<>(); + private List resources; + private String domainId; } 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 b6e1991c0..a3256c86d 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 @@ -1,10 +1,18 @@ package com.tencent.supersonic.auth.api.authorization.service; +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 javax.servlet.http.HttpServletRequest; +import java.util.List; public interface AuthService { - AuthorizedResourceResp queryAuthorizedResources(HttpServletRequest request, QueryAuthResReq req); + List queryAuthGroups(String domainId, Integer groupId); + + void updateAuthGroup(AuthGroup group); + + void removeAuthGroup(AuthGroup group); + + AuthorizedResourceResp queryAuthorizedResources(QueryAuthResReq req, HttpServletRequest request); } diff --git a/auth/authentication/pom.xml b/auth/authentication/pom.xml index 77afc102b..091e1f1de 100644 --- a/auth/authentication/pom.xml +++ b/auth/authentication/pom.xml @@ -1,6 +1,6 @@ - auth diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/dataobject/UserDOExample.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/dataobject/UserDOExample.java index 2272afe73..522407eff 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/dataobject/UserDOExample.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/dataobject/UserDOExample.java @@ -37,13 +37,6 @@ public class UserDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -54,8 +47,8 @@ public class UserDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -65,6 +58,13 @@ public class UserDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -116,13 +116,6 @@ public class UserDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -133,8 +126,8 @@ public class UserDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -144,6 +137,13 @@ public class UserDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_user null */ @@ -561,38 +561,6 @@ public class UserDOExample { 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; @@ -628,5 +596,37 @@ public class UserDOExample { 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/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java index fe769c5a3..b245ece49 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/DefaultAuthenticationInterceptor.java @@ -14,14 +14,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; -@Component @Slf4j public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor { - @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws AccessException { diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/InterceptorFactory.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/InterceptorFactory.java index b9e4203ef..a67d5caec 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/InterceptorFactory.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/domain/interceptor/InterceptorFactory.java @@ -22,7 +22,7 @@ public class InterceptorFactory implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { for (AuthenticationInterceptor authenticationInterceptor : authenticationInterceptors) { registry.addInterceptor(authenticationInterceptor).addPathPatterns("/**") - .excludePathPatterns("/", "/webapp/**","/error"); + .excludePathPatterns("/", "/webapp/**", "/error"); } } diff --git a/auth/authorization/pom.xml b/auth/authorization/pom.xml index 692a63f43..78907dfd8 100644 --- a/auth/authorization/pom.xml +++ b/auth/authorization/pom.xml @@ -1,6 +1,6 @@ - auth diff --git a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/application/AuthApplicationService.java b/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/application/AuthApplicationService.java deleted file mode 100644 index 149f0853d..000000000 --- a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/application/AuthApplicationService.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.tencent.supersonic.auth.authorization.application; - -import com.google.common.base.Strings; -import com.google.gson.Gson; -import com.tencent.supersonic.auth.api.authorization.pojo.AuthRes; -import com.tencent.supersonic.auth.api.authorization.pojo.AuthResGrp; -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.authorization.domain.pojo.AuthGroup; -import com.tencent.supersonic.auth.authorization.domain.pojo.AuthRule; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -@Component -@Slf4j -public class AuthApplicationService { - - @Autowired - private JdbcTemplate jdbcTemplate; - - private List load() { - List rows = jdbcTemplate.queryForList("select config from s2_auth_groups", String.class); - Gson g = new Gson(); - return rows.stream().map(row -> g.fromJson(row, AuthGroup.class)).collect(Collectors.toList()); - } - - public List queryAuthGroups(String domainId, Integer groupId) { - return load().stream() - .filter(group -> (Objects.isNull(groupId) || groupId.equals(group.getGroupId())) - && domainId.equals(group.getDomainId())) - .collect(Collectors.toList()); - } - - public void updateAuthGroup(AuthGroup group) { - Gson g = new Gson(); - if (group.getGroupId() == null) { - int nextGroupId = 1; - String sql = "select max(group_id) as group_id from s2_auth_groups"; - Integer obj = jdbcTemplate.queryForObject(sql, Integer.class); - if (obj != null) { - nextGroupId = obj + 1; - } - group.setGroupId(nextGroupId); - jdbcTemplate.update("insert into s2_auth_groups (group_id, config) values (?, ?);", nextGroupId, - g.toJson(group)); - } else { - jdbcTemplate.update("update s2_auth_groups set config = ? where group_id = ?;", g.toJson(group), - group.getGroupId()); - } - } - - public AuthorizedResourceResp queryAuthorizedResources(QueryAuthResReq req, HttpServletRequest request) { - List groups = load().stream(). - filter(group -> group.getAuthorizedUsers().contains(req.getUser()) && req.getDomainId() - .equals(group.getDomainId())). - collect(Collectors.toList()); - AuthorizedResourceResp resource = new AuthorizedResourceResp(); - Map> authGroupsByDomainId = groups.stream() - .collect(Collectors.groupingBy(AuthGroup::getDomainId)); - Map> reqAuthRes = req.getResources().stream() - .collect(Collectors.groupingBy(AuthRes::getDomainId)); - - for (String domainId : reqAuthRes.keySet()) { - List reqResourcesList = reqAuthRes.get(domainId); - AuthResGrp rg = new AuthResGrp(); - if (authGroupsByDomainId.containsKey(domainId)) { - List authGroups = authGroupsByDomainId.get(domainId); - for (AuthRes reqRes : reqResourcesList) { - for (AuthGroup authRuleGroup : authGroups) { - List authRules = authRuleGroup.getAuthRules(); - List allAuthItems = new ArrayList<>(); - authRules.stream().forEach(authRule -> allAuthItems.addAll(authRule.resourceNames())); - - if (allAuthItems.contains(reqRes.getName())) { - rg.getGroup().add(reqRes); - } - - } - } - } - if (Objects.nonNull(rg) && !CollectionUtils.isEmpty(rg.getGroup())) { - resource.getResources().add(rg); - } - } - - if (StringUtils.isNotEmpty(req.getDomainId())) { - List authGroups = authGroupsByDomainId.get(req.getDomainId()); - if (!CollectionUtils.isEmpty(authGroups)) { - for (AuthGroup group : authGroups) { - if (group.getDimensionFilters() != null - && group.getDimensionFilters().stream().anyMatch(expr -> !Strings.isNullOrEmpty(expr))) { - DimensionFilter df = new DimensionFilter(); - df.setDescription(group.getDimensionFilterDescription()); - df.setExpressions(group.getDimensionFilters()); - resource.getFilters().add(df); - } - } - } - } - - return resource; - } - - public void removeAuthGroup(AuthGroup group) { - jdbcTemplate.update("delete from s2_auth_groups where group_id = ?", group.getGroupId()); - } -} 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 d63608b9d..9e7797b9f 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 @@ -1,24 +1,148 @@ package com.tencent.supersonic.auth.authorization.application; +import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.tencent.supersonic.auth.api.authorization.pojo.AuthRes; +import com.tencent.supersonic.auth.api.authorization.pojo.AuthResGrp; +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 javax.servlet.http.HttpServletRequest; + +import com.tencent.supersonic.auth.api.authorization.pojo.AuthGroup; +import com.tencent.supersonic.auth.api.authorization.pojo.AuthRule; 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.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; @Service @Slf4j public class AuthServiceImpl implements AuthService { - private final AuthApplicationService authApplicationService; + private JdbcTemplate jdbcTemplate; - public AuthServiceImpl(AuthApplicationService authApplicationService) { - this.authApplicationService = authApplicationService; + public AuthServiceImpl(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + private List load() { + List rows = jdbcTemplate.queryForList("select config from s2_auth_groups", String.class); + Gson g = new Gson(); + return rows.stream().map(row -> g.fromJson(row, AuthGroup.class)).collect(Collectors.toList()); } @Override - public AuthorizedResourceResp queryAuthorizedResources(HttpServletRequest request, QueryAuthResReq req) { - return authApplicationService.queryAuthorizedResources(req, request); + public List queryAuthGroups(String domainId, Integer groupId) { + return load().stream() + .filter(group -> (Objects.isNull(groupId) || groupId.equals(group.getGroupId())) + && domainId.equals(group.getDomainId())) + .collect(Collectors.toList()); } + + @Override + public void updateAuthGroup(AuthGroup group) { + Gson g = new Gson(); + if (group.getGroupId() == null) { + int nextGroupId = 1; + String sql = "select max(group_id) as group_id from s2_auth_groups"; + Integer obj = jdbcTemplate.queryForObject(sql, Integer.class); + if (obj != null) { + nextGroupId = obj + 1; + } + group.setGroupId(nextGroupId); + jdbcTemplate.update("insert into s2_auth_groups (group_id, config) values (?, ?);", nextGroupId, + g.toJson(group)); + } else { + jdbcTemplate.update("update s2_auth_groups set config = ? where group_id = ?;", g.toJson(group), + group.getGroupId()); + } + } + + @Override + public void removeAuthGroup(AuthGroup group) { + jdbcTemplate.update("delete from s2_auth_groups where group_id = ?", group.getGroupId()); + } + + + @Override + public AuthorizedResourceResp queryAuthorizedResources(QueryAuthResReq req, HttpServletRequest request) { + List groups = getAuthGroups(req); + AuthorizedResourceResp resource = new AuthorizedResourceResp(); + Map> authGroupsByDomainId = groups.stream() + .collect(Collectors.groupingBy(AuthGroup::getDomainId)); + Map> reqAuthRes = req.getResources().stream() + .collect(Collectors.groupingBy(AuthRes::getDomainId)); + + for (String domainId : reqAuthRes.keySet()) { + List reqResourcesList = reqAuthRes.get(domainId); + AuthResGrp rg = new AuthResGrp(); + if (authGroupsByDomainId.containsKey(domainId)) { + List authGroups = authGroupsByDomainId.get(domainId); + for (AuthRes reqRes : reqResourcesList) { + for (AuthGroup authRuleGroup : authGroups) { + List authRules = authRuleGroup.getAuthRules(); + List allAuthItems = new ArrayList<>(); + authRules.forEach(authRule -> allAuthItems.addAll(authRule.resourceNames())); + + if (allAuthItems.contains(reqRes.getName())) { + rg.getGroup().add(reqRes); + } + + } + } + } + if (!CollectionUtils.isEmpty(rg.getGroup())) { + resource.getResources().add(rg); + } + } + + if (StringUtils.isNotEmpty(req.getDomainId())) { + List authGroups = authGroupsByDomainId.get(req.getDomainId()); + if (!CollectionUtils.isEmpty(authGroups)) { + for (AuthGroup group : authGroups) { + if (group.getDimensionFilters() != null + && group.getDimensionFilters().stream().anyMatch(expr -> !Strings.isNullOrEmpty(expr))) { + DimensionFilter df = new DimensionFilter(); + df.setDescription(group.getDimensionFilterDescription()); + df.setExpressions(group.getDimensionFilters()); + resource.getFilters().add(df); + } + } + } + } + + return resource; + } + + private List getAuthGroups(QueryAuthResReq req) { + List groups = load().stream(). + filter(group -> { + if (!Objects.equals(group.getDomainId(), req.getDomainId())) { + return false; + } + if (!CollectionUtils.isEmpty(group.getAuthorizedUsers()) && group.getAuthorizedUsers() + .contains(req.getUser())) { + return true; + } + for (String deparmentId : req.getDepartmentIds()) { + if (!CollectionUtils.isEmpty(group.getAuthorizedDepartmentIds()) + && group.getAuthorizedDepartmentIds().contains(deparmentId)) { + return true; + } + } + return false; + }).collect(Collectors.toList()); + log.info("user:{} department:{} authGroups:{}", req.getUser(), req.getDepartmentIds(), groups); + return groups; + } + } diff --git a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/rest/AuthController.java b/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/rest/AuthController.java index 378212412..780f5bbc3 100644 --- a/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/rest/AuthController.java +++ b/auth/authorization/src/main/java/com/tencent/supersonic/auth/authorization/rest/AuthController.java @@ -2,8 +2,8 @@ package com.tencent.supersonic.auth.authorization.rest; import com.tencent.supersonic.auth.api.authorization.request.QueryAuthResReq; import com.tencent.supersonic.auth.api.authorization.response.AuthorizedResourceResp; -import com.tencent.supersonic.auth.authorization.application.AuthApplicationService; -import com.tencent.supersonic.auth.authorization.domain.pojo.AuthGroup; +import com.tencent.supersonic.auth.api.authorization.service.AuthService; +import com.tencent.supersonic.auth.api.authorization.pojo.AuthGroup; import java.util.List; import javax.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; @@ -19,16 +19,16 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class AuthController { - private final AuthApplicationService service; + private final AuthService authService; - public AuthController(AuthApplicationService service) { - this.service = service; + public AuthController(AuthService authService) { + this.authService = authService; } @GetMapping("/queryGroup") public List queryAuthGroup(@RequestParam("domainId") String domainId, @RequestParam(value = "groupId", required = false) Integer groupId) { - return service.queryAuthGroups(domainId, groupId); + return authService.queryAuthGroups(domainId, groupId); } /** @@ -37,12 +37,12 @@ public class AuthController { @PostMapping("/createGroup") public void newAuthGroup(@RequestBody AuthGroup group) { group.setGroupId(null); - service.updateAuthGroup(group); + authService.updateAuthGroup(group); } @PostMapping("/removeGroup") public void removeAuthGroup(@RequestBody AuthGroup group) { - service.removeAuthGroup(group); + authService.removeAuthGroup(group); } /** @@ -55,7 +55,7 @@ public class AuthController { if (group.getGroupId() == null || group.getGroupId() == 0) { throw new RuntimeException("groupId is empty"); } - service.updateAuthGroup(group); + authService.updateAuthGroup(group); } /** @@ -68,6 +68,6 @@ public class AuthController { @PostMapping("/queryAuthorizedRes") public AuthorizedResourceResp queryAuthorizedResources(@RequestBody QueryAuthResReq req, HttpServletRequest request) { - return service.queryAuthorizedResources(req, request); + return authService.queryAuthorizedResources(req, request); } } diff --git a/auth/pom.xml b/auth/pom.xml index 77dcfcab7..f3962ea15 100644 --- a/auth/pom.xml +++ b/auth/pom.xml @@ -1,6 +1,6 @@ - supersonic diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SchemaMapper.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SchemaMapper.java similarity index 89% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SchemaMapper.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SchemaMapper.java index 7c89eca4f..caf15515c 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SchemaMapper.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SchemaMapper.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.api.service; +package com.tencent.supersonic.chat.api.component; import com.tencent.supersonic.chat.api.request.QueryContextReq; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticLayer.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticLayer.java similarity index 86% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticLayer.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticLayer.java index 7f56e689a..e524d8189 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticLayer.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticLayer.java @@ -1,8 +1,9 @@ -package com.tencent.supersonic.chat.api.service; +package com.tencent.supersonic.chat.api.component; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import java.util.List; @@ -23,6 +24,8 @@ public interface SemanticLayer { QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user); + QueryResultWithSchemaResp queryBySql(QuerySqlReq querySqlReq, User user); + DomainSchemaResp getDomainSchemaInfo(Long domain); List getDomainSchemaInfo(List ids); diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticParser.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticParser.java similarity index 78% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticParser.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticParser.java index deaf48b4c..218537502 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticParser.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticParser.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.api.service; +package com.tencent.supersonic.chat.api.component; import com.tencent.supersonic.chat.api.pojo.ChatContext; @@ -13,5 +13,5 @@ import com.tencent.supersonic.chat.api.request.QueryContextReq; */ public interface SemanticParser { - boolean parse(QueryContextReq queryContext, ChatContext chatCtx); + void parse(QueryContextReq queryContext, ChatContext chatContext); } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticQuery.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticQuery.java new file mode 100644 index 000000000..88429f69e --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/component/SemanticQuery.java @@ -0,0 +1,18 @@ +package com.tencent.supersonic.chat.api.component; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.response.QueryResultResp; + +/** + * This class defines the contract for a semantic query that executes specific type of + * query based on the results of semantic parsing. + */ +public interface SemanticQuery { + + String getQueryMode(); + + QueryResultResp execute(User user); + + SemanticParseInfo getParseInfo(); +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryFilter.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryFilter.java new file mode 100644 index 000000000..c1bb4c4ac --- /dev/null +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryFilter.java @@ -0,0 +1,16 @@ +package com.tencent.supersonic.chat.api.pojo; + +import lombok.Data; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +public class QueryFilter { + + private List filters = new ArrayList<>(); + + private Map params = new HashMap<>(); + +} diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementCount.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryMatchInfo.java similarity index 61% rename from chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementCount.java rename to chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryMatchInfo.java index 02932c77f..7e866f050 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementCount.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/QueryMatchInfo.java @@ -3,8 +3,10 @@ package com.tencent.supersonic.chat.api.pojo; import lombok.Data; @Data -public class SchemaElementCount { +public class QueryMatchInfo { + SchemaElementType elementType; + String detectWord; private Integer count = 0; private double maxSimilarity; } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java index fd5f6cdf0..592ee3bbe 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaElementMatch.java @@ -1,10 +1,16 @@ package com.tencent.supersonic.chat.api.pojo; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import lombok.ToString; @Data @ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor public class SchemaElementMatch { SchemaElementType elementType; @@ -18,7 +24,4 @@ public class SchemaElementMatch { String word; Long frequency; - - public SchemaElementMatch() { - } } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java index d13c840d6..66f8c2ca3 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SchemaMapInfo.java @@ -21,12 +21,12 @@ public class SchemaMapInfo { return domainElementMatches; } - public void setMatchedElements(Integer domain, List elementMatches) { - domainElementMatches.put(domain, elementMatches); - } - public void setDomainElementMatches( Map> domainElementMatches) { this.domainElementMatches = domainElementMatches; } + + public void setMatchedElements(Integer domain, List elementMatches) { + domainElementMatches.put(domain, elementMatches); + } } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticParseInfo.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/pojo/SemanticParseInfo.java index c7bd543e0..03adf3897 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 @@ -5,6 +5,7 @@ import com.tencent.supersonic.common.enums.AggregateTypeEnum; import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.Order; import com.tencent.supersonic.common.pojo.SchemaItem; + import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; @@ -27,4 +28,7 @@ public class SemanticParseInfo { private DateConf dateInfo; private Long limit; private Boolean nativeQuery = false; + private Double bonus = 0d; + private List elementMatches = new ArrayList<>(); + private Object info; } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/request/QueryContextReq.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/request/QueryContextReq.java index 71037c1b6..87622822f 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/request/QueryContextReq.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/request/QueryContextReq.java @@ -1,11 +1,14 @@ package com.tencent.supersonic.chat.api.request; - import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.QueryFilter; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import lombok.Data; +import java.util.ArrayList; +import java.util.List; + @Data public class QueryContextReq { @@ -13,7 +16,8 @@ public class QueryContextReq { private Integer chatId; private Integer domainId = 0; private User user; - private SemanticParseInfo parseInfo = new SemanticParseInfo(); + private QueryFilter queryFilter; + private List candidateQueries = new ArrayList<>(); private SchemaMapInfo mapInfo = new SchemaMapInfo(); private boolean saveAnswer = true; } diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/response/QueryResultResp.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/response/QueryResultResp.java index fa70b13a8..6ed1fc587 100644 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/response/QueryResultResp.java +++ b/chat/api/src/main/java/com/tencent/supersonic/chat/api/response/QueryResultResp.java @@ -11,13 +11,13 @@ import lombok.Data; @Data public class QueryResultResp { + public EntityInfo entityInfo; private Long queryId; private String queryMode; private String querySql; private int queryState; private List queryColumns; private QueryAuthorization queryAuthorization; - public EntityInfo entityInfo; private SemanticParseInfo chatContext; private Object response; private List> queryResults; diff --git a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticQuery.java b/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticQuery.java deleted file mode 100644 index 5cb650cfb..000000000 --- a/chat/api/src/main/java/com/tencent/supersonic/chat/api/service/SemanticQuery.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.tencent.supersonic.chat.api.service; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaElementCount; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; - -import java.io.Serializable; -import java.util.List; - -/** - * This interface defines the contract for a semantic query that executes specific type of - * query based on the results of semantic parsing. - */ -public interface SemanticQuery extends Serializable { - - String getQueryMode(); - - QueryResultResp execute(QueryContextReq queryCtx, ChatContext chatCtx) throws Exception; - - SchemaElementCount match(List elementMatches, QueryContextReq queryCtx); - - void updateContext(QueryResultResp queryResponse, ChatContext chatCtx, QueryContextReq queryCtx); - - SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx); - -} diff --git a/chat/core/pom.xml b/chat/core/pom.xml index e7ba122ed..63369ba78 100644 --- a/chat/core/pom.xml +++ b/chat/core/pom.xml @@ -113,6 +113,12 @@ semantic-api ${project.version} + + + + + + com.tencent.supersonic semantic-query @@ -125,6 +131,12 @@ ${project.version} compile + + com.tencent.supersonic + semantic-query + ${project.version} + compile + - \ No newline at end of file + diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ChatServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/ChatServiceImpl.java index 5663f3f9a..1ae1e4cbd 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ChatServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/ChatServiceImpl.java @@ -18,20 +18,19 @@ import com.tencent.supersonic.chat.domain.service.ChatService; import java.text.SimpleDateFormat; import java.util.List; import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; @Service("ChatService") @Primary +@Slf4j public class ChatServiceImpl implements ChatService { private ChatContextRepository chatContextRepository; private ChatRepository chatRepository; private ChatQueryRepository chatQueryRepository; - private final Logger logger = LoggerFactory.getLogger(ChatService.class); - public ChatServiceImpl(ChatContextRepository chatContextRepository, ChatRepository chatRepository, ChatQueryRepository chatQueryRepository) { @@ -64,27 +63,32 @@ public class ChatServiceImpl implements ChatService { @Override public void updateContext(ChatContext chatCtx) { - logger.debug("save ChatContext {}", chatCtx); + log.debug("save ChatContext {}", chatCtx); chatContextRepository.updateContext(chatCtx); } + @Override + public void updateContext(ChatContext chatCtx, QueryContextReq queryCtx, SemanticParseInfo semanticParseInfo) { + chatCtx.setParseInfo(semanticParseInfo); + chatCtx.setQueryText(queryCtx.getQueryText()); + updateContext(chatCtx); + } + @Override public void switchContext(ChatContext chatCtx) { - logger.debug("switchContext ChatContext {}", chatCtx); + log.debug("switchContext ChatContext {}", chatCtx); chatCtx.setParseInfo(new SemanticParseInfo()); } @Override public Boolean addChat(User user, String chatName) { - SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - String datetime = tempDate.format(new java.util.Date()); ChatDO intelligentConversionDO = new ChatDO(); intelligentConversionDO.setChatName(chatName); intelligentConversionDO.setCreator(user.getName()); - intelligentConversionDO.setCreateTime(datetime); + intelligentConversionDO.setCreateTime(getCurrentTime()); intelligentConversionDO.setIsDelete(0); - intelligentConversionDO.setLastTime(datetime); + intelligentConversionDO.setLastTime(getCurrentTime()); intelligentConversionDO.setLastQuestion("Hello, welcome to using supersonic"); intelligentConversionDO.setIsTop(0); return chatRepository.createChat(intelligentConversionDO); @@ -97,9 +101,7 @@ public class ChatServiceImpl implements ChatService { @Override public boolean updateChatName(Long chatId, String chatName, String userName) { - SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - String lastTime = tempDate.format(new java.util.Date()); - return chatRepository.updateChatName(chatId, chatName, lastTime, userName); + return chatRepository.updateChatName(chatId, chatName, getCurrentTime(), userName); } @Override @@ -129,6 +131,8 @@ public class ChatServiceImpl implements ChatService { @Override public void addQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx) { chatQueryRepository.createChatQuery(queryResponse, queryContext, chatCtx); + chatRepository.updateLastQuestion(chatCtx.getChatId().longValue(), queryContext.getQueryText(), + getCurrentTime()); } @Override @@ -141,4 +145,9 @@ public class ChatServiceImpl implements ChatService { return chatQueryRepository.updateChatQuery(chatQueryDO); } + private String getCurrentTime() { + SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return tempDate.format(new java.util.Date()); + } + } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ConfigServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/ConfigServiceImpl.java index 209f9b407..63ba2fa20 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/ConfigServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/ConfigServiceImpl.java @@ -2,9 +2,7 @@ package com.tencent.supersonic.chat.application; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.service.SemanticLayer; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.chat.domain.pojo.config.ChatConfig; import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigBase; import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigEditReq; @@ -14,14 +12,22 @@ import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric; import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; import com.tencent.supersonic.chat.domain.pojo.config.ItemVisibilityInfo; +import com.tencent.supersonic.chat.domain.pojo.config.KnowledgeInfo; import com.tencent.supersonic.chat.domain.repository.ChatConfigRepository; import com.tencent.supersonic.chat.domain.service.ConfigService; import com.tencent.supersonic.chat.domain.utils.ChatConfigUtils; +import com.tencent.supersonic.chat.domain.utils.ComponentFactory; +import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; import com.tencent.supersonic.common.util.json.JsonUtil; +import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.DomainResp; +import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; import 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; @@ -35,15 +41,16 @@ import org.springframework.util.CollectionUtils; public class ConfigServiceImpl implements ConfigService { private final ChatConfigRepository chaConfigRepository; - private final SemanticLayer semanticLayer; private final ChatConfigUtils chatConfigUtils; + private final DefaultSemanticInternalUtils defaultSemanticUtils; + public ConfigServiceImpl(ChatConfigRepository chaConfigRepository, - @Lazy SemanticLayer semanticLayer, - ChatConfigUtils chatConfigUtils) { + ChatConfigUtils chatConfigUtils, + @Lazy DefaultSemanticInternalUtils defaultSemanticUtils) { this.chaConfigRepository = chaConfigRepository; - this.semanticLayer = semanticLayer; this.chatConfigUtils = chatConfigUtils; + this.defaultSemanticUtils = defaultSemanticUtils; } @Override @@ -101,19 +108,19 @@ public class ConfigServiceImpl implements ConfigService { } public EntityRichInfo fetchEntityDescByDomainId(Long domainId) { - + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); ChatConfigInfo chaConfigDesc = chaConfigRepository.getConfigByDomainId(domainId); - return fetchEntityDescByConfig(chaConfigDesc); + DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domainId); + return fetchEntityDescByConfig(chaConfigDesc, domainSchemaDesc); } - public EntityRichInfo fetchEntityDescByConfig(ChatConfigInfo chatConfigDesc) { + public EntityRichInfo fetchEntityDescByConfig(ChatConfigInfo chatConfigDesc, DomainSchemaResp domain) { Long domainId = chatConfigDesc.getDomainId(); EntityRichInfo entityDesc = new EntityRichInfo(); if (Objects.isNull(chatConfigDesc) || Objects.isNull(chatConfigDesc.getEntity())) { log.info("domainId:{}, entityDesc info is null", domainId); return entityDesc; } - DomainSchemaResp domain = semanticLayer.getDomainSchemaInfo(domainId); entityDesc.setDomainId(domain.getId()); entityDesc.setDomainBizName(domain.getBizName()); @@ -128,13 +135,14 @@ public class ConfigServiceImpl implements ConfigService { public List fetchDefaultMetricDescByDomainId(Long domainId) { + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); ChatConfigInfo chatConfigDesc = chaConfigRepository.getConfigByDomainId(domainId); - return fetchDefaultMetricDescByConfig(chatConfigDesc); + DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domainId); + return fetchDefaultMetricDescByConfig(chatConfigDesc, domainSchemaDesc); } - public List fetchDefaultMetricDescByConfig(ChatConfigInfo chatConfigDesc) { + public List fetchDefaultMetricDescByConfig(ChatConfigInfo chatConfigDesc, DomainSchemaResp domain) { Long domainId = chatConfigDesc.getDomainId(); - DomainSchemaResp domain = semanticLayer.getDomainSchemaInfo(domainId); List defaultMetricDescList = new ArrayList<>(); if (Objects.isNull(chatConfigDesc) || CollectionUtils.isEmpty(chatConfigDesc.getDefaultMetrics())) { log.info("domainId:{}, defaultMetricDescList info is null", domainId); @@ -158,14 +166,17 @@ public class ConfigServiceImpl implements ConfigService { } public ItemVisibilityInfo fetchVisibilityDescByDomainId(Long domainId) { + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); ChatConfigInfo chatConfigDesc = chaConfigRepository.getConfigByDomainId(domainId); - return fetchVisibilityDescByConfig(chatConfigDesc); + DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domainId); + return fetchVisibilityDescByConfig(chatConfigDesc, domainSchemaDesc); } - private ItemVisibilityInfo fetchVisibilityDescByConfig(ChatConfigInfo chatConfigDesc) { + private ItemVisibilityInfo fetchVisibilityDescByConfig(ChatConfigInfo chatConfigDesc, + DomainSchemaResp domainSchemaDesc) { ItemVisibilityInfo itemVisibilityDesc = new ItemVisibilityInfo(); Long domainId = chatConfigDesc.getDomainId(); - DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domainId); + List dimIdAllList = chatConfigUtils.generateAllDimIdList(domainSchemaDesc); List metricIdAllList = chatConfigUtils.generateAllMetricIdList(domainSchemaDesc); @@ -194,18 +205,65 @@ public class ConfigServiceImpl implements ConfigService { @Override public ChatConfigRichInfo getConfigRichInfo(Long domainId) { + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); ChatConfigRichInfo chaConfigRichDesc = new ChatConfigRichInfo(); ChatConfigInfo chatConfigDesc = chaConfigRepository.getConfigByDomainId(domainId); + if (Objects.isNull(chatConfigDesc)) { + log.info("there is no chatConfigDesc for domainId:{}", domainId); + return chaConfigRichDesc; + } BeanUtils.copyProperties(chatConfigDesc, chaConfigRichDesc); - DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domainId); - chaConfigRichDesc.setBizName(domainSchemaDesc.getBizName()); - chaConfigRichDesc.setName(domainSchemaDesc.getName()); + DomainSchemaResp domainSchemaInfo = semanticLayer.getDomainSchemaInfo(domainId); + chaConfigRichDesc.setBizName(domainSchemaInfo.getBizName()); + chaConfigRichDesc.setName(domainSchemaInfo.getName()); - chaConfigRichDesc.setDefaultMetrics(fetchDefaultMetricDescByConfig(chatConfigDesc)); - chaConfigRichDesc.setVisibility(fetchVisibilityDescByConfig(chatConfigDesc)); - chaConfigRichDesc.setEntity(fetchEntityDescByConfig(chatConfigDesc)); + chaConfigRichDesc.setKnowledgeInfos( + fillKnowledgeBizName(chaConfigRichDesc.getKnowledgeInfos(), domainSchemaInfo)); + chaConfigRichDesc.setDefaultMetrics(fetchDefaultMetricDescByConfig(chatConfigDesc, domainSchemaInfo)); + chaConfigRichDesc.setVisibility(fetchVisibilityDescByConfig(chatConfigDesc, domainSchemaInfo)); + chaConfigRichDesc.setEntity(fetchEntityDescByConfig(chatConfigDesc, domainSchemaInfo)); return chaConfigRichDesc; } + + private List fillKnowledgeBizName(List knowledgeInfos, + DomainSchemaResp domainSchemaInfo) { + if (CollectionUtils.isEmpty(knowledgeInfos)) { + return new ArrayList<>(); + } + Map dimIdAndRespPair = domainSchemaInfo.getDimensions().stream() + .collect(Collectors.toMap(DimSchemaResp::getId, Function.identity())); + knowledgeInfos.stream().forEach(knowledgeInfo -> { + if (Objects.nonNull(knowledgeInfo)) { + DimSchemaResp dimSchemaResp = dimIdAndRespPair.get(knowledgeInfo.getItemId()); + if (Objects.nonNull(dimSchemaResp)) { + knowledgeInfo.setBizName(dimSchemaResp.getBizName()); + } + if (CollectionUtils.isEmpty(knowledgeInfo.getBlackList())) { + knowledgeInfo.setBlackList(new ArrayList<>()); + } + if (CollectionUtils.isEmpty(knowledgeInfo.getRuleList())) { + knowledgeInfo.setRuleList(new ArrayList<>()); + } + if (CollectionUtils.isEmpty(knowledgeInfo.getWhiteList())) { + knowledgeInfo.setWhiteList(new ArrayList<>()); + } + } + }); + return knowledgeInfos; + } + + @Override + public List getAllChatRichConfig() { + List chatConfigRichInfoList = new ArrayList<>(); + List domainRespList = defaultSemanticUtils.getDomainListForAdmin(); + domainRespList.stream().forEach(domainResp -> { + ChatConfigRichInfo chatConfigRichInfo = getConfigRichInfo(domainResp.getId()); + if (Objects.nonNull(chatConfigRichInfo)) { + chatConfigRichInfoList.add(chatConfigRichInfo); + } + }); + return chatConfigRichInfoList; + } } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/DomainEntityService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/DomainEntityService.java index 052b918c7..935bb9090 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/DomainEntityService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/DomainEntityService.java @@ -2,49 +2,44 @@ package com.tencent.supersonic.chat.application; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.chat.api.pojo.DataInfo; import com.tencent.supersonic.chat.api.pojo.DomainInfo; import com.tencent.supersonic.chat.api.pojo.EntityInfo; import com.tencent.supersonic.chat.api.pojo.Filter; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticLayer; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; +import com.tencent.supersonic.chat.domain.utils.ComponentFactory; import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import java.util.ArrayList; import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - @Service +@Slf4j public class DomainEntityService { - private final Logger logger = LoggerFactory.getLogger(DomainEntityService.class); - @Autowired - private SemanticLayer semanticLayer; + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); @Autowired private DefaultSemanticInternalUtils defaultSemanticUtils; - public EntityInfo getEntityInfo(QueryContextReq queryCtx, ChatContext chatCtx, User user) { - SemanticParseInfo parseInfo = queryCtx.getParseInfo(); - + public EntityInfo getEntityInfo(SemanticParseInfo parseInfo, User user) { if (parseInfo != null && parseInfo.getDomainId() > 0) { EntityInfo entityInfo = getEntityInfo(parseInfo.getDomainId()); if (parseInfo.getDimensionFilters().size() <= 0) { @@ -56,7 +51,8 @@ public class DomainEntityService { String domainInfoPrimaryName = entityInfo.getDomainInfo().getPrimaryEntityBizName(); String domainInfoId = ""; for (Filter chatFilter : parseInfo.getDimensionFilters()) { - if (chatFilter.getBizName().equals(domainInfoPrimaryName)) { + if (chatFilter != null && chatFilter.getBizName() != null && chatFilter.getBizName() + .equals(domainInfoPrimaryName)) { if (chatFilter.getOperator().equals(FilterOperatorEnum.EQUALS)) { domainInfoId = chatFilter.getValue().toString(); } @@ -72,7 +68,7 @@ public class DomainEntityService { return entityInfo; } catch (Exception e) { - logger.error("setMaintDomain error {}", e); + log.error("setMaintDomain error {}", e); } } } @@ -88,7 +84,7 @@ public class DomainEntityService { private EntityInfo getEntityInfo(EntityRichInfo entityDesc) { EntityInfo entityInfo = new EntityInfo(); - if (entityDesc != null) { + if (entityDesc != null && Objects.nonNull(entityDesc.getDomainId())) { DomainInfo domainInfo = new DomainInfo(); domainInfo.setItemId(Integer.valueOf(entityDesc.getDomainId().intValue())); domainInfo.setName(entityDesc.getDomainName()); @@ -148,7 +144,7 @@ public class DomainEntityService { queryResultWithColumns = semanticLayer.queryByStruct(SchemaInfoConverter.convertTo(semanticParseInfo), user); } catch (Exception e) { - logger.warn("setMainDomain queryByStruct error, e:", e); + log.warn("setMainDomain queryByStruct error, e:", e); } if (queryResultWithColumns != null) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/QueryServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/QueryServiceImpl.java index e9aed284f..46d2b8a2a 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/QueryServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/QueryServiceImpl.java @@ -2,52 +2,44 @@ package com.tencent.supersonic.chat.application; import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.*; import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.api.service.SchemaMapper; -import com.tencent.supersonic.chat.api.service.SemanticLayer; -import com.tencent.supersonic.chat.api.service.SemanticParser; -import com.tencent.supersonic.chat.api.service.SemanticQuery; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.chat.application.query.SemanticQueryFactory; +import com.tencent.supersonic.chat.application.query.QuerySelector; import com.tencent.supersonic.chat.domain.pojo.chat.QueryData; -import com.tencent.supersonic.chat.domain.service.ChatService; +import com.tencent.supersonic.chat.domain.pojo.search.QueryState; import com.tencent.supersonic.chat.domain.service.QueryService; +import com.tencent.supersonic.chat.domain.service.ChatService; +import com.tencent.supersonic.chat.domain.utils.ComponentFactory; import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.util.json.JsonUtil; +import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.support.SpringFactoriesLoader; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; @Service +@Component("chatQueryService") +@Primary +@Slf4j public class QueryServiceImpl implements QueryService { - private final Logger logger = LoggerFactory.getLogger(QueryServiceImpl.class); - private List schemaMappers; - private List semanticParsers; @Autowired private ChatService chatService; - @Autowired - private SemanticLayer semanticLayer; - public QueryServiceImpl() { - schemaMappers = SpringFactoriesLoader.loadFactories(SchemaMapper.class, - Thread.currentThread().getContextClassLoader()); - semanticParsers = SpringFactoriesLoader.loadFactories(SemanticParser.class, - Thread.currentThread().getContextClassLoader()); - } + private List schemaMappers = ComponentFactory.getSchemaMappers(); + private List semanticParsers = ComponentFactory.getSemanticParsers(); + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + private QuerySelector querySelector = ComponentFactory.getQuerySelector(); + @Override public QueryResultResp executeQuery(QueryContextReq queryCtx) throws Exception { schemaMappers.stream().forEach(s -> s.map(queryCtx)); @@ -55,24 +47,29 @@ public class QueryServiceImpl implements QueryService { ChatContext chatCtx = chatService.getOrCreateContext(queryCtx.getChatId()); for (SemanticParser semanticParser : semanticParsers) { - logger.info("semanticParser processing:{}", JsonUtil.prettyToString(semanticParser)); - boolean isFinish = semanticParser.parse(queryCtx, chatCtx); - if (isFinish) { - logger.info("semanticParser is finish ,semanticParser:{}", semanticParser.getClass().getName()); - break; + log.info("semanticParser processing:[{}]", semanticParser.getClass().getName()); + semanticParser.parse(queryCtx, chatCtx); + } + + if (queryCtx.getCandidateQueries().size() > 0) { + log.info("pick before [{}]", queryCtx.getCandidateQueries().stream().collect( + Collectors.toList())); + SemanticQuery semanticQuery = querySelector.select(queryCtx.getCandidateQueries()); + log.info("pick after [{}]", semanticQuery); + + QueryResultResp queryResponse = semanticQuery.execute(queryCtx.getUser()); + if (queryResponse != null) { + // update chat context after a successful semantic query + if (queryCtx.isSaveAnswer() && queryResponse.getQueryState() == QueryState.NORMAL.getState()) { + chatService.updateContext(chatCtx, queryCtx, semanticQuery.getParseInfo()); + } + queryResponse.setChatContext(chatCtx.getParseInfo()); + chatService.addQuery(queryResponse, queryCtx, chatCtx); + return queryResponse; } } - // submit semantic query based on the result of semantic parsing - SemanticQuery query = SemanticQueryFactory.get(queryCtx.getParseInfo().getQueryMode()); - QueryResultResp queryResponse = query.execute(queryCtx, chatCtx); - - // update chat context after a successful semantic query - query.updateContext(queryResponse, chatCtx, queryCtx); - - chatService.addQuery(queryResponse, queryCtx, chatCtx); - - return queryResponse; + return null; } @Override @@ -82,7 +79,7 @@ public class QueryServiceImpl implements QueryService { } @Override - public QueryResultResp queryData(QueryData queryData, User user) throws Exception { + public QueryResultResp executeDirectQuery(QueryData queryData, User user) throws Exception { SemanticParseInfo semanticParseInfo = new SemanticParseInfo(); QueryResultResp queryResponse = new QueryResultResp(); BeanUtils.copyProperties(queryData, semanticParseInfo); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/RecommendServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/RecommendServiceImpl.java index 727ec651c..6044b08d0 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/RecommendServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/RecommendServiceImpl.java @@ -2,14 +2,15 @@ package com.tencent.supersonic.chat.application; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.domain.utils.ComponentFactory; import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; import com.tencent.supersonic.chat.domain.pojo.chat.RecommendResponse; import com.tencent.supersonic.chat.domain.service.RecommendService; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.stereotype.Service; /*** @@ -18,8 +19,7 @@ import org.springframework.stereotype.Service; @Service public class RecommendServiceImpl implements RecommendService { - @Autowired - private SemanticLayer semanticLayer; + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); @Override public RecommendResponse recommend(QueryContextReq queryCtx) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/SearchServiceImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/SearchServiceImpl.java index da7288f7a..f9361d1fa 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/SearchServiceImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/SearchServiceImpl.java @@ -32,9 +32,9 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -43,9 +43,11 @@ import org.springframework.stereotype.Service; * search service impl */ @Service +@Slf4j public class SearchServiceImpl implements SearchService { - private static final Logger LOGGER = LoggerFactory.getLogger(SearchServiceImpl.class); + private static final int RESULT_SIZE = 10; + @Autowired private WordNatureService wordNatureService; @Autowired @@ -53,9 +55,6 @@ public class SearchServiceImpl implements SearchService { @Autowired private SearchMatchStrategy searchMatchStrategy; - private static final int RESULT_SIZE = 10; - - @Override public List search(QueryContextReq queryCtx) { String queryText = queryCtx.getQueryText(); @@ -67,7 +66,7 @@ public class SearchServiceImpl implements SearchService { // 2.detect by segment List originals = HanlpHelper.getSegment().seg(queryText.toLowerCase()).stream() .collect(Collectors.toList()); - Map> regTextMap = searchMatchStrategy.matchWithMatchText(queryText, originals, + Map> regTextMap = searchMatchStrategy.match(queryText, originals, queryCtx.getDomainId()); regTextMap.entrySet().stream().forEach(m -> HanlpHelper.transLetterOriginal(m.getValue())); // 3.get the most matching data @@ -77,14 +76,14 @@ public class SearchServiceImpl implements SearchService { .reduce((entry1, entry2) -> entry1.getKey().getDetectSegment().length() >= entry2.getKey().getDetectSegment().length() ? entry1 : entry2); - LOGGER.debug("mostSimilarSearchResult:{}", mostSimilarSearchResult); + log.debug("mostSimilarSearchResult:{}", mostSimilarSearchResult); // 4.optimize the results after the query if (!mostSimilarSearchResult.isPresent()) { - LOGGER.info("unable to find any information through search , queryCtx:{}", queryCtx); + log.info("unable to find any information through search , queryCtx:{}", queryCtx); return Lists.newArrayList(); } Map.Entry> searchTextEntry = mostSimilarSearchResult.get(); - LOGGER.info("searchTextEntry:{},queryCtx:{}", searchTextEntry, queryCtx); + log.info("searchTextEntry:{},queryCtx:{}", searchTextEntry, queryCtx); Set searchResults = new LinkedHashSet(); DomainInfoStat domainStat = NatureHelper.getDomainStat(originals); @@ -98,7 +97,7 @@ public class SearchServiceImpl implements SearchService { // 4.2 process based on dimension values MatchText matchText = searchTextEntry.getKey(); Map natureToNameMap = getNatureToNameMap(searchTextEntry, new HashSet<>(possibleDomains)); - LOGGER.debug("possibleDomains:{},natureToNameMap:{}", possibleDomains, natureToNameMap); + log.debug("possibleDomains:{},natureToNameMap:{}", possibleDomains, natureToNameMap); for (Map.Entry natureToNameEntry : natureToNameMap.entrySet()) { searchDimensionValue(metricsDb, domainToName, domainStat.getMetricDomainCount(), searchResults, @@ -120,7 +119,7 @@ public class SearchServiceImpl implements SearchService { Long contextDomain = chatService.getContextDomain(queryCtx.getChatId()); - LOGGER.debug("possibleDomains:{},domainStat:{},contextDomain:{}", possibleDomains, domainStat, contextDomain); + log.debug("possibleDomains:{},domainStat:{},contextDomain:{}", possibleDomains, domainStat, contextDomain); // If nothing is recognized or only metric are present, then add the contextDomain. if (nothingOrOnlyMetric(domainStat) && effectiveDomain(contextDomain)) { @@ -249,7 +248,7 @@ public class SearchServiceImpl implements SearchService { domainToName.get(domain), domain, semanticType)); } } - LOGGER.info("parseResult:{},dimensionMetricClassIds:{},possibleDomains:{}", mapResult, + log.info("parseResult:{},dimensionMetricClassIds:{},possibleDomains:{}", mapResult, dimensionMetricClassIds, possibleDomains); } return existMetric; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/ApplicationStartedInit.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/ApplicationStartedInit.java index fa1630538..517851ed0 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/ApplicationStartedInit.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/knowledge/ApplicationStartedInit.java @@ -45,7 +45,7 @@ public class ApplicationStartedInit implements ApplicationListener wordNatures = wordNatureService.getAllWordNature(); @@ -55,6 +55,7 @@ public class ApplicationStartedInit implements ApplicationListener preWordNatures = new ArrayList<>(); private LoadingCache cache = CacheBuilder.newBuilder() @@ -39,14 +38,14 @@ public class WordNatureService { new CacheLoader() { @Override public DomainInfos load(String key) { - LOGGER.info("load getDomainSchemaInfo cache [{}]", key); + log.info("load getDomainSchemaInfo cache [{}]", key); return SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>())); } } ); public List getAllWordNature() { - + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); DomainInfos domainInfos = SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>())); List natures = new ArrayList<>(); @@ -64,7 +63,7 @@ public class WordNatureService { private void addNatureToResult(NatureType value, List metas, List natures) { List natureList = WordNatureStrategyFactory.get(value).getWordNatureList(metas); - LOGGER.debug("nature type:{} , nature size:{}", value.name(), natureList.size()); + log.debug("nature type:{} , nature size:{}", value.name(), natureList.size()); natures.addAll(natureList); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/DatabaseSchemaMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/DatabaseSchemaMapper.java new file mode 100644 index 000000000..d9b5173b8 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/DatabaseSchemaMapper.java @@ -0,0 +1,144 @@ +package com.tencent.supersonic.chat.application.mapper; + +import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.component.SchemaMapper; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.application.knowledge.WordNatureService; +import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; +import com.tencent.supersonic.common.nlp.ItemDO; +import com.tencent.supersonic.common.util.context.ContextUtils; +import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; + +@Slf4j +public class DatabaseSchemaMapper implements SchemaMapper { + + @Override + public void map(QueryContextReq queryContext) { + + log.debug("before db mapper,mapInfo:{}", queryContext.getMapInfo()); + + List terms = HanlpHelper.getSegment().seg(queryContext.getQueryText().toLowerCase()).stream() + .collect(Collectors.toList()); + + WordNatureService wordNatureService = ContextUtils.getBean(WordNatureService.class); + + DomainInfos domainInfos = wordNatureService.getCache().getUnchecked(""); + + detectAndAddToSchema(queryContext, terms, domainInfos.getDimensions(), + SchemaElementType.DIMENSION); + detectAndAddToSchema(queryContext, terms, domainInfos.getMetrics(), SchemaElementType.METRIC); + + log.debug("after db mapper,mapInfo:{}", queryContext.getMapInfo()); + } + + private void detectAndAddToSchema(QueryContextReq queryContext, List terms, List domains, + SchemaElementType schemaElementType) { + try { + String queryText = queryContext.getQueryText(); + + Map> domainResultSet = getResultSet(queryText, terms, domains); + + addToSchemaMapInfo(domainResultSet, queryContext.getMapInfo(), schemaElementType); + + } catch (Exception e) { + log.error("detectAndAddToSchema error", e); + } + } + + private Map> getResultSet(String queryText, List terms, List domains) { + + MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); + + Map> nameToItems = getNameToItems(domains); + + Map regOffsetToLength = terms.stream().sorted(Comparator.comparing(Term::length)) + .collect(Collectors.toMap(Term::getOffset, term -> term.word.length(), (value1, value2) -> value2)); + + Map> domainResultSet = new HashMap<>(); + for (Integer index = 0; index <= queryText.length() - 1; ) { + for (Integer i = index; i <= queryText.length(); ) { + i = mapperHelper.getStepIndex(regOffsetToLength, i); + if (i <= queryText.length()) { + String detectSegment = queryText.substring(index, i); + nameToItems.forEach( + (name, newItemDOs) -> { + if (name.contains(detectSegment) + && mapperHelper.getSimilarity(detectSegment, name) + >= mapperHelper.getMetricDimensionThresholdConfig()) { + Set preItemDOS = domainResultSet.putIfAbsent(detectSegment, newItemDOs); + if (Objects.nonNull(preItemDOS)) { + preItemDOS.addAll(newItemDOs); + } + } + } + ); + } + } + index = mapperHelper.getStepIndex(regOffsetToLength, index); + } + return domainResultSet; + } + + private Map> getNameToItems(List domains) { + return domains.stream() + .collect(Collectors.toMap(ItemDO::getName, a -> { + Set result = new HashSet<>(); + result.add(a); + return result; + }, (k1, k2) -> { + k1.addAll(k2); + return k1; + })); + } + + private void addToSchemaMapInfo(Map> mapResultRowSet, SchemaMapInfo schemaMap, + SchemaElementType schemaElementType) { + if (Objects.isNull(mapResultRowSet) || mapResultRowSet.size() <= 0) { + return; + } + MapperHelper mapperHelper = ContextUtils.getBean(MapperHelper.class); + + for (Map.Entry> entry : mapResultRowSet.entrySet()) { + String detectWord = entry.getKey(); + Set itemDOS = entry.getValue(); + for (ItemDO itemDO : itemDOS) { + + List elements = schemaMap.getMatchedElements(itemDO.getDomain()); + if (CollectionUtils.isEmpty(elements)) { + elements = new ArrayList<>(); + schemaMap.setMatchedElements(itemDO.getDomain(), elements); + } + Set regElementSet = elements.stream() + .filter(elementMatch -> schemaElementType.equals(elementMatch.getElementType())) + .map(elementMatch -> elementMatch.getElementID()) + .collect(Collectors.toSet()); + + if (regElementSet.contains(itemDO.getItemId())) { + continue; + } + SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() + .elementID(itemDO.getItemId()).word(itemDO.getName()).frequency(10000L) + .elementType(schemaElementType).detectWord(detectWord) + .similarity(mapperHelper.getSimilarity(detectWord, itemDO.getName())) + .build(); + log.info("schemaElementType:{},add to schema, elementMatch {}", schemaElementType, schemaElementMatch); + elements.add(schemaElementMatch); + } + } + + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapper.java index 392e604af..56fc6cb02 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/HanlpSchemaMapper.java @@ -1,17 +1,17 @@ package com.tencent.supersonic.chat.application.mapper; import com.hankcs.hanlp.seg.common.Term; +import com.tencent.supersonic.chat.api.component.SchemaMapper; import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SchemaMapper; import com.tencent.supersonic.chat.application.knowledge.NatureHelper; +import com.tencent.supersonic.chat.domain.pojo.search.MatchText; import com.tencent.supersonic.chat.domain.utils.NatureConverter; import com.tencent.supersonic.common.nlp.MapResult; import com.tencent.supersonic.common.nlp.NatureType; import com.tencent.supersonic.common.util.context.ContextUtils; -import com.tencent.supersonic.common.util.json.JsonUtil; import com.tencent.supersonic.knowledge.application.online.BaseWordNature; import com.tencent.supersonic.knowledge.application.online.WordNatureStrategyFactory; import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper; @@ -19,15 +19,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +@Slf4j public class HanlpSchemaMapper implements SchemaMapper { - private static final Logger LOGGER = LoggerFactory.getLogger(HanlpSchemaMapper.class); - @Override public void map(QueryContextReq queryContext) { @@ -35,22 +34,37 @@ public class HanlpSchemaMapper implements SchemaMapper { .collect(Collectors.toList()); terms.forEach( - item -> LOGGER.info("word:{},nature:{},frequency:{}", item.word, item.nature.toString(), + item -> log.info("word:{},nature:{},frequency:{}", item.word, item.nature.toString(), item.getFrequency()) ); QueryMatchStrategy matchStrategy = ContextUtils.getBean(QueryMatchStrategy.class); - List matches = matchStrategy.match(queryContext.getQueryText(), terms, queryContext.getDomainId()); + Map> matchResult = matchStrategy.match(queryContext.getQueryText(), terms, + queryContext.getDomainId()); + List matches = new ArrayList<>(); + if (Objects.nonNull(matchResult)) { + Optional> first = matchResult.entrySet().stream() + .filter(entry -> CollectionUtils.isNotEmpty(entry.getValue())) + .map(entry -> entry.getValue()).findFirst(); + if (first.isPresent()) { + matches = first.get(); + } + } HanlpHelper.transLetterOriginal(matches); - LOGGER.info("queryContext:{},matches:{}", queryContext, matches); + log.info("queryContext:{},matches:{}", queryContext, matches); - convertTermsToSchemaMapInfo(matches, queryContext.getMapInfo()); + convertTermsToSchemaMapInfo(matches, queryContext.getMapInfo(), terms); } - private void convertTermsToSchemaMapInfo(List mapResults, SchemaMapInfo schemaMap) { + private void convertTermsToSchemaMapInfo(List mapResults, SchemaMapInfo schemaMap, List terms) { if (CollectionUtils.isEmpty(mapResults)) { return; } + + Map wordNatureToFrequency = terms.stream().collect( + Collectors.toMap(entry -> entry.getWord() + entry.getNature(), + term -> Long.valueOf(term.getFrequency()), (value1, value2) -> value2)); + for (MapResult mapResult : mapResults) { for (String nature : mapResult.getNatures()) { Integer domain = NatureHelper.getDomain(nature); @@ -61,17 +75,18 @@ public class HanlpSchemaMapper implements SchemaMapper { if (Objects.isNull(elementType)) { continue; } - SchemaElementMatch schemaElementMatch = new SchemaElementMatch(); - schemaElementMatch.setElementType(elementType); BaseWordNature baseWordNature = WordNatureStrategyFactory.get(NatureType.getNatureType(nature)); Integer elementID = baseWordNature.getElementID(nature); - schemaElementMatch.setElementID(elementID); - Long frequency = baseWordNature.getFrequency(nature); - schemaElementMatch.setFrequency(frequency); - schemaElementMatch.setWord(mapResult.getName()); - schemaElementMatch.setSimilarity(mapResult.getSimilarity()); - schemaElementMatch.setDetectWord(mapResult.getDetectWord()); + Long frequency = wordNatureToFrequency.get(mapResult.getName() + nature); + SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() + .elementType(elementType) + .elementID(elementID) + .frequency(frequency) + .word(mapResult.getName()) + .similarity(mapResult.getSimilarity()) + .detectWord(mapResult.getDetectWord()) + .build(); Map> domainElementMatches = schemaMap.getDomainElementMatches(); List schemaElementMatches = domainElementMatches.putIfAbsent(domain, diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MapperHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MapperHelper.java new file mode 100644 index 000000000..55309da3d --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MapperHelper.java @@ -0,0 +1,83 @@ +package com.tencent.supersonic.chat.application.mapper; + +import com.hankcs.hanlp.algorithm.EditDistance; +import com.tencent.supersonic.chat.application.knowledge.NatureHelper; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * Mapper helper + */ + +@Data +@Service +@Slf4j +public class MapperHelper { + + @Value("${one.detection.size:6}") + private Integer oneDetectionSize; + @Value("${one.detection.max.size:20}") + private Integer oneDetectionMaxSize; + @Value("${metric.dimension.threshold:0.3}") + private Double metricDimensionThresholdConfig; + @Value("${dimension.value.threshold:0.5}") + private Double dimensionValueThresholdConfig; + + public Integer getStepIndex(Map regOffsetToLength, Integer index) { + Integer subRegLength = regOffsetToLength.get(index); + if (Objects.nonNull(subRegLength)) { + index = index + subRegLength; + } else { + index++; + } + return index; + } + + public Integer getStepOffset(List termList, Integer index) { + for (int j = 0; j < termList.size() - 1; j++) { + if (termList.get(j) <= index && termList.get(j + 1) > index) { + return termList.get(j); + } + } + return index; + } + + public double getThresholdMatch(List natures) { + if (existDimensionValues(natures)) { + return dimensionValueThresholdConfig; + } + return metricDimensionThresholdConfig; + } + + /*** + * exist dimension values + * @param natures + * @return + */ + public boolean existDimensionValues(List natures) { + for (String nature : natures) { + if (NatureHelper.isDimensionValueClassId(nature)) { + return true; + } + } + return false; + } + + /*** + * get similarity + * @param detectSegment + * @param matchName + * @return + */ + public double getSimilarity(String detectSegment, String matchName) { + String detectSegmentLower = detectSegment == null ? null : detectSegment.toLowerCase(); + String matchNameLower = matchName == null ? null : matchName.toLowerCase(); + return 1 - (double) EditDistance.compute(detectSegmentLower, matchNameLower) / Math.max(matchName.length(), + detectSegment.length()); + } +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MatchStrategy.java index 9e1348ae4..9b98f9d60 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/MatchStrategy.java @@ -1,8 +1,6 @@ package com.tencent.supersonic.chat.application.mapper; -import com.hankcs.hanlp.algorithm.EditDistance; import com.hankcs.hanlp.seg.common.Term; -import com.tencent.supersonic.chat.application.knowledge.NatureHelper; import com.tencent.supersonic.chat.domain.pojo.search.MatchText; import com.tencent.supersonic.common.nlp.MapResult; import java.util.List; @@ -13,33 +11,6 @@ import java.util.Map; */ public interface MatchStrategy { - List match(String text, List terms, Integer detectDomainId); + Map> match(String text, List terms, Integer detectDomainId); - - Map> matchWithMatchText(String text, List originals, Integer detectDomainId); - - /*** - * exist dimension values - * @param natures - * @return - */ - default boolean existDimensionValues(List natures) { - for (String nature : natures) { - if (NatureHelper.isDimensionValueClassId(nature)) { - return true; - } - } - return false; - } - - /*** - * get similarity - * @param detectSegment - * @param matchName - * @return - */ - default double getSimilarity(String detectSegment, String matchName) { - return 1 - (double) EditDistance.compute(detectSegment, matchName) / Math.max(matchName.length(), - detectSegment.length()); - } } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryFilterMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryFilterMapper.java new file mode 100644 index 000000000..dccf8290b --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryFilterMapper.java @@ -0,0 +1,50 @@ +package com.tencent.supersonic.chat.application.mapper; + +import com.google.common.collect.Lists; +import com.tencent.supersonic.chat.api.component.SchemaMapper; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.request.QueryContextReq; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; +import java.util.List; + + +@Slf4j +public class QueryFilterMapper implements SchemaMapper { + + private Long FREQUENCY = 9999999L; + + private double SIMILARITY = 1.0; + + @Override + public void map(QueryContextReq queryContext) { + Integer domainId = queryContext.getDomainId(); + if (domainId == null || domainId <= 0 || queryContext.getQueryFilter() == null) { + return; + } + QueryFilter queryFilter = queryContext.getQueryFilter(); + SchemaMapInfo schemaMapInfo = queryContext.getMapInfo(); + List schemaElementMatches = schemaMapInfo.getMatchedElements(domainId); + convertFilterToSchemaMapInfo(queryFilter.getFilters(), schemaElementMatches); + } + + private void convertFilterToSchemaMapInfo(List filters, List schemaElementMatches) { + log.info("schemaElementMatches before queryFilerMapper:{}", schemaElementMatches); + if (CollectionUtils.isEmpty(schemaElementMatches)) { + schemaElementMatches = Lists.newArrayList(); + } + for (Filter filter : filters) { + SchemaElementMatch schemaElementMatch = SchemaElementMatch.builder() + .elementType(SchemaElementType.VALUE) + .elementID(filter.getElementID().intValue()) + .frequency(FREQUENCY) + .word(String.valueOf(filter.getValue())) + .similarity(SIMILARITY) + .detectWord(filter.getName()) + .build(); + schemaElementMatches.add(schemaElementMatch); + } + log.info("schemaElementMatches after queryFilerMapper:{}", schemaElementMatches); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryMatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryMatchStrategy.java index 11a689843..86a389a2f 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryMatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/QueryMatchStrategy.java @@ -5,42 +5,34 @@ import com.tencent.supersonic.chat.domain.pojo.search.MatchText; import com.tencent.supersonic.common.nlp.MapResult; import com.tencent.supersonic.common.nlp.NatureType; import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - 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.Objects; import java.util.Set; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * match strategy implement */ @Service +@Slf4j public class QueryMatchStrategy implements MatchStrategy { - private static final Logger LOGGER = LoggerFactory.getLogger(QueryMatchStrategy.class); - public static final double STEP = 0.1; - @Value("${one.detection.size:6}") - private Integer oneDetectionSize; - @Value("${one.detection.max.size:20}") - private Integer oneDetectionMaxSize; - @Value("${metric.dimension.threshold:0.3}") - private Double metricDimensionThresholdConfig; - @Value("${dimension.value.threshold:0.5}") - private Double dimensionValueThresholdConfig; + @Autowired + private MapperHelper mapperHelper; @Override - public List match(String text, List terms, Integer detectDomainId) { + public Map> match(String text, List terms, Integer detectDomainId) { if (CollectionUtils.isEmpty(terms) || StringUtils.isEmpty(text)) { return null; } @@ -50,17 +42,14 @@ public class QueryMatchStrategy implements MatchStrategy { List offsetList = terms.stream().sorted(Comparator.comparing(Term::getOffset)) .map(term -> term.getOffset()).collect(Collectors.toList()); - LOGGER.debug("retryCount:{},terms:{},regOffsetToLength:{},offsetList:{},detectDomainId:{}", terms, + log.debug("retryCount:{},terms:{},regOffsetToLength:{},offsetList:{},detectDomainId:{}", terms, regOffsetToLength, offsetList, detectDomainId); - return detect(text, regOffsetToLength, offsetList, detectDomainId); - } - - @Override - public Map> matchWithMatchText(String text, List originals, - Integer detectDomainId) { - - return null; + List detects = detect(text, regOffsetToLength, offsetList, detectDomainId); + Map> result = new HashMap<>(); + MatchText matchText = new MatchText(text, text); + result.put(matchText, detects); + return result; } private List detect(String text, Map regOffsetToLength, List offsetList, @@ -72,15 +61,15 @@ public class QueryMatchStrategy implements MatchStrategy { Set mapResultRowSet = new LinkedHashSet(); for (Integer i = index; i <= text.length(); ) { - int offset = getStepOffset(offsetList, index); - i = getStepIndex(regOffsetToLength, i); + int offset = mapperHelper.getStepOffset(offsetList, index); + i = mapperHelper.getStepIndex(regOffsetToLength, i); if (i <= text.length()) { List mapResults = detectByStep(text, detectDomainId, index, i, offset); mapResultRowSet.addAll(mapResults); } } - index = getStepIndex(regOffsetToLength, index); + index = mapperHelper.getStepIndex(regOffsetToLength, index); results.addAll(mapResultRowSet); } return results; @@ -88,11 +77,13 @@ public class QueryMatchStrategy implements MatchStrategy { private List detectByStep(String text, Integer detectDomainId, Integer index, Integer i, int offset) { String detectSegment = text.substring(index, i); + Integer oneDetectionSize = mapperHelper.getOneDetectionSize(); // step1. pre search - LinkedHashSet mapResults = Suggester.prefixSearch(detectSegment, oneDetectionMaxSize) + LinkedHashSet mapResults = Suggester.prefixSearch(detectSegment, + mapperHelper.getOneDetectionMaxSize()) .stream().collect(Collectors.toCollection(LinkedHashSet::new)); // step2. suffix search - LinkedHashSet suffixMapResults = Suggester.suffixSearch(detectSegment, oneDetectionMaxSize) + LinkedHashSet suffixMapResults = Suggester.suffixSearch(detectSegment, oneDetectionSize) .stream().collect(Collectors.toCollection(LinkedHashSet::new)); mapResults.addAll(suffixMapResults); @@ -105,7 +96,7 @@ public class QueryMatchStrategy implements MatchStrategy { .collect(Collectors.toCollection(LinkedHashSet::new)); // step4. filter by classId if (Objects.nonNull(detectDomainId) && detectDomainId > 0) { - LOGGER.debug("detectDomainId:{}, before parseResults:{}", mapResults); + log.debug("detectDomainId:{}, before parseResults:{}", mapResults); mapResults = mapResults.stream().map(entry -> { List natures = entry.getNatures().stream().filter( nature -> nature.startsWith(NatureType.NATURE_SPILT + detectDomainId) || (nature.startsWith( @@ -114,25 +105,27 @@ public class QueryMatchStrategy implements MatchStrategy { entry.setNatures(natures); return entry; }).collect(Collectors.toCollection(LinkedHashSet::new)); - LOGGER.info("after domainId parseResults:{}", mapResults); + log.info("after domainId parseResults:{}", mapResults); } // step5. filter by similarity mapResults = mapResults.stream() - .filter(term -> getSimilarity(detectSegment, term.getName()) >= getThresholdMatch(term.getNatures())) + .filter(term -> mapperHelper.getSimilarity(detectSegment, term.getName()) + >= mapperHelper.getThresholdMatch(term.getNatures())) .filter(term -> CollectionUtils.isNotEmpty(term.getNatures())) .collect(Collectors.toCollection(LinkedHashSet::new)); - LOGGER.debug("metricDimensionThreshold:{},dimensionValueThreshold:{},after isSimilarity parseResults:{}", + log.debug("metricDimensionThreshold:{},dimensionValueThreshold:{},after isSimilarity parseResults:{}", mapResults); mapResults = mapResults.stream().map(parseResult -> { parseResult.setOffset(offset); - parseResult.setSimilarity(getSimilarity(detectSegment, parseResult.getName())); + parseResult.setSimilarity(mapperHelper.getSimilarity(detectSegment, parseResult.getName())); return parseResult; }).collect(Collectors.toCollection(LinkedHashSet::new)); // step6. take only one dimension or 10 metric/dimension value per rond. - List dimensionMetrics = mapResults.stream().filter(entry -> existDimensionValues(entry.getNatures())) + List dimensionMetrics = mapResults.stream() + .filter(entry -> mapperHelper.existDimensionValues(entry.getNatures())) .collect(Collectors.toList()) .stream() .limit(1) @@ -144,31 +137,4 @@ public class QueryMatchStrategy implements MatchStrategy { return mapResults.stream().limit(oneDetectionSize).collect(Collectors.toList()); } } - - private Integer getStepIndex(Map regOffsetToLength, Integer index) { - Integer subRegLength = regOffsetToLength.get(index); - if (Objects.nonNull(subRegLength)) { - index = index + subRegLength; - } else { - index++; - } - return index; - } - - private Integer getStepOffset(List termList, Integer index) { - for (int j = 0; j < termList.size() - 1; j++) { - if (termList.get(j) <= index && termList.get(j + 1) > index) { - return termList.get(j); - } - } - return index; - } - - private double getThresholdMatch(List natures) { - if (existDimensionValues(natures)) { - return dimensionValueThresholdConfig; - } - return metricDimensionThresholdConfig; - } - } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/SearchMatchStrategy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/SearchMatchStrategy.java index 8e7c57013..38c449a8e 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/SearchMatchStrategy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/mapper/SearchMatchStrategy.java @@ -23,15 +23,8 @@ public class SearchMatchStrategy implements MatchStrategy { private static final int SEARCH_SIZE = 3; - @Override - public List match(String text, List terms, Integer detectDomainId) { - - return null; - } - - @Override - public Map> matchWithMatchText(String text, List originals, + public Map> match(String text, List originals, Integer detectDomainId) { Map regOffsetToLength = originals.stream() diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/AggregateSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/AggregateSemanticParser.java index 6a6c9d092..9a9940c45 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/AggregateSemanticParser.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/AggregateSemanticParser.java @@ -1,59 +1,82 @@ package com.tencent.supersonic.chat.application.parser; +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.component.SemanticQuery; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticParser; -import com.tencent.supersonic.chat.application.parser.resolver.AggregateTypeResolver; -import com.tencent.supersonic.chat.application.query.MetricCompare; -import com.tencent.supersonic.chat.application.query.MetricFilter; +import com.tencent.supersonic.chat.application.query.EntityListFilter; import com.tencent.supersonic.chat.application.query.MetricGroupBy; import com.tencent.supersonic.chat.application.query.MetricOrderBy; import com.tencent.supersonic.common.enums.AggregateTypeEnum; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.common.util.context.ContextUtils; -import java.util.List; -import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.extern.slf4j.Slf4j; -@Component +@Slf4j public class AggregateSemanticParser implements SemanticParser { - private final Logger logger = LoggerFactory.getLogger(AggregateSemanticParser.class); public static final Integer TOPN_LIMIT = 1000; - private AggregateTypeResolver aggregateTypeResolver; + private static Map aggregateRegexMap = new HashMap<>(); + + static { + aggregateRegexMap.put(AggregateTypeEnum.MAX, Pattern.compile("(?i)(最大值|最大|max|峰值|最高|最多)")); + aggregateRegexMap.put(AggregateTypeEnum.MIN, Pattern.compile("(?i)(最小值|最小|min|最低|最少)")); + aggregateRegexMap.put(AggregateTypeEnum.SUM, Pattern.compile("(?i)(汇总|总和|sum)")); + aggregateRegexMap.put(AggregateTypeEnum.AVG, Pattern.compile("(?i)(平均值|日均|平均|avg)")); + aggregateRegexMap.put(AggregateTypeEnum.TOPN, Pattern.compile("(?i)(top)")); + aggregateRegexMap.put(AggregateTypeEnum.DISTINCT, Pattern.compile("(?i)(uv)")); + aggregateRegexMap.put(AggregateTypeEnum.COUNT, Pattern.compile("(?i)(总数|pv)")); + aggregateRegexMap.put(AggregateTypeEnum.NONE, Pattern.compile("(?i)(明细)")); + } + + public static AggregateTypeEnum resolveAggregateType(String queryText) { + + Map aggregateCount = new HashMap<>(aggregateRegexMap.size()); + for (Map.Entry entry : aggregateRegexMap.entrySet()) { + Matcher matcher = entry.getValue().matcher(queryText); + int count = 0; + while (matcher.find()) { + count++; + } + if (count > 0) { + aggregateCount.put(entry.getKey(), count); + } + } + + return aggregateCount.entrySet().stream().max(Map.Entry.comparingByValue()).map(entry -> entry.getKey()) + .orElse(null); + } @Override - public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) { - aggregateTypeResolver = ContextUtils.getBean(AggregateTypeResolver.class); + public void parse(QueryContextReq queryContext, ChatContext chatContext) { + AggregateTypeEnum aggregateType = resolveAggregateType(queryContext.getQueryText()); - AggregateTypeEnum aggregateType = aggregateTypeResolver.resolve(queryContext.getQueryText()); + for (SemanticQuery semanticQuery : queryContext.getCandidateQueries()) { + SemanticParseInfo semanticParse = semanticQuery.getParseInfo(); - SemanticParseInfo semanticParse = queryContext.getParseInfo(); - - Set metrics = semanticParse.getMetrics(); - - semanticParse.setNativeQuery(getNativeQuery(aggregateType, queryContext)); - - semanticParse.setAggType(aggregateType); - //semanticParse.setOrders(getOrder(aggregateType, metrics)); - semanticParse.setLimit(Long.valueOf(TOPN_LIMIT)); - resetQueryModeByAggregateType(queryContext, aggregateType); - return false; + semanticParse.setNativeQuery(getNativeQuery(aggregateType, semanticParse)); + semanticParse.setAggType(aggregateType); + if (Objects.isNull(semanticParse.getLimit()) || semanticParse.getLimit() <= 0) { + semanticParse.setLimit(Long.valueOf(TOPN_LIMIT)); + } + resetQueryModeByAggregateType(semanticParse, aggregateType); + } } /** * query mode reset by the AggregateType * - * @param queryContext + * @param parseInfo * @param aggregateType */ - private void resetQueryModeByAggregateType(QueryContextReq queryContext, AggregateTypeEnum aggregateType) { + private void resetQueryModeByAggregateType(SemanticParseInfo parseInfo, + AggregateTypeEnum aggregateType) { - SemanticParseInfo parseInfo = queryContext.getParseInfo(); String queryMode = parseInfo.getQueryMode(); if (MetricGroupBy.QUERY_MODE.equals(queryMode) || MetricGroupBy.QUERY_MODE.equals(queryMode)) { if (AggregateTypeEnum.MAX.equals(aggregateType) || AggregateTypeEnum.MIN.equals(aggregateType) @@ -62,23 +85,18 @@ public class AggregateSemanticParser implements SemanticParser { } else { parseInfo.setQueryMode(MetricGroupBy.QUERY_MODE); } + log.info("queryMode mode [{}]->[{}]", queryMode, parseInfo.getQueryMode()); } - if (MetricFilter.QUERY_MODE.equals(queryMode) || MetricCompare.QUERY_MODE.equals(queryMode)) { - if (aggregateTypeResolver.hasCompareIntentionalWords(queryContext.getQueryText())) { - parseInfo.setQueryMode(MetricCompare.QUERY_MODE); - } else { - parseInfo.setQueryMode(MetricFilter.QUERY_MODE); - } - } - logger.info("queryMode mode [{}]->[{}]", queryMode, parseInfo.getQueryMode()); } - private boolean getNativeQuery(AggregateTypeEnum aggregateType, QueryContextReq queryContext) { + private boolean getNativeQuery(AggregateTypeEnum aggregateType, SemanticParseInfo semanticParse) { if (AggregateTypeEnum.TOPN.equals(aggregateType)) { return true; } - return queryContext.getParseInfo().getNativeQuery(); + if (EntityListFilter.QUERY_MODE.equals(semanticParse.getQueryMode()) && (semanticParse.getMetrics() == null + || semanticParse.getMetrics().isEmpty())) { + return true; + } + return semanticParse.getNativeQuery(); } - - } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/DomainResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainResolver.java similarity index 59% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/DomainResolver.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainResolver.java index 9c32fcd38..b3ca4e295 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/DomainResolver.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainResolver.java @@ -1,10 +1,12 @@ -package com.tencent.supersonic.chat.application.parser.resolver; +package com.tencent.supersonic.chat.application.parser; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticQuery; +import com.tencent.supersonic.chat.api.component.SemanticQuery; + import java.util.Map; public interface DomainResolver { @@ -12,6 +14,6 @@ public interface DomainResolver { Integer resolve(Map domainQueryModes, QueryContextReq queryCtx, ChatContext chatCtx, SchemaMapInfo schemaMap); - boolean isDomainSwitch(ChatContext chatCtx, QueryContextReq queryCtx); + boolean isDomainSwitch(ChatContext chatCtx, SemanticParseInfo semanticParseInfo); } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainSemanticParser.java index 10d5db455..32cb52923 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainSemanticParser.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DomainSemanticParser.java @@ -1,125 +1,111 @@ package com.tencent.supersonic.chat.application.parser; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.*; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticLayer; -import com.tencent.supersonic.chat.api.service.SemanticParser; -import com.tencent.supersonic.chat.api.service.SemanticQuery; -import com.tencent.supersonic.chat.application.parser.resolver.DomainResolver; -import com.tencent.supersonic.chat.application.parser.resolver.SemanticQueryResolver; +import com.tencent.supersonic.chat.application.query.*; import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; +import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; +import com.tencent.supersonic.chat.domain.utils.*; +import com.tencent.supersonic.common.pojo.SchemaItem; import com.tencent.supersonic.common.util.context.ContextUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; -@Component +@Slf4j public class DomainSemanticParser implements SemanticParser { - private final Logger logger = LoggerFactory.getLogger(DomainSemanticParser.class); - private List domainResolverList; - - private SemanticQueryResolver semanticQueryResolver; - - public DomainSemanticParser() { - domainResolverList = SpringFactoriesLoader.loadFactories(DomainResolver.class, - Thread.currentThread().getContextClassLoader()); - } + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); @Override - public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) { - DomainInfos domainInfosDb = SchemaInfoConverter.convert( - ContextUtils.getBean(SemanticLayer.class).getDomainSchemaInfo(new ArrayList<>())); + public void parse(QueryContextReq queryContext, ChatContext chatContext) { + DomainInfos domainInfosDb = SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>())); Map domainToName = domainInfosDb.getDomainToName(); - SchemaMapInfo mapInfo = queryContext.getMapInfo(); - SemanticParseInfo parseInfo = queryContext.getParseInfo(); - //domainResolver = ContextUtils.getBean(DomainResolver.class); - semanticQueryResolver = ContextUtils.getBean(SemanticQueryResolver.class); - - Map domainSemanticQuery = new HashMap<>(); - // Round 1: find all domains that can be resolved to any query mode - - for (Integer domain : mapInfo.getMatchedDomains()) { - List elementMatches = mapInfo.getMatchedElements(domain); - - SemanticQuery query = semanticQueryResolver.resolve(elementMatches, queryContext); - - if (Objects.nonNull(query)) { - domainSemanticQuery.put(domain, query); + // iterate all schemaElementMatches to resolve semantic query + for (Integer domainId : mapInfo.getMatchedDomains()) { + List elementMatches = mapInfo.getMatchedElements(domainId); + Map> queryMatches = resolveQuery(elementMatches, queryContext); + for (Map.Entry> match : queryMatches.entrySet()) { + addCandidateQuery(queryContext, chatContext, domainId.longValue(), + domainToName.get(domainId), match.getKey(), match.getValue()); } } - // only one domain is found, no need to rank - if (domainSemanticQuery.size() == 1) { - Optional> match = domainSemanticQuery.entrySet().stream().findFirst(); - if (match.isPresent()) { - logger.info("select by only one [{}:{}]", match.get().getKey(), match.get().getValue()); - parseInfo.setDomainId(Long.valueOf(match.get().getKey())); - parseInfo.setDomainName(domainToName.get(Integer.valueOf(match.get().getKey()))); - parseInfo.setQueryMode(match.get().getValue().getQueryMode()); - return false; - } - } else if (domainSemanticQuery.size() > 1) { - // will choose one by the domain select - Optional domainId = domainResolverList.stream() - .map(domainResolver -> domainResolver.resolve(domainSemanticQuery, queryContext, chatCtx, mapInfo)) - .filter(d -> d > 0).findFirst(); - if (domainId.isPresent() && domainId.get() > 0) { - for (Map.Entry match : domainSemanticQuery.entrySet()) { - if (match.getKey().equals(domainId.get())) { - logger.info("select by selectStrategy [{}:{}]", domainId.get(), match.getValue()); - parseInfo.setDomainId(Long.valueOf(match.getKey())); - parseInfo.setDomainName(domainToName.get(Integer.valueOf(match.getKey()))); - parseInfo.setQueryMode(match.getValue().getQueryMode()); - return false; + + // if no candidates have been found yet, count in chat context and try again + if (queryContext.getCandidateQueries().size() <= 0) { + if (chatContext.getParseInfo() != null && chatContext.getParseInfo().getDomainId() > 0) { + Integer chatDomainId = Integer.valueOf(chatContext.getParseInfo().getDomainId().intValue()); + if (mapInfo.getMatchedDomains().contains(chatDomainId)) { + List elementMatches = mapInfo.getMatchedElements(chatDomainId); + detectionContext(chatContext); + Map> queryMatches = tryParseByContext(elementMatches, + chatContext, queryContext); + for (Map.Entry> match : queryMatches.entrySet()) { + addCandidateQuery(queryContext, chatContext, chatDomainId.longValue(), + domainToName.get(chatDomainId), match.getKey(), match.getValue()); } } } } - // Round 2: no domains can be found yet, count in chat context - if (chatCtx.getParseInfo() != null && chatCtx.getParseInfo().getDomainId() > 0) { - Integer chatDomain = Integer.valueOf(chatCtx.getParseInfo().getDomainId().intValue()); - if (mapInfo.getMatchedDomains().contains(chatDomain) || CollectionUtils.isEmpty( - mapInfo.getMatchedDomains())) { - List elementMatches = mapInfo.getMatchedElements(chatDomain); - if (CollectionUtils.isEmpty(elementMatches)) { - parseInfo.setDomainId(Long.valueOf(chatDomain)); - parseInfo.setDomainName(domainToName.get(chatDomain)); - parseInfo.setQueryMode(chatCtx.getParseInfo().getQueryMode()); - return false; - } - - SemanticQuery query = tryParseByContext(elementMatches, chatCtx, queryContext); - if (Objects.nonNull(query)) { - logger.info("select by context count [{}:{}]", chatDomain, query); - parseInfo.setDomainId(Long.valueOf(chatDomain)); - parseInfo.setDomainName(domainToName.get(chatDomain)); - parseInfo.setQueryMode(query.getQueryMode()); - return false; - } - } - } - // Round 3: no domains can be found yet, count in default metric - return false; } + private void addCandidateQuery(QueryContextReq queryContext, ChatContext chatContext, + Long domainId, String domainName, + RuleSemanticQuery semanticQuery, List elementMatches) { + if (semanticQuery != null) { + fillParseInfo(semanticQuery, domainId, domainName, elementMatches); + // inherit from context + inheritContext(semanticQuery, chatContext); + // default metric, date, dimension + injectDefaultMetric(semanticQuery, queryContext, chatContext); + queryContext.getCandidateQueries().add(semanticQuery); + } + } + + protected void inheritContext(RuleSemanticQuery semanticQuery, ChatContext chatContext) { + // is domain switch + SemanticParseInfo semanticParse = semanticQuery.getParseInfo(); + DomainResolver domainResolver = ComponentFactory.getDomainResolver(); + if (!domainResolver.isDomainSwitch(chatContext, semanticParse)) { + semanticQuery.inheritContext(chatContext); + } + } + + protected void injectDefaultMetric(RuleSemanticQuery semanticQuery, QueryContextReq queryContext, + ChatContext chatContext) { + DefaultMetricUtils defaultMetricUtils = ContextUtils.getBean(DefaultMetricUtils.class); + defaultMetricUtils.injectDefaultMetric(semanticQuery.getParseInfo(), queryContext, chatContext); + } + + /** + * get the chatContext for the tryParseByContext + * + * @param chatContext + */ + protected void detectionContext(ChatContext chatContext) { + if (chatContext.getParseInfo() != null) { + SemanticParseInfo semanticParseInfo = chatContext.getParseInfo(); + if (semanticParseInfo.getQueryMode().equals(EntityDetail.QUERY_MODE)) { + // EntityDetail model will unset some items + semanticParseInfo.setDateInfo(null); + semanticParseInfo.setMetrics(new HashSet<>()); + semanticParseInfo.setDimensions(new HashSet<>()); + } + } + } /** * try to add ChatContext to SchemaElementMatch and look if match QueryMode @@ -128,8 +114,8 @@ public class DomainSemanticParser implements SemanticParser { * @param chatCtx * @return */ - private SemanticQuery tryParseByContext(List elementMatches, ChatContext chatCtx, - QueryContextReq searchCt) { + private Map> tryParseByContext(List elementMatches, + ChatContext chatCtx, QueryContextReq queryCtx) { if (chatCtx.getParseInfo() != null && chatCtx.getParseInfo().getEntity() > 0) { Long entityCount = elementMatches.stream().filter(i -> SchemaElementType.ENTITY.equals(i.getElementType())) .count(); @@ -137,27 +123,29 @@ public class DomainSemanticParser implements SemanticParser { .count(); if (entityCount <= 0 && metricCount <= 0 && ContextHelper.hasEntityId(chatCtx)) { // try entity parse - SchemaElementMatch entityElementMatch = new SchemaElementMatch(); - entityElementMatch.setElementType(SchemaElementType.ENTITY); + SchemaElementMatch entityElementMatch = SchemaElementMatch.builder() + .elementType(SchemaElementType.ENTITY).build(); List newSchemaElementMatch = new ArrayList<>(); if (!CollectionUtils.isEmpty(elementMatches)) { newSchemaElementMatch.addAll(elementMatches); } newSchemaElementMatch.add(entityElementMatch); - SemanticQuery semanticQuery = doParseByContext(newSchemaElementMatch, chatCtx, searchCt); - if (Objects.nonNull(semanticQuery)) { - return semanticQuery; + Map> queryMatches = doParseByContext(newSchemaElementMatch, + chatCtx, queryCtx); + if (queryMatches.size() > 0) { + return queryMatches; } } } - return doParseByContext(elementMatches, chatCtx, searchCt); + return doParseByContext(elementMatches, chatCtx, queryCtx); } - private SemanticQuery doParseByContext(List elementMatches, ChatContext chatCtx, - QueryContextReq searchCt) { - SemanticParseInfo contextSemanticParseInfo = chatCtx.getParseInfo(); - if (contextSemanticParseInfo != null) { - List newSchemaElementMatch = new ArrayList<>(); + + private Map> doParseByContext(List elementMatches, + ChatContext chatCtx, QueryContextReq queryCtx) { + SemanticParseInfo contextSemanticParse = chatCtx.getParseInfo(); + if (contextSemanticParse != null) { + List newElementMatches = new ArrayList<>(); List> trySchemaElementTypes = new LinkedList<>(); // try DIMENSION+METRIC+VALUE // try DIMENSION+METRIC METRIC+VALUE DIMENSION+VALUE @@ -175,18 +163,122 @@ public class DomainSemanticParser implements SemanticParser { trySchemaElementTypes.add(new ArrayList<>(Arrays.asList(SchemaElementType.DIMENSION))); for (List schemaElementTypes : trySchemaElementTypes) { - newSchemaElementMatch.clear(); + newElementMatches.clear(); if (!CollectionUtils.isEmpty(elementMatches)) { - newSchemaElementMatch.addAll(elementMatches); + newElementMatches.addAll(elementMatches); } - ContextHelper.mergeContextSchemaElementMatch(newSchemaElementMatch, elementMatches, schemaElementTypes, - contextSemanticParseInfo); - SemanticQuery semanticQuery = semanticQueryResolver.resolve(newSchemaElementMatch, searchCt); - if (semanticQuery != null) { - return semanticQuery; + ContextHelper.mergeContextSchemaElementMatch(newElementMatches, elementMatches, schemaElementTypes, + contextSemanticParse); + Map> queryMatches = resolveQuery(newElementMatches, + queryCtx); + if (queryMatches.size() > 0) { + return queryMatches; } } } - return null; + return new HashMap<>(); } -} + + private Map> resolveQuery(List elementMatches, + QueryContextReq queryCtx) { + Map> matchMap = new HashMap<>(); + + for (RuleSemanticQuery semanticQuery : RuleSemanticQueryManager.getSemanticQueries()) { + List matches = semanticQuery.match(elementMatches, queryCtx); + + if (matches.size() > 0) { + log.info("resolve match [{}:{}] ", semanticQuery.getQueryMode(), matches.size()); + matchMap.put(RuleSemanticQueryManager.create(semanticQuery.getQueryMode()), matches); + } + } + + return matchMap; + } + + public void fillParseInfo(SemanticQuery query, Long domainId, String domainName, + List elementMatches) { + SemanticParseInfo parseInfo = query.getParseInfo(); + parseInfo.setDomainId(domainId); + parseInfo.setDomainName(domainName); + parseInfo.setQueryMode(query.getQueryMode()); + parseInfo.getElementMatches().addAll(elementMatches); + + DefaultSemanticInternalUtils defaultSemanticUtils = ContextUtils.getBean(DefaultSemanticInternalUtils.class); + SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + + DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(parseInfo.getDomainId()); + ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(parseInfo.getDomainId()); + Map dimensionDescMap = domainSchemaDesc.getDimensions().stream() + .collect(Collectors.toMap(DimSchemaResp::getId, Function.identity())); + Map metricDescMap = domainSchemaDesc.getMetrics().stream() + .collect(Collectors.toMap(MetricSchemaResp::getId, Function.identity())); + Map> dim2Values = new HashMap<>(); + + for (SchemaElementMatch schemaElementMatch : elementMatches) { + Long elementID = Long.valueOf(schemaElementMatch.getElementID()); + switch (schemaElementMatch.getElementType()) { + case ID: + case VALUE: + if (dimensionDescMap.containsKey(elementID)) { + if (dim2Values.containsKey(elementID)) { + dim2Values.get(elementID).add(schemaElementMatch); + } else { + dim2Values.put(elementID, new ArrayList<>(Arrays.asList(schemaElementMatch))); + } + } + break; + case DIMENSION: + DimSchemaResp dimensionDesc = dimensionDescMap.get(elementID); + if (dimensionDesc != null) { + SchemaItem dimensionParseInfo = new SchemaItem(); + dimensionParseInfo.setBizName(dimensionDesc.getBizName()); + dimensionParseInfo.setName(dimensionDesc.getName()); + dimensionParseInfo.setId(dimensionDesc.getId()); + parseInfo.getDimensions().add(dimensionParseInfo); + } + break; + case METRIC: + MetricSchemaResp metricDesc = metricDescMap.get(elementID); + if (metricDesc != null) { + SchemaItem metricItem = new SchemaItem(); + metricItem.setBizName(metricDesc.getBizName()); + metricItem.setName(metricDesc.getName()); + metricItem.setId(metricDesc.getId()); + metricItem.setCreatedAt(null); + metricItem.setUpdatedAt(null); + parseInfo.getMetrics().add(metricItem); + } + break; + default: + } + } + + if (!dim2Values.isEmpty()) { + for (Map.Entry> entry : dim2Values.entrySet()) { + DimSchemaResp dimensionDesc = dimensionDescMap.get(entry.getKey()); + if (entry.getValue().size() == 1) { + SchemaElementMatch schemaElementMatch = entry.getValue().get(0); + Filter dimensionFilter = new Filter(); + dimensionFilter.setValue(schemaElementMatch.getWord()); + dimensionFilter.setBizName(dimensionDesc.getBizName()); + dimensionFilter.setName(dimensionDesc.getName()); + dimensionFilter.setOperator(FilterOperatorEnum.EQUALS); + dimensionFilter.setElementID(Long.valueOf(schemaElementMatch.getElementID())); + parseInfo.getDimensionFilters().add(dimensionFilter); + ContextHelper.setEntityId(entry.getKey(), schemaElementMatch.getWord(), chaConfigRichDesc, + parseInfo); + } else { + Filter dimensionFilter = new Filter(); + List vals = new ArrayList<>(); + entry.getValue().stream().forEach(i -> vals.add(i.getWord())); + dimensionFilter.setValue(vals); + dimensionFilter.setBizName(dimensionDesc.getBizName()); + dimensionFilter.setName(dimensionDesc.getName()); + dimensionFilter.setOperator(FilterOperatorEnum.IN); + dimensionFilter.setElementID(entry.getKey()); + parseInfo.getDimensionFilters().add(dimensionFilter); + } + } + } + } +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/BaseDomainResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/HeuristicDomainResolver.java similarity index 57% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/BaseDomainResolver.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/HeuristicDomainResolver.java index 62edf7521..1b781be17 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/BaseDomainResolver.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/HeuristicDomainResolver.java @@ -1,36 +1,117 @@ -package com.tencent.supersonic.chat.application.parser.resolver; +package com.tencent.supersonic.chat.application.parser; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaElementCount; -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.*; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticQuery; +import com.tencent.supersonic.chat.api.component.SemanticQuery; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; -@Slf4j -public abstract class BaseDomainResolver implements DomainResolver { +import java.util.*; +import java.util.stream.Collectors; - @Override - public boolean isDomainSwitch(ChatContext chatCtx, QueryContextReq searchCtx) { - Long contextDomain = chatCtx.getParseInfo().getDomainId(); - Long currentDomain = searchCtx.getParseInfo().getDomainId(); - boolean noSwitch = currentDomain == null || contextDomain == null || contextDomain.equals(currentDomain); - log.info("ChatContext isDomainSwitch [{}]", !noSwitch); - return !noSwitch; +@Slf4j +public class HeuristicDomainResolver implements DomainResolver { + + protected static Integer selectDomainBySchemaElementCount(Map domainQueryModes, + SchemaMapInfo schemaMap) { + Map domainTypeMap = getDomainTypeMap(schemaMap); + if (domainTypeMap.size() == 1) { + Integer domainSelect = domainTypeMap.entrySet().stream().collect(Collectors.toList()).get(0).getKey(); + if (domainQueryModes.containsKey(domainSelect)) { + log.info("selectDomain from domainTypeMap not order [{}]", domainSelect); + return domainSelect; + } + } else { + Map.Entry maxDomain = domainTypeMap.entrySet().stream() + .filter(entry -> domainQueryModes.containsKey(entry.getKey())) + .sorted(ContextHelper.DomainStatComparator).findFirst().orElse(null); + if (maxDomain != null) { + log.info("selectDomain from domainTypeMap order [{}]", maxDomain.getKey()); + return maxDomain.getKey(); + } + } + return 0; } - public abstract Integer selectDomain(Map domainQueryModes, QueryContextReq searchCtx, - ChatContext chatCtx, SchemaMapInfo schemaMap); + /** + * to check can switch domain if context exit domain + * + * @return false will use context domain, true will use other domain , maybe include context domain + */ + protected static boolean isAllowSwitch(Map domainQueryModes, SchemaMapInfo schemaMap, + ChatContext chatCtx, QueryContextReq searchCtx, Integer domainId) { + if (!Objects.nonNull(domainId) || domainId <= 0) { + return true; + } + // except content domain, calculate the number of types for each domain, if numbers<=1 will not switch + Map domainTypeMap = getDomainTypeMap(schemaMap); + log.info("isAllowSwitch domainTypeMap [{}]", domainTypeMap); + long otherDomainTypeNumBigOneCount = domainTypeMap.entrySet().stream() + .filter(entry -> domainQueryModes.containsKey(entry.getKey()) && !entry.getKey().equals(domainId)) + .filter(entry -> entry.getValue().getCount() > 1).count(); + if (otherDomainTypeNumBigOneCount >= 1) { + return true; + } + // if query text only contain time , will not switch + for (SemanticQuery semanticQuery : domainQueryModes.values()) { + SemanticParseInfo semanticParseInfo = semanticQuery.getParseInfo(); + if (semanticParseInfo == null) { + continue; + } + if (searchCtx.getQueryText() != null && semanticParseInfo.getDateInfo() != null) { + if (semanticParseInfo.getDateInfo().getText() != null) { + if (semanticParseInfo.getDateInfo().getText().equalsIgnoreCase(searchCtx.getQueryText())) { + log.info("timeParseResults is not null , can not switch context , timeParseResults:{},", + semanticParseInfo.getDateInfo()); + return false; + } + } + } + } + + // if context domain not in schemaMap , will switch + if (schemaMap.getMatchedElements(domainId) == null || schemaMap.getMatchedElements(domainId).size() <= 0) { + log.info("domainId not in schemaMap "); + return true; + } + // other will not switch + return false; + } + + public static Map getDomainTypeMap(SchemaMapInfo schemaMap) { + Map domainCount = new HashMap<>(); + for (Map.Entry> entry : schemaMap.getDomainElementMatches().entrySet()) { + List schemaElementMatches = schemaMap.getMatchedElements(entry.getKey()); + if (schemaElementMatches != null && schemaElementMatches.size() > 0) { + if (!domainCount.containsKey(entry.getKey())) { + domainCount.put(entry.getKey(), new QueryMatchInfo()); + } + QueryMatchInfo queryMatchInfo = domainCount.get(entry.getKey()); + Set schemaElementTypes = new HashSet<>(); + schemaElementMatches.stream() + .forEach(schemaElementMatch -> schemaElementTypes.add(schemaElementMatch.getElementType())); + SchemaElementMatch schemaElementMatchMax = schemaElementMatches.stream() + .sorted(ContextHelper.schemaElementMatchComparatorBySimilarity).findFirst().orElse(null); + if (schemaElementMatchMax != null) { + queryMatchInfo.setMaxSimilarity(schemaElementMatchMax.getSimilarity()); + } + queryMatchInfo.setCount(schemaElementTypes.size()); + + } + } + return domainCount; + } + + @Override + public boolean isDomainSwitch(ChatContext chatCtx, SemanticParseInfo semanticParseInfo) { + Long contextDomain = chatCtx.getParseInfo().getDomainId(); + Long currentDomain = semanticParseInfo.getDomainId(); + boolean noSwitch = + currentDomain == null || contextDomain == null || contextDomain.equals(currentDomain); + log.debug("ChatContext isDomainSwitch [{}] [{}]", + semanticParseInfo.getQueryMode(), !noSwitch); + return !noSwitch; + } @Override public Integer resolve(Map domainQueryModes, QueryContextReq searchCtx, @@ -44,88 +125,23 @@ public abstract class BaseDomainResolver implements DomainResolver { return selectDomainBySchemaElementCount(domainQueryModes, schemaMap); } - protected static Integer selectDomainBySchemaElementCount(Map domainQueryModes, + public Integer selectDomain(Map domainQueryModes, QueryContextReq searchCtx, + ChatContext chatCtx, SchemaMapInfo schemaMap) { - Map domainTypeMap = getDomainTypeMap(schemaMap); - if (domainTypeMap.size() == 1) { - Integer domainSelect = domainTypeMap.entrySet().stream().collect(Collectors.toList()).get(0).getKey(); - if (domainQueryModes.containsKey(domainSelect)) { - log.info("selectDomain from domainTypeMap not order [{}]", domainSelect); - return domainSelect; - } - } else { - Map.Entry maxDomain = domainTypeMap.entrySet().stream() - .filter(entry -> domainQueryModes.containsKey(entry.getKey())) - .sorted(ContextHelper.DomainStatComparator).findFirst().orElse(null); - if (maxDomain != null) { - log.info("selectDomain from domainTypeMap order [{}]", maxDomain.getKey()); - return maxDomain.getKey(); + // if QueryContext has domainId and in domainQueryModes + if (domainQueryModes.containsKey(searchCtx.getDomainId())) { + log.info("selectDomain from QueryContext [{}]", searchCtx.getDomainId()); + return searchCtx.getDomainId(); + } + // if ChatContext has domainId and in domainQueryModes + if (chatCtx.getParseInfo().getDomainId() > 0) { + Integer domainId = Integer.valueOf(chatCtx.getParseInfo().getDomainId().intValue()); + if (!isAllowSwitch(domainQueryModes, schemaMap, chatCtx, searchCtx, domainId)) { + log.info("selectDomain from ChatContext [{}]", domainId); + return domainId; } } + // default 0 return 0; } - - - /** - * to check can switch domain if context exit domain - * - * @return false will use context domain, true will use other domain , maybe include context domain - */ - protected static boolean isAllowSwitch(Map domainQueryModes, SchemaMapInfo schemaMap, - ChatContext chatCtx, QueryContextReq searchCtx, Integer domainId) { - if (!Objects.nonNull(domainId) || domainId <= 0) { - return true; - } - // except content domain, calculate the number of types for each domain, if numbers<=1 will not switch - Map domainTypeMap = getDomainTypeMap(schemaMap); - log.info("isAllowSwitch domainTypeMap [{}]", domainTypeMap); - long otherDomainTypeNumBigOneCount = domainTypeMap.entrySet().stream() - .filter(entry -> domainQueryModes.containsKey(entry.getKey()) && !entry.getKey().equals(domainId)) - .filter(entry -> entry.getValue().getCount() > 1).count(); - if (otherDomainTypeNumBigOneCount >= 1) { - return true; - } - // if query text only contain time , will not switch - if (searchCtx.getQueryText() != null && searchCtx.getParseInfo().getDateInfo() != null) { - if (searchCtx.getParseInfo().getDateInfo().getText() != null) { - if (searchCtx.getParseInfo().getDateInfo().getText().equalsIgnoreCase(searchCtx.getQueryText())) { - log.info("timeParseResults is not null , can not switch context , timeParseResults:{},", - searchCtx.getParseInfo().getDateInfo()); - return false; - } - } - } - // if context domain not in schemaMap , will switch - if (schemaMap.getMatchedElements(domainId) == null || schemaMap.getMatchedElements(domainId).size() <= 0) { - log.info("domainId not in schemaMap "); - return true; - } - // other will not switch - return false; - } - - protected static Map getDomainTypeMap(SchemaMapInfo schemaMap) { - Map domainCount = new HashMap<>(); - for (Map.Entry> entry : schemaMap.getDomainElementMatches().entrySet()) { - List schemaElementMatches = schemaMap.getMatchedElements(entry.getKey()); - if (schemaElementMatches != null && schemaElementMatches.size() > 0) { - if (!domainCount.containsKey(entry.getKey())) { - domainCount.put(entry.getKey(), new SchemaElementCount()); - } - SchemaElementCount schemaElementCount = domainCount.get(entry.getKey()); - Set schemaElementTypes = new HashSet<>(); - schemaElementMatches.stream() - .forEach(schemaElementMatch -> schemaElementTypes.add(schemaElementMatch.getElementType())); - SchemaElementMatch schemaElementMatchMax = schemaElementMatches.stream() - .sorted(ContextHelper.schemaElementMatchComparatorBySimilarity).findFirst().orElse(null); - if (schemaElementMatchMax != null) { - schemaElementCount.setMaxSimilarity(schemaElementMatchMax.getSimilarity()); - } - schemaElementCount.setCount(schemaElementTypes.size()); - - } - } - return domainCount; - } - -} +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/LLMSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/LLMSemanticParser.java new file mode 100644 index 000000000..ebb633a1d --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/LLMSemanticParser.java @@ -0,0 +1,148 @@ +package com.tencent.supersonic.chat.application.parser; + +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.application.knowledge.WordNatureService; +import com.tencent.supersonic.chat.application.query.LLMSemanticQuery; +import com.tencent.supersonic.chat.domain.config.LLMConfig; +import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; +import com.tencent.supersonic.chat.domain.pojo.chat.LLMReq; +import com.tencent.supersonic.chat.domain.pojo.chat.LLMResp; +import com.tencent.supersonic.chat.domain.pojo.chat.LLMSchema; +import com.tencent.supersonic.chat.domain.utils.DslToSemanticInfo; +import com.tencent.supersonic.chat.domain.utils.SemanticSatisfactionChecker; +import com.tencent.supersonic.common.nlp.ItemDO; +import com.tencent.supersonic.common.util.context.ContextUtils; +import com.tencent.supersonic.common.util.json.JsonUtil; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.support.SpringFactoriesLoader; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +@Slf4j +public class LLMSemanticParser implements SemanticParser { + + @Override + public void parse(QueryContextReq queryContext, ChatContext chatCtx) { + if (SemanticSatisfactionChecker.check(queryContext)) { + log.info("There is no need parse by llm , queryText:{}", queryContext.getQueryText()); + return; + } + + Integer domainId = getDomainId(queryContext, chatCtx); + LLMResp llmResp = requestLLM(queryContext, domainId); + if (Objects.isNull(llmResp)) { + return; + } + LLMSemanticQuery semanticQuery = new LLMSemanticQuery(); + SemanticParseInfo parseInfo = semanticQuery.getParseInfo(); + String sql = convertToSql(llmResp, parseInfo); + parseInfo.setDomainId(Long.valueOf(domainId)); + parseInfo.setBonus(queryContext.getQueryText().length() * 1.0); + parseInfo.setQueryMode(LLMSemanticQuery.QUERY_MODE); + parseInfo.setInfo(sql); + queryContext.getCandidateQueries().add(semanticQuery); + return; + } + + protected String convertToSql(LLMResp llmResp, SemanticParseInfo parseInfo) { + return DslToSemanticInfo.convert(parseInfo, llmResp); + } + + protected LLMResp requestLLM(QueryContextReq queryContext, Integer domainId) { + try { + final LLMConfig llmConfig = ContextUtils.getBean(LLMConfig.class); + + DomainInfos domainInfos = ContextUtils.getBean(WordNatureService.class).getCache().getUnchecked(""); + + Map domainIdToName = domainInfos.getDomains().stream() + .collect(Collectors.toMap(ItemDO::getDomain, a -> a.getName(), (k1, k2) -> k1)); + + Map itemIdToName = domainInfos.getDimensions().stream() + .filter(entry -> domainId.equals(entry.getDomain())) + .collect(Collectors.toMap(ItemDO::getItemId, ItemDO::getName, (value1, value2) -> value2)); + + String domainName = domainIdToName.get(domainId); + LLMReq llmReq = new LLMReq(); + llmReq.setQueryText(queryContext.getQueryText()); + + List matchedElements = queryContext.getMapInfo().getMatchedElements(domainId); + + List fieldNameList = matchedElements.stream() + .filter(schemaElementMatch -> + SchemaElementType.METRIC.equals(schemaElementMatch.getElementType()) || + SchemaElementType.DIMENSION.equals(schemaElementMatch.getElementType()) || + SchemaElementType.VALUE.equals(schemaElementMatch.getElementType())) + .map(schemaElementMatch -> { + if (!SchemaElementType.VALUE.equals(schemaElementMatch.getElementType())) { + return schemaElementMatch.getWord(); + } + return itemIdToName.get(schemaElementMatch.getElementID()); + }) + .filter(name -> StringUtils.isNotEmpty(name) && !name.contains("%")) + .collect(Collectors.toList()); + + LLMSchema llmSchema = new LLMSchema(); + llmSchema.setDomainName(domainName); + llmSchema.setFieldNameList(fieldNameList); + llmReq.setSchema(llmSchema); + + log.info("domainId:{},llmReq:{}", domainId, llmReq); + String questUrl = llmConfig.getUrl() + llmConfig.getQueryToSqlPath(); + + RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(JsonUtil.toString(llmReq), headers); + + log.info("requestLLM request:{},entity:{}", questUrl, entity); + ResponseEntity responseEntity = restTemplate.exchange(questUrl, HttpMethod.POST, entity, + LLMResp.class); + + log.info("requestLLM result:{}", responseEntity); + return responseEntity.getBody(); + } catch (Exception e) { + log.error("requestLLM error", e); + } + return null; + } + + protected Integer getDomainId(QueryContextReq queryContext, ChatContext chatCtx) { + SchemaMapInfo mapInfo = queryContext.getMapInfo(); + Set matchedDomains = mapInfo.getMatchedDomains(); + Map domainQueryModes = new HashMap<>(); + for (Integer matchedDomain : matchedDomains) { + domainQueryModes.put(matchedDomain, new LLMSemanticQuery()); + } + List domainResolverList = SpringFactoriesLoader.loadFactories(DomainResolver.class, + Thread.currentThread().getContextClassLoader()); + Optional domainId = domainResolverList.stream() + .map(domainResolver -> domainResolver.resolve(domainQueryModes, queryContext, chatCtx, + queryContext.getMapInfo())).filter(d -> d > 0).findFirst(); + if (domainId.isPresent()) { + return domainId.get(); + } + return 0; + } +} + + diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/ListFilterParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/ListFilterParser.java deleted file mode 100644 index a3f7a1e4f..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/ListFilterParser.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.tencent.supersonic.chat.application.parser; - -import static com.tencent.supersonic.common.constant.Constants.DAY; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticParser; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.chat.application.query.EntityListFilter; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; -import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; -import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.common.pojo.DateConf; -import com.tencent.supersonic.common.pojo.Order; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.common.util.context.ContextUtils; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import org.springframework.beans.BeanUtils; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -@Component -public class ListFilterParser implements SemanticParser { - - - private DefaultSemanticInternalUtils defaultSemanticUtils; - - @Override - public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) { - defaultSemanticUtils = ContextUtils.getBean(DefaultSemanticInternalUtils.class); - - String queryMode = queryContext.getParseInfo().getQueryMode(); - if (!EntityListFilter.QUERY_MODE.equals(queryMode)) { - return false; - } - this.fillDateEntityFilter(queryContext.getParseInfo()); - this.addEntityDetailAndOrderByMetric(queryContext, chatCtx); - this.dealNativeQuery(queryContext, true); - return true; - - } - - private void fillDateEntityFilter(SemanticParseInfo semanticParseInfo) { - DateConf dateInfo = new DateConf(); - dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); - dateInfo.setUnit(1); - dateInfo.setPeriod(DAY); - dateInfo.setText(String.format("近1天")); - semanticParseInfo.setDateInfo(dateInfo); - } - - private void addEntityDetailAndOrderByMetric(QueryContextReq queryContext, ChatContext chatCtx) { - if (queryContext.getParseInfo().getDomainId() > 0L) { - ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo( - queryContext.getParseInfo().getDomainId()); - if (chaConfigRichDesc != null) { - SemanticParseInfo semanticParseInfo = queryContext.getParseInfo(); - Set dimensions = new LinkedHashSet(); - Set primaryDimensions = this.addPrimaryDimension(chaConfigRichDesc.getEntity(), dimensions); - Set metrics = new LinkedHashSet(); - if (chaConfigRichDesc.getEntity() != null - && chaConfigRichDesc.getEntity().getEntityInternalDetailDesc() != null) { - chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getMetricList().stream() - .forEach((m) -> metrics.add(this.getMetric(m))); - chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getDimensionList().stream() - .filter((m) -> !primaryDimensions.contains(m.getBizName())) - .forEach((m) -> dimensions.add(this.getDimension(m))); - } - - semanticParseInfo.setDimensions(dimensions); - semanticParseInfo.setMetrics(metrics); - Set orders = new LinkedHashSet(); - if (chaConfigRichDesc.getEntity() != null - && chaConfigRichDesc.getEntity().getEntityInternalDetailDesc() != null) { - chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getMetricList().stream() - .forEach((metric) -> orders.add(new Order(metric.getBizName(), Constants.DESC_UPPER))); - } - - semanticParseInfo.setOrders(orders); - } - } - - } - - private Set addPrimaryDimension(EntityRichInfo entity, Set dimensions) { - Set primaryDimensions = new HashSet(); - if (!Objects.isNull(entity) && !CollectionUtils.isEmpty(entity.getEntityIds())) { - entity.getEntityIds().stream().forEach((dimSchemaDesc) -> { - SchemaItem dimension = new SchemaItem(); - BeanUtils.copyProperties(dimSchemaDesc, dimension); - dimensions.add(dimension); - primaryDimensions.add(dimSchemaDesc.getBizName()); - }); - return primaryDimensions; - } else { - return primaryDimensions; - } - } - - private SchemaItem getMetric(MetricSchemaResp metricSchemaDesc) { - SchemaItem queryMeta = new SchemaItem(); - queryMeta.setId(metricSchemaDesc.getId()); - queryMeta.setBizName(metricSchemaDesc.getBizName()); - queryMeta.setName(metricSchemaDesc.getName()); - return queryMeta; - } - - private SchemaItem getDimension(DimSchemaResp dimSchemaDesc) { - SchemaItem queryMeta = new SchemaItem(); - queryMeta.setId(dimSchemaDesc.getId()); - queryMeta.setBizName(dimSchemaDesc.getBizName()); - queryMeta.setName(dimSchemaDesc.getName()); - return queryMeta; - } - - private void dealNativeQuery(QueryContextReq queryContext, boolean isNativeQuery) { - if (Objects.nonNull(queryContext) && Objects.nonNull(queryContext.getParseInfo())) { - queryContext.getParseInfo().setNativeQuery(isNativeQuery); - } - - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParser.java index 0d6bbd5a7..e63abf831 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParser.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParser.java @@ -1,22 +1,30 @@ package com.tencent.supersonic.chat.application.parser; +import com.tencent.supersonic.chat.api.component.SemanticParser; +import com.tencent.supersonic.chat.api.component.SemanticQuery; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticParser; +import com.tencent.supersonic.chat.application.query.MetricSemanticQuery; +import com.tencent.supersonic.chat.application.query.RuleSemanticQuery; +import com.tencent.supersonic.chat.application.query.RuleSemanticQueryManager; import com.tencent.supersonic.common.constant.Constants; import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; import java.time.LocalDate; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.collections.CollectionUtils; import org.apache.logging.log4j.util.Strings; -import org.springframework.stereotype.Component; -@Component public class TimeSemanticParser implements SemanticParser { - public TimeSemanticParser() { - } + private static final Pattern recentPeriodPattern = Pattern.compile( + ".*(?(近|过去)((?\\d+)|(?[一二三四五六七八九十百千万亿]+))个?(?[天周月年])).*"); private int zhNumParse(String zhNumStr) { Stack stack = new Stack<>(); @@ -42,11 +50,8 @@ public class TimeSemanticParser implements SemanticParser { return stack.stream().mapToInt(s -> s).sum(); } - private static final Pattern recentPeriodPattern = Pattern.compile( - ".*(?(近|过去)((?\\d+)|(?[一二三四五六七八九十百千万亿]+))个?(?[天周月年])).*"); - @Override - public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) { + public void parse(QueryContextReq queryContext, ChatContext chatContext) { Matcher m = recentPeriodPattern.matcher(queryContext.getQueryText()); if (m.matches()) { int num = 0; @@ -61,18 +66,19 @@ public class TimeSemanticParser implements SemanticParser { DateConf info = new DateConf(); String zhPeriod = m.group("zhPeriod"); int days; + info.setPeriod(Constants.DAY); switch (zhPeriod) { case "周": days = 7; - info.setPeriod(Constants.WEEK); + //info.setPeriod(Constants.WEEK); break; case "月": days = 30; - info.setPeriod(Constants.MONTH); + //info.setPeriod(Constants.MONTH); break; case "年": days = 365; - info.setPeriod(Constants.YEAR); + //info.setPeriod(Constants.YEAR); break; default: days = 1; @@ -87,9 +93,53 @@ public class TimeSemanticParser implements SemanticParser { info.setText(text); info.setStartDate(LocalDate.now().minusDays(days).toString()); info.setUnit(days); - queryContext.getParseInfo().setDateInfo(info); + //queryContext.getParseInfo().setDateInfo(info); + for (SemanticQuery query : queryContext.getCandidateQueries()) { + if (query instanceof MetricSemanticQuery) { + query.getParseInfo().setDateInfo(info); + } + } + doParseOnlyTime(queryContext, chatContext, info); + } + } + } + + protected void doParseOnlyTime(QueryContextReq queryContext, ChatContext chatContext, DateConf info) { + if (!queryContext.getCandidateQueries().isEmpty() || chatContext.getParseInfo() == null || Objects.isNull( + info.getText())) { + return; + } + if (info.getText().equals(queryContext.getQueryText()) && queryContext.getMapInfo().getDomainElementMatches() + .isEmpty() + ) { + if (Objects.nonNull(chatContext.getParseInfo().getQueryMode()) && Objects.nonNull( + chatContext.getParseInfo().getDomainId()) && chatContext.getParseInfo().getDomainId() > 0) { + if (Objects.nonNull(chatContext.getParseInfo().getDateInfo()) && !chatContext.getParseInfo() + .getDateInfo().getPeriod().equals(info.getPeriod())) { + if (!CollectionUtils.isEmpty(chatContext.getParseInfo().getDimensions())) { + String dateField = TimeDimensionEnum.DAY.getName(); + if (Constants.MONTH.equals(chatContext.getParseInfo().getDateInfo().getPeriod())) { + dateField = TimeDimensionEnum.MONTH.getName(); + } + if (Constants.WEEK.equals(chatContext.getParseInfo().getDateInfo().getPeriod())) { + dateField = TimeDimensionEnum.WEEK.getName(); + } + Set dimensions = new HashSet<>(); + for (SchemaItem schemaItem : chatContext.getParseInfo().getDimensions()) { + if (schemaItem.getBizName().equals(dateField)) { + continue; + } + dimensions.add(schemaItem); + } + chatContext.getParseInfo().setDimensions(dimensions); + } + } + chatContext.getParseInfo().setDateInfo(info); + RuleSemanticQuery semanticQuery = RuleSemanticQueryManager.create( + chatContext.getParseInfo().getQueryMode()); + semanticQuery.setParseInfo(chatContext.getParseInfo()); + queryContext.getCandidateQueries().add(semanticQuery); } } - return false; } } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/AggregateTypeResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/AggregateTypeResolver.java deleted file mode 100644 index 3f2b6a3e2..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/AggregateTypeResolver.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tencent.supersonic.chat.application.parser.resolver; - -import com.tencent.supersonic.common.enums.AggregateTypeEnum; - -/*** - * aggregate parser - */ -public interface AggregateTypeResolver { - - AggregateTypeEnum resolve(String queryText); - - boolean hasCompareIntentionalWords(String queryText); - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/DomainSemanticQueryResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/DomainSemanticQueryResolver.java deleted file mode 100644 index 61a505c7a..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/DomainSemanticQueryResolver.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.tencent.supersonic.chat.application.parser.resolver; - -import com.tencent.supersonic.chat.api.pojo.SchemaElementCount; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticQuery; -import com.tencent.supersonic.chat.application.query.SemanticQueryFactory; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Component -public class DomainSemanticQueryResolver implements SemanticQueryResolver { - - private static final Logger LOGGER = LoggerFactory.getLogger(DomainSemanticQueryResolver.class); - - @Override - public SemanticQuery resolve(List elementMatches, QueryContextReq queryCtx) { - Map matchMap = new HashMap<>(); - - for (SemanticQuery semanticQuery : SemanticQueryFactory.getSemanticQueries()) { - - SchemaElementCount match = semanticQuery.match(elementMatches, queryCtx); - - if (match != null && match.getCount() > 0 && match.getMaxSimilarity() > 0) { - LOGGER.info("resolve match [{}:{}] ", semanticQuery.getQueryMode(), match); - matchMap.put(semanticQuery, match); - } - - } - // get the similarity max - Map.Entry matchMax = matchMap.entrySet().stream() - .sorted(ContextHelper.SemanticQueryStatComparator).findFirst().orElse(null); - if (matchMax != null) { - LOGGER.info("resolve max [{}:{}] ", matchMax.getKey().getQueryMode(), matchMax.getValue()); - return matchMax.getKey(); - } - return null; - } -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/HeuristicDomainResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/HeuristicDomainResolver.java deleted file mode 100644 index 12ec57684..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/HeuristicDomainResolver.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.tencent.supersonic.chat.application.parser.resolver; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SchemaElementCount; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticQuery; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - - -@Service("DomainResolver") -@Slf4j -public class HeuristicDomainResolver extends BaseDomainResolver { - - @Override - public Integer selectDomain(Map domainQueryModes, QueryContextReq searchCtx, - ChatContext chatCtx, - SchemaMapInfo schemaMap) { - // if QueryContext has domainId and in domainQueryModes - if (domainQueryModes.containsKey(searchCtx.getDomainId())) { - log.info("selectDomain from QueryContext [{}]", searchCtx.getDomainId()); - return searchCtx.getDomainId(); - } - // if ChatContext has domainId and in domainQueryModes - if (chatCtx.getParseInfo().getDomainId() > 0) { - Integer domainId = Integer.valueOf(chatCtx.getParseInfo().getDomainId().intValue()); - if (!isAllowSwitch(domainQueryModes, schemaMap, chatCtx, searchCtx, domainId)) { - log.info("selectDomain from ChatContext [{}]", domainId); - return domainId; - } - } - // default 0 - return 0; - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/RegexAggregateTypeResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/RegexAggregateTypeResolver.java deleted file mode 100644 index 80a5d7647..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/RegexAggregateTypeResolver.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.tencent.supersonic.chat.application.parser.resolver; - -import com.tencent.supersonic.common.enums.AggregateTypeEnum; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Service; - -@Service -@Slf4j -@Primary -public class RegexAggregateTypeResolver implements AggregateTypeResolver { - - private static Map aggregateRegexMap = new HashMap<>(); - private static Pattern compareIntentionalWord = Pattern.compile("(?i)(比较|对比)"); - - static { - aggregateRegexMap.put(AggregateTypeEnum.MAX, Pattern.compile("(?i)(最大值|最大|max|峰值|最高)")); - aggregateRegexMap.put(AggregateTypeEnum.MIN, Pattern.compile("(?i)(最小值|最小|min|最低)")); - aggregateRegexMap.put(AggregateTypeEnum.SUM, Pattern.compile("(?i)(汇总|总和|sum)")); - aggregateRegexMap.put(AggregateTypeEnum.AVG, Pattern.compile("(?i)(平均值|日均|平均|avg)")); - aggregateRegexMap.put(AggregateTypeEnum.TOPN, Pattern.compile("(?i)(top)")); - aggregateRegexMap.put(AggregateTypeEnum.DISTINCT, Pattern.compile("(?i)(uv)")); - aggregateRegexMap.put(AggregateTypeEnum.COUNT, Pattern.compile("(?i)(总数|pv)")); - aggregateRegexMap.put(AggregateTypeEnum.NONE, Pattern.compile("(?i)(明细)")); - } - - @Override - public AggregateTypeEnum resolve(String text) { - - Map aggregateCount = new HashMap<>(aggregateRegexMap.size()); - for (Entry entry : aggregateRegexMap.entrySet()) { - Matcher matcher = entry.getValue().matcher(text); - int count = 0; - while (matcher.find()) { - count++; - } - if (count > 0) { - aggregateCount.put(entry.getKey(), count); - } - } - return aggregateCount.entrySet().stream().max(Map.Entry.comparingByValue()).map(entry -> entry.getKey()) - .orElse(null); - } - - @Override - public boolean hasCompareIntentionalWords(String queryText) { - return compareIntentionalWord.matcher(queryText).find(); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/SemanticQueryResolver.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/SemanticQueryResolver.java deleted file mode 100644 index 908937f2a..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/resolver/SemanticQueryResolver.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tencent.supersonic.chat.application.parser.resolver; - -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticQuery; -import java.util.List; - -/** - * Base interface for resolving query mode. - */ -public interface SemanticQueryResolver { - - SemanticQuery resolve(List elementMatches, QueryContextReq queryCtx); -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/BaseSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/BaseSemanticQuery.java deleted file mode 100644 index 74c509a86..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/BaseSemanticQuery.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.EntityInfo; -import com.tencent.supersonic.chat.api.pojo.SchemaElementCount; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.response.QueryResultResp; -import com.tencent.supersonic.chat.api.service.SemanticLayer; -import com.tencent.supersonic.chat.api.service.SemanticQuery; -import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; -import com.tencent.supersonic.chat.application.DomainEntityService; -import com.tencent.supersonic.chat.application.parser.resolver.DomainResolver; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; -import com.tencent.supersonic.chat.domain.pojo.search.QueryState; -import com.tencent.supersonic.chat.domain.service.ChatService; -import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; -import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; -import com.tencent.supersonic.common.util.context.ContextUtils; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - - -public abstract class BaseSemanticQuery implements SemanticQuery { - - protected QueryModeOption queryModeOption = QueryModeOption.build(); - private static final Logger LOGGER = LoggerFactory.getLogger(BaseSemanticQuery.class); - - @Override - public QueryResultResp execute(QueryContextReq queryCtx, ChatContext chatCtx) { - - DomainResolver domainResolver = ContextUtils.getBean(DomainResolver.class); - ChatService chatService = ContextUtils.getBean(ChatService.class); - SemanticLayer semanticLayer = ContextUtils.getBean(SemanticLayer.class); - - SemanticParseInfo semanticParse = queryCtx.getParseInfo(); - - String queryMode = semanticParse.getQueryMode(); - - if (semanticParse.getDomainId() < 0 || StringUtils.isEmpty(queryMode)) { - // reach here some error may happen - LOGGER.error("not find QueryMode"); - throw new RuntimeException("not find QueryMode"); - } - - supplyMetadata(semanticLayer, queryCtx); - - // is domain switch - if (domainResolver.isDomainSwitch(chatCtx, queryCtx)) { - chatService.switchContext(chatCtx); - } - // submit semantic query based on the result of semantic parsing - SemanticParseInfo semanticParseInfo = getContext(chatCtx, queryCtx); - QueryResultResp queryResponse = new QueryResultResp(); - QueryResultWithSchemaResp queryResult = semanticLayer.queryByStruct( - SchemaInfoConverter.convertTo(semanticParseInfo), queryCtx.getUser()); - if (queryResult != null) { - queryResponse.setQueryAuthorization(queryResult.getQueryAuthorization()); - } - String sql = queryResult == null ? null : queryResult.getSql(); - List> resultList = queryResult == null ? new ArrayList<>() - : queryResult.getResultList(); - List columns = queryResult == null ? new ArrayList<>() : queryResult.getColumns(); - queryResponse.setQuerySql(sql); - queryResponse.setQueryResults(resultList); - queryResponse.setQueryColumns(columns); - queryResponse.setQueryMode(queryMode); - - // add domain info - EntityInfo entityInfo = ContextUtils.getBean(DomainEntityService.class) - .getEntityInfo(queryCtx, chatCtx, queryCtx.getUser()); - queryResponse.setEntityInfo(entityInfo); - return queryResponse; - - } - - private void supplyMetadata(SemanticLayer semanticLayer, QueryContextReq queryCtx) { - DefaultSemanticInternalUtils defaultSemanticUtils = ContextUtils.getBean(DefaultSemanticInternalUtils.class); - - SchemaMapInfo mapInfo = queryCtx.getMapInfo(); - SemanticParseInfo semanticParse = queryCtx.getParseInfo(); - Long domain = semanticParse.getDomainId(); - List schemaElementMatches = mapInfo.getMatchedElements(domain.intValue()); - DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domain); - ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(domain); - - // supply metadata - if (!CollectionUtils.isEmpty(schemaElementMatches)) { - this.queryModeOption.addQuerySemanticParseInfo(schemaElementMatches, domainSchemaDesc, - chaConfigRichDesc, semanticParse); - } - } - - @Override - public void updateContext(QueryResultResp queryResponse, ChatContext chatCtx, QueryContextReq queryCtx) { - if (queryCtx.isSaveAnswer() && queryResponse != null - && queryResponse.getQueryState() == QueryState.NORMAL.getState()) { - chatCtx.setParseInfo(getParseInfo(queryCtx, chatCtx)); - chatCtx.setQueryText(queryCtx.getQueryText()); - ContextUtils.getBean(ChatService.class).updateContext(chatCtx); - } - queryResponse.setChatContext(queryCtx.getParseInfo()); - } - - public abstract SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx); - - - @Override - public SchemaElementCount match(List elementMatches, QueryContextReq queryCtx) { - return queryModeOption.match(elementMatches, queryCtx); - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityDetail.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityDetail.java index 78b0e62c0..db626d7af 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityDetail.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityDetail.java @@ -1,26 +1,22 @@ package com.tencent.supersonic.chat.application.query; -import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; -@Service -public class EntityDetail extends BaseSemanticQuery { +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.domain.utils.ContextHelper; +import org.springframework.stereotype.Component; + +@Component +public class EntityDetail extends EntitySemanticQuery { public static String QUERY_MODE = "ENTITY_DETAIL"; public EntityDetail() { - queryModeOption.setAggregation(QueryModeElementOption.unused()); - queryModeOption.setDate(QueryModeElementOption.unused()); - queryModeOption.setDimension(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, - 1); - queryModeOption.setFilter(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setMetric(QueryModeElementOption.unused()); - queryModeOption.setEntity(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_MOST, 1); - queryModeOption.setDomain(QueryModeElementOption.optional()); + super(); + queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1) + .addOption(VALUE, REQUIRED, AT_LEAST, 1); } @Override @@ -29,21 +25,9 @@ public class EntityDetail extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getDimensionFilters(), - semanticParseInfo.getDimensionFilters()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } - - @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getDimensionFilters(), semanticParseInfo.getDimensionFilters()); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + ContextHelper.addIfEmpty(chatContext.getParseInfo().getDimensionFilters(), + parseInfo.getDimensionFilters()); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListFilter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListFilter.java index 06e3d3999..1bf46041f 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListFilter.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListFilter.java @@ -1,26 +1,42 @@ package com.tencent.supersonic.chat.application.query; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; +import static com.tencent.supersonic.common.constant.Constants.DAY; + import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; +import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; +import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; +import com.tencent.supersonic.common.constant.Constants; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.pojo.Order; +import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.common.util.context.ContextUtils; +import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; -@Service -public class EntityListFilter extends BaseSemanticQuery { +@Slf4j +@Component +public class EntityListFilter extends EntitySemanticQuery { public static String QUERY_MODE = "ENTITY_LIST_FILTER"; private static Long entityListLimit = 200L; public EntityListFilter() { - queryModeOption.setAggregation(QueryModeElementOption.unused()); - queryModeOption.setDate(QueryModeElementOption.unused()); - queryModeOption.setDimension(QueryModeElementOption.unused()); - queryModeOption.setFilter(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setMetric(QueryModeElementOption.unused()); - queryModeOption.setEntity(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setDomain(QueryModeElementOption.optional()); + super(); + queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 1); } @Override @@ -28,23 +44,98 @@ public class EntityListFilter extends BaseSemanticQuery { return QUERY_MODE; } - @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getDimensionFilters(), - semanticParseInfo.getDimensionFilters()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getDimensionFilters(), semanticParseInfo.getDimensionFilters()); - semanticParseInfo.setLimit(entityListLimit); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); + parseInfo.setLimit(entityListLimit); + this.fillDateEntityFilter(parseInfo); + this.addEntityDetailAndOrderByMetric(parseInfo); + this.dealNativeQuery(parseInfo, true); + } + + + private void fillDateEntityFilter(SemanticParseInfo semanticParseInfo) { + DateConf dateInfo = new DateConf(); + dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); + dateInfo.setUnit(1); + dateInfo.setPeriod(DAY); + dateInfo.setText(String.format("近1天")); + semanticParseInfo.setDateInfo(dateInfo); + } + + private void addEntityDetailAndOrderByMetric(SemanticParseInfo semanticParseInfo) { + if (semanticParseInfo.getDomainId() > 0L) { + DefaultSemanticInternalUtils defaultSemanticUtils = ContextUtils.getBean( + DefaultSemanticInternalUtils.class); + ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo( + semanticParseInfo.getDomainId()); + if (chaConfigRichDesc != null) { + //SemanticParseInfo semanticParseInfo = queryContext.getParseInfo(); + Set dimensions = new LinkedHashSet(); + Set primaryDimensions = this.addPrimaryDimension(chaConfigRichDesc.getEntity(), dimensions); + Set metrics = new LinkedHashSet(); + if (chaConfigRichDesc.getEntity() != null + && chaConfigRichDesc.getEntity().getEntityInternalDetailDesc() != null) { + chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getMetricList().stream() + .forEach((m) -> metrics.add(this.getMetric(m))); + chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getDimensionList().stream() + .filter((m) -> !primaryDimensions.contains(m.getBizName())) + .forEach((m) -> dimensions.add(this.getDimension(m))); + } + + semanticParseInfo.setDimensions(dimensions); + semanticParseInfo.setMetrics(metrics); + Set orders = new LinkedHashSet(); + if (chaConfigRichDesc.getEntity() != null + && chaConfigRichDesc.getEntity().getEntityInternalDetailDesc() != null) { + chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getMetricList().stream() + .forEach((metric) -> orders.add(new Order(metric.getBizName(), Constants.DESC_UPPER))); + } + + semanticParseInfo.setOrders(orders); + } + } + + } + + private Set addPrimaryDimension(EntityRichInfo entity, Set dimensions) { + Set primaryDimensions = new HashSet(); + if (!Objects.isNull(entity) && !CollectionUtils.isEmpty(entity.getEntityIds())) { + entity.getEntityIds().stream().forEach((dimSchemaDesc) -> { + SchemaItem dimension = new SchemaItem(); + BeanUtils.copyProperties(dimSchemaDesc, dimension); + dimensions.add(dimension); + primaryDimensions.add(dimSchemaDesc.getBizName()); + }); + return primaryDimensions; + } else { + return primaryDimensions; + } + } + + private SchemaItem getMetric(MetricSchemaResp metricSchemaDesc) { + SchemaItem queryMeta = new SchemaItem(); + queryMeta.setId(metricSchemaDesc.getId()); + queryMeta.setBizName(metricSchemaDesc.getBizName()); + queryMeta.setName(metricSchemaDesc.getName()); + return queryMeta; + } + + private SchemaItem getDimension(DimSchemaResp dimSchemaDesc) { + SchemaItem queryMeta = new SchemaItem(); + queryMeta.setId(dimSchemaDesc.getId()); + queryMeta.setBizName(dimSchemaDesc.getBizName()); + queryMeta.setName(dimSchemaDesc.getName()); + return queryMeta; + } + + private void dealNativeQuery(SemanticParseInfo semanticParseInfo, boolean isNativeQuery) { + if (Objects.nonNull(semanticParseInfo)) { + semanticParseInfo.setNativeQuery(isNativeQuery); + } + } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListTopN.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListTopN.java index 48fb8df14..4f7f9769c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListTopN.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityListTopN.java @@ -1,27 +1,23 @@ package com.tencent.supersonic.chat.application.query; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.METRIC; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; + import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service -public class EntityListTopN extends BaseSemanticQuery { +@Component +public class EntityListTopN extends EntitySemanticQuery { public static String QUERY_MODE = "ENTITY_LIST_TOPN"; - public EntityListTopN() { - queryModeOption.setAggregation(QueryModeElementOption.optional()); - queryModeOption.setDate(QueryModeElementOption.optional()); - queryModeOption.setDimension(QueryModeElementOption.unused()); - queryModeOption.setFilter(QueryModeElementOption.unused()); - queryModeOption.setMetric(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setEntity(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setDomain(QueryModeElementOption.optional()); - queryModeOption.setSupportOrderBy(true); + super(); + queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1) + .setSupportOrderBy(true); } @Override @@ -30,22 +26,10 @@ public class EntityListTopN extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateTime(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } - - @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatCtx.getParseInfo(), semanticParseInfo); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); + ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityMetricFilter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityMetricFilter.java index a42f2d94d..4139f83ea 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityMetricFilter.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntityMetricFilter.java @@ -1,26 +1,24 @@ package com.tencent.supersonic.chat.application.query; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.METRIC; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; + import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service -public class EntityMetricFilter extends BaseSemanticQuery { +@Component +public class EntityMetricFilter extends EntitySemanticQuery { public static String QUERY_MODE = "ENTITY_METRIC_FILTER"; - public EntityMetricFilter() { - queryModeOption.setAggregation(QueryModeElementOption.optional()); - queryModeOption.setDate(QueryModeElementOption.optional()); - queryModeOption.setDimension(QueryModeElementOption.unused()); - queryModeOption.setFilter(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setMetric(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setEntity(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setDomain(QueryModeElementOption.optional()); + super(); + queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1) + .addOption(VALUE, REQUIRED, AT_LEAST, 1); } @Override @@ -29,21 +27,9 @@ public class EntityMetricFilter extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getDimensionFilters(), - semanticParseInfo.getDimensionFilters()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } - - @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getDimensionFilters(), semanticParseInfo.getDimensionFilters()); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntitySemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntitySemanticQuery.java new file mode 100644 index 000000000..416af0244 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/EntitySemanticQuery.java @@ -0,0 +1,13 @@ +package com.tencent.supersonic.chat.application.query; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; + +public abstract class EntitySemanticQuery extends RuleSemanticQuery { + + public EntitySemanticQuery() { + super(); + queryMatcher.addOption(ENTITY, REQUIRED, AT_LEAST, 1); + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/HeuristicQuerySelector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/HeuristicQuerySelector.java new file mode 100644 index 000000000..9e2ffd615 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/HeuristicQuerySelector.java @@ -0,0 +1,63 @@ +package com.tencent.supersonic.chat.application.query; + +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.common.constant.Constants; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HeuristicQuerySelector implements QuerySelector { + + @Override + public SemanticQuery select(List candidateQueries) { + double maxScore = 0; + SemanticQuery pickedQuery = null; + + for (SemanticQuery query : candidateQueries) { + if (query instanceof LLMSemanticQuery) { + log.info("force to use LLM if existed"); + return query; + } + + SemanticParseInfo semanticParse = query.getParseInfo(); + double score = computeScore(semanticParse); + if (score > maxScore) { + maxScore = score; + pickedQuery = query; + } + log.info("candidate query (domain={}, queryMode={}) with score={}", + semanticParse.getDomainName(), semanticParse.getQueryMode(), score); + } + + return pickedQuery; + } + + private double computeScore(SemanticParseInfo semanticParse) { + double score = 0; + + Map maxSimilarityMatch = new HashMap<>(); + for (SchemaElementMatch match : semanticParse.getElementMatches()) { + SchemaElementType type = match.getElementType(); + if (!maxSimilarityMatch.containsKey(type) || + match.getSimilarity() > maxSimilarityMatch.get(type).getSimilarity()) { + maxSimilarityMatch.put(type, match); + } + } + + for (SchemaElementMatch match : maxSimilarityMatch.values()) { + score += + Optional.ofNullable(match.getDetectWord()).orElse(Constants.EMPTY).length() * match.getSimilarity(); + } + + // bonus is a special construct to control the final score + score += semanticParse.getBonus(); + + return score; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/LLMSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/LLMSemanticQuery.java new file mode 100644 index 000000000..d7a7fbbdc --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/LLMSemanticQuery.java @@ -0,0 +1,71 @@ +package com.tencent.supersonic.chat.application.query; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.EntityInfo; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.response.QueryResultResp; +import com.tencent.supersonic.chat.application.DomainEntityService; +import com.tencent.supersonic.chat.domain.utils.ComponentFactory; +import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; +import com.tencent.supersonic.common.util.context.ContextUtils; +import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Slf4j +public class LLMSemanticQuery implements SemanticQuery { + + public static String QUERY_MODE = "DSL"; + + private SemanticParseInfo semanticParse = new SemanticParseInfo(); + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + + @Override + public String getQueryMode() { + return QUERY_MODE; + } + + @Override + public QueryResultResp execute(User user) { + String queryMode = semanticParse.getQueryMode(); + + if (semanticParse.getDomainId() < 0 || StringUtils.isEmpty(queryMode)) { + // reach here some error may happen + log.error("not find QueryMode"); + throw new RuntimeException("not find QueryMode"); + } + QueryResultResp queryResponse = new QueryResultResp(); + QueryResultWithSchemaResp queryResult = semanticLayer.queryBySql( + SchemaInfoConverter.convertToQuerySqlReq(semanticParse), user); + + if (queryResult != null) { + queryResponse.setQueryAuthorization(queryResult.getQueryAuthorization()); + } + String sql = queryResult == null ? null : queryResult.getSql(); + List> resultList = queryResult == null ? new ArrayList<>() + : queryResult.getResultList(); + List columns = queryResult == null ? new ArrayList<>() : queryResult.getColumns(); + queryResponse.setQuerySql(sql); + queryResponse.setQueryResults(resultList); + queryResponse.setQueryColumns(columns); + queryResponse.setQueryMode(queryMode); + + // add domain info + EntityInfo entityInfo = ContextUtils.getBean(DomainEntityService.class) + .getEntityInfo(semanticParse, user); + queryResponse.setEntityInfo(entityInfo); + return queryResponse; + } + + @Override + public SemanticParseInfo getParseInfo() { + return semanticParse; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricCompare.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricCompare.java index 96d7189be..3a215dd18 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricCompare.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricCompare.java @@ -1,39 +1,43 @@ package com.tencent.supersonic.chat.application.query; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.ENTITY; +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.VALUE; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_MOST; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.OPTIONAL; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; + import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.Filter; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import com.tencent.supersonic.chat.domain.utils.ContextHelper; import com.tencent.supersonic.common.pojo.SchemaItem; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service @Slf4j -public class MetricCompare extends BaseSemanticQuery { +@Component +public class MetricCompare extends MetricSemanticQuery { public static String QUERY_MODE = "METRIC_COMPARE"; - + public static Pattern intentWordPattern = Pattern.compile("(?i)(比较|对比)"); public MetricCompare() { - queryModeOption.setAggregation(QueryModeElementOption.optional()); - queryModeOption.setDate(QueryModeElementOption.optional()); - queryModeOption.setDimension(QueryModeElementOption.unused()); - queryModeOption.setFilter(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setMetric(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setEntity(QueryModeElementOption.unused()); - queryModeOption.setDomain(QueryModeElementOption.optional()); - queryModeOption.setSupportCompare(true); - queryModeOption.setSupportOrderBy(true); + super(); + queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 2) + .addOption(ENTITY, OPTIONAL, AT_MOST, 1); + + queryMatcher.setSupportCompare(true); + queryMatcher.setSupportOrderBy(true); } @Override @@ -42,26 +46,22 @@ public class MetricCompare extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCt) { - SemanticParseInfo semanticParseInfo = chatCt.getParseInfo(); - ContextHelper.updateTime(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.addIfEmpty(queryCtx.getParseInfo().getDimensionFilters(), - semanticParseInfo.getDimensionFilters()); - ContextHelper.updateList(queryCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; + public List match(List candidateElementMatches, QueryContextReq queryCtx) { + if (intentWordPattern.matcher(queryCtx.getQueryText()).find()) { + return super.match(candidateElementMatches, queryCtx); + } else { + return new ArrayList<>(); + } } @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatCtx.getParseInfo(), semanticParseInfo); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - mergeAppend(chatCtx.getParseInfo().getDimensionFilters(), semanticParseInfo.getDimensionFilters()); - addCompareDimension(semanticParseInfo); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); + ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); + mergeAppend(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); + addCompareDimension(parseInfo); + parseInfo.setBonus(2 * 1.0); } private void addCompareDimension(SemanticParseInfo semanticParseInfo) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricDomain.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricDomain.java index f90325a31..ed38701dc 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricDomain.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricDomain.java @@ -1,26 +1,23 @@ package com.tencent.supersonic.chat.application.query; - import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service -public class MetricDomain extends BaseSemanticQuery { +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.*; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.*; + +@Component +public class MetricDomain extends MetricSemanticQuery { public static String QUERY_MODE = "METRIC_DOMAIN"; public MetricDomain() { - queryModeOption.setAggregation(QueryModeElementOption.optional()); - queryModeOption.setDate(QueryModeElementOption.optional()); - queryModeOption.setDimension(QueryModeElementOption.unused()); - queryModeOption.setFilter(QueryModeElementOption.unused()); - queryModeOption.setMetric(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setEntity(QueryModeElementOption.unused()); - queryModeOption.setDomain(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); + super(); + queryMatcher.addOption(DOMAIN, REQUIRED, AT_LEAST, 1); } @Override @@ -29,22 +26,10 @@ public class MetricDomain extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateTime(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } - - @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatCtx.getParseInfo(), semanticParseInfo); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); + ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricFilter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricFilter.java index c0e813fc6..a1ccd7975 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricFilter.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricFilter.java @@ -1,25 +1,25 @@ package com.tencent.supersonic.chat.application.query; import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service -public class MetricFilter extends BaseSemanticQuery { +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.*; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.*; + +@Component +public class MetricFilter extends MetricSemanticQuery { public static String QUERY_MODE = "METRIC_FILTER"; public MetricFilter() { - queryModeOption.setAggregation(QueryModeElementOption.optional()); - queryModeOption.setDate(QueryModeElementOption.optional()); - queryModeOption.setDimension(QueryModeElementOption.unused()); - queryModeOption.setFilter(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setMetric(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setEntity(QueryModeElementOption.unused()); - queryModeOption.setDomain(QueryModeElementOption.optional()); + super(); + queryMatcher.addOption(VALUE, REQUIRED, AT_LEAST, 1) + .addOption(ENTITY, OPTIONAL, AT_MOST, 1); + } @Override @@ -28,25 +28,10 @@ public class MetricFilter extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateTime(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getDimensionFilters(), - semanticParseInfo.getDimensionFilters()); - ContextHelper.updateList(queryCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } - - @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatCtx.getParseInfo(), semanticParseInfo); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getDimensionFilters(), semanticParseInfo.getDimensionFilters()); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); + ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); + ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricGroupBy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricGroupBy.java index 4b5a5dd95..b65909e64 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricGroupBy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricGroupBy.java @@ -2,26 +2,21 @@ package com.tencent.supersonic.chat.application.query; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service -public class MetricGroupBy extends BaseSemanticQuery { +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.*; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.*; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.*; + +@Component +public class MetricGroupBy extends MetricSemanticQuery { public static String QUERY_MODE = "METRIC_GROUPBY"; - public MetricGroupBy() { - queryModeOption.setAggregation(QueryModeElementOption.optional()); - queryModeOption.setDate(QueryModeElementOption.optional()); - queryModeOption.setDimension(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, - 1); - queryModeOption.setFilter(QueryModeElementOption.unused()); - queryModeOption.setMetric(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setEntity(QueryModeElementOption.unused()); - queryModeOption.setDomain(QueryModeElementOption.optional()); + super(); + queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1); } @Override @@ -30,24 +25,11 @@ public class MetricGroupBy extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateTime(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.updateList(queryCtx.getParseInfo().getDimensions(), semanticParseInfo.getDimensions()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } - - @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatCtx.getParseInfo(), semanticParseInfo); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getDimensions(), semanticParseInfo.getDimensions()); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); + ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); + ContextHelper.addIfEmpty(chatParseInfo.getDimensions(), parseInfo.getDimensions()); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricOrderBy.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricOrderBy.java index 5ce8f9b21..9eb671d21 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricOrderBy.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricOrderBy.java @@ -1,27 +1,18 @@ package com.tencent.supersonic.chat.application.query; import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service -public class MetricOrderBy extends BaseSemanticQuery { +@Component +public class MetricOrderBy extends RuleSemanticQuery { public static String QUERY_MODE = "METRIC_ORDERBY"; public MetricOrderBy() { - queryModeOption.setAggregation(QueryModeElementOption.optional()); - queryModeOption.setDate(QueryModeElementOption.optional()); - queryModeOption.setDimension(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, - 1); - queryModeOption.setFilter(QueryModeElementOption.optional()); - queryModeOption.setMetric(SchemaElementOption.REQUIRED, QueryModeElementOption.RequireNumberType.AT_LEAST, 1); - queryModeOption.setEntity(QueryModeElementOption.unused()); - queryModeOption.setDomain(QueryModeElementOption.optional()); - queryModeOption.setSupportOrderBy(true); + super(); } @Override @@ -30,24 +21,12 @@ public class MetricOrderBy extends BaseSemanticQuery { } @Override - public SemanticParseInfo getParseInfo(QueryContextReq queryCtx, ChatContext chatCtx) { - SemanticParseInfo semanticParseInfo = chatCtx.getParseInfo(); - ContextHelper.updateTime(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateDomain(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateSemanticQuery(queryCtx.getParseInfo(), semanticParseInfo); - ContextHelper.updateList(queryCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.updateList(queryCtx.getParseInfo().getDimensions(), semanticParseInfo.getDimensions()); - ContextHelper.updateEntity(queryCtx.getParseInfo(), semanticParseInfo); - return semanticParseInfo; - } - - @Override - public SemanticParseInfo getContext(ChatContext chatCtx, QueryContextReq queryCtx) { - SemanticParseInfo semanticParseInfo = queryCtx.getParseInfo(); - ContextHelper.updateTimeIfEmpty(chatCtx.getParseInfo(), semanticParseInfo); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getMetrics(), semanticParseInfo.getMetrics()); - ContextHelper.addIfEmpty(chatCtx.getParseInfo().getDimensions(), semanticParseInfo.getDimensions()); - return semanticParseInfo; + public void inheritContext(ChatContext chatContext) { + SemanticParseInfo chatParseInfo = chatContext.getParseInfo(); + ContextHelper.updateTimeIfEmpty(chatParseInfo, parseInfo); + ContextHelper.addIfEmpty(chatParseInfo.getMetrics(), parseInfo.getMetrics()); + ContextHelper.addIfEmpty(chatParseInfo.getDimensions(), parseInfo.getDimensions()); + ContextHelper.addIfEmpty(chatParseInfo.getDimensionFilters(), parseInfo.getDimensionFilters()); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricSemanticQuery.java new file mode 100644 index 000000000..95797c2d7 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/MetricSemanticQuery.java @@ -0,0 +1,13 @@ +package com.tencent.supersonic.chat.application.query; + +import static com.tencent.supersonic.chat.api.pojo.SchemaElementType.METRIC; +import static com.tencent.supersonic.chat.application.query.QueryMatchOption.RequireNumberType.AT_LEAST; +import static com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption.REQUIRED; + +public abstract class MetricSemanticQuery extends RuleSemanticQuery { + + public MetricSemanticQuery() { + super(); + queryMatcher.addOption(METRIC, REQUIRED, AT_LEAST, 1); + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatchOption.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatchOption.java new file mode 100644 index 000000000..e740a0c44 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatchOption.java @@ -0,0 +1,43 @@ +package com.tencent.supersonic.chat.application.query; + +import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; +import lombok.Data; + +@Data +public class QueryMatchOption { + + private SchemaElementOption schemaElementOption; + private RequireNumberType requireNumberType; + private Integer requireNumber; + + public static QueryMatchOption build(SchemaElementOption schemaElementOption, + RequireNumberType requireNumberType, Integer requireNumber) { + QueryMatchOption queryMatchOption = new QueryMatchOption(); + queryMatchOption.requireNumber = requireNumber; + queryMatchOption.requireNumberType = requireNumberType; + queryMatchOption.schemaElementOption = schemaElementOption; + return queryMatchOption; + } + + public static QueryMatchOption optional() { + QueryMatchOption queryMatchOption = new QueryMatchOption(); + queryMatchOption.setSchemaElementOption(SchemaElementOption.OPTIONAL); + queryMatchOption.setRequireNumber(0); + queryMatchOption.setRequireNumberType(RequireNumberType.AT_LEAST); + return queryMatchOption; + } + + public static QueryMatchOption unused() { + QueryMatchOption queryMatchOption = new QueryMatchOption(); + queryMatchOption.setSchemaElementOption(SchemaElementOption.UNUSED); + queryMatchOption.setRequireNumber(0); + queryMatchOption.setRequireNumberType(RequireNumberType.EQUAL); + return queryMatchOption; + } + + public enum RequireNumberType { + AT_MOST, AT_LEAST, EQUAL + } + + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatcher.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatcher.java new file mode 100644 index 000000000..53ecea73b --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryMatcher.java @@ -0,0 +1,113 @@ +package com.tencent.supersonic.chat.application.query; + +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; +import com.tencent.supersonic.common.enums.AggregateTypeEnum; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import lombok.Data; +import lombok.ToString; + +@Data +@ToString +public class QueryMatcher { + + private HashMap elementOptionMap = new HashMap<>(); + private boolean supportCompare; + private boolean supportOrderBy; + private List orderByTypes = Arrays.asList(AggregateTypeEnum.MAX, AggregateTypeEnum.MIN, + AggregateTypeEnum.TOPN); + + public QueryMatcher() { + for (SchemaElementType type : SchemaElementType.values()) { + if (type.equals(SchemaElementType.DOMAIN)) { + elementOptionMap.put(type, QueryMatchOption.optional()); + } else { + elementOptionMap.put(type, QueryMatchOption.unused()); + } + } + } + + public QueryMatcher addOption(SchemaElementType type, SchemaElementOption option, + QueryMatchOption.RequireNumberType requireNumberType, Integer requireNumber) { + elementOptionMap.put(type, QueryMatchOption.build(option, requireNumberType, requireNumber)); + return this; + } + + /** + * Match schema element with current query according to the options. + * + * @param candidateElementMatches + * @return a list of all matched schema elements, + * empty list if no matches can be found + */ + public List match(List candidateElementMatches) { + List elementMatches = new ArrayList<>(); + + HashMap schemaElementTypeCount = new HashMap<>(); + for (SchemaElementMatch schemaElementMatch : candidateElementMatches) { + SchemaElementType schemaElementType = schemaElementMatch.getElementType(); + if (schemaElementTypeCount.containsKey(schemaElementType)) { + schemaElementTypeCount.put(schemaElementType, schemaElementTypeCount.get(schemaElementType) + 1); + } else { + schemaElementTypeCount.put(schemaElementType, 1); + } + } + + // check if current query options are satisfied, return immediately if not + for (Map.Entry e : elementOptionMap.entrySet()) { + SchemaElementType elementType = e.getKey(); + QueryMatchOption elementOption = e.getValue(); + if (!isMatch(elementOption, getCount(schemaElementTypeCount, elementType))) { + return new ArrayList<>(); + } + } + + // add element match if its element type is not declared as unused + for (SchemaElementMatch elementMatch : candidateElementMatches) { + QueryMatchOption elementOption = elementOptionMap.get(elementMatch.getElementType()); + if (Objects.nonNull(elementOption) && !elementOption.getSchemaElementOption() + .equals(SchemaElementOption.UNUSED)) { + elementMatches.add(elementMatch); + } + } + + return elementMatches; + } + + private int getCount(HashMap schemaElementTypeCount, + SchemaElementType schemaElementType) { + if (schemaElementTypeCount.containsKey(schemaElementType)) { + return schemaElementTypeCount.get(schemaElementType); + } + return 0; + } + + private boolean isMatch(QueryMatchOption queryMatchOption, int count) { + // check if required but empty + if (queryMatchOption.getSchemaElementOption().equals(SchemaElementOption.REQUIRED) && count <= 0) { + return false; + } + if (queryMatchOption.getRequireNumberType().equals(QueryMatchOption.RequireNumberType.AT_LEAST) + && count < queryMatchOption.getRequireNumber()) { + return false; + } + if (queryMatchOption.getRequireNumberType().equals(QueryMatchOption.RequireNumberType.AT_MOST) + && count > queryMatchOption.getRequireNumber()) { + return false; + } + + return true; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryModeElementOption.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryModeElementOption.java deleted file mode 100644 index 2d0a07ec9..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryModeElementOption.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; -import lombok.Data; - -@Data -public class QueryModeElementOption { - - public enum RequireNumberType { - AT_MOST, AT_LEAST, EQUAL - } - - private SchemaElementOption schemaElementOption; - private RequireNumberType requireNumberType; - private Integer requireNumber; - - public static QueryModeElementOption build(SchemaElementOption schemaElementOption, - RequireNumberType requireNumberType, Integer requireNumber) { - QueryModeElementOption queryModeElementOption = new QueryModeElementOption(); - queryModeElementOption.requireNumber = requireNumber; - queryModeElementOption.requireNumberType = requireNumberType; - queryModeElementOption.schemaElementOption = schemaElementOption; - return queryModeElementOption; - } - - public static QueryModeElementOption optional() { - QueryModeElementOption queryModeElementOption = new QueryModeElementOption(); - queryModeElementOption.setSchemaElementOption(SchemaElementOption.OPTIONAL); - queryModeElementOption.setRequireNumber(0); - queryModeElementOption.setRequireNumberType(RequireNumberType.AT_LEAST); - return queryModeElementOption; - } - - public static QueryModeElementOption unused() { - QueryModeElementOption queryModeElementOption = new QueryModeElementOption(); - queryModeElementOption.setSchemaElementOption(SchemaElementOption.UNUSED); - queryModeElementOption.setRequireNumber(0); - queryModeElementOption.setRequireNumberType(RequireNumberType.EQUAL); - return queryModeElementOption; - } - - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryModeOption.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryModeOption.java deleted file mode 100644 index 043a817ca..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QueryModeOption.java +++ /dev/null @@ -1,307 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.pojo.SchemaElementCount; -import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; -import com.tencent.supersonic.chat.api.pojo.SchemaElementType; -import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; -import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; -import com.tencent.supersonic.chat.application.parser.resolver.AggregateTypeResolver; -import com.tencent.supersonic.chat.domain.pojo.chat.SchemaElementOption; -import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; -import com.tencent.supersonic.chat.domain.utils.ContextHelper; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; -import com.tencent.supersonic.common.pojo.SchemaItem; -import com.tencent.supersonic.common.util.context.ContextUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import lombok.Data; -import lombok.ToString; - -@Data -@ToString -public class QueryModeOption { - - private QueryModeElementOption domain; - private QueryModeElementOption entity; - private QueryModeElementOption metric; - private QueryModeElementOption dimension; - private QueryModeElementOption filter; - private QueryModeElementOption date; - - private QueryModeElementOption aggregation; - private boolean supportCompare = false; - private boolean supportOrderBy = false; - List orderByTypes = Arrays.asList(AggregateTypeEnum.MAX, AggregateTypeEnum.MIN, - AggregateTypeEnum.TOPN); - - public static QueryModeOption build() { - return new QueryModeOption(); - } - - public QueryModeOption setDimension(SchemaElementOption dimension, - QueryModeElementOption.RequireNumberType requireNumberType, Integer requireNumber) { - this.dimension = QueryModeElementOption.build(dimension, requireNumberType, requireNumber); - return this; - } - - public QueryModeOption setDomain(SchemaElementOption domain, - QueryModeElementOption.RequireNumberType requireNumberType, Integer requireNumber) { - this.domain = QueryModeElementOption.build(domain, requireNumberType, requireNumber); - return this; - } - - public QueryModeOption setEntity(SchemaElementOption entity, - QueryModeElementOption.RequireNumberType requireNumberType, Integer requireNumber) { - this.entity = QueryModeElementOption.build(entity, requireNumberType, requireNumber); - return this; - } - - public QueryModeOption setFilter(SchemaElementOption filter, - QueryModeElementOption.RequireNumberType requireNumberType, Integer requireNumber) { - this.filter = QueryModeElementOption.build(filter, requireNumberType, requireNumber); - return this; - } - - public QueryModeOption setMetric(SchemaElementOption metric, - QueryModeElementOption.RequireNumberType requireNumberType, Integer requireNumber) { - this.metric = QueryModeElementOption.build(metric, requireNumberType, requireNumber); - return this; - } - - /** - * add query semantic parse info - * @param schemaElementMatches - * @param domainSchemaDesc - * @param chaConfigRichDesc - * @param semanticParseInfo - */ - public void addQuerySemanticParseInfo(List schemaElementMatches, - DomainSchemaResp domainSchemaDesc, ChatConfigRichInfo chaConfigRichDesc, - SemanticParseInfo semanticParseInfo) { - Map dimensionDescMap = domainSchemaDesc.getDimensions().stream() - .collect(Collectors.toMap(DimSchemaResp::getId, Function.identity())); - Map metricDescMap = domainSchemaDesc.getMetrics().stream() - .collect(Collectors.toMap(MetricSchemaResp::getId, Function.identity())); - - Map> values = getLinkSchemaElementMatch(schemaElementMatches, dimensionDescMap, - semanticParseInfo, metricDescMap); - if (!values.isEmpty()) { - for (Map.Entry> entry : values.entrySet()) { - DimSchemaResp dimensionDesc = dimensionDescMap.get(entry.getKey()); - if (entry.getValue().size() == 1) { - SchemaElementMatch schemaElementMatch = entry.getValue().get(0); - Filter chatFilter = new Filter(); - chatFilter.setValue(schemaElementMatch.getWord()); - chatFilter.setBizName(dimensionDesc.getBizName()); - chatFilter.setName(dimensionDesc.getName()); - chatFilter.setOperator(FilterOperatorEnum.EQUALS); - chatFilter.setElementID(Long.valueOf(schemaElementMatch.getElementID())); - semanticParseInfo.getDimensionFilters().add(chatFilter); - ContextHelper.setEntityId(entry.getKey(), schemaElementMatch.getWord(), chaConfigRichDesc, - semanticParseInfo); - } else { - Filter chatFilter = new Filter(); - List vals = new ArrayList<>(); - entry.getValue().stream().forEach(i -> vals.add(i.getWord())); - chatFilter.setValue(vals); - chatFilter.setBizName(dimensionDesc.getBizName()); - chatFilter.setName(dimensionDesc.getName()); - chatFilter.setOperator(FilterOperatorEnum.IN); - chatFilter.setElementID(entry.getKey()); - semanticParseInfo.getDimensionFilters().add(chatFilter); - } - } - } - } - - private Map> getLinkSchemaElementMatch(List schemaElementMatches, - Map dimensionDescMap, SemanticParseInfo semanticParseInfo, - Map metricDescMap) { - Map> values = new HashMap<>(); - for (SchemaElementMatch schemaElementMatch : schemaElementMatches) { - Long elementID = Long.valueOf(schemaElementMatch.getElementID()); - switch (schemaElementMatch.getElementType()) { - case DATE: - case DOMAIN: - case ENTITY: - break; - case ID: - case VALUE: - case DIMENSION: - if (dimensionDescMap.containsKey(elementID)) { - DimSchemaResp dimensionDesc = dimensionDescMap.get(elementID); - SchemaItem dimensionParseInfo = new SchemaItem(); - dimensionParseInfo.setBizName(dimensionDesc.getBizName()); - dimensionParseInfo.setName(dimensionDesc.getName()); - dimensionParseInfo.setId(dimensionDesc.getId()); - if (!dimension.getSchemaElementOption().equals(SchemaElementOption.UNUSED) - && schemaElementMatch.getElementType().equals(SchemaElementType.DIMENSION)) { - semanticParseInfo.getDimensions().add(dimensionParseInfo); - } - if (!filter.getSchemaElementOption().equals(SchemaElementOption.UNUSED) && ( - schemaElementMatch.getElementType().equals(SchemaElementType.VALUE) - || schemaElementMatch.getElementType().equals(SchemaElementType.ID))) { - if (values.containsKey(elementID)) { - values.get(elementID).add(schemaElementMatch); - } else { - values.put(elementID, new ArrayList<>(Arrays.asList(schemaElementMatch))); - } - } - } - break; - case METRIC: - if (!metric.getSchemaElementOption().equals(SchemaElementOption.UNUSED)) { - if (metricDescMap.containsKey(elementID)) { - MetricSchemaResp metricDesc = metricDescMap.get(elementID); - SchemaItem metric = new SchemaItem(); - metric.setBizName(metricDesc.getBizName()); - metric.setName(metricDesc.getName()); - metric.setId(metricDesc.getId()); - semanticParseInfo.getMetrics().add(metric); - } - } - break; - default: - } - } - return values; - } - - /** - * math - * @param elementMatches - * @param queryCtx - * @return - */ - public SchemaElementCount match(List elementMatches, QueryContextReq queryCtx) { - AggregateTypeResolver aggregateTypeResolver = ContextUtils.getBean(AggregateTypeResolver.class); - - boolean isCompareType = aggregateTypeResolver.hasCompareIntentionalWords(queryCtx.getQueryText()); - boolean isOrderByType = orderByTypes.contains(aggregateTypeResolver.resolve(queryCtx.getQueryText())); - - if ((isOrderByType && !supportOrderBy) || (isCompareType && !supportCompare)) { - return new SchemaElementCount(); - } - - SchemaElementCount schemaElementCount = new SchemaElementCount(); - schemaElementCount.setCount(0); - schemaElementCount.setMaxSimilarity(0); - HashMap schemaElementTypeCount = new HashMap<>(); - for (SchemaElementMatch schemaElementMatch : elementMatches) { - SchemaElementType schemaElementType = schemaElementMatch.getElementType(); - if (schemaElementTypeCount.containsKey(schemaElementType)) { - schemaElementTypeCount.put(schemaElementType, schemaElementTypeCount.get(schemaElementType) + 1); - } else { - schemaElementTypeCount.put(schemaElementType, 1); - } - } - // test each element - if (!isMatch(domain, getCount(schemaElementTypeCount, SchemaElementType.DOMAIN))) { - return schemaElementCount; - } - if (!isMatch(dimension, getCount(schemaElementTypeCount, SchemaElementType.DIMENSION))) { - return schemaElementCount; - } - if (!isMatch(metric, getCount(schemaElementTypeCount, SchemaElementType.METRIC))) { - return schemaElementCount; - } - int filterCount = getCount(schemaElementTypeCount, SchemaElementType.VALUE) + getCount(schemaElementTypeCount, - SchemaElementType.ID); - if (!isMatch(filter, filterCount)) { - return schemaElementCount; - } - if (!isMatch(entity, getCount(schemaElementTypeCount, SchemaElementType.ENTITY))) { - return schemaElementCount; - } - if (!isMatch(date, getCount(schemaElementTypeCount, SchemaElementType.DATE))) { - return schemaElementCount; - } - // count the max similarity - double similarity = 0; - Set schemaElementTypeSet = new HashSet<>(); - for (SchemaElementMatch schemaElementMatch : elementMatches) { - double schemaElementMatchSimilarity = getSimilarity(schemaElementMatch); - if (schemaElementMatchSimilarity > similarity) { - similarity = schemaElementMatchSimilarity; - } - schemaElementTypeSet.add(schemaElementMatch.getElementType()); - } - schemaElementCount.setCount(schemaElementTypeSet.size()); - schemaElementCount.setMaxSimilarity(similarity); - return schemaElementCount; - } - - private int getCount(HashMap schemaElementTypeCount, - SchemaElementType schemaElementType) { - if (schemaElementTypeCount.containsKey(schemaElementType)) { - return schemaElementTypeCount.get(schemaElementType); - } - return 0; - } - - private double getSimilarity(SchemaElementMatch schemaElementMatch) { - switch (schemaElementMatch.getElementType()) { - case DATE: - return getSimilarity(date, schemaElementMatch.getSimilarity()); - case DOMAIN: - return getSimilarity(domain, schemaElementMatch.getSimilarity()); - case ENTITY: - return getSimilarity(entity, schemaElementMatch.getSimilarity()); - case DIMENSION: - return getSimilarity(dimension, schemaElementMatch.getSimilarity()); - case METRIC: - return getSimilarity(metric, schemaElementMatch.getSimilarity()); - case ID: - case VALUE: - return getSimilarity(filter, schemaElementMatch.getSimilarity()); - default: - return 0; - } - } - - private double getSimilarity(QueryModeElementOption queryModeElementOption, double similarity) { - if (queryModeElementOption.getSchemaElementOption().equals(SchemaElementOption.REQUIRED)) { - return similarity; - } - return 0; - } - - private boolean isMatch(QueryModeElementOption queryModeElementOption, int count) { - // first find if unused but not empty - if (queryModeElementOption.getSchemaElementOption().equals(SchemaElementOption.UNUSED) && count > 0) { - return false; - } - // find if required but empty - if (queryModeElementOption.getSchemaElementOption().equals(SchemaElementOption.REQUIRED) && count <= 0) { - return false; - } - // find if count no satisfy - if (queryModeElementOption.getRequireNumberType().equals(QueryModeElementOption.RequireNumberType.EQUAL) - && queryModeElementOption.getRequireNumber() != count) { - return false; - } - if (queryModeElementOption.getRequireNumberType().equals(QueryModeElementOption.RequireNumberType.AT_LEAST) - && count < queryModeElementOption.getRequireNumber()) { - return false; - } - if (queryModeElementOption.getRequireNumberType().equals(QueryModeElementOption.RequireNumberType.AT_MOST) - && count > queryModeElementOption.getRequireNumber()) { - return false; - } - // here default satisfy - return true; - } - -} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QuerySelector.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QuerySelector.java new file mode 100644 index 000000000..e84b43586 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/QuerySelector.java @@ -0,0 +1,13 @@ +package com.tencent.supersonic.chat.application.query; + +import com.tencent.supersonic.chat.api.component.SemanticQuery; + +import java.util.List; + +/** + * This interface defines the contract for a selector that picks the most suitable semantic query. + **/ +public interface QuerySelector { + + SemanticQuery select(List candidateQueries); +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQuery.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQuery.java new file mode 100644 index 000000000..6583ad91e --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQuery.java @@ -0,0 +1,87 @@ +package com.tencent.supersonic.chat.application.query; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.*; +import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.api.response.QueryResultResp; +import com.tencent.supersonic.chat.application.DomainEntityService; +import com.tencent.supersonic.chat.domain.utils.ComponentFactory; +import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; +import com.tencent.supersonic.common.util.context.ContextUtils; +import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; +import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.*; + +@Slf4j +@ToString +public abstract class RuleSemanticQuery implements SemanticQuery, Serializable { + + protected SemanticParseInfo parseInfo = new SemanticParseInfo(); + protected List schemaElementMatches = new ArrayList<>(); + protected QueryMatcher queryMatcher = new QueryMatcher(); + protected SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); + + public RuleSemanticQuery() { + RuleSemanticQueryManager.register(this); + } + + public List match(List candidateElementMatches, QueryContextReq queryCtx) { + return queryMatcher.match(candidateElementMatches); + } + + public abstract void inheritContext(ChatContext chatContext); + + @Override + public QueryResultResp execute(User user) { + String queryMode = parseInfo.getQueryMode(); + + if (parseInfo.getDomainId() < 0 || StringUtils.isEmpty(queryMode)) { + // reach here some error may happen + log.error("not find QueryMode"); + throw new RuntimeException("not find QueryMode"); + } + + List semanticQueryModes = RuleSemanticQueryManager.getSemanticQueryModes(); + if (!semanticQueryModes.contains(parseInfo.getQueryMode())) { + return null; + } + + QueryResultResp queryResponse = new QueryResultResp(); + QueryResultWithSchemaResp queryResult = semanticLayer.queryByStruct( + SchemaInfoConverter.convertTo(parseInfo), user); + + if (queryResult != null) { + queryResponse.setQueryAuthorization(queryResult.getQueryAuthorization()); + } + String sql = queryResult == null ? null : queryResult.getSql(); + List> resultList = queryResult == null ? new ArrayList<>() + : queryResult.getResultList(); + List columns = queryResult == null ? new ArrayList<>() : queryResult.getColumns(); + queryResponse.setQuerySql(sql); + queryResponse.setQueryResults(resultList); + queryResponse.setQueryColumns(columns); + queryResponse.setQueryMode(queryMode); + + // add domain info + EntityInfo entityInfo = ContextUtils.getBean(DomainEntityService.class) + .getEntityInfo(parseInfo, user); + queryResponse.setEntityInfo(entityInfo); + return queryResponse; + } + + @Override + public SemanticParseInfo getParseInfo() { + return parseInfo; + } + + public void setParseInfo(SemanticParseInfo parseInfo) { + this.parseInfo = parseInfo; + } +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQueryManager.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQueryManager.java new file mode 100644 index 000000000..74c608dec --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/RuleSemanticQueryManager.java @@ -0,0 +1,39 @@ +package com.tencent.supersonic.chat.application.query; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * RuleSemanticQueryManager + */ +public class RuleSemanticQueryManager { + + private static Map semanticQueryMap = new ConcurrentHashMap<>(); + + public static RuleSemanticQuery create(String queryMode) { + RuleSemanticQuery semanticQuery = semanticQueryMap.get(queryMode); + if (Objects.isNull(semanticQuery)) { + throw new RuntimeException("no supported queryMode :" + queryMode); + } + try { + return semanticQuery.getClass().getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new RuntimeException("no supported queryMode :" + queryMode); + } + } + + public static void register(RuleSemanticQuery query) { + semanticQueryMap.put(query.getQueryMode(), query); + } + + public static List getSemanticQueries() { + return new ArrayList<>(semanticQueryMap.values()); + } + + public static List getSemanticQueryModes() { + return new ArrayList<>(semanticQueryMap.keySet()); + } +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/SemanticQueryFactory.java b/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/SemanticQueryFactory.java deleted file mode 100644 index b9f798c49..000000000 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/query/SemanticQueryFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.tencent.supersonic.chat.application.query; - -import com.tencent.supersonic.chat.api.service.SemanticQuery; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.util.CollectionUtils; - -/** - * SemanticQueryFactory - */ -public class SemanticQueryFactory { - - private static Map strategyFactory = new ConcurrentHashMap<>(); - - private static List semanticQueries; - - - public static SemanticQuery get(String queryMode) { - if (CollectionUtils.isEmpty(strategyFactory)) { - init(); - } - - SemanticQuery semanticQuery = strategyFactory.get(queryMode); - if (Objects.isNull(semanticQuery)) { - throw new RuntimeException("not support queryMode :" + queryMode); - } - return semanticQuery; - } - - private static void init() { - for (SemanticQuery semanticQuery : getSemanticQueries()) { - strategyFactory.put(semanticQuery.getQueryMode(), semanticQuery); - } - } - - public static List getSemanticQueries() { - if (CollectionUtils.isEmpty(semanticQueries)) { - semanticQueries = SpringFactoriesLoader.loadFactories(SemanticQuery.class, - Thread.currentThread().getContextClassLoader()); - } - return semanticQueries; - } -} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/config/LLMConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/config/LLMConfig.java new file mode 100644 index 000000000..2a2310036 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/config/LLMConfig.java @@ -0,0 +1,23 @@ +package com.tencent.supersonic.chat.domain.config; + + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Data +public class LLMConfig { + + + @Value("${llm.url:}") + private String url; + + @Value("${query2sql.path:query2sql}") + private String queryToSqlPath; + + + @Value("${query2sql.endpoint:}") + private String endpoint; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDOExample.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDOExample.java index 4db464747..99d6cd109 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDOExample.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/ChatQueryDOExample.java @@ -5,6 +5,7 @@ import java.util.Date; import java.util.List; public class ChatQueryDOExample { + protected String orderByClause; protected boolean distinct; protected List oredCriteria; @@ -15,23 +16,22 @@ public class ChatQueryDOExample { oredCriteria = new ArrayList(); } - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - - public String getOrderByClause() { return orderByClause; } - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } public boolean isDistinct() { return distinct; } + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + public List getOredCriteria() { return oredCriteria; } @@ -65,22 +65,22 @@ public class ChatQueryDOExample { distinct = false; } - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - public Integer getLimitStart() { return limitStart; } - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } public Integer getLimitEnd() { return limitEnd; } + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + protected abstract static class GeneratedCriteria { protected List criteria; @@ -589,38 +589,6 @@ public class ChatQueryDOExample { 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; @@ -656,5 +624,37 @@ public class ChatQueryDOExample { 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/domain/dataobject/QueryDO.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/QueryDO.java index d930b8680..4564714b0 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/QueryDO.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/dataobject/QueryDO.java @@ -5,6 +5,9 @@ import lombok.Data; @Data public class QueryDO { + public String aggregator = "trend"; + public String startTime; + public String endTime; private long id; private long questionId; private String createTime; @@ -19,10 +22,7 @@ public class QueryDO { private int isDeleted; private String module; private long chatId; - public String aggregator = "trend"; private int topNum; - public String startTime; - public String endTime; private String querySql; private Object queryColumn; private Object entityInfo; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMReq.java new file mode 100644 index 000000000..a656d69c9 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMReq.java @@ -0,0 +1,11 @@ +package com.tencent.supersonic.chat.domain.pojo.chat; + +import lombok.Data; + +@Data +public class LLMReq { + + private String queryText; + private LLMSchema schema; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMResp.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMResp.java new file mode 100644 index 000000000..b750161bf --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMResp.java @@ -0,0 +1,20 @@ +package com.tencent.supersonic.chat.domain.pojo.chat; + +import java.util.List; +import lombok.Data; + +@Data +public class LLMResp { + + private String query; + + private String domainName; + + private String sqlOutput; + + private List fields; + + private String schemaLinkingOutput; + + private String schemaLinkStr; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMSchema.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMSchema.java new file mode 100644 index 000000000..a94141bcc --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/LLMSchema.java @@ -0,0 +1,13 @@ +package com.tencent.supersonic.chat.domain.pojo.chat; + +import java.util.List; +import lombok.Data; + +@Data +public class LLMSchema { + + private String domainName; + + private List fieldNameList; + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/PageQueryInfoReq.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/PageQueryInfoReq.java index 0d0df60a9..a6b092ae1 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/PageQueryInfoReq.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/chat/PageQueryInfoReq.java @@ -15,20 +15,20 @@ public class PageQueryInfoReq { return pageSize; } - public int getCurrent() { - return current; + public void setPageSize(int pageSize) { + this.pageSize = pageSize; } - public String getUserName() { - return userName; + public int getCurrent() { + return current; } public void setCurrent(int current) { this.current = current; } - public void setPageSize(int pageSize) { - this.pageSize = pageSize; + public String getUserName() { + return userName; } public void setUserName(String userName) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeInfo.java index 393d2f0fb..5ccd0c1dd 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeInfo.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/pojo/config/KnowledgeInfo.java @@ -1,8 +1,10 @@ package com.tencent.supersonic.chat.domain.pojo.config; import com.tencent.supersonic.common.enums.TypeEnums; + import java.util.List; import javax.validation.constraints.NotNull; + import lombok.Data; /** @@ -17,6 +19,7 @@ public class KnowledgeInfo { */ private Long itemId; + private String bizName; /** * type: IntentionTypeEnum * temporarily only supports dimension-related information diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatRepository.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatRepository.java index a46859306..da1990ed0 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatRepository.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/repository/ChatRepository.java @@ -12,6 +12,8 @@ public interface ChatRepository { Boolean updateChatName(Long chatId, String chatName, String lastTime, String creator); + Boolean updateLastQuestion(Long chatId, String lastQuestion, String lastTime); + Boolean updateConversionIsTop(Long chatId, int isTop); boolean updateFeedback(QueryDO queryDO); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ChatService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ChatService.java index 79dd8ceb3..531232822 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ChatService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ChatService.java @@ -3,6 +3,7 @@ package com.tencent.supersonic.chat.domain.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.SemanticParseInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; import com.tencent.supersonic.chat.api.response.QueryResultResp; import com.tencent.supersonic.chat.domain.dataobject.ChatDO; @@ -24,6 +25,8 @@ public interface ChatService { public void updateContext(ChatContext chatCtx); + public void updateContext(ChatContext chatCtx, QueryContextReq queryCtx, SemanticParseInfo semanticParseInfo); + public void switchContext(ChatContext chatCtx); public Boolean addChat(User user, String chatName); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ConfigService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ConfigService.java index 64acd2dd1..4a313fea8 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ConfigService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/ConfigService.java @@ -18,4 +18,6 @@ public interface ConfigService { List search(ChatConfigFilter filter, User user); ChatConfigRichInfo getConfigRichInfo(Long domainId); + + List getAllChatRichConfig(); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/QueryService.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/QueryService.java index e9c0af105..f80be7fb7 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/QueryService.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/service/QueryService.java @@ -11,9 +11,9 @@ import com.tencent.supersonic.chat.domain.pojo.chat.QueryData; */ public interface QueryService { - public QueryResultResp executeQuery(QueryContextReq queryCtx) throws Exception; + QueryResultResp executeQuery(QueryContextReq queryCtx) throws Exception; - public SemanticParseInfo queryContext(QueryContextReq queryCtx); + SemanticParseInfo queryContext(QueryContextReq queryCtx); - QueryResultResp queryData(QueryData queryData, User user) throws Exception; + QueryResultResp executeDirectQuery(QueryData queryData, User user) throws Exception; } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ChatConfigUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ChatConfigUtils.java index c3517d08a..f79114003 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ChatConfigUtils.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ChatConfigUtils.java @@ -88,7 +88,7 @@ public class ChatConfigUtils { } public EntityInternalDetail generateEntityDetailData(EntityDetailData detailData, - DomainSchemaResp domainSchemaDesc) { + DomainSchemaResp domainSchemaDesc) { EntityInternalDetail entityInternalDetailDesc = new EntityInternalDetail(); if (Objects.isNull(detailData)) { return entityInternalDetailDesc; @@ -100,7 +100,7 @@ public class ChatConfigUtils { } public Map generateMetricIdAndDescPair(List metricIds, - DomainSchemaResp domainSchemaDesc) { + DomainSchemaResp domainSchemaDesc) { Map metricIdAndDescPair = new HashMap<>(); List metricDescList = generateMetricDesc(metricIds, domainSchemaDesc); @@ -118,6 +118,9 @@ public class ChatConfigUtils { } public List generateAllMetricIdList(DomainSchemaResp domainSchemaDesc) { + if (Objects.isNull(domainSchemaDesc) || CollectionUtils.isEmpty(domainSchemaDesc.getMetrics())) { + return new ArrayList<>(); + } Map> metricIdAndDescPair = domainSchemaDesc.getMetrics() .stream().collect(Collectors.groupingBy(MetricSchemaResp::getId)); return new ArrayList<>(metricIdAndDescPair.keySet()); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ComponentFactory.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ComponentFactory.java new file mode 100644 index 000000000..6fcdcb4ed --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ComponentFactory.java @@ -0,0 +1,67 @@ +package com.tencent.supersonic.chat.domain.utils; + +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 java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.tencent.supersonic.chat.application.parser.DomainResolver; +import com.tencent.supersonic.chat.application.query.QuerySelector; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.core.io.support.SpringFactoriesLoader; + +public class ComponentFactory { + + private static List schemaMappers = new ArrayList<>(); + private static List semanticParsers = new ArrayList<>(); + private static SemanticLayer semanticLayer; + private static QuerySelector querySelector; + private static DomainResolver domainResolver; + + public static List getSchemaMappers() { + return CollectionUtils.isEmpty(schemaMappers) ? init(SchemaMapper.class, schemaMappers) : schemaMappers; + } + + public static List getSemanticParsers() { + return CollectionUtils.isEmpty(semanticParsers) ? init(SemanticParser.class, semanticParsers) : semanticParsers; + } + + public static SemanticLayer getSemanticLayer() { + if (Objects.isNull(semanticLayer)) { + semanticLayer = init(SemanticLayer.class); + } + return semanticLayer; + } + + public static void setSemanticLayer(SemanticLayer layer) { + semanticLayer = layer; + } + + public static QuerySelector getQuerySelector() { + if (Objects.isNull(querySelector)) { + querySelector = init(QuerySelector.class); + } + return querySelector; + } + + public static DomainResolver getDomainResolver() { + if (Objects.isNull(domainResolver)) { + domainResolver = init(DomainResolver.class); + } + return domainResolver; + } + + private static List init(Class factoryType, List list) { + list.addAll(SpringFactoriesLoader.loadFactories(factoryType, + Thread.currentThread().getContextClassLoader())); + return list; + } + + private static T init(Class factoryType) { + return SpringFactoriesLoader.loadFactories(factoryType, + Thread.currentThread().getContextClassLoader()).get(0); + } +} \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ContextHelper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ContextHelper.java index 9ceeb84fd..2d647c245 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ContextHelper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/ContextHelper.java @@ -2,11 +2,11 @@ package com.tencent.supersonic.chat.domain.utils; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.Filter; -import com.tencent.supersonic.chat.api.pojo.SchemaElementCount; +import com.tencent.supersonic.chat.api.pojo.QueryMatchInfo; import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; -import com.tencent.supersonic.chat.api.service.SemanticQuery; +import com.tencent.supersonic.chat.api.component.SemanticQuery; import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; import com.tencent.supersonic.common.pojo.SchemaItem; @@ -22,6 +22,21 @@ import java.util.Optional; public class ContextHelper { + public static Comparator> DomainStatComparator + = (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue()); + public static Comparator> SemanticQueryStatComparator + = (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue()); + /** + * similarity desc + */ + public static Comparator schemaElementMatchComparatorBySimilarity + = new Comparator() { + @Override + public int compare(SchemaElementMatch o1, SchemaElementMatch o2) { + return (int) ((o2.getSimilarity() - o1.getSimilarity()) * 100); + } + }; + public static void updateDomain(SemanticParseInfo from, SemanticParseInfo to) { if (from != null && from.getDomainId() != null) { to.setDomainId(from.getDomainId()); @@ -65,6 +80,15 @@ public class ContextHelper { } } + public static void updateDomainIfEmpty(SemanticParseInfo from, SemanticParseInfo to) { + if (from != null && from.getDomainId() != null && to.getDomainId() == null) { + to.setDomainId(from.getDomainId()); + } + + if (from != null && from.getDomainName() != null && to.getDomainName() == null) { + to.setDomainName(from.getDomainName()); + } + } /** * add from to list if list is empty and from is not empty @@ -105,7 +129,7 @@ public class ContextHelper { /** * count desc > similarity desc */ - public static int domainSchemaElementCountComparator(SchemaElementCount o1, SchemaElementCount o2) { + public static int domainSchemaElementCountComparator(QueryMatchInfo o1, QueryMatchInfo o2) { int difference = o1.getCount() - o2.getCount(); if (difference == 0) { return (int) ((o1.getMaxSimilarity() - o2.getMaxSimilarity()) * 100); @@ -113,22 +137,6 @@ public class ContextHelper { return difference; } - public static Comparator> DomainStatComparator - = (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue()); - - public static Comparator> SemanticQueryStatComparator - = (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue()); - /** - * similarity desc - */ - public static Comparator schemaElementMatchComparatorBySimilarity - = new Comparator() { - @Override - public int compare(SchemaElementMatch o1, SchemaElementMatch o2) { - return (int) ((o2.getSimilarity() - o1.getSimilarity()) * 100); - } - }; - public static void setEntityId(Long dimensionId, String value, ChatConfigRichInfo chaConfigRichDesc, SemanticParseInfo semanticParseInfo) { if (chaConfigRichDesc != null && chaConfigRichDesc.getEntity() != null) { @@ -152,35 +160,42 @@ public class ContextHelper { * @param toSchemaElementMatch * @param elementMatches * @param schemaElementTypes - * @param contextSemanticParseInfo + * @param contextSemanticParse */ public static void mergeContextSchemaElementMatch(List toSchemaElementMatch, List elementMatches, List schemaElementTypes, - SemanticParseInfo contextSemanticParseInfo) { + SemanticParseInfo contextSemanticParse) { + + SchemaElementMatch domainMatch = SchemaElementMatch.builder() + .elementType(SchemaElementType.DOMAIN) + .elementID(contextSemanticParse.getDomainId().intValue()) + .similarity(1.0) + .word(contextSemanticParse.getDomainName()) + .detectWord(contextSemanticParse.getDomainName()) + .build(); + toSchemaElementMatch.add(domainMatch); + for (SchemaElementType schemaElementType : schemaElementTypes) { switch (schemaElementType) { case DIMENSION: - if (contextSemanticParseInfo.getDimensions() != null - && contextSemanticParseInfo.getDimensions().size() > 0) { - for (SchemaItem dimension : contextSemanticParseInfo.getDimensions()) { + if (contextSemanticParse.getDimensions().size() > 0) { + for (SchemaItem dimension : contextSemanticParse.getDimensions()) { addSchemaElementMatch(toSchemaElementMatch, elementMatches, SchemaElementType.DIMENSION, dimension); } } break; case METRIC: - if (contextSemanticParseInfo.getMetrics() != null - && contextSemanticParseInfo.getMetrics().size() > 0) { - for (SchemaItem metric : contextSemanticParseInfo.getMetrics()) { + if (contextSemanticParse.getMetrics().size() > 0) { + for (SchemaItem metric : contextSemanticParse.getMetrics()) { addSchemaElementMatch(toSchemaElementMatch, elementMatches, SchemaElementType.METRIC, metric); } } break; case VALUE: - if (contextSemanticParseInfo.getDimensionFilters() != null - && contextSemanticParseInfo.getDimensionFilters().size() > 0) { - for (Filter chatFilter : contextSemanticParseInfo.getDimensionFilters()) { + if (contextSemanticParse.getDimensionFilters().size() > 0) { + for (Filter chatFilter : contextSemanticParse.getDimensionFilters()) { if (!isInSchemaElementMatchList(elementMatches, SchemaElementType.VALUE, chatFilter.getValue().toString())) { toSchemaElementMatch.add( @@ -228,13 +243,12 @@ public class ContextHelper { private static SchemaElementMatch getSchemaElementMatchByContext(int id, String word, SchemaElementType schemaElementType) { - SchemaElementMatch schemaElementMatch = new SchemaElementMatch(); - schemaElementMatch.setElementID(id); - schemaElementMatch.setElementType(schemaElementType); - schemaElementMatch.setWord(word); - // todo default similarity - schemaElementMatch.setSimilarity(0.5); - return schemaElementMatch; + return SchemaElementMatch.builder() + .elementID(id) + .elementType(schemaElementType) + .word(word) + .similarity(0.5) + .build(); } } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DefaultMetricSemanticParser.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultMetricUtils.java similarity index 54% rename from chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DefaultMetricSemanticParser.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultMetricUtils.java index 2d8036ecf..24d6d8530 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/application/parser/DefaultMetricSemanticParser.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultMetricUtils.java @@ -1,4 +1,4 @@ -package com.tencent.supersonic.chat.application.parser; +package com.tencent.supersonic.chat.domain.utils; import static java.time.LocalDate.now; @@ -8,22 +8,21 @@ import com.tencent.supersonic.chat.api.pojo.SchemaElementType; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.chat.api.service.SemanticParser; -import com.tencent.supersonic.chat.application.parser.resolver.DomainResolver; +import com.tencent.supersonic.chat.application.parser.DomainResolver; import com.tencent.supersonic.chat.application.query.EntityDetail; import com.tencent.supersonic.chat.application.query.EntityListFilter; +import com.tencent.supersonic.chat.application.query.EntityListTopN; import com.tencent.supersonic.chat.application.query.EntityMetricFilter; import com.tencent.supersonic.chat.application.query.MetricDomain; import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo; import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric; import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; -import com.tencent.supersonic.chat.domain.service.ChatService; -import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.SchemaItem; import com.tencent.supersonic.common.util.context.ContextUtils; import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -31,99 +30,129 @@ import java.util.Objects; import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @Slf4j @Component -public class DefaultMetricSemanticParser implements SemanticParser { +public class DefaultMetricUtils { - private final Logger logger = LoggerFactory.getLogger(DefaultMetricSemanticParser.class); - private DomainResolver selectStrategy; - private ChatService chatService; - private DefaultSemanticInternalUtils defaultSemanticUtils; - - @Override - public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) { - selectStrategy = ContextUtils.getBean(DomainResolver.class); - chatService = ContextUtils.getBean(ChatService.class); - defaultSemanticUtils = ContextUtils.getBean(DefaultSemanticInternalUtils.class); - String queryMode = queryContext.getParseInfo().getQueryMode(); + /** + * supplementary default metric date dimension + */ + public void injectDefaultMetric(SemanticParseInfo semanticParseInfo, QueryContextReq queryContext, + ChatContext chatContext) { + String queryMode = semanticParseInfo.getQueryMode(); + ChatConfigRichInfo chaConfigRichDesc = null; if (StringUtils.isNotEmpty(queryMode)) { - // QueryMode Selected + if (semanticParseInfo == null) { + return; + } if (!EntityListFilter.QUERY_MODE.equals(queryMode)) { + boolean isFillThemeDefaultMetricLogic = false; + boolean isAddEntityDetailDimensionMetric = false; Integer domainId = queryContext.getDomainId().intValue(); - List matchedElements = queryContext.getMapInfo().getMatchedElements(domainId); if (!CollectionUtils.isEmpty(matchedElements)) { long metricCount = matchedElements.stream() .filter(schemaElementMatch -> schemaElementMatch.getElementType() .equals(SchemaElementType.METRIC)).count(); if (metricCount <= 0) { - if (chatCtx.getParseInfo() == null - || chatCtx.getParseInfo().getMetrics() == null - || chatCtx.getParseInfo().getMetrics().size() <= 0) { - logger.info("fillThemeDefaultMetricLogic"); - fillThemeDefaultMetricLogic(queryContext.getParseInfo()); + if (chatContext.getParseInfo() == null + || chatContext.getParseInfo().getMetrics() == null + || chatContext.getParseInfo().getMetrics().size() <= 0) { + log.info("fillThemeDefaultMetricLogic"); + isFillThemeDefaultMetricLogic = true; } } + } else { + log.info("fillThemeDefaultMetricLogic for empty matchedElements "); + isFillThemeDefaultMetricLogic = true; } - fillDateDomain(chatCtx, queryContext); + if (EntityDetail.QUERY_MODE.equals(queryMode) || EntityMetricFilter.QUERY_MODE.equals(queryMode)) { + isAddEntityDetailDimensionMetric = true; + dealNativeQuery(semanticParseInfo, queryContext, true); + } + + if (isFillThemeDefaultMetricLogic) { + if (chaConfigRichDesc == null) { + chaConfigRichDesc = getChatConfigRichInfo(semanticParseInfo.getDomainId()); + } + fillThemeDefaultMetricLogic(semanticParseInfo, chaConfigRichDesc, queryContext); + } + if (isAddEntityDetailDimensionMetric) { + if (chaConfigRichDesc == null) { + chaConfigRichDesc = getChatConfigRichInfo(semanticParseInfo.getDomainId()); + } + addEntityDetailDimensionMetric(semanticParseInfo, chaConfigRichDesc, queryContext, chatContext); + } + fillDateDomain(semanticParseInfo, chatContext, chaConfigRichDesc, queryContext); } - } - defaultQueryMode(queryContext, chatCtx); - - if (EntityDetail.QUERY_MODE.equals(queryMode) || EntityMetricFilter.QUERY_MODE.equals(queryMode)) { - addEntityDetailDimensionMetric(queryContext, chatCtx); - dealNativeQuery(queryContext, true); - } - - return false; - } - - private void dealNativeQuery(QueryContextReq queryContext, boolean isNativeQuery) { - if (Objects.nonNull(queryContext) && Objects.nonNull(queryContext.getParseInfo())) { - queryContext.getParseInfo().setNativeQuery(isNativeQuery); + defaultQueryMode(semanticParseInfo, queryContext, chatContext); + addEntityTopDimension(semanticParseInfo, chaConfigRichDesc); } } - private Set addPrimaryDimension(EntityRichInfo entity, List dimensions) { + public void dealNativeQuery(SemanticParseInfo semanticParseInfo, QueryContextReq queryContext, + boolean isNativeQuery) { + if (Objects.nonNull(queryContext) && Objects.nonNull(semanticParseInfo)) { + semanticParseInfo.setNativeQuery(isNativeQuery); + } + } + + public Set addPrimaryDimension(EntityRichInfo entity, List dimensions) { Set primaryDimensions = new HashSet<>(); if (Objects.isNull(entity) || CollectionUtils.isEmpty(entity.getEntityIds())) { return primaryDimensions; } entity.getEntityIds().stream().forEach(dimSchemaDesc -> { SchemaItem dimension = new SchemaItem(); - BeanUtils.copyProperties(dimSchemaDesc, dimension); + //BeanUtils.copyProperties(dimSchemaDesc, dimension); + dimension.setName(dimSchemaDesc.getName()); + dimension.setBizName(dimSchemaDesc.getBizName()); + dimension.setId(dimSchemaDesc.getId()); dimensions.add(dimension); primaryDimensions.add(dimSchemaDesc.getBizName()); }); return primaryDimensions; } - protected void addEntityDetailDimensionMetric(QueryContextReq queryContext, ChatContext chatCtx) { - if (queryContext.getParseInfo().getDomainId() > 0) { - Long domainId = queryContext.getParseInfo().getDomainId(); - ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(domainId); + public void addEntityTopDimension(SemanticParseInfo semanticParseInfo, ChatConfigRichInfo chaConfigRichDesc) { + if (!semanticParseInfo.getQueryMode().equals(EntityListTopN.QUERY_MODE) || !semanticParseInfo.getDimensions() + .isEmpty()) { + return; + } + if (semanticParseInfo.getDomainId() > 0) { + Long domainId = semanticParseInfo.getDomainId(); + if (chaConfigRichDesc == null) { + chaConfigRichDesc = getChatConfigRichInfo(domainId); + } + if (chaConfigRichDesc != null && chaConfigRichDesc.getEntity() != null) { + List dimensions = new ArrayList<>(); + addPrimaryDimension(chaConfigRichDesc.getEntity(), dimensions); + semanticParseInfo.setDimensions(new HashSet<>(dimensions)); + semanticParseInfo.setLimit(1L); + } + } + } + + public void addEntityDetailDimensionMetric(SemanticParseInfo semanticParseInfo, + ChatConfigRichInfo chaConfigRichDesc, QueryContextReq queryContext, + ChatContext chatCtx) { + if (semanticParseInfo.getDomainId() > 0) { + Long domainId = semanticParseInfo.getDomainId(); + if (chaConfigRichDesc != null) { if (chaConfigRichDesc.getEntity() == null || chaConfigRichDesc.getEntity().getEntityInternalDetailDesc() == null) { return; } - SemanticParseInfo semanticParseInfo = queryContext.getParseInfo(); - Set metrics = new LinkedHashSet(); - chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getMetricList().stream() - .forEach(m -> metrics.add(getMetric(m))); - semanticParseInfo.setMetrics(metrics); List schemaElementMatches = queryContext.getMapInfo() .getMatchedElements(domainId.intValue()); if (CollectionUtils.isEmpty(schemaElementMatches) || schemaElementMatches.stream() .filter(s -> SchemaElementType.DIMENSION.equals(s.getElementType())).count() <= 0) { - logger.info("addEntityDetailDimensionMetric catch"); + log.info("addEntityDetailDimensionMetric catch"); Set dimensions = new LinkedHashSet(); chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getDimensionList().stream() .forEach(m -> dimensions.add(getDimension(m))); @@ -134,10 +163,10 @@ public class DefaultMetricSemanticParser implements SemanticParser { } } - protected void defaultQueryMode(QueryContextReq queryContext, ChatContext chatCtx) { + public void defaultQueryMode(SemanticParseInfo semanticParseInfo, QueryContextReq queryContext, + ChatContext chatCtx) { SchemaMapInfo schemaMap = queryContext.getMapInfo(); - SemanticParseInfo parseInfo = queryContext.getParseInfo(); - if (StringUtils.isEmpty(parseInfo.getQueryMode())) { + if (StringUtils.isEmpty(semanticParseInfo.getQueryMode())) { if (chatCtx.getParseInfo() != null && chatCtx.getParseInfo().getDomainId() > 0) { // Long domain = chatCtx.getParseInfo().getDomainId(); @@ -154,9 +183,9 @@ public class DefaultMetricSemanticParser implements SemanticParser { .filter(e -> e.getElementType().equals(SchemaElementType.METRIC)).count(); if (filterNUm > 0 && dimensionNUm > 0 && metricrNUm > 0) { // default as entity detail queryMode - logger.info("defaultQueryMode [{}]", EntityDetail.QUERY_MODE); - parseInfo.setQueryMode(EntityDetail.QUERY_MODE); - parseInfo.setDomainId(domain); + log.info("defaultQueryMode [{}]", EntityDetail.QUERY_MODE); + semanticParseInfo.setQueryMode(EntityDetail.QUERY_MODE); + semanticParseInfo.setDomainId(domain); return; } Long entityNUm = elementMatches.stream() @@ -165,21 +194,21 @@ public class DefaultMetricSemanticParser implements SemanticParser { // default as metric domain if (metricrNUm > 0 || MetricDomain.QUERY_MODE.equals(queryMode)) { // default as entity detail queryMode - logger.info("defaultQueryMode [{}]", MetricDomain.QUERY_MODE); - parseInfo.setQueryMode(MetricDomain.QUERY_MODE); - parseInfo.setDomainId(domain); + log.info("defaultQueryMode [{}]", MetricDomain.QUERY_MODE); + semanticParseInfo.setQueryMode(MetricDomain.QUERY_MODE); + semanticParseInfo.setDomainId(domain); return; } } } - if (CollectionUtils.isEmpty(schemaMap.getMatchedDomains()) && parseInfo != null - && parseInfo.getDateInfo() != null) { + if (CollectionUtils.isEmpty(schemaMap.getMatchedDomains()) && semanticParseInfo != null + && semanticParseInfo.getDateInfo() != null) { // only query time if (MetricDomain.QUERY_MODE.equals(queryMode)) { // METRIC_DOMAIN context - logger.info("defaultQueryMode [{}]", MetricDomain.QUERY_MODE); - parseInfo.setQueryMode(MetricDomain.QUERY_MODE); - parseInfo.setDomainId(domain); + log.info("defaultQueryMode [{}]", MetricDomain.QUERY_MODE); + semanticParseInfo.setQueryMode(MetricDomain.QUERY_MODE); + semanticParseInfo.setDomainId(domain); return; } } @@ -188,12 +217,14 @@ public class DefaultMetricSemanticParser implements SemanticParser { } - private void fillDateDomain(ChatContext chatCtx, QueryContextReq queryContext) { - SemanticParseInfo parseInfo = queryContext.getParseInfo(); + public void fillDateDomain(SemanticParseInfo parseInfo, ChatContext chatCtx, ChatConfigRichInfo chaConfigRichDesc, + QueryContextReq queryContext) { + //SemanticParseInfo parseInfo = queryContext.getParseInfo(); if (parseInfo == null || parseInfo.getDateInfo() == null) { + DomainResolver selectStrategy = ComponentFactory.getDomainResolver(); boolean isUpdateTime = false; - if (selectStrategy.isDomainSwitch(chatCtx, queryContext)) { + if (selectStrategy.isDomainSwitch(chatCtx, parseInfo)) { isUpdateTime = true; } if (chatCtx.getParseInfo() == null @@ -201,23 +232,31 @@ public class DefaultMetricSemanticParser implements SemanticParser { isUpdateTime = true; } if (isUpdateTime && parseInfo != null && parseInfo.getDomainId() > 0) { - logger.info("fillThemeDefaultTime"); - fillThemeDefaultTime(parseInfo.getDomainId(), parseInfo); + fillThemeDefaultTime(parseInfo.getDomainId(), chaConfigRichDesc, parseInfo); } } } - private void fillThemeDefaultMetricLogic(SemanticParseInfo semanticParseInfo) { - ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo( - semanticParseInfo.getDomainId()); + public void fillThemeDefaultMetricLogic(SemanticParseInfo semanticParseInfo, ChatConfigRichInfo chaConfigRichDesc, + QueryContextReq queryContext) { + //SemanticParseInfo semanticParseInfo = queryContext.getParseInfo(); if (Objects.isNull(chaConfigRichDesc) || CollectionUtils.isEmpty(chaConfigRichDesc.getDefaultMetrics())) { log.info("there is no defaultMetricIds info"); return; } - if (CollectionUtils.isEmpty(semanticParseInfo.getMetrics()) && CollectionUtils.isEmpty( - semanticParseInfo.getDimensions())) { + if (queryContext.getMapInfo() == null || !queryContext.getMapInfo().getMatchedDomains() + .contains(chaConfigRichDesc.getDomainId().intValue())) { + return; + } + List schemaElementMatches = queryContext.getMapInfo() + .getMatchedElements(chaConfigRichDesc.getDomainId().intValue()); + long metricNum = schemaElementMatches.stream().filter(e -> e.getElementType().equals(SchemaElementType.METRIC)) + .count(); + long dimensionNum = schemaElementMatches.stream() + .filter(e -> e.getElementType().equals(SchemaElementType.DIMENSION)).count(); + if (metricNum <= 0 && dimensionNum <= 0) { Set metrics = new LinkedHashSet(); chaConfigRichDesc.getDefaultMetrics().stream().forEach(metric -> { SchemaItem metricTmp = new SchemaItem(); @@ -240,9 +279,15 @@ public class DefaultMetricSemanticParser implements SemanticParser { } - private void fillThemeDefaultTime(Long domain, SemanticParseInfo semanticParseInfo) { - ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo( - semanticParseInfo.getDomainId()); + public void fillThemeDefaultTime(Long domain, ChatConfigRichInfo chaConfigRichDesc, + SemanticParseInfo semanticParseInfo) { + if (!Objects.isNull(semanticParseInfo.getDateInfo()) && !Objects.isNull( + semanticParseInfo.getDateInfo().getDateMode())) { + return; + } + if (chaConfigRichDesc == null) { + chaConfigRichDesc = getChatConfigRichInfo(semanticParseInfo.getDomainId()); + } if (!Objects.isNull(chaConfigRichDesc) && !CollectionUtils.isEmpty(chaConfigRichDesc.getDefaultMetrics())) { DefaultMetric defaultMetricInfo = chaConfigRichDesc.getDefaultMetrics().get(0); DateConf dateInfo = new DateConf(); @@ -252,9 +297,16 @@ public class DefaultMetricSemanticParser implements SemanticParser { dateInfo.setEndDate(now().minusDays(1).toString()); dateInfo.setPeriod(defaultMetricInfo.getPeriod()); semanticParseInfo.setDateInfo(dateInfo); + log.info("fillThemeDefaultTime"); } } + public ChatConfigRichInfo getChatConfigRichInfo(Long domain) { + DefaultSemanticInternalUtils defaultSemanticUtils = ContextUtils.getBean(DefaultSemanticInternalUtils.class); + ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(domain); + return chaConfigRichDesc; + } + private SchemaItem getMetric(MetricSchemaResp metricSchemaDesc) { SchemaItem queryMeta = new SchemaItem(); queryMeta.setId(metricSchemaDesc.getId()); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultSemanticInternalUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultSemanticInternalUtils.java index ca9f6f407..aa163dffc 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultSemanticInternalUtils.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DefaultSemanticInternalUtils.java @@ -19,10 +19,12 @@ import com.tencent.supersonic.common.result.ReturnCode; import com.tencent.supersonic.common.util.context.S2ThreadContext; import com.tencent.supersonic.common.util.context.ThreadContext; import com.tencent.supersonic.common.util.json.JsonUtil; + import java.net.URI; import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; + import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.BeanUtils; @@ -139,13 +141,13 @@ public class DefaultSemanticInternalUtils { headers.set(authenticationConfig.getTokenHttpHeaderKey(), threadContext.getToken()); } } else { - log.info("threadContext is null:{}", Objects.isNull(threadContext)); + log.debug("threadContext is null:{}", Objects.isNull(threadContext)); } } - public List getDomainListForUser(User user) { + public List getDomainListForAdmin() { Object domainDescListObject = fetchHttpResult(semanticUrl + fetchDomainListPath, null, HttpMethod.GET); - List domainDescList = (List) domainDescListObject; + List domainDescList = JsonUtil.toList(JsonUtil.toString(domainDescListObject), DomainResp.class); return domainDescList; } } \ No newline at end of file diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictMetaUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictMetaUtils.java index 9590908aa..919a7b14e 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictMetaUtils.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictMetaUtils.java @@ -3,7 +3,7 @@ package com.tencent.supersonic.chat.domain.utils; import static com.tencent.supersonic.common.constant.Constants.DAY; import static com.tencent.supersonic.common.constant.Constants.UNDERLINE; -import com.tencent.supersonic.chat.api.service.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; import com.tencent.supersonic.chat.domain.dataobject.DimValueDO; @@ -32,15 +32,12 @@ import org.springframework.util.CollectionUtils; @Component public class DictMetaUtils { + private final DefaultSemanticInternalUtils defaultSemanticUtils; @Value("${model.internal.metric.suffix:internal_cnt}") private String internalMetricNameSuffix; + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); - private final SemanticLayer semanticLayer; - private final DefaultSemanticInternalUtils defaultSemanticUtils; - - public DictMetaUtils(SemanticLayer semanticLayer, - DefaultSemanticInternalUtils defaultSemanticUtils) { - this.semanticLayer = semanticLayer; + public DictMetaUtils(DefaultSemanticInternalUtils defaultSemanticUtils) { this.defaultSemanticUtils = defaultSemanticUtils; } @@ -131,7 +128,7 @@ public class DictMetaUtils { } private void fillDimValueDOList(List dimValueDOList, Long domainId, - Map dimIdAndDescPair) { + Map dimIdAndDescPair) { ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(domainId); if (Objects.nonNull(chaConfigRichDesc)) { diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictQueryUtils.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictQueryUtils.java index d1f72fafe..2b6c2610f 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictQueryUtils.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DictQueryUtils.java @@ -6,7 +6,7 @@ import static com.tencent.supersonic.common.constant.Constants.COMMA; import static com.tencent.supersonic.common.constant.Constants.UNDERLINE_DOUBLE; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.service.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticLayer; import com.tencent.supersonic.semantic.api.core.pojo.QueryColumn; import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; @@ -19,6 +19,7 @@ import com.tencent.supersonic.common.enums.AggOperatorEnum; import com.tencent.supersonic.common.pojo.Aggregator; import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.Order; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -26,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.StringJoiner; + import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Value; @@ -36,9 +38,8 @@ import org.springframework.util.CollectionUtils; @Component public class DictQueryUtils { - private final SemanticLayer semanticLayer; Long frequencyMax = 99999999L; - + private SemanticLayer semanticLayer = ComponentFactory.getSemanticLayer(); @Value("${dimension.multi.value.split:#}") private String dimMultiValueSplit; @@ -48,11 +49,6 @@ public class DictQueryUtils { @Value("${dimension.max.limit:3000000}") private Long dimMaxLimit; - public DictQueryUtils(SemanticLayer semanticLayer) { - this.semanticLayer = semanticLayer; - } - - public List fetchDimValueSingle(Long domainId, DefaultMetric defaultMetricDesc, Dim4Dict dim4Dict, User user) { List data = new ArrayList<>(); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfo.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfo.java new file mode 100644 index 000000000..ee35e2864 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfo.java @@ -0,0 +1,89 @@ +package com.tencent.supersonic.chat.domain.utils; + +import static java.time.LocalDate.now; + +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.application.knowledge.WordNatureService; +import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; +import com.tencent.supersonic.chat.domain.pojo.chat.LLMResp; +import com.tencent.supersonic.common.nlp.ItemDO; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.util.calcite.SqlParseUtils; +import com.tencent.supersonic.common.util.calcite.SqlParserInfo; +import com.tencent.supersonic.common.util.context.ContextUtils; +import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DslToSemanticInfo { + + public static final String SUB_TABLE = " ( select * from t_{0} where {1} >= ''{2}'' and {1} <= ''{3}'' ) as t_sub_{0}"; + private static final Logger LOG = LoggerFactory.getLogger(DslToSemanticInfo.class); + + public static String convert(SemanticParseInfo parseInfo, LLMResp llmResp) { + + String sqlOutput = llmResp.getSqlOutput(); + String domainName = llmResp.getDomainName(); + + DomainInfos domainInfos = ContextUtils.getBean(WordNatureService.class).getCache().getUnchecked(""); + + SqlParserInfo sqlParseInfo = SqlParseUtils.getSqlParseInfo(sqlOutput); + String tableName = sqlParseInfo.getTableName(); + if (StringUtils.isEmpty(domainName)) { + domainName = tableName; + } + + List allFields = sqlParseInfo.getAllFields(); + Map domainNameToId = domainInfos.getDomains().stream() + .collect(Collectors.toMap(ItemDO::getName, a -> a.getDomain(), (k1, k2) -> k1)); + + Integer domainId = domainNameToId.get(domainName); + LOG.info("sqlParseInfo:{} ,domainName:{},domainId:{}", sqlParseInfo, domainName, domainId); + + List fieldList = domainInfos.getMetrics(); + fieldList.addAll(domainInfos.getDimensions()); + Map fieldToBizName = getMapInfo(domainId, fieldList); + + for (String fieldName : allFields) { + String fieldBizName = fieldToBizName.get(fieldName); + if (StringUtils.isNotEmpty(fieldBizName)) { + sqlOutput = sqlOutput.replaceAll(fieldName, fieldBizName); + } + } + DateConf dateInfo = new DateConf(); + if (Objects.nonNull(parseInfo) && Objects.nonNull(parseInfo.getDateInfo())) { + dateInfo = parseInfo.getDateInfo(); + } else { + String startDate = now().plusDays(-4).toString(); + String endDate = now().plusDays(-4).toString(); + dateInfo.setStartDate(startDate); + dateInfo.setEndDate(endDate); + } + + String startDate = dateInfo.getStartDate(); + String endDate = dateInfo.getEndDate(); + String period = dateInfo.getPeriod(); + TimeDimensionEnum timeDimension = TimeDimensionEnum.valueOf(period); + String dayField = timeDimension.getName(); + + // add dayno + String subTable = MessageFormat.format(SUB_TABLE, domainId, dayField, startDate, endDate); + String querySql = sqlOutput.replaceAll(tableName, subTable); + + LOG.info("querySql:{},sqlOutput:{},dateInfo:{}", querySql, sqlOutput, dateInfo); + return querySql; + } + + private static Map getMapInfo(Integer domainId, List metrics) { + return metrics.stream().filter(entry -> entry.getDomain().equals(domainId)) + .collect(Collectors.toMap(ItemDO::getName, a -> a.getBizName(), (k1, k2) -> k1)); + } + + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SchemaInfoConverter.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SchemaInfoConverter.java index facfaef98..a6b013cbe 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SchemaInfoConverter.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SchemaInfoConverter.java @@ -20,15 +20,19 @@ import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; import com.tencent.supersonic.semantic.api.query.pojo.Filter; +import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.util.Strings; +import org.springframework.beans.BeanUtils; import org.springframework.util.CollectionUtils; public class SchemaInfoConverter { @@ -66,6 +70,23 @@ public class SchemaInfoConverter { return queryStructCmd; } + + /*** + * convert to QuerySqlReq + * @param parseInfo + * @return + */ + public static QuerySqlReq convertToQuerySqlReq(SemanticParseInfo parseInfo) { + QuerySqlReq querySqlReq = new QuerySqlReq(); + Object info = parseInfo.getInfo(); + if (Objects.nonNull(info)) { + querySqlReq.setSql(info.toString()); + } + querySqlReq.setDomainId(parseInfo.getDomainId()); + return querySqlReq; + } + + private static List getAggregatorByMetric(Set metrics, AggregateTypeEnum aggregateType) { List aggregators = new ArrayList<>(); String agg = (aggregateType == null || aggregateType.equals(AggregateTypeEnum.NONE)) ? "" @@ -131,6 +152,7 @@ public class SchemaInfoConverter { domainDO.setName(domainSchemaDesc.getName()); domainDO.setItemId(domain); result.getDomains().add(domainDO); + domainDO.setBizName(domainSchemaDesc.getBizName()); // entity List entityNames = domainSchemaDesc.getEntityNames(); if (!CollectionUtils.isEmpty(entityNames)) { @@ -149,7 +171,16 @@ public class SchemaInfoConverter { metricDO.setName(metric.getName()); metricDO.setItemId(Math.toIntExact(metric.getId())); metricDO.setUseCnt(metric.getUseCnt()); + metricDO.setBizName(metric.getBizName()); result.getMetrics().add(metricDO); + + String metricAlias = metric.getAlias(); + if (StringUtils.isNotEmpty(metricAlias)) { + ItemDO aliasMetricDO = new ItemDO(); + BeanUtils.copyProperties(metricDO, aliasMetricDO); + aliasMetricDO.setName(metricAlias); + result.getMetrics().add(aliasMetricDO); + } } // dimension for (DimSchemaResp dimension : domainSchemaDesc.getDimensions()) { @@ -158,7 +189,16 @@ public class SchemaInfoConverter { dimensionDO.setName(dimension.getName()); dimensionDO.setItemId(Math.toIntExact(dimension.getId())); dimensionDO.setUseCnt(dimension.getUseCnt()); + dimensionDO.setBizName(dimension.getBizName()); result.getDimensions().add(dimensionDO); + + String dimensionAlias = dimension.getAlias(); + if (StringUtils.isNotEmpty(dimensionAlias)) { + ItemDO aliasDimensionDO = new ItemDO(); + BeanUtils.copyProperties(dimensionDO, aliasDimensionDO); + aliasDimensionDO.setName(dimensionAlias); + result.getDimensions().add(aliasDimensionDO); + } } } return result; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SemanticSatisfactionChecker.java b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SemanticSatisfactionChecker.java new file mode 100644 index 000000000..336eb7556 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/domain/utils/SemanticSatisfactionChecker.java @@ -0,0 +1,93 @@ +package com.tencent.supersonic.chat.domain.utils; + + +import com.tencent.supersonic.chat.api.component.SemanticQuery; +import com.tencent.supersonic.chat.api.pojo.Filter; +import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch; +import com.tencent.supersonic.chat.api.pojo.SchemaElementType; +import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo; +import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.common.pojo.SchemaItem; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * utils to check current parse info is enough to query result + */ +@Slf4j +public class SemanticSatisfactionChecker { + + private static final double THRESHOLD = 0.8; + + // check all the parse info in candidate + public static boolean check(QueryContextReq queryCtx) { + for (SemanticQuery query : queryCtx.getCandidateQueries()) { + SemanticParseInfo semanticParseInfo = query.getParseInfo(); + Long domainId = semanticParseInfo.getDomainId(); + List schemaElementMatches = queryCtx.getMapInfo() + .getMatchedElements(domainId.intValue()); + if (check(queryCtx.getQueryText(), semanticParseInfo, schemaElementMatches)) { + return true; + } + } + return false; + } + + //check single parse info + private static boolean check(String text, SemanticParseInfo semanticParseInfo, + List schemaElementMatches) { + if (CollectionUtils.isEmpty(schemaElementMatches)) { + return false; + } + List detectWords = Lists.newArrayList(); + Map detectWordMap = schemaElementMatches.stream() + .collect(Collectors.toMap(SchemaElementMatch::getElementID, SchemaElementMatch::getDetectWord, + (id1, id2) -> id1)); + // get detect word in text by element id in semantic layer + Long domainId = semanticParseInfo.getDomainId(); + if (domainId != null && domainId > 0) { + for (SchemaElementMatch schemaElementMatch : schemaElementMatches) { + if (SchemaElementType.DOMAIN.equals(schemaElementMatch.getElementType())) { + detectWords.add(schemaElementMatch.getDetectWord()); + } + } + } + + for (Filter filter : semanticParseInfo.getDimensionFilters()) { + detectWords.add( + detectWordMap.getOrDefault(Optional.ofNullable(filter.getElementID()).orElse(0L).intValue(), "")); + } + for (SchemaItem schemaItem : semanticParseInfo.getMetrics()) { + detectWords.add( + detectWordMap.getOrDefault(Optional.ofNullable(schemaItem.getId()).orElse(0L).intValue(), "")); + // only first metric + break; + } + for (SchemaItem schemaItem : semanticParseInfo.getDimensions()) { + detectWords.add( + detectWordMap.getOrDefault(Optional.ofNullable(schemaItem.getId()).orElse(0L).intValue(), "")); + // only first dimension + break; + } + //compare the length between detect words and query text + String detectWordsDistinct = StringUtils.join(new HashSet<>(detectWords), ""); + int detectWordsLength = detectWordsDistinct.length(); + int queryTextLength = text.length(); + double degree = detectWordsLength * 1.0 / queryTextLength; + if (degree > THRESHOLD) { + log.info("queryMode:{} has satisfied semantic check, degree:{}, detectWords:{}, parse info:{}", + semanticParseInfo.getQueryMode(), degree, detectWordsDistinct, semanticParseInfo); + return true; + } + return false; + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatMapper.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatMapper.java index 1c04a07ba..5c7627158 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatMapper.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/mapper/ChatMapper.java @@ -16,6 +16,8 @@ public interface ChatMapper { Boolean updateChatName(Long chatId, String chatName, String lastTime, String creator); + Boolean updateLastQuestion(Long chatId, String lastQuestion, String lastTime); + Boolean updateConversionIsTop(Long chatId, int isTop); boolean updateFeedback(QueryDO queryDO); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatConfigRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatConfigRepositoryImpl.java index e823466c9..4bb9ac28d 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatConfigRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatConfigRepositoryImpl.java @@ -12,10 +12,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Repository; import org.springframework.util.CollectionUtils; @Repository +@Primary public class ChatConfigRepositoryImpl implements ChatConfigRepository { private final ChatConfigUtils chatConfigUtils; @@ -65,4 +67,4 @@ public class ChatConfigRepositoryImpl implements ChatConfigRepository { return chatConfigUtils.chatConfigDO2Descriptor(chaConfigPO); } -} \ No newline at end of file +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatContextRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatContextRepositoryImpl.java index f4d70647f..54ab46a83 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatContextRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatContextRepositoryImpl.java @@ -7,6 +7,7 @@ import com.tencent.supersonic.chat.domain.dataobject.ChatContextDO; import com.tencent.supersonic.chat.domain.repository.ChatContextRepository; import com.tencent.supersonic.chat.infrastructure.mapper.ChatContextMapper; import com.tencent.supersonic.common.util.json.JsonUtil; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Repository; @@ -14,6 +15,7 @@ import org.springframework.stereotype.Repository; @Primary public class ChatContextRepositoryImpl implements ChatContextRepository { + @Autowired(required = false) private final ChatContextMapper chatContextMapper; public ChatContextRepositoryImpl(ChatContextMapper chatContextMapper) { @@ -62,6 +64,14 @@ public class ChatContextRepositoryImpl implements ChatContextRepository { chatContextDO.setUser(chatContext.getUser()); if (chatContext.getParseInfo() != null) { Gson g = new Gson(); + chatContext.getParseInfo().getDimensions().stream().forEach(d -> { + d.setUpdatedAt(null); + d.setCreatedAt(null); + }); + chatContext.getParseInfo().getMetrics().stream().forEach(d -> { + d.setUpdatedAt(null); + d.setCreatedAt(null); + }); chatContextDO.setSemanticParse(g.toJson(chatContext.getParseInfo())); } return chatContextDO; diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatQueryRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatQueryRepositoryImpl.java index f8743b543..7b1e273d3 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatQueryRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatQueryRepositoryImpl.java @@ -14,6 +14,7 @@ import com.tencent.supersonic.chat.domain.repository.ChatQueryRepository; import com.tencent.supersonic.chat.infrastructure.mapper.ChatQueryDOMapper; import com.tencent.supersonic.common.util.json.JsonUtil; import com.tencent.supersonic.common.util.mybatis.PageUtils; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -36,7 +37,7 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { @Override public PageInfo getChatQuery(PageQueryInfoReq pageQueryInfoCommend, long chatId) { ChatQueryDOExample example = new ChatQueryDOExample(); - example.setOrderByClause("question_id"); + example.setOrderByClause("question_id desc"); Criteria criteria = example.createCriteria(); criteria.andChatIdEqualTo(chatId); criteria.andUserNameEqualTo(pageQueryInfoCommend.getUserName()); @@ -47,7 +48,9 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { PageInfo chatQueryVOPageInfo = PageUtils.pageInfo2PageInfoVo(pageInfo); chatQueryVOPageInfo.setList( - pageInfo.getList().stream().map(chatQueryDO -> convertTo(chatQueryDO)).collect(Collectors.toList())); + pageInfo.getList().stream().map(this::convertTo) + .sorted(Comparator.comparingInt(o -> o.getQuestionId().intValue())) + .collect(Collectors.toList())); return chatQueryVOPageInfo; } @@ -55,6 +58,7 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { ChatQueryVO chatQueryVO = new ChatQueryVO(); BeanUtils.copyProperties(chatQueryDO, chatQueryVO); QueryResultResp queryResponse = JsonUtil.toObject(chatQueryDO.getQueryResponse(), QueryResultResp.class); + queryResponse.setQueryId(chatQueryDO.getQuestionId()); chatQueryVO.setQueryResponse(queryResponse); return chatQueryVO; } @@ -68,7 +72,9 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository { chatQueryDO.setQueryState(queryResponse.getQueryState()); chatQueryDO.setQueryText(queryContext.getQueryText()); chatQueryDO.setQueryResponse(JsonUtil.toString(queryResponse)); - Long queryId = Long.valueOf(chatQueryDOMapper.insert(chatQueryDO)); + chatQueryDOMapper.insert(chatQueryDO); + ChatQueryDO lastChatQuery = getLastChatQuery(queryContext.getChatId()); + Long queryId = lastChatQuery.getQuestionId(); queryResponse.setQueryId(queryId); } diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatRepositoryImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatRepositoryImpl.java index 30bed3b03..e40d2ff85 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatRepositoryImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/repository/ChatRepositoryImpl.java @@ -36,6 +36,11 @@ public class ChatRepositoryImpl implements ChatRepository { return chatMapper.updateChatName(chatId, chatName, lastTime, creator); } + @Override + public Boolean updateLastQuestion(Long chatId, String lastQuestion, String lastTime) { + return chatMapper.updateLastQuestion(chatId, lastQuestion, lastTime); + } + @Override public Boolean updateConversionIsTop(Long chatId, int isTop) { return chatMapper.updateConversionIsTop(chatId, isTop); diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticConfig.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticConfig.java new file mode 100644 index 000000000..af86760a3 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticConfig.java @@ -0,0 +1,35 @@ +package com.tencent.supersonic.chat.infrastructure.semantic; + +import com.tencent.supersonic.chat.application.ConfigServiceImpl; +import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; +import lombok.Data; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +@Data +public class DefaultSemanticConfig { + + @Value("${semantic.url.prefix:http://localhost:8081}") + private String semanticUrl; + + @Value("${searchByStruct.path:/api/semantic/query/struct}") + private String searchByStructPath; + + @Value("${searchByStruct.path:/api/semantic/query/sql}") + private String searchBySqlPath; + + @Value("${fetchDomainSchemaPath.path:/api/semantic/schema}") + private String fetchDomainSchemaPath; + + @Autowired + private DefaultSemanticInternalUtils defaultSemanticInternalUtils; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ConfigServiceImpl chaConfigService; +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/LocalSemanticLayerImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/LocalSemanticLayerImpl.java new file mode 100644 index 000000000..dc7322450 --- /dev/null +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/LocalSemanticLayerImpl.java @@ -0,0 +1,181 @@ +package com.tencent.supersonic.chat.infrastructure.semantic; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigInfo; +import com.tencent.supersonic.chat.domain.pojo.config.ItemVisibility; +import com.tencent.supersonic.common.util.context.ContextUtils; +import com.tencent.supersonic.common.util.json.JsonUtil; +import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; +import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import com.tencent.supersonic.semantic.query.domain.SchemaService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; +import com.tencent.supersonic.semantic.query.domain.QueryService; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Slf4j +public class LocalSemanticLayerImpl implements SemanticLayer { + + private static final Cache> domainSchemaCache = + CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); + private SchemaService schemaService; + + @Override + public QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user) { + deletionDuplicated(queryStructReq); + onlyQueryFirstMetric(queryStructReq); + try { + QueryService queryService = ContextUtils.getBean(QueryService.class); + QueryResultWithSchemaResp queryResultWithSchemaResp = queryService.queryByStruct(queryStructReq, user); + return queryResultWithSchemaResp; + } catch (Exception e) { + log.info("queryByStruct has an exception:{}", e.toString()); + } + return null; + } + + @Override + public QueryResultWithSchemaResp queryBySql(QuerySqlReq querySqlReq, User user) { + try { + QueryService queryService = ContextUtils.getBean(QueryService.class); + Object object = queryService.queryBySql(querySqlReq, user); + QueryResultWithSchemaResp queryResultWithSchemaResp = JsonUtil.toObject(JsonUtil.toString(object), + QueryResultWithSchemaResp.class); + return queryResultWithSchemaResp; + } catch (Exception e) { + log.info("queryByStruct has an exception:{}", e.toString()); + } + return null; + } + + public List fetchDomainSchemaAll(List ids) { + + DomainSchemaFilterReq filter = new DomainSchemaFilterReq(); + filter.setDomainIds(ids); + User user = new User(1L, "admin", "admin", "admin@email"); + schemaService = ContextUtils.getBean(SchemaService.class); + return schemaService.fetchDomainSchema(filter, user); + } + + + @SneakyThrows + public List fetchDomainSchema(List ids) { +// return domainSchemaCache.get(String.valueOf(ids), () -> { +// List data = fetchDomainSchemaAll(ids); +// fillEntityNameAndFilterBlackElement(data); +// return data; +// }); + + List data = fetchDomainSchemaAll(ids); + fillEntityNameAndFilterBlackElement(data); + return data; + } + + @Override + public DomainSchemaResp getDomainSchemaInfo(Long domain) { + List ids = new ArrayList<>(); + ids.add(domain); + List domainSchemaResps = fetchDomainSchema(ids); + if (!CollectionUtils.isEmpty(domainSchemaResps)) { + Optional domainSchemaResp = domainSchemaResps.stream() + .filter(d -> d.getId().equals(domain)).findFirst(); + if (domainSchemaResp.isPresent()) { + DomainSchemaResp domainSchema = domainSchemaResp.get(); + return domainSchema; + } + } + return null; + } + + @Override + public List getDomainSchemaInfo(List ids) { + return fetchDomainSchema(ids); + } + + public DomainSchemaResp fillEntityNameAndFilterBlackElement(DomainSchemaResp domainSchemaResp) { + if (Objects.isNull(domainSchemaResp) || Objects.isNull(domainSchemaResp.getId())) { + return domainSchemaResp; + } + ChatConfigInfo chaConfigInfo = getConfigBaseInfo(domainSchemaResp.getId()); + + // fill entity names + fillEntityNamesInfo(domainSchemaResp, chaConfigInfo); + + // filter black element + filterBlackDim(domainSchemaResp, chaConfigInfo); + filterBlackMetric(domainSchemaResp, chaConfigInfo); + return domainSchemaResp; + } + + public void fillEntityNameAndFilterBlackElement(List domainSchemaRespList) { + if (!CollectionUtils.isEmpty(domainSchemaRespList)) { + domainSchemaRespList.stream() + .forEach(domainSchemaResp -> fillEntityNameAndFilterBlackElement(domainSchemaResp)); + } + } + + private void filterBlackMetric(DomainSchemaResp domainSchemaResp, ChatConfigInfo chaConfigInfo) { + ItemVisibility visibility = chaConfigInfo.getVisibility(); + if (Objects.nonNull(chaConfigInfo) && Objects.nonNull(visibility) + && !CollectionUtils.isEmpty(visibility.getBlackMetricIdList()) + && !CollectionUtils.isEmpty(domainSchemaResp.getMetrics())) { + List metric4Chat = domainSchemaResp.getMetrics().stream() + .filter(metric -> !visibility.getBlackMetricIdList().contains(metric.getId())) + .collect(Collectors.toList()); + domainSchemaResp.setMetrics(metric4Chat); + } + } + + private void filterBlackDim(DomainSchemaResp domainSchemaResp, ChatConfigInfo chatConfigInfo) { + ItemVisibility visibility = chatConfigInfo.getVisibility(); + if (Objects.nonNull(chatConfigInfo) && Objects.nonNull(visibility) + && !CollectionUtils.isEmpty(visibility.getBlackDimIdList()) + && !CollectionUtils.isEmpty(domainSchemaResp.getDimensions())) { + List dim4Chat = domainSchemaResp.getDimensions().stream() + .filter(dim -> !visibility.getBlackDimIdList().contains(dim.getId())) + .collect(Collectors.toList()); + domainSchemaResp.setDimensions(dim4Chat); + } + } + + private void fillEntityNamesInfo(DomainSchemaResp domainSchemaResp, ChatConfigInfo chatConfigInfo) { + if (Objects.nonNull(chatConfigInfo) && Objects.nonNull(chatConfigInfo.getEntity()) + && !CollectionUtils.isEmpty(chatConfigInfo.getEntity().getNames())) { + domainSchemaResp.setEntityNames(chatConfigInfo.getEntity().getNames()); + } + } + + private void deletionDuplicated(QueryStructReq queryStructReq) { + if (!CollectionUtils.isEmpty(queryStructReq.getGroups()) && queryStructReq.getGroups().size() > 1) { + Set groups = new HashSet<>(); + groups.addAll(queryStructReq.getGroups()); + queryStructReq.getGroups().clear(); + queryStructReq.getGroups().addAll(groups); + } + } + + private void onlyQueryFirstMetric(QueryStructReq queryStructReq) { + if (!CollectionUtils.isEmpty(queryStructReq.getAggregators()) && queryStructReq.getAggregators().size() > 1) { + log.info("multi metric in aggregators:{} , only query first one", queryStructReq.getAggregators()); + queryStructReq.setAggregators(queryStructReq.getAggregators().subList(0, 1)); + } + } + + public ChatConfigInfo getConfigBaseInfo(Long domain) { + DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); + return defaultSemanticConfig.getChaConfigService().fetchConfigByDomainId(domain); + } + +} diff --git a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticLayerImpl.java b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/RemoteSemanticLayerImpl.java similarity index 72% rename from chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticLayerImpl.java rename to chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/RemoteSemanticLayerImpl.java index 3a1c48e84..c7b0a687c 100644 --- a/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/DefaultSemanticLayerImpl.java +++ b/chat/core/src/main/java/com/tencent/supersonic/chat/infrastructure/semantic/RemoteSemanticLayerImpl.java @@ -3,17 +3,20 @@ package com.tencent.supersonic.chat.infrastructure.semantic; import static com.tencent.supersonic.common.constant.Constants.TRUE_LOWER; import com.alibaba.fastjson.JSON; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.gson.Gson; import com.tencent.supersonic.auth.api.authentication.constant.UserConstants; import com.tencent.supersonic.auth.api.authentication.pojo.User; -import com.tencent.supersonic.chat.api.service.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.common.util.context.ContextUtils; import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; +import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; -import com.tencent.supersonic.chat.application.ConfigServiceImpl; import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigInfo; import com.tencent.supersonic.chat.domain.pojo.config.ItemVisibility; import com.tencent.supersonic.chat.domain.utils.DefaultSemanticInternalUtils; @@ -27,70 +30,62 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; -@Service -public class DefaultSemanticLayerImpl implements SemanticLayer { - - private final Logger logger = LoggerFactory.getLogger(DefaultSemanticLayerImpl.class); - - @Value("${semantic.url.prefix:http://localhost:8081}") - private String semanticUrl; - - @Value("${searchByStruct.path:/api/semantic/query/struct}") - private String searchByStructPath; - - @Value("${fetchDomainSchemaPath.path:/api/semantic/schema}") - private String fetchDomainSchemaPath; - - @Autowired - private DefaultSemanticInternalUtils defaultSemanticInternalUtils; +@Slf4j +public class RemoteSemanticLayerImpl implements SemanticLayer { + private static final Cache> domainSchemaCache = + CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); private ParameterizedTypeReference> structTypeRef = new ParameterizedTypeReference>() { }; - @Autowired - private RestTemplate restTemplate; - - @Autowired - private ConfigServiceImpl chaConfigService; - @Override public QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructReq, User user) { deletionDuplicated(queryStructReq); onlyQueryFirstMetric(queryStructReq); - return searchByStruct(semanticUrl + searchByStructPath, queryStructReq); + DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); + return searchByRestTemplate( + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getSearchByStructPath(), + new Gson().toJson(queryStructReq)); } - public QueryResultWithSchemaResp searchByStruct(String url, QueryStructReq queryStructReq) { + @Override + public QueryResultWithSchemaResp queryBySql(QuerySqlReq querySqlReq, User user) { + DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); + return searchByRestTemplate(defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getSearchBySqlPath(), + new Gson().toJson(querySqlReq)); + } + + public QueryResultWithSchemaResp searchByRestTemplate(String url, String jsonReq) { + DefaultSemanticInternalUtils defaultSemanticInternalUtils = ContextUtils.getBean( + DefaultSemanticInternalUtils.class); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); defaultSemanticInternalUtils.fillToken(headers); URI requestUrl = UriComponentsBuilder.fromHttpUrl(url).build().encode().toUri(); - Gson gson = new Gson(); - HttpEntity entity = new HttpEntity<>(gson.toJson(queryStructReq), headers); - logger.info("searchByStruct {}", entity.getBody()); + HttpEntity entity = new HttpEntity<>(jsonReq, headers); + log.info("url:{},searchByRestTemplate:{}", url, entity.getBody()); ResultData responseBody; try { - ResponseEntity> responseEntity = restTemplate.exchange(requestUrl, - HttpMethod.POST, entity, structTypeRef); + DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); + ResponseEntity> responseEntity = defaultSemanticConfig.getRestTemplate() + .exchange(requestUrl, + HttpMethod.POST, entity, structTypeRef); responseBody = responseEntity.getBody(); - logger.debug("ApiResponse responseBody:{}", responseBody); + log.info("ApiResponse responseBody:{}", responseBody); QueryResultWithSchemaResp semanticQuery = new QueryResultWithSchemaResp(); if (ReturnCode.SUCCESS.getCode() == responseBody.getCode()) { QueryResultWithSchemaResp data = responseBody.getData(); @@ -101,17 +96,23 @@ public class DefaultSemanticLayerImpl implements SemanticLayer { return semanticQuery; } } catch (Exception e) { - throw new RuntimeException("search semantic struct interface error", e); + throw new RuntimeException("search semantic interface error,url:" + url, e); } throw new CommonException(responseBody.getCode(), responseBody.getMsg()); } public List fetchDomainSchemaAll(List ids) { + DefaultSemanticInternalUtils defaultSemanticInternalUtils = ContextUtils.getBean( + DefaultSemanticInternalUtils.class); HttpHeaders headers = new HttpHeaders(); headers.set(UserConstants.INTERNAL, TRUE_LOWER); headers.setContentType(MediaType.APPLICATION_JSON); defaultSemanticInternalUtils.fillToken(headers); - URI requestUrl = UriComponentsBuilder.fromHttpUrl(semanticUrl + fetchDomainSchemaPath).build().encode().toUri(); + DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); + + URI requestUrl = UriComponentsBuilder.fromHttpUrl( + defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDomainSchemaPath()).build() + .encode().toUri(); DomainSchemaFilterReq filter = new DomainSchemaFilterReq(); filter.setDomainIds(ids); ParameterizedTypeReference>> responseTypeRef = @@ -119,11 +120,13 @@ public class DefaultSemanticLayerImpl implements SemanticLayer { }; HttpEntity entity = new HttpEntity<>(JSON.toJSONString(filter), headers); + try { - ResponseEntity>> responseEntity = restTemplate.exchange(requestUrl, - HttpMethod.POST, entity, responseTypeRef); + ResponseEntity>> responseEntity = defaultSemanticConfig.getRestTemplate() + .exchange(requestUrl, + HttpMethod.POST, entity, responseTypeRef); ResultData> responseBody = responseEntity.getBody(); - logger.debug("ApiResponse responseBody:{}", responseBody); + log.debug("ApiResponse responseBody:{}", responseBody); if (ReturnCode.SUCCESS.getCode() == responseBody.getCode()) { List data = responseBody.getData(); return data; @@ -135,10 +138,13 @@ public class DefaultSemanticLayerImpl implements SemanticLayer { } + @SneakyThrows public List fetchDomainSchema(List ids) { - List data = fetchDomainSchemaAll(ids); - fillEntityNameAndFilterBlackElement(data); - return data; + return domainSchemaCache.get(String.valueOf(ids), () -> { + List data = fetchDomainSchemaAll(ids); + fillEntityNameAndFilterBlackElement(data); + return data; + }); } @Override @@ -226,13 +232,14 @@ public class DefaultSemanticLayerImpl implements SemanticLayer { private void onlyQueryFirstMetric(QueryStructReq queryStructReq) { if (!CollectionUtils.isEmpty(queryStructReq.getAggregators()) && queryStructReq.getAggregators().size() > 1) { - logger.info("multi metric in aggregators:{} , only query first one", queryStructReq.getAggregators()); + log.info("multi metric in aggregators:{} , only query first one", queryStructReq.getAggregators()); queryStructReq.setAggregators(queryStructReq.getAggregators().subList(0, 1)); } } public ChatConfigInfo getConfigBaseInfo(Long domain) { - return chaConfigService.fetchConfigByDomainId(domain); + DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class); + return defaultSemanticConfig.getChaConfigService().fetchConfigByDomainId(domain); } } 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 1852c1d6e..a3e568857 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 @@ -43,16 +43,16 @@ public class ChatConfigController { @PostMapping public Long addChatConfig(@RequestBody ChatConfigBase extendBaseCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return configService.addConfig(extendBaseCmd, user); } @PutMapping public Long editDomainExtend(@RequestBody ChatConfigEditReq extendEditCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return configService.editConfig(extendEditCmd, user); } @@ -60,8 +60,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); } @@ -72,6 +72,11 @@ public class ChatConfigController { return configService.getConfigRichInfo(domainId); } + @GetMapping("/richDesc/all") + public List getAllChatRichConfig() { + return configService.getAllChatRichConfig(); + } + /** * get domain list @@ -79,24 +84,22 @@ public class ChatConfigController { * @param */ @GetMapping("/domainList") - public List getDomainList(HttpServletRequest request, - HttpServletResponse response) { - User user = UserHolder.findUser(request, response); - return defaultSemanticUtils.getDomainListForUser(user); + public List getDomainList() { + return defaultSemanticUtils.getDomainListForAdmin(); } @PostMapping("/dimension/page") public PageInfo queryDimension(@RequestBody PageDimensionReq pageDimensionCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return defaultSemanticUtils.queryDimensionPage(pageDimensionCmd, user); } @PostMapping("/metric/page") public PageInfo queryMetric(@RequestBody PageMetricReq pageMetrricCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return defaultSemanticUtils.queryMetricPage(pageMetrricCmd, user); } 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 249f2d1b4..f56131f90 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 @@ -28,7 +28,7 @@ public class ChatController { } @PostMapping("/save") - public Boolean save(@RequestParam(value = "chatName", required = true) String chatName, + public Boolean save(@RequestParam(value = "chatName") String chatName, HttpServletRequest request, HttpServletResponse response) { return chatService.addChat(UserHolder.findUser(request, response), chatName); } @@ -40,36 +40,36 @@ public class ChatController { } @PostMapping("/delete") - public Boolean deleteConversion(@RequestParam(value = "chatId", required = true) long chatId, + public Boolean deleteConversion(@RequestParam(value = "chatId") long chatId, HttpServletRequest request, HttpServletResponse response) { String userName = UserHolder.findUser(request, response).getName(); return chatService.deleteChat(chatId, userName); } @PostMapping("/updateChatName") - public Boolean updateConversionName(@RequestParam(value = "chatId", required = true) Long chatId, - @RequestParam(value = "chatName", required = true) String chatName, + public Boolean updateConversionName(@RequestParam(value = "chatId") Long chatId, + @RequestParam(value = "chatName") String chatName, HttpServletRequest request, HttpServletResponse response) { String userName = UserHolder.findUser(request, response).getName(); return chatService.updateChatName(chatId, chatName, userName); } @PostMapping("/updateQAFeedback") - public Boolean updateQAFeedback(@RequestParam(value = "id", required = true) Integer id, - @RequestParam(value = "score", required = true) Integer score, - @RequestParam(value = "feedback", required = true) String feedback) { + public Boolean updateQAFeedback(@RequestParam(value = "id") Integer id, + @RequestParam(value = "score") Integer score, + @RequestParam(value = "feedback", required = false) String feedback) { return chatService.updateFeedback(id, score, feedback); } @PostMapping("/updateChatIsTop") - public Boolean updateConversionIsTop(@RequestParam(value = "chatId", required = true) Long chatId, - @RequestParam(value = "isTop", required = true) int isTop) { + public Boolean updateConversionIsTop(@RequestParam(value = "chatId") Long chatId, + @RequestParam(value = "isTop") int isTop) { return chatService.updateChatIsTop(chatId, isTop); } @PostMapping("/pageQueryInfo") public PageInfo pageQueryInfo(@RequestBody PageQueryInfoReq pageQueryInfoCommend, - @RequestParam(value = "chatId", required = true) long chatId, + @RequestParam(value = "chatId") long chatId, HttpServletRequest request, HttpServletResponse response) { pageQueryInfoCommend.setUserName(UserHolder.findUser(request, response).getName()); 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 e237ac104..9ffd97e18 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 @@ -9,6 +9,7 @@ import com.tencent.supersonic.chat.domain.service.SearchService; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -22,7 +23,9 @@ import org.springframework.web.bind.annotation.RestController; public class ChatQueryController { @Autowired + @Qualifier("chatQueryService") private QueryService queryService; + @Autowired private SearchService searchService; @@ -51,7 +54,7 @@ public class ChatQueryController { @PostMapping("queryData") public Object queryData(@RequestBody QueryData queryData, HttpServletRequest request, HttpServletResponse response) throws Exception { - return queryService.queryData(queryData, UserHolder.findUser(request, response)); + return queryService.executeDirectQuery(queryData, UserHolder.findUser(request, response)); } } diff --git a/chat/core/src/main/resources/mapper/ChatMapper.xml b/chat/core/src/main/resources/mapper/ChatMapper.xml index f6dd7e1ab..b2f737d72 100644 --- a/chat/core/src/main/resources/mapper/ChatMapper.xml +++ b/chat/core/src/main/resources/mapper/ChatMapper.xml @@ -38,6 +38,13 @@ and creator = #{creator} + + update s2_chat + set last_question = #{lastQuestion}, + last_time = #{lastTime} + where chat_id = #{chatId} + + insert into s2_chat (chat_name, create_time, last_time, creator, last_question, is_delete, is_top) @@ -80,7 +87,7 @@ update s2_chat_query set score=#{score}, feedback=#{feedback} - where id = #{id} + where question_id = #{id} selectByExampleWithBLOBs(ChatQueryDOExample example); - - /** - * - * @mbg.generated - */ - List selectByExample(ChatQueryDOExample example); - - /** - * - * @mbg.generated - */ - ChatQueryDO selectByPrimaryKey(Long id); - - /** - * - * @mbg.generated - */ - int updateByPrimaryKeySelective(ChatQueryDO record); - - /** - * - * @mbg.generated - */ - int updateByPrimaryKeyWithBLOBs(ChatQueryDO record); - - /** - * - * @mbg.generated - */ - int updateByPrimaryKey(ChatQueryDO record); -} \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParserTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParserTest.java index 73e7ab656..14b67ec23 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParserTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/TimeSemanticParserTest.java @@ -3,12 +3,24 @@ package com.tencent.supersonic.chat.application.parser; import com.tencent.supersonic.chat.api.pojo.ChatContext; import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo; import com.tencent.supersonic.chat.api.request.QueryContextReq; -import com.tencent.supersonic.common.pojo.DateConf; import org.junit.jupiter.api.Test; class TimeSemanticParserTest { +// private HeuristicQuerySelector voteStrategy = new HeuristicQuerySelector() { +// @Override +// public void init(List semanticParsers) { +// List queryMode = new ArrayList<>(Arrays.asList(EntityDetail.QUERY_MODE)); +// for(SemanticParser semanticParser : semanticParsers) { +// if(semanticParser.getName().equals(TimeSemanticParser.PARSER_MODE)) { +// semanticParser.getQueryModes().clear(); +// semanticParser.getQueryModes().addAll(queryMode); +// } +// } +// } +// }; + @Test void parse() { TimeSemanticParser timeSemanticParser = new TimeSemanticParser(); @@ -16,12 +28,15 @@ class TimeSemanticParserTest { QueryContextReq queryContext = new QueryContextReq(); ChatContext chatCtx = new ChatContext(); SchemaMapInfo schemaMap = new SchemaMapInfo(); + queryContext.setQueryText("supersonic最近30天访问次数"); + //voteStrategy.init(new ArrayList<>(Arrays.asList(timeSemanticParser))); + timeSemanticParser.parse(queryContext, chatCtx); - boolean parse = timeSemanticParser.parse(queryContext, chatCtx); - - DateConf dateInfo = queryContext.getParseInfo().getDateInfo(); + //DateConf dateInfo = queryContext.getParseInfo(timeSemanticParser.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/application/parser/aggregate/AggregateSemanticParserTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateSemanticParserTest.java new file mode 100644 index 000000000..cc996969f --- /dev/null +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/AggregateSemanticParserTest.java @@ -0,0 +1,38 @@ +package com.tencent.supersonic.chat.application.parser.aggregate; + +import static org.junit.Assert.assertEquals; + +import com.tencent.supersonic.chat.application.parser.AggregateSemanticParser; +import com.tencent.supersonic.common.enums.AggregateTypeEnum; +import org.junit.jupiter.api.Test; + +class AggregateSemanticParserTest { + + @Test + void getAggregateParser() { + AggregateSemanticParser aggregateParser = new AggregateSemanticParser(); + AggregateTypeEnum aggregateType = aggregateParser.resolveAggregateType("supsersonic产品访问次数最大值"); + assertEquals(aggregateType, AggregateTypeEnum.MAX); + + aggregateType = aggregateParser.resolveAggregateType("supsersonic产品pv"); + assertEquals(aggregateType, AggregateTypeEnum.COUNT); + + aggregateType = aggregateParser.resolveAggregateType("supsersonic产品uv"); + assertEquals(aggregateType, AggregateTypeEnum.DISTINCT); + + aggregateType = aggregateParser.resolveAggregateType("supsersonic产品访问次数最大值"); + assertEquals(aggregateType, AggregateTypeEnum.MAX); + + aggregateType = aggregateParser.resolveAggregateType("supsersonic产品访问次数最小值"); + assertEquals(aggregateType, AggregateTypeEnum.MIN); + + aggregateType = aggregateParser.resolveAggregateType("supsersonic产品访问次数平均值"); + assertEquals(aggregateType, AggregateTypeEnum.AVG); + + aggregateType = aggregateParser.resolveAggregateType("supsersonic产品访问次数topN"); + assertEquals(aggregateType, AggregateTypeEnum.TOPN); + + aggregateType = aggregateParser.resolveAggregateType("supsersonic产品访问次数汇总"); + assertEquals(aggregateType, AggregateTypeEnum.SUM); + } +} \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/RegexAggregateTypeEnumResolverTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/RegexAggregateTypeEnumResolverTest.java deleted file mode 100644 index ef97c085e..000000000 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/application/parser/aggregate/RegexAggregateTypeEnumResolverTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.tencent.supersonic.chat.application.parser.aggregate; - -import static org.junit.Assert.assertEquals; - -import com.tencent.supersonic.chat.application.parser.resolver.RegexAggregateTypeResolver; -import com.tencent.supersonic.common.enums.AggregateTypeEnum; -import org.junit.jupiter.api.Test; - -class RegexAggregateTypeEnumResolverTest { - - @Test - void getAggregateParser() { - RegexAggregateTypeResolver regexAggregateParser = new RegexAggregateTypeResolver(); - AggregateTypeEnum aggregateType = regexAggregateParser.resolve("supsersonic产品访问次数最大值"); - assertEquals(aggregateType, AggregateTypeEnum.MAX); - - aggregateType = regexAggregateParser.resolve("supsersonic产品pv"); - assertEquals(aggregateType, AggregateTypeEnum.COUNT); - - aggregateType = regexAggregateParser.resolve("supsersonic产品uv"); - assertEquals(aggregateType, AggregateTypeEnum.DISTINCT); - - aggregateType = regexAggregateParser.resolve("supsersonic产品访问次数最大值"); - assertEquals(aggregateType, AggregateTypeEnum.MAX); - - aggregateType = regexAggregateParser.resolve("supsersonic产品访问次数最小值"); - assertEquals(aggregateType, AggregateTypeEnum.MIN); - - aggregateType = regexAggregateParser.resolve("supsersonic产品访问次数平均值"); - assertEquals(aggregateType, AggregateTypeEnum.AVG); - - aggregateType = regexAggregateParser.resolve("supsersonic产品访问次数topN"); - assertEquals(aggregateType, AggregateTypeEnum.TOPN); - - aggregateType = regexAggregateParser.resolve("supsersonic产品访问次数汇总"); - assertEquals(aggregateType, AggregateTypeEnum.SUM); - } -} \ No newline at end of file diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfoTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfoTest.java new file mode 100644 index 000000000..ce2b98da4 --- /dev/null +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/domain/utils/DslToSemanticInfoTest.java @@ -0,0 +1,28 @@ +package com.tencent.supersonic.chat.domain.utils; + +import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum; +import java.text.MessageFormat; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +/** + * @author lex luo + * @date 2023/6/29 16:05 + */ +class DslToSemanticInfoTest { + + @Test + void search() { + + Integer domainId = 1; + String dayField = TimeDimensionEnum.DAY.getName(); + String startDate = "2023-04-01"; + String endDate = "2023-06-01"; + + String format = MessageFormat.format(DslToSemanticInfo.SUB_TABLE, domainId, dayField, startDate, endDate); + + Assert.assertEquals(format, + " ( select * from t_1 where sys_imp_date >= '2023-04-01' and sys_imp_date <= '2023-06-01' ) as t_sub_1"); + + } +} \ 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 9602f9f16..7279ed301 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,11 +6,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; -@SpringBootApplication(scanBasePackages = {"com.tencent.supersonic"} +@SpringBootApplication(scanBasePackages = {"com.tencent.supersonic.chat"} // , exclude = {DataSourceAutoConfiguration.class} ) -@ComponentScan("com.tencent.supersonic") -@MapperScan("com.tencent.supersonic") +@ComponentScan("com.tencent.supersonic.chat") +@MapperScan("com.tencent.supersonic.chat") public class ChatBizLauncher { public static void main(String[] args) { diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java index 209ffb358..5ca6ebceb 100644 --- a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/ContextTest.java @@ -1,14 +1,16 @@ package com.tencent.supersonic.chat.test.context; +import com.tencent.supersonic.chat.domain.utils.ComponentFactory; import com.tencent.supersonic.chat.infrastructure.mapper.ChatContextMapper; import com.tencent.supersonic.chat.infrastructure.repository.ChatContextRepositoryImpl; -import com.tencent.supersonic.chat.infrastructure.semantic.DefaultSemanticLayerImpl; +import com.tencent.supersonic.chat.infrastructure.semantic.RemoteSemanticLayerImpl; import com.tencent.supersonic.chat.test.ChatBizLauncher; import com.tencent.supersonic.semantic.core.domain.DimensionService; import com.tencent.supersonic.semantic.core.domain.DomainService; import com.tencent.supersonic.semantic.core.domain.MetricService; import com.tencent.supersonic.semantic.query.domain.QueryService; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.test.context.SpringBootTest; @@ -23,7 +25,8 @@ import org.springframework.web.client.RestTemplate; @MockBean(DomainService.class) @MockBean(ChatContextMapper.class) @MockBean(RestTemplate.class) -@MockBean(DefaultSemanticLayerImpl.class) +@MockBean(RemoteSemanticLayerImpl.class) +@MockBean(ComponentFactory.class) //@MybatisTest //@AutoConfigureMybatis //@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 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 ee6c23432..cd8404f12 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 @@ -5,7 +5,8 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; import com.tencent.supersonic.chat.api.pojo.ChatContext; -import com.tencent.supersonic.chat.api.service.SemanticLayer; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.domain.service.QueryService; import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; import com.tencent.supersonic.semantic.api.core.response.DimensionResp; import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; @@ -20,7 +21,6 @@ import com.tencent.supersonic.chat.domain.pojo.config.EntityInternalDetail; import com.tencent.supersonic.chat.domain.pojo.config.EntityRichInfo; import com.tencent.supersonic.chat.domain.pojo.chat.DomainInfos; import com.tencent.supersonic.chat.domain.service.ChatService; -import com.tencent.supersonic.chat.domain.service.QueryService; import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter; import com.tencent.supersonic.chat.infrastructure.mapper.ChatContextMapper; import com.tencent.supersonic.chat.infrastructure.repository.ChatContextRepositoryImpl; @@ -39,51 +39,6 @@ import org.springframework.web.client.RestTemplate; @Configuration public class MockBeansConfiguration { - @Bean - public ChatContextRepositoryImpl getChatContextRepository() { - return Mockito.mock(ChatContextRepositoryImpl.class); - } - - @Bean - public QueryService getQueryService() { - return Mockito.mock(QueryService.class); - } - - @Bean - public DimensionService getDimensionService() { - return Mockito.mock(DimensionService.class); - } - - @Bean - public MetricService getMetricService() { - return Mockito.mock(MetricService.class); - } - - @Bean - public DomainService getDomainService() { - return Mockito.mock(DomainService.class); - } - - @Bean - public ChatContextMapper getChatContextMapper() { - return Mockito.mock(ChatContextMapper.class); - } - - @Bean - public ConfigServiceImpl getDomainExtendService() { - return Mockito.mock(ConfigServiceImpl.class); - } - - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } -// @Bean -// public SemanticLayer getSemanticService() { -// return Mockito.mock(HttpSemanticServiceImpl.class); -// } - - public static void getOrCreateContextMock(ChatService chatService) { ChatContext context = new ChatContext(); context.setChatId(1); @@ -142,8 +97,6 @@ public class MockBeansConfiguration { when(configService.fetchConfigByDomainId(anyLong())).thenReturn(chaConfigDesc); } - //queryDimensionDescs - public static void dimensionDescBuild(DimensionService dimensionService, List dimensionDescs) { when(dimensionService.getDimensions(anyList())).thenReturn(dimensionDescs); } @@ -167,4 +120,50 @@ public class MockBeansConfiguration { dimensionDesc.setBizName(bizName); return dimensionDesc; } + + @Bean + public ChatContextRepositoryImpl getChatContextRepository() { + return Mockito.mock(ChatContextRepositoryImpl.class); + } +// @Bean +// public SemanticLayer getSemanticService() { +// return Mockito.mock(HttpSemanticServiceImpl.class); +// } + + @Bean + public QueryService getQueryService() { + return Mockito.mock(QueryService.class); + } + + @Bean + public DimensionService getDimensionService() { + return Mockito.mock(DimensionService.class); + } + + @Bean + public MetricService getMetricService() { + return Mockito.mock(MetricService.class); + } + + //queryDimensionDescs + + @Bean + public DomainService getDomainService() { + return Mockito.mock(DomainService.class); + } + + @Bean + public ChatContextMapper getChatContextMapper() { + return Mockito.mock(ChatContextMapper.class); + } + + @Bean + public ConfigServiceImpl getDomainExtendService() { + return Mockito.mock(ConfigServiceImpl.class); + } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } } diff --git a/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/QueryServiceImplTest.java b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/QueryServiceImplTest.java new file mode 100644 index 000000000..9506aa6f4 --- /dev/null +++ b/chat/core/src/test/java/com/tencent/supersonic/chat/test/context/QueryServiceImplTest.java @@ -0,0 +1,177 @@ +package com.tencent.supersonic.chat.test.context; + +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.component.SemanticLayer; +import com.tencent.supersonic.chat.api.pojo.ChatContext; +import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper; +import com.tencent.supersonic.chat.application.mapper.QueryMatchStrategy; +import com.tencent.supersonic.chat.application.parser.DomainSemanticParser; +import com.tencent.supersonic.chat.domain.service.ChatService; +import com.tencent.supersonic.chat.test.ChatBizLauncher; +import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester; +import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ChatBizLauncher.class) +public class QueryServiceImplTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(QueryServiceImplTest.class); + +// @MockBean +// private QueryService queryService; + + //private SemanticLayer semanticLayer = mock(SemanticLayer.class); + +// @MockBean +// private DefaultSemanticLayerImpl semanticLayer; + //SemanticLayer + @Autowired + public QueryMatchStrategy queryMatchStrategy; + @Autowired(required = false) + public Suggester suggester; + @MockBean + private SemanticLayer semanticLayer;//= ComponentFactory.getSemanticLayer(); + +// @Before +// public void setUp() { +// //List getDomainSchemaInfo(List ids) +// List domainSchemaRespList=MockUtils.getChatContext(); +// Mockito.when(semanticLayer.getDomainSchemaInfo(Mockito.anyList())).thenReturn(domainSchemaRespList); +// } + @MockBean + private DomainSemanticParser domainSemanticParser; + @MockBean + private HanlpSchemaMapper hanlpSchemaMapper; + @MockBean + private ChatService chatService; + +//// @Autowired(required = false) +//// private ChatService chatService; + + //private SemanticLayer semanticLayer ; + + @Test + public void test() throws Exception { + QueryContextReq queryContextReq = getQueryContextReq("超音数访问次数"); + //hanlpSchemaMapper.map(queryContextReq); +// List terms = HanlpHelper.getSegment().seg(queryContextReq.getQueryText().toLowerCase()).stream() +// .collect(Collectors.toList()); +// LOGGER.info("terms::::{}",terms); +// MockUtils.putSuggester(); +// List matches = queryMatchStrategy.match(queryContextReq.getQueryText(), terms, queryContextReq.getDomainId()); +// HanlpHelper.transLetterOriginal(matches); +// HanlpSchemaMapperHelper.convertTermsToSchemaMapInfo(matches, queryContextReq.getMapInfo()); + HanlpSchemaMapper hanlpSchemaMapper = new HanlpSchemaMapper(); + hanlpSchemaMapper.map(queryContextReq); + //QueryContextReq queryContextReq=MockUtils.getQueryContextReq("METRIC_FILTER"); + LOGGER.info("QueryContextReq::::{}", queryContextReq.getMapInfo().getMatchedDomains()); + LOGGER.info("QueryContextReq::::{}", queryContextReq.getMapInfo().getDomainElementMatches()); + LOGGER.info("QueryContextReq::::{}", queryContextReq); + +// //chatService=new ChatServiceImpl(); +// ChatContext chatCtx = chatService.getOrCreateContext(queryContextReq.getChatId()); +// if (chatCtx == null) { +// chatCtx=new ChatContext(); +// chatCtx.setChatId(queryContextReq.getChatId()); +// } +// LOGGER.info("chatService::::{}",chatService); +// LOGGER.info("ChatContext::::{}",chatCtx); + ChatContext chatCtx = new ChatContext();//MockUtils.getChatContext1(); + //semanticLayer = ComponentFactory.getSemanticLayer(); +// DomainSemanticParser domainSemanticParser=new DomainSemanticParser(); +// domainSemanticParser.parse(queryContextReq,chatCtx); + + //DomainSemanticParser + + //domainSemanticParser=new DomainSemanticParser(); + LOGGER.info("domainSemanticParser::::{}", domainSemanticParser); + //SemanticLayer semanticLayer= mock(SemanticLayer.class); + //List domainSchemaRespList=MockUtils.getChatContext(); + +// //SemanticLayer semanticLayer = mock(SemanticLayer.class); +// when(semanticLayer.getDomainSchemaInfo(Mockito.anyList())).thenReturn(domainSchemaRespList); +// domainSemanticParser.parse(queryContextReq,chatCtx); +// LOGGER.info("QueryContextReq::::{}",queryContextReq); +// TimeSemanticParser timeSemanticParser=new TimeSemanticParser(); +// timeSemanticParser.parse(queryContextReq,chatCtx); +// AggregateSemanticParser aggregateSemanticParser=new AggregateSemanticParser(); +// aggregateSemanticParser.parse(queryContextReq,chatCtx); +// //PickStrategy pickStrategy = ComponentFactory.getPickStrategy(); +// LOGGER.info("pickStrategy::::{}",pickStrategy); +// pickStrategy=new ScoreBasedPickStrategy(); +// SemanticParseInfo semanticParse = pickStrategy.pick(queryContextReq, chatCtx); +// LOGGER.info("semanticParse::::{}",semanticParse); + //SemanticQueryExecutorHelper semanticQueryExecutorHelper=new SemanticQueryExecutorHelper(); + //semanticQueryExecutorHelper.execute(queryContextReq.getParseInfo(),queryContextReq.getUser()); +// LOGGER.info("queryContextReq::::{}",queryContextReq.getMapInfo().getMatchedDomains()); +// LOGGER.info("queryContextReq::::{}",queryContextReq.getMapInfo().getDomainElementMatches()); +// LOGGER.info("queryContextReq::::{}",queryContextReq.getCandidateParseInfos()); +// LOGGER.info("queryContextReq::::{}",queryContextReq.getDomainId()); + +// List queryExecutors = ComponentFactory.getQueryExecutors(); +// QueryResultResp queryResponse=new QueryResultResp(); +// for (QueryExecutor executor : queryExecutors) { +// queryResponse = executor.execute(semanticParse, queryContextReq.getUser()); +// if (queryResponse != null) { +// // update chat context after a successful semantic query +// if (queryContextReq.isSaveAnswer() && queryResponse.getQueryState() == QueryState.NORMAL.getState()) { +// chatService.updateContext(chatCtx, queryContextReq, semanticParse); +// } +// queryResponse.setChatContext(chatCtx.getParseInfo()); +// chatService.addQuery(queryResponse, queryContextReq, chatCtx); +// break; +// } +// } + + //assertThat(found.getName()).isEqualTo(name); + } + + public QueryContextReq getQueryContextReq(String query) { + QueryContextReq queryContextReq = new QueryContextReq(); + queryContextReq.setQueryText(query);//"alice的访问次数" + queryContextReq.setChatId(1); + queryContextReq.setUser(new User(1L, "admin", "admin", "admin@email")); + return queryContextReq; + } + + @TestConfiguration + static class EmployeeServiceImplTestContextConfiguration { + + @Bean + public QueryMatchStrategy queryMatchStrategyService() { + return new QueryMatchStrategy(); + } +// @Bean +// public SemanticLayer querySemanticLayer() { +// return new DefaultSemanticLayerImpl(); +// } + //@Bean + //public DomainSemanticParser queryDomainSemanticParser() { + // return new DomainSemanticParser(); + //} + +// @Bean +// public RestTemplate getRestTemplate(){ +// return new RestTemplate(); +// } +// +// @Bean +// public DefaultSemanticInternalUtils getUtils(){ +// return new DefaultSemanticInternalUtils(); +// } + + } +} diff --git a/chat/core/src/test/resources/hanlp.properties b/chat/core/src/test/resources/hanlp.properties index 19f09d02f..84fada8d0 100644 --- a/chat/core/src/test/resources/hanlp.properties +++ b/chat/core/src/test/resources/hanlp.properties @@ -1 +1 @@ -CustomDictionaryPath=data/dictionary/custom/23_285.txt \ No newline at end of file +CustomDictionaryPath=data/dictionary/custom/DimValue_1_2.txt diff --git a/chat/knowledge/src/main/java/com/hankcs/hanlp/collection/trie/bintrie/BaseNode.java b/chat/knowledge/src/main/java/com/hankcs/hanlp/collection/trie/bintrie/BaseNode.java index ec978fe09..895634c1e 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 @@ -19,6 +19,7 @@ public abstract class BaseNode implements Comparable { * 状态数组,方便读取的时候用 */ static final Status[] ARRAY_STATUS = Status.values(); + public String prefix = null; /** * 子节点 */ @@ -36,8 +37,6 @@ public abstract class BaseNode implements Comparable { */ protected V value; - public String prefix = null; - public BaseNode transition(String path, int begin) { BaseNode cur = this; for (int i = begin; i < path.length(); ++i) { @@ -231,37 +230,6 @@ public abstract class BaseNode implements Comparable { } } - public enum Status { - /** - * 未指定,用于删除词条 - */ - UNDEFINED_0, - /** - * 不是词语的结尾 - */ - NOT_WORD_1, - /** - * 是个词语的结尾,并且还可以继续 - */ - WORD_MIDDLE_2, - /** - * 是个词语的结尾,并且没有继续 - */ - WORD_END_3, - } - - public class TrieEntry extends AbstractMap.SimpleEntry implements Comparable { - - public TrieEntry(String key, V value) { - super(key, value); - } - - @Override - public int compareTo(TrieEntry o) { - return getKey().compareTo(String.valueOf(o.getKey())); - } - } - @Override public String toString() { return "BaseNode{" @@ -316,4 +284,35 @@ public abstract class BaseNode implements Comparable { } } + public enum Status { + /** + * 未指定,用于删除词条 + */ + UNDEFINED_0, + /** + * 不是词语的结尾 + */ + NOT_WORD_1, + /** + * 是个词语的结尾,并且还可以继续 + */ + WORD_MIDDLE_2, + /** + * 是个词语的结尾,并且没有继续 + */ + WORD_END_3, + } + + public class TrieEntry extends AbstractMap.SimpleEntry implements Comparable { + + public TrieEntry(String key, V value) { + super(key, value); + } + + @Override + public int compareTo(TrieEntry o) { + return getKey().compareTo(String.valueOf(o.getKey())); + } + } + } diff --git a/chat/knowledge/src/main/java/com/hankcs/hanlp/dictionary/CoreDictionary.java b/chat/knowledge/src/main/java/com/hankcs/hanlp/dictionary/CoreDictionary.java index e97c9f903..fecc6cb1e 100644 --- a/chat/knowledge/src/main/java/com/hankcs/hanlp/dictionary/CoreDictionary.java +++ b/chat/knowledge/src/main/java/com/hankcs/hanlp/dictionary/CoreDictionary.java @@ -26,9 +26,16 @@ import java.util.TreeMap; */ public class CoreDictionary { - public static DoubleArrayTrie trie = new DoubleArrayTrie(); - public static final String PATH = HanLP.Config.CoreDictionaryPath; + public static DoubleArrayTrie trie = new DoubleArrayTrie(); + // 一些特殊的WORD_ID + public static final int NR_WORD_ID = getWordID(Predefine.TAG_PEOPLE); + public static final int NS_WORD_ID = getWordID(Predefine.TAG_PLACE); + public static final int NT_WORD_ID = getWordID(Predefine.TAG_GROUP); + public static final int T_WORD_ID = getWordID(Predefine.TAG_TIME); + public static final int X_WORD_ID = getWordID(Predefine.TAG_CLUSTER); + public static final int M_WORD_ID = getWordID(Predefine.TAG_NUMBER); + public static final int NX_WORD_ID = getWordID(Predefine.TAG_PROPER); // 自动加载词典 static { @@ -40,15 +47,6 @@ public class CoreDictionary { } } - // 一些特殊的WORD_ID - public static final int NR_WORD_ID = getWordID(Predefine.TAG_PEOPLE); - public static final int NS_WORD_ID = getWordID(Predefine.TAG_PLACE); - public static final int NT_WORD_ID = getWordID(Predefine.TAG_GROUP); - public static final int T_WORD_ID = getWordID(Predefine.TAG_TIME); - public static final int X_WORD_ID = getWordID(Predefine.TAG_CLUSTER); - public static final int M_WORD_ID = getWordID(Predefine.TAG_NUMBER); - public static final int NX_WORD_ID = getWordID(Predefine.TAG_PROPER); - private static boolean load(String path) { logger.info("核心词典开始加载:" + path); if (loadDat(path)) { @@ -200,6 +198,29 @@ public class CoreDictionary { return trie.get(key) != null; } + /** + * 获取词语的ID + * + * @param a 词语 + * @return ID, 如果不存在, 则返回-1 + */ + public static int getWordID(String a) { + return CoreDictionary.trie.exactMatchSearch(a); + } + + /** + * 热更新核心词典
+ * 集群环境(或其他IOAdapter)需要自行删除缓存文件 + * + * @return 是否成功 + */ + public static boolean reload() { + String path = CoreDictionary.PATH; + IOUtil.deleteFile(path + Predefine.BIN_EXT); + + return load(path); + } + /** * 核心词典中的词属性 */ @@ -366,28 +387,5 @@ public class CoreDictionary { } } } - - /** - * 获取词语的ID - * - * @param a 词语 - * @return ID, 如果不存在, 则返回-1 - */ - public static int getWordID(String a) { - return CoreDictionary.trie.exactMatchSearch(a); - } - - /** - * 热更新核心词典
- * 集群环境(或其他IOAdapter)需要自行删除缓存文件 - * - * @return 是否成功 - */ - public static boolean reload() { - String path = CoreDictionary.PATH; - IOUtil.deleteFile(path + Predefine.BIN_EXT); - - return load(path); - } } diff --git a/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/WordBasedSegment.java b/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/WordBasedSegment.java index 47204ec23..b467abba3 100644 --- a/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/WordBasedSegment.java +++ b/chat/knowledge/src/main/java/com/hankcs/hanlp/seg/WordBasedSegment.java @@ -236,6 +236,10 @@ public abstract class WordBasedSegment extends Segment { } } + protected static void speechTagging(List vertexList) { + Viterbi.compute(vertexList, CoreDictionaryTransformMatrixDictionary.transformMatrixDictionary); + } + protected void generateWordNet(final WordNet wordNetStorage) { final char[] charArray = wordNetStorage.charArray; DoubleArrayTrie.Searcher searcher = CoreDictionary.trie.getSearcher(charArray, 0); @@ -322,10 +326,6 @@ public abstract class WordBasedSegment extends Segment { return termList; } - protected static void speechTagging(List vertexList) { - Viterbi.compute(vertexList, CoreDictionaryTransformMatrixDictionary.transformMatrixDictionary); - } - protected void addTerms(List terms, Vertex vertex, int offset) { for (int i = 0; i < vertex.attribute.nature.length; i++) { Term term = new Term(vertex.realWord, vertex.attribute.nature[i]); diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/BaseWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/BaseWordNature.java index 09873cfd2..fe5de093c 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/BaseWordNature.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/BaseWordNature.java @@ -49,11 +49,4 @@ public abstract class BaseWordNature { return 0; } - public Long getFrequency(String nature) { - String[] split = nature.split(NatureType.NATURE_SPILT); - if (split.length >= 3) { - return Long.valueOf(split[2]); - } - return 0L; - } } diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DomainWordNature.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DomainWordNature.java index 8583e64e7..d76234985 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DomainWordNature.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/application/online/DomainWordNature.java @@ -27,8 +27,4 @@ public class DomainWordNature extends BaseWordNature { return result; } - @Override - public Long getFrequency(String nature) { - return 0L; - } } diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HanlpHelper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HanlpHelper.java index 8b22766f6..f5962d852 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HanlpHelper.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HanlpHelper.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; import org.springframework.util.ResourceUtils; /** @@ -21,13 +22,13 @@ import org.springframework.util.ResourceUtils; */ public class HanlpHelper { - private static final Logger LOGGER = LoggerFactory.getLogger(HanlpHelper.class); public static final String FILE_SPILT = "/"; public static final String SPACE_SPILT = "#"; - private static volatile Segment segment; - public static volatile DynamicCustomDictionary CustomDictionary; public static final String DICT_MAIN_FILE_NAME = "CustomDictionary.txt"; public static final String DICT_CLASS = "classes"; + private static final Logger LOGGER = LoggerFactory.getLogger(HanlpHelper.class); + public static volatile DynamicCustomDictionary CustomDictionary; + private static volatile Segment segment; static { // reset hanlp config @@ -152,11 +153,14 @@ public class HanlpHelper { } public static boolean addToCustomDictionary(WordNature wordNature) { - LOGGER.debug("wordNature:{}", wordNature); + LOGGER.info("wordNature:{}", wordNature); return getDynamicCustomDictionary().insert(wordNature.getWord(), wordNature.getNatureWithFrequency()); } public static void transLetterOriginal(List mapResults) { + if (CollectionUtils.isEmpty(mapResults)) { + return; + } for (MapResult mapResult : mapResults) { if (MultiCustomDictionary.isLowerLetter(mapResult.getName())) { if (CustomDictionary.contains(mapResult.getName())) { diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HdfsFileHelper.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HdfsFileHelper.java index a7d2cea16..48863fbf5 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HdfsFileHelper.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/HdfsFileHelper.java @@ -53,6 +53,7 @@ public class HdfsFileHelper { /** * reset path + * * @param customDictionary * @throws IOException */ diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/MultiCustomDictionary.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/MultiCustomDictionary.java index 6c31b5c6b..2a678cf98 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/MultiCustomDictionary.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/MultiCustomDictionary.java @@ -42,20 +42,6 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { super(path); } - public boolean load(String... path) { - this.path = path; - long start = System.currentTimeMillis(); - if (!this.loadMainDictionary(path[0])) { - Predefine.logger.warning("自定义词典" + Arrays.toString(path) + "加载失败"); - return false; - } else { - Predefine.logger.info( - "自定义词典加载成功:" + this.dat.size() + "个词条,耗时" + (System.currentTimeMillis() - start) + "ms"); - this.path = path; - return true; - } - } - /*** * load dictionary * @param path @@ -139,10 +125,6 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { } } - public boolean loadMainDictionary(String mainPath) { - return loadMainDictionary(mainPath, this.path, this.dat, true, addToSuggesterTrie); - } - /*** * load main dictionary * @param mainPath @@ -291,6 +273,53 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { } } + public static boolean isLetters(String str) { + char[] chars = str.toCharArray(); + if (chars.length <= 1) { + return false; + } + for (int i = 0; i < chars.length; i++) { + if ((chars[i] >= 'A' && chars[i] <= 'Z')) { + return true; + } + } + return false; + } + + public static boolean isLowerLetter(String str) { + char[] chars = str.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if ((chars[i] >= 'a' && chars[i] <= 'z')) { + return true; + } + } + return false; + } + + public static String getWordBySpace(String word) { + if (word.contains(HanlpHelper.SPACE_SPILT)) { + return word.replace(HanlpHelper.SPACE_SPILT, " "); + } + return word; + } + + public boolean load(String... path) { + this.path = path; + long start = System.currentTimeMillis(); + if (!this.loadMainDictionary(path[0])) { + Predefine.logger.warning("自定义词典" + Arrays.toString(path) + "加载失败"); + return false; + } else { + Predefine.logger.info( + "自定义词典加载成功:" + this.dat.size() + "个词条,耗时" + (System.currentTimeMillis() - start) + "ms"); + this.path = path; + return true; + } + } + + public boolean loadMainDictionary(String mainPath) { + return loadMainDictionary(mainPath, this.path, this.dat, true, addToSuggesterTrie); + } public boolean reload() { if (this.path != null && this.path.length != 0) { @@ -344,35 +373,4 @@ public class MultiCustomDictionary extends DynamicCustomDictionary { return true; } } - - - public static boolean isLetters(String str) { - char[] chars = str.toCharArray(); - if (chars.length <= 1) { - return false; - } - for (int i = 0; i < chars.length; i++) { - if ((chars[i] >= 'A' && chars[i] <= 'Z')) { - return true; - } - } - return false; - } - - public static boolean isLowerLetter(String str) { - char[] chars = str.toCharArray(); - for (int i = 0; i < chars.length; i++) { - if ((chars[i] >= 'a' && chars[i] <= 'z')) { - return true; - } - } - return false; - } - - public static String getWordBySpace(String word) { - if (word.contains(HanlpHelper.SPACE_SPILT)) { - return word.replace(HanlpHelper.SPACE_SPILT, " "); - } - return word; - } } \ No newline at end of file diff --git a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/Suggester.java b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/Suggester.java index 1fd7fea87..36b700ed0 100644 --- a/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/Suggester.java +++ b/chat/knowledge/src/main/java/com/tencent/supersonic/knowledge/infrastructure/nlp/Suggester.java @@ -23,13 +23,12 @@ import org.springframework.util.CollectionUtils; @Service public class Suggester { + public static final int SEARCH_SIZE = 200; private static final Logger LOGGER = LoggerFactory.getLogger(Suggester.class); private static BinTrie> trie; private static BinTrie> suffixTrie; private static String localFileCache = ""; - public static final int SEARCH_SIZE = 200; - static { trie = new BinTrie<>(); suffixTrie = new BinTrie<>(); @@ -53,7 +52,7 @@ public class Suggester { return result.stream().map( entry -> { String name = entry.getKey().replace("#", " "); - return new MapResult(name, entry.getValue(),key); + return new MapResult(name, entry.getValue(), key); } ).sorted((a, b) -> -(b.getName().length() - a.getName().length())) .limit(SEARCH_SIZE) diff --git a/common/pom.xml b/common/pom.xml index 1c6d449ae..70397847c 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -124,6 +124,12 @@ ${pagehelper.version} + + org.apache.calcite + calcite-core + ${calcite.version} + +
diff --git a/common/src/main/java/com/tencent/supersonic/common/constant/Constants.java b/common/src/main/java/com/tencent/supersonic/common/constant/Constants.java index e172e6def..5d06e987b 100644 --- a/common/src/main/java/com/tencent/supersonic/common/constant/Constants.java +++ b/common/src/main/java/com/tencent/supersonic/common/constant/Constants.java @@ -40,6 +40,7 @@ public class Constants { public static final String DAY = "DAY"; public static final String DAY_FORMAT = "yyyy-MM-dd"; + public static final String MONTH_FORMAT = "yyyy-MM"; public static final String DAY_FORMAT_INT = "YYYYMMDD"; public static final String MONTH = "MONTH"; public static final String WEEK = "WEEK"; diff --git a/common/src/main/java/com/tencent/supersonic/common/nlp/ItemDO.java b/common/src/main/java/com/tencent/supersonic/common/nlp/ItemDO.java index 8a7078e60..df47bb072 100644 --- a/common/src/main/java/com/tencent/supersonic/common/nlp/ItemDO.java +++ b/common/src/main/java/com/tencent/supersonic/common/nlp/ItemDO.java @@ -1,7 +1,7 @@ package com.tencent.supersonic.common.nlp; +import com.google.common.base.Objects; import java.io.Serializable; -import java.util.Objects; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -14,8 +14,18 @@ public class ItemDO implements Serializable { private Integer domain; private Integer itemId; private String name; + private String bizName; private Long useCnt = 0L; + public ItemDO() { + } + + public ItemDO(Integer domain, Integer itemId, String name, String bizName) { + this.domain = domain; + this.itemId = itemId; + this.name = name; + this.bizName = bizName; + } @Override public boolean equals(Object o) { @@ -26,7 +36,14 @@ public class ItemDO implements Serializable { return false; } ItemDO itemDO = (ItemDO) o; - return Objects.equals(domain, itemDO.domain) && Objects.equals(itemId, itemDO.itemId) - && Objects.equals(name, itemDO.name); + return Objects.equal(domain, itemDO.domain) && Objects.equal(itemId, + itemDO.itemId) && Objects.equal(name, itemDO.name) + && Objects.equal(bizName, itemDO.bizName) && Objects.equal( + useCnt, itemDO.useCnt); + } + + @Override + public int hashCode() { + return Objects.hashCode(domain, itemId, name, bizName, useCnt); } } diff --git a/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParseUtils.java b/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParseUtils.java new file mode 100644 index 000000000..a926d928c --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParseUtils.java @@ -0,0 +1,160 @@ +package com.tencent.supersonic.common.util.calcite; + +import java.util.List; +import java.util.stream.Collectors; +import org.apache.calcite.sql.SqlBasicCall; +import org.apache.calcite.sql.SqlIdentifier; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlNodeList; +import org.apache.calcite.sql.SqlOrderBy; +import org.apache.calcite.sql.SqlSelect; +import org.apache.calcite.sql.parser.SqlParseException; +import org.apache.calcite.sql.parser.SqlParser; + +/** + * sql parse utils + */ +public class SqlParseUtils { + + /** + * get sql parseInfo + * + * @param sql + * @return + */ + public static SqlParserInfo getSqlParseInfo(String sql) { + try { + SqlParser parser = SqlParser.create(sql); + SqlNode sqlNode = parser.parseQuery(); + SqlParserInfo sqlParserInfo = new SqlParserInfo(); + handlerSQL(sqlNode, sqlParserInfo); + + List collect = sqlParserInfo.getAllFields().stream().distinct().collect(Collectors.toList()); + + sqlParserInfo.setAllFields(collect); + return sqlParserInfo; + } catch (SqlParseException e) { + throw new RuntimeException("getSqlParseInfo", e); + } + } + + /** + * hanlder sql + * + * @param sqlNode + * @param sqlParserInfo + */ + public static void handlerSQL(SqlNode sqlNode, SqlParserInfo sqlParserInfo) { + SqlKind kind = sqlNode.getKind(); + + switch (kind) { + case SELECT: + handlerSelect(sqlNode, sqlParserInfo); + break; + case ORDER_BY: + handlerOrderBy(sqlNode, sqlParserInfo); + break; + } + } + + /** + * hanlder order by + * + * @param node + * @param sqlParserInfo + */ + private static void handlerOrderBy(SqlNode node, SqlParserInfo sqlParserInfo) { + SqlOrderBy sqlOrderBy = (SqlOrderBy) node; + SqlNode query = sqlOrderBy.query; + handlerSQL(query, sqlParserInfo); + SqlNodeList orderList = sqlOrderBy.orderList; + handlerField(orderList, sqlParserInfo); + } + + /** + * hanlder select + * + * @param select + * @param sqlParserInfo + */ + private static void handlerSelect(SqlNode select, SqlParserInfo sqlParserInfo) { + SqlSelect sqlSelect = (SqlSelect) select; + SqlNodeList selectList = sqlSelect.getSelectList(); + + selectList.getList().forEach(list -> { + handlerField(list, sqlParserInfo); + }); + String tableName = handlerFrom(sqlSelect.getFrom()); + sqlParserInfo.setTableName(tableName); + + if (sqlSelect.hasWhere()) { + handlerField(sqlSelect.getWhere(), sqlParserInfo); + } + if (sqlSelect.hasOrderBy()) { + handlerField(sqlSelect.getOrderList(), sqlParserInfo); + } + SqlNodeList group = sqlSelect.getGroup(); + if (group != null) { + group.forEach(groupField -> { + handlerField(groupField, sqlParserInfo); + }); + } + } + + /** + * hander from + * + * @param from + * @return + */ + private static String handlerFrom(SqlNode from) { + SqlKind kind = from.getKind(); + switch (kind) { + case IDENTIFIER: + SqlIdentifier sqlIdentifier = (SqlIdentifier) from; + return sqlIdentifier.getSimple(); + case AS: + SqlBasicCall sqlBasicCall = (SqlBasicCall) from; + SqlNode sqlNode = sqlBasicCall.getOperandList().get(0); + SqlSelect sqlSelect = (SqlSelect) sqlNode; + return handlerFrom(sqlSelect.getFrom()); + } + return ""; + } + + /** + * handler field + * + * @param field + * @param sqlParserInfo + */ + private static void handlerField(SqlNode field, SqlParserInfo sqlParserInfo) { + SqlKind kind = field.getKind(); + switch (kind) { + case AS: + List operandList1 = ((SqlBasicCall) field).getOperandList(); + SqlNode left_as = operandList1.get(0); + handlerField(left_as, sqlParserInfo); + break; + case IDENTIFIER: + SqlIdentifier sqlIdentifier = (SqlIdentifier) field; + sqlParserInfo.getAllFields().add(sqlIdentifier.getSimple()); + break; + default: + if (field instanceof SqlBasicCall) { + List operandList2 = ((SqlBasicCall) field).getOperandList(); + for (int i = 0; i < operandList2.size(); i++) { + handlerField(operandList2.get(i), sqlParserInfo); + } + } + if (field instanceof SqlNodeList) { + ((SqlNodeList) field).getList().forEach(node -> { + handlerField(node, sqlParserInfo); + }); + } + break; + } + } +} + diff --git a/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParserInfo.java b/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParserInfo.java new file mode 100644 index 000000000..cab347a03 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/calcite/SqlParserInfo.java @@ -0,0 +1,17 @@ +package com.tencent.supersonic.common.util.calcite; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import lombok.Data; +import lombok.ToString; + +@Data +@ToString +public class SqlParserInfo implements Serializable { + + private String tableName; + + private List allFields = new ArrayList<>(); + +} \ No newline at end of file diff --git a/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContext.java b/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContext.java index d54e831af..74b152401 100644 --- a/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContext.java +++ b/common/src/main/java/com/tencent/supersonic/common/util/context/ThreadContext.java @@ -4,6 +4,9 @@ package com.tencent.supersonic.common.util.context; import lombok.Builder; import lombok.Data; import lombok.ToString; +import java.util.Map; + +import java.util.Map; @Builder @ToString @@ -16,4 +19,6 @@ public class ThreadContext { private String token; + private Map extendInfo; + } \ No newline at end of file diff --git a/docs/images/supersonic_components.png b/docs/images/supersonic_components.png index 718f91818..295f9eb0b 100644 Binary files a/docs/images/supersonic_components.png and b/docs/images/supersonic_components.png differ diff --git a/launchers/chat/pom.xml b/launchers/chat/pom.xml index 970d20f01..3cc1d1875 100644 --- a/launchers/chat/pom.xml +++ b/launchers/chat/pom.xml @@ -1,6 +1,6 @@ - launchers @@ -100,4 +100,4 @@ - \ No newline at end of file +
diff --git a/launchers/chat/src/main/resources/META-INF/spring.factories b/launchers/chat/src/main/resources/META-INF/spring.factories index b0497080c..19f37234b 100644 --- a/launchers/chat/src/main/resources/META-INF/spring.factories +++ b/launchers/chat/src/main/resources/META-INF/spring.factories @@ -1,32 +1,23 @@ -com.tencent.supersonic.chat.api.service.SchemaMapper=\ - com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper +com.tencent.supersonic.chat.api.component.SchemaMapper=\ + com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper, \ + com.tencent.supersonic.chat.application.mapper.DatabaseSchemaMapper, \ + com.tencent.supersonic.chat.application.mapper.QueryFilterMapper -com.tencent.supersonic.chat.application.parser.resolver.DomainResolver=\ - com.tencent.supersonic.chat.application.parser.resolver.HeuristicDomainResolver - -com.tencent.supersonic.chat.api.service.SemanticParser=\ - com.tencent.supersonic.chat.application.parser.TimeSemanticParser, \ +com.tencent.supersonic.chat.api.component.SemanticParser=\ com.tencent.supersonic.chat.application.parser.DomainSemanticParser, \ - com.tencent.supersonic.chat.application.parser.ListFilterParser, \ - com.tencent.supersonic.chat.application.parser.DefaultMetricSemanticParser, \ + com.tencent.supersonic.chat.application.parser.TimeSemanticParser, \ com.tencent.supersonic.chat.application.parser.AggregateSemanticParser +# com.tencent.supersonic.chat.application.parser.LLMSemanticParser -com.tencent.supersonic.chat.api.service.SemanticQuery=\ - com.tencent.supersonic.chat.application.query.EntityDetail, \ - com.tencent.supersonic.chat.application.query.EntityListTopN, \ - com.tencent.supersonic.chat.application.query.EntityMetricFilter, \ - com.tencent.supersonic.chat.application.query.EntityListFilter, \ - com.tencent.supersonic.chat.application.query.MetricCompare, \ - com.tencent.supersonic.chat.application.query.MetricDomain, \ - com.tencent.supersonic.chat.application.query.MetricFilter, \ - com.tencent.supersonic.chat.application.query.MetricGroupBy, \ - com.tencent.supersonic.chat.application.query.MetricOrderBy +com.tencent.supersonic.chat.api.component.SemanticLayer=\ + com.tencent.supersonic.chat.infrastructure.semantic.RemoteSemanticLayerImpl +com.tencent.supersonic.chat.application.query.QuerySelector=\ + com.tencent.supersonic.chat.application.query.HeuristicQuerySelector -com.tencent.supersonic.chat.api.service.SemanticLayer=\ - com.tencent.supersonic.chat.infrastructure.semantic.DefaultSemanticLayerImpl - +com.tencent.supersonic.chat.application.parser.DomainResolver=\ + com.tencent.supersonic.chat.application.parser.HeuristicDomainResolver com.tencent.supersonic.auth.authentication.domain.interceptor.AuthenticationInterceptor=\ - com.tencent.supersonic.auth.authentication.domain.interceptor.DefaultAuthenticationInterceptor \ No newline at end of file + com.tencent.supersonic.auth.authentication.domain.interceptor.DefaultAuthenticationInterceptor diff --git a/launchers/chat/src/main/resources/application-local.yaml b/launchers/chat/src/main/resources/application-local.yaml index 1c28fd136..121adbce5 100644 --- a/launchers/chat/src/main/resources/application-local.yaml +++ b/launchers/chat/src/main/resources/application-local.yaml @@ -16,10 +16,10 @@ server: port: 9080 authentication: - enable: true + enable: false exclude: path: /api/auth/user/register,/api/auth/user/login semantic: url: - prefix: http://127.0.0.1:9081 \ No newline at end of file + prefix: http://127.0.0.1:9081 diff --git a/launchers/chat/src/main/resources/db/chat-data-h2.sql b/launchers/chat/src/main/resources/db/chat-data-h2.sql index 48d7d332c..f88969f27 100644 --- a/launchers/chat/src/main/resources/db/chat-data-h2.sql +++ b/launchers/chat/src/main/resources/db/chat-data-h2.sql @@ -3,7 +3,7 @@ insert into s2_user (id, `name`, password, display_name, email) values (2, 'jack insert into s2_user (id, `name`, password, display_name, email) values (3, 'tom','123456','tom','tom@xx.com'); insert into s2_user (id, `name`, password, display_name, email) values (4, 'lucy','123456','lucy','lucy@xx.com'); -insert into s2_chat_config (id, domain_id, default_metrics, visibility, entity_info, dictionary_info, created_at, updated_at, created_by, updated_by, status) values (2, 1, '[{"metricId":1,"unit":7,"period":"DAY"}]','{"blackDimIdList":[],"blackMetricIdList":[]}','{"entityIds":[2],"names":["用户","用户姓名"],"detailData":{"dimensionIds":[1,2],"metricIds":[2]}}','[{"itemId":1,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":2,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":3,"type":"DIMENSION","blackList":[],"isDictInfo":true}]','2023-05-24 18:00:00', '2023-05-25 11:00:00', 'admin', 'admin', 1 ); +insert into s2_chat_config (`id` ,`domain_id` ,`default_metrics`,`visibility`,`entity_info` ,`dictionary_info`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (1,1,'[{"metricId":1,"unit":7,"period":"DAY"}]','{"blackDimIdList":[],"blackMetricIdList":[]}','{"entityIds":[2],"names":["用户","用户姓名"],"detailData":{"dimensionIds":[1,2],"metricIds":[2]}}','[{"itemId":1,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":2,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":3,"type":"DIMENSION","blackList":[],"isDictInfo":true}]','2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (1, '超音数访问统计','2023-06-10 10:00:52.495','2023-06-10 10:00:52','admin','您好,欢迎使用内容智能小Q','0','0'); insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (2, '用户访问统计','2023-06-10 10:01:04.528','2023-06-10 10:01:04','admin','您好,欢迎使用内容智能小Q','0','0'); diff --git a/launchers/common/pom.xml b/launchers/common/pom.xml index 9e2c3a7ac..0863ac9c5 100644 --- a/launchers/common/pom.xml +++ b/launchers/common/pom.xml @@ -1,6 +1,6 @@ - launchers diff --git a/launchers/common/src/main/java/com/tencent/supersonic/config/RestTemplateConfig.java b/launchers/common/src/main/java/com/tencent/supersonic/config/RestTemplateConfig.java index c1446534f..7bc0d3d6f 100644 --- a/launchers/common/src/main/java/com/tencent/supersonic/config/RestTemplateConfig.java +++ b/launchers/common/src/main/java/com/tencent/supersonic/config/RestTemplateConfig.java @@ -1,7 +1,13 @@ package com.tencent.supersonic.config; +import java.nio.charset.StandardCharsets; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.LaxRedirectStrategy; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.client.RestTemplate; @Configuration @@ -9,6 +15,14 @@ public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { - return new RestTemplate(); + HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(); + httpRequestFactory.setConnectionRequestTimeout(2000); + httpRequestFactory.setConnectTimeout(10000); + httpRequestFactory.setReadTimeout(7200000); + HttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build(); + httpRequestFactory.setHttpClient(httpClient); + RestTemplate restTemplate = new RestTemplate(httpRequestFactory); + restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); + return restTemplate; } } diff --git a/launchers/common/src/main/java/com/tencent/supersonic/config/SpringContextUtil.java b/launchers/common/src/main/java/com/tencent/supersonic/config/SpringContextUtil.java index e8e6f6197..64e293132 100644 --- a/launchers/common/src/main/java/com/tencent/supersonic/config/SpringContextUtil.java +++ b/launchers/common/src/main/java/com/tencent/supersonic/config/SpringContextUtil.java @@ -10,15 +10,15 @@ public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringContextUtil.applicationContext = applicationContext; } - public static ApplicationContext getApplicationContext() { - return applicationContext; - } - public static Object getBean(String name) throws BeansException { return applicationContext.getBean(name); } diff --git a/launchers/pom.xml b/launchers/pom.xml index ef38fc7ca..af879b7d9 100644 --- a/launchers/pom.xml +++ b/launchers/pom.xml @@ -1,6 +1,6 @@ - supersonic @@ -16,10 +16,11 @@ chat semantic common + standalone 8 8 - \ No newline at end of file + diff --git a/launchers/semantic/pom.xml b/launchers/semantic/pom.xml index 676fdeecc..f05a52ffd 100644 --- a/launchers/semantic/pom.xml +++ b/launchers/semantic/pom.xml @@ -1,6 +1,6 @@ - launchers diff --git a/launchers/semantic/src/main/resources/application-local.yaml b/launchers/semantic/src/main/resources/application-local.yaml index 4977d37c8..39e9d0715 100644 --- a/launchers/semantic/src/main/resources/application-local.yaml +++ b/launchers/semantic/src/main/resources/application-local.yaml @@ -18,6 +18,6 @@ spring: data: classpath:db/semantic-data-h2.sql authentication: - enable: true + enable: false exclude: path: /api/auth/user/register,/api/auth/user/login \ No newline at end of file diff --git a/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql b/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql index 649ad3132..4d484dee7 100644 --- a/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql +++ b/launchers/semantic/src/main/resources/db/semantic-schema-h2.sql @@ -84,6 +84,7 @@ CREATE TABLE IF NOT EXISTS `s2_metric` ( `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'; @@ -106,6 +107,8 @@ CREATE TABLE IF NOT EXISTS `s2_dimension` ( `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, PRIMARY KEY (`id`) ); COMMENT ON TABLE s2_dimension IS 'dimension information table'; diff --git a/launchers/semantic/src/main/resources/model/s2_time_stat.yaml b/launchers/semantic/src/main/resources/model/s2_time_stat.yaml deleted file mode 100644 index 8d2916389..000000000 --- a/launchers/semantic/src/main/resources/model/s2_time_stat.yaml +++ /dev/null @@ -1,22 +0,0 @@ -data_source: - name: s2_stay_time_statis - sql_query: select imp_date,page,stay_hours from s2_stay_time_statis - identifiers: - - name: sys_imp_date - type: primary - expr: imp_date - - name: user_name - type: primary - dimensions: - - name: page - type: categorical - - name: imp_date - type: time - type_params: - is_primary: True - time_granularity: day - measures: - - name: stay_hours - agg: sum - expr: stay_hours - create_metric: True \ No newline at end of file diff --git a/launchers/semantic/src/main/resources/model/s2_uv.yaml b/launchers/semantic/src/main/resources/model/s2_uv.yaml deleted file mode 100644 index c67b88130..000000000 --- a/launchers/semantic/src/main/resources/model/s2_uv.yaml +++ /dev/null @@ -1,26 +0,0 @@ -data_source: - name: s2_pv_uv_statis - sql_query: select imp_date,user_name from s2_pv_uv_statis - identifiers: - - name: sys_imp_date - type: primary - expr: imp_date - - name: user_name - type: primary - dimensions: - - name: page - type: categorical - - name: sys_imp_date - type: time - type_params: - is_primary: True - time_granularity: day - measures: - - name: uv - agg: count_distinct - expr: user_name - create_metric: True - - name: pv - agg: sum - expr: 1 - create_metric: True \ No newline at end of file diff --git a/launchers/standalone/pom.xml b/launchers/standalone/pom.xml new file mode 100644 index 000000000..665faab73 --- /dev/null +++ b/launchers/standalone/pom.xml @@ -0,0 +1,126 @@ + + + + launchers + com.tencent.supersonic + ${revision} + + 4.0.0 + + launchers-standalone + + + 8 + 8 + com.tencent.supersonic.StandaloneLauncher + + + + com.tencent.supersonic + launchers-common + ${project.version} + + + + com.tencent.supersonic + chat-core + ${project.version} + + + + com.tencent.supersonic + auth-authorization + ${project.version} + + + + com.h2database + h2 + ${h2.version} + + + + javax.servlet.jsp + jsp-api + 2.0 + compile + + + com.tencent.supersonic + semantic-query + ${project.version} + + + + com.tencent.supersonic + semantic-core + ${project.version} + + + com.tencent.supersonic + auth-api + ${project.version} + + + junit + junit + test + + + + + + + local + + + com.h2database + h2 + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + *.* + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4 + + false + + + ${start-class} + + + + ../../assembly/build/build.xml + + + + + make-assembly + package + + single + + + + + + + + diff --git a/launchers/standalone/src/main/bin/env.sh b/launchers/standalone/src/main/bin/env.sh new file mode 100644 index 000000000..969d3fe90 --- /dev/null +++ b/launchers/standalone/src/main/bin/env.sh @@ -0,0 +1,2 @@ +export APP_NAME=chat-service +export MAIN_CLASS=com.tencent.supersonic.Launcher diff --git a/launchers/standalone/src/main/bin/run.sh b/launchers/standalone/src/main/bin/run.sh new file mode 100755 index 000000000..00d517aea --- /dev/null +++ b/launchers/standalone/src/main/bin/run.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +binDir=$(cd "$(dirname "$0")"; pwd) +baseDir=$(readlink -f $binDir/../) +libDir=$baseDir/lib +confDir=$baseDir/conf +webDir=$baseDir/webapp + +source ${baseDir}/bin/env.sh + + +CLASSPATH="" +CLASSPATH=$CLASSPATH:$confDir + +for jarPath in $libDir/*.jar; do + CLASSPATH=$CLASSPATH:$jarPath +done + + + +export CLASSPATH +export LANG="zh_CN.UTF-8" + +cd $baseDir + +if [[ "$JAVA_HOME" == "" ]]; then + JAVA_HOME=$(ls /usr/jdk64/jdk* -d 2>/dev/null | xargs | awk '{print "'$APP_NAME'"}') +fi +export PATH=$JAVA_HOME/bin:$PATH + +command="-Dfile.encoding="UTF-8" -Duser.language="Zh" -Duser.region="CN" -Duser.timezone="GMT+08" -Xms1024m -Xmx2048m "$MAIN_CLASS + +mkdir -p $baseDir/logs +if [[ "$is_test" == "true" ]]; then + java -Dspring.profiles.active="dev" $command >/dev/null 2>$baseDir/logs/error.log & +else + java $command $baseDir >/dev/null 2>$baseDir/logs/error.log & +fi diff --git a/launchers/standalone/src/main/bin/service.sh b/launchers/standalone/src/main/bin/service.sh new file mode 100755 index 000000000..3176eb811 --- /dev/null +++ b/launchers/standalone/src/main/bin/service.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +binDir=$(cd "$(dirname "$0")"; pwd) +baseDir=$(readlink -f $binDir/../) +confDir=$baseDir/conf +source ${baseDir}/bin/env.sh + +commond=$1 + +function start() +{ + pid=$(ps aux | grep $MAIN_CLASS | grep -v grep |grep $baseDir | awk '{print "'$APP_NAME'"}') + if [[ "$pid" == "" ]]; then + logs=$baseDir/logs/service.sh.log + env DEPLOY=true $baseDir/bin/run.sh $MAIN_CLASS && echo "Process started, see logs/error with logs/error command" + return 0 + else + echo "Process (PID = $pid) is running." + return 1 + fi +} + +function stop() +{ + pid=$(ps aux | grep $MAIN_CLASS | grep -v grep|grep $baseDir| awk '{print $2}') + if [[ "$pid" == "" ]]; then + echo "Process is not running !" + return 1 + else + kill -9 $pid + echo "Process (PID = $pid) is killed !" + return 0 + fi +} + +case "$commond" in + start) + echo -e "Starting $APP_NAME" + start + ;; + stop) + echo -e "Stopping $APP_NAME" + stop + ;; + restart) + echo -e "Resetting $APP_NAME" + stop + start + ;; + *) + echo "Use command {start|stop|status|restart} to run." + exit 1 +esac + +exit 0 diff --git a/launchers/standalone/src/main/java/com/tencent/supersonic/StandaloneLauncher.java b/launchers/standalone/src/main/java/com/tencent/supersonic/StandaloneLauncher.java new file mode 100644 index 000000000..0356d5a94 --- /dev/null +++ b/launchers/standalone/src/main/java/com/tencent/supersonic/StandaloneLauncher.java @@ -0,0 +1,20 @@ +package com.tencent.supersonic; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * StandaloneLauncher + **/ +@SpringBootApplication(scanBasePackages = {"com.tencent.supersonic"}, + exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) +@EnableScheduling +public class StandaloneLauncher { + + public static void main(String[] args) { + SpringApplication.run(StandaloneLauncher.class, args); + } +} diff --git a/launchers/standalone/src/main/java/com/tencent/supersonic/db/MybatisConfig.java b/launchers/standalone/src/main/java/com/tencent/supersonic/db/MybatisConfig.java new file mode 100644 index 000000000..f3428741a --- /dev/null +++ b/launchers/standalone/src/main/java/com/tencent/supersonic/db/MybatisConfig.java @@ -0,0 +1,31 @@ +package com.tencent.supersonic.db; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import javax.sql.DataSource; + + +@Configuration +@MapperScan(value = "com.tencent.supersonic", annotationClass = Mapper.class) +public class MybatisConfig { + + private static final String MAPPER_LOCATION = "classpath*:mapper/**/*.xml"; + + @Bean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { + SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); + org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); + configuration.setMapUnderscoreToCamelCase(true); + bean.setConfiguration(configuration); + bean.setDataSource(dataSource); + + bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION)); + return bean.getObject(); + } +} diff --git a/launchers/standalone/src/main/resources/META-INF/spring.factories b/launchers/standalone/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..573471a9f --- /dev/null +++ b/launchers/standalone/src/main/resources/META-INF/spring.factories @@ -0,0 +1,23 @@ +com.tencent.supersonic.chat.api.component.SchemaMapper=\ + com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper, \ + com.tencent.supersonic.chat.application.mapper.DatabaseSchemaMapper, \ + com.tencent.supersonic.chat.application.mapper.QueryFilterMapper + +com.tencent.supersonic.chat.api.component.SemanticParser=\ + com.tencent.supersonic.chat.application.parser.DomainSemanticParser, \ + com.tencent.supersonic.chat.application.parser.TimeSemanticParser, \ + com.tencent.supersonic.chat.application.parser.AggregateSemanticParser +# com.tencent.supersonic.chat.application.parser.LLMSemanticParser + + +com.tencent.supersonic.chat.api.component.SemanticLayer=\ + com.tencent.supersonic.chat.infrastructure.semantic.LocalSemanticLayerImpl + +com.tencent.supersonic.chat.application.query.QuerySelector=\ + com.tencent.supersonic.chat.application.query.HeuristicQuerySelector + +com.tencent.supersonic.chat.application.parser.DomainResolver=\ + com.tencent.supersonic.chat.application.parser.HeuristicDomainResolver + +com.tencent.supersonic.auth.authentication.domain.interceptor.AuthenticationInterceptor=\ + com.tencent.supersonic.auth.authentication.domain.interceptor.DefaultAuthenticationInterceptor diff --git a/launchers/standalone/src/main/resources/application-local.yaml b/launchers/standalone/src/main/resources/application-local.yaml new file mode 100644 index 000000000..4c029c184 --- /dev/null +++ b/launchers/standalone/src/main/resources/application-local.yaml @@ -0,0 +1,28 @@ +spring: + h2: + console: + path: /h2-console/chat + # enabled web + enabled: true + datasource: + driver-class-name: org.h2.Driver + schema: classpath:db/schema-h2.sql + data: classpath:db/data-h2.sql + url: jdbc:h2:mem:semantic;DATABASE_TO_UPPER=false + username: root + password: semantic + +server: + port: 9080 + +authentication: + enable: false + exclude: + path: /api/auth/user/register,/api/auth/user/login + +semantic: + url: + prefix: http://127.0.0.1:9081 + +mybatis: + mapper-locations=classpath:mappers/custom/*.xml,classpath*:/mappers/*.xml diff --git a/launchers/standalone/src/main/resources/application.yaml b/launchers/standalone/src/main/resources/application.yaml new file mode 100644 index 000000000..83b731d26 --- /dev/null +++ b/launchers/standalone/src/main/resources/application.yaml @@ -0,0 +1,7 @@ +spring: + profiles: + active: local + application: + name: chat +mybatis: + mapper-locations=classpath:mappers/custom/*.xml,classpath*:/mappers/*.xml diff --git a/launchers/standalone/src/main/resources/data/README.url b/launchers/standalone/src/main/resources/data/README.url new file mode 100644 index 000000000..e37374f27 --- /dev/null +++ b/launchers/standalone/src/main/resources/data/README.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=https://github.com/hankcs/HanLP/ diff --git a/launchers/standalone/src/main/resources/data/dictionary/CoreNatureDictionary.mini.txt b/launchers/standalone/src/main/resources/data/dictionary/CoreNatureDictionary.mini.txt new file mode 100644 index 000000000..6014daa6e --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/CoreNatureDictionary.mini.txt @@ -0,0 +1,3 @@ +龚 nr 1 +龛 ng 1 +龛影 n 1 \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/data/dictionary/CoreNatureDictionary.ngram.mini.txt b/launchers/standalone/src/main/resources/data/dictionary/CoreNatureDictionary.ngram.mini.txt new file mode 100644 index 000000000..562f7f1cc --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/CoreNatureDictionary.ngram.mini.txt @@ -0,0 +1,4 @@ +买@水果 1 +然后@来 1 +我@遗忘 10 +遗忘@我 10 \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_1.txt b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_1.txt new file mode 100644 index 000000000..c21ae2edb --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_1.txt @@ -0,0 +1,5 @@ +hr _1_1 876 +sales _1_1 872 +marketing _1_1 310 +strategy _1_1 360 +sales _1_1 500 \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_2.txt b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_2.txt new file mode 100644 index 000000000..e0570f4b0 --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_2.txt @@ -0,0 +1,7 @@ +tom _1_2 52 +alice _1_2 47 +lucy _1_2 31 +dean _1_2 36 +john _1_2 50 +jack _1_2 38 +admin _1_2 70 \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_3.txt b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_3.txt new file mode 100644 index 000000000..f519c23fb --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/custom/DimValue_1_3.txt @@ -0,0 +1,6 @@ +p1 _1_3 52 +p2 _1_3 47 +p3 _1_3 31 +p4 _1_3 36 +p5 _1_3 50 +p6 _1_3 38 \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/data/dictionary/other/CharTable.txt b/launchers/standalone/src/main/resources/data/dictionary/other/CharTable.txt new file mode 100644 index 000000000..a66a33e07 --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/other/CharTable.txt @@ -0,0 +1,4890 @@ += +A=a +B=b +C=c +D=d +E=e +F=f +G=g +H=h +I=i +J=j +K=k +L=l +M=m +N=n +O=o +P=p +Q=q +R=r +S=s +T=t +U=u +V=v +W=w +X=x +Y=y +Z=z +[=《 +]=》 +{=《 +}=》 + = +«=《 +»=》 +“=" +”=" +•=· +‹=《 +›=》 +①=一 +②=二 +③=三 +④=四 +⑤=五 +⑥=六 +⑦=七 +⑧=八 +⑨=九 +⑩=十 +〈=《 +〉=》 +「=“ +」=” +『=‘ +』=’ +【=《 +】=》 +〔=《 +〕=》 +〖=《 +〗=" +〝=" +〞=" +と=之 +ふ=子 +ル=儿 +ㄖ=日 +丟=丢 +両=两 +並=并 +丼=井 +乁=乙 +乗=乘 +乧=斗 +乷=沙 +乹=乾 +乾=干 +亀=龟 +亁=乾 +亂=乱 +亙=亘 +亝=斋 +亞=亚 +亯=享 +亱=夜 +亷=廉 +亾=亡 +仈=八 +仏=佛 +仛=托 +仩=上 +仯=秒 +仴=月 +仸=袄 +仹=丰 +仺=仓 +伕=夫 +伖=友 +伝=传 +伮=奴 +佀=侣 +佇=伫 +佋=召 +佔=占 +佘=畲 +佡=仙 +佪=徊 +佱=企 +佲=铭 +併=并 +佷=很 +佹=危 +佽=次 +侀=型 +來=来 +侇=姨 +侎=眯 +侓=律 +侖=仑 +侢=再 +侶=侣 +侷=局 +侹=廷 +俁=俣 +係=系 +俆=徐 +俔=伣 +俠=侠 +俢=修 +俥=伡 +俬=私 +俻=备 +俽=欣 +倀=伥 +倁=蜘 +倂=并 +倆=俩 +倈=俫 +倉=仓 +個=个 +倐=倏 +們=们 +倖=幸 +倞=京 +倣=仿 +倫=伦 +倳=事 +倶=具 +倸=睬 +倹=俭 +倻=椰 +倽=啥 +偅=重 +偉=伟 +偓=屋 +偘=侃 +偡=湛 +偢=秋 +偪=逼 +偲=思 +側=侧 +偵=侦 +偸=偷 +偺=咱 +偽=伪 +傑=杰 +傓=扇 +傖=伧 +傘=伞 +備=备 +傚=效 +傢=家 +傪=参 +傭=佣 +傯=偬 +傳=传 +傴=伛 +債=债 +傷=伤 +傹=镜 +傾=倾 +僂=偻 +僅=仅 +僉=佥 +僊=仙 +働=動 +僐=善 +僑=侨 +僒=窘 +僕=仆 +僜=澄 +僞=伪 +僟=机 +僥=侥 +僨=偾 +僮=童 +僱=雇 +價=价 +僽=愁 +儀=仪 +儁=俊 +儂=侬 +億=亿 +儈=侩 +儉=俭 +儌=侥 +儐=傧 +儔=俦 +儕=侪 +儘=尽 +償=偿 +優=优 +儭=亲 +儲=储 +儵=倏 +儷=俪 +儸=箩 +儹=攒 +儺=傩 +儻=傥 +儼=俨 +兇=凶 +兌=兑 +兎=兔 +兒=儿 +兗=兖 +兠=兜 +內=内 +兩=两 +兯=节 +兲=天 +兿=艺 +冄=冉 +冇=没 +冊=册 +冋=回 +冐=冒 +冨=富 +冩=写 +冪=幂 +冴=讶 +冺=泯 +凂=免 +凃=涂 +凅=固 +凈=净 +凊=清 +凍=冻 +凗=摧 +凘=斯 +凜=凛 +凞=熙 +凢=几 +凣=凡 +処=处 +凧=巾 +凱=凯 +凲=兼 +凴=凭 +凾=涵 +刄=刃 +刅=办 +刋=刊 +別=别 +刦=劫 +刧=劫 +刪=删 +刴=剁 +刼=劫 +剄=刭 +則=则 +剋=克 +剎=刹 +剏=创 +剗=刬 +剘=期 +剙=創 +剛=刚 +剝=剥 +剨=割 +剮=剐 +剳=劄 +剴=剀 +創=创 +剷=铲 +剹=戮 +剼=删 +劃=划 +劄=札 +劇=剧 +劈=噼 +劉=刘 +劊=刽 +劌=刿 +劍=剑 +劑=剂 +劒=剑 +劦=力 +効=效 +勁=劲 +勄=敏 +勅=敕 +勌=倦 +動=动 +勗=勖 +務=务 +勛=勋 +勝=胜 +勞=劳 +勠=戮 +勢=势 +勦=剿 +勧=劝 +勩=勚 +勱=劢 +勳=勋 +勵=励 +勸=劝 +勻=匀 +勼=九 +匄=亡 +匊=菊 +匋=掏 +匑=躬 +匢=勿 +匨=壮 +匬=愈 +匭=匦 +匯=汇 +匱=匮 +匲=奁 +匳=奁 +匴=算 +匵=椟 +匼=合 +匽=宴 +區=区 +卂=汛 +卆=杂 +協=协 +卙=甚 +卛=率 +卬=仰 +卲=邵 +卹=恤 +卻=却 +卽=即 +厊=芽 +厐=庞 +厔=室 +厗=辛 +厙=厍 +厛=听 +厞=匪 +厠=厕 +厡=原 +厤=历 +厫=廒 +厭=厌 +厯=历 +厰=厂 +厲=厉 +厴=厣 +厷=公 +厾=去 +參=参 +叄=叁 +収=收 +叒=双 +叚=假 +叜=叟 +叡=睿 +叢=丛 +叧=另 +叺=入 +吂=盲 +吒=咤 +吘=午 +吚=咿 +吢=吣 +吳=吴 +吶=呐 +吷=决 +吿=告 +呁=钧 +呂=吕 +呉=吴 +呌=叫 +呎=迟 +呞=司 +呪=咒 +呮=只 +呱=哌 +呴=句 +呺=号 +咊=和 +咑=打 +咓=瓦 +咗=左 +咜=它 +咟=百 +咮=珠 +咰=询 +咷=啕 +咼=呙 +哃=同 +哋=的 +哠=告 +員=员 +哢=咔 +哣=痘 +哬=呵 +哯=现 +哴=琅 +哾=悦 +唂=谷 +唄=呗 +唍=完 +唎=例 +唕=唣 +唘=启 +唚=吣 +唡=俩 +唥=冷 +唦=砂 +唫=金 +唰=刷 +唵=俺 +唶=锡 +唸=念 +唻=来 +唽=析 +啇=商 +啌=控 +啍=享 +啎=忤 +問=问 +啑=捷 +啓=启 +啗=啖 +啘=婉 +啚=鄙 +啝=和 +啞=哑 +啟=启 +啢=唡 +啣=衔 +啨=晴 +啩=挂 +啱=岩 +啴=单 +喎=㖞 +喐=郁 +喒=咱 +喖=枯 +喚=唤 +喥=度 +喦=岩 +喪=丧 +喫=吃 +喬=乔 +單=单 +喰=食 +喲=哟 +営=宫 +喼=急 +嗁=啼 +嗆=呛 +嗇=啬 +嗊=唝 +嗎=吗 +嗏=茶 +嗐=害 +嗗=骨 +嗚=呜 +嗛=谦 +嗩=唢 +嗬=呵 +嗱=拿 +嗶=哔 +嗹=莲 +嗻=遮 +嗼=摸 +嘂=叫 +嘄=鸣 +嘆=叹 +嘋=教 +嘍=喽 +嘓=啯 +嘔=呕 +嘖=啧 +嘗=尝 +嘙=婆 +嘚=得 +嘜=唛 +嘠=嘎 +嘢=野 +嘩=哗 +嘫=然 +嘮=唠 +嘯=啸 +嘰=叽 +嘵=哓 +嘸=呒 +嘽=啴 +噂=遵 +噅=咴 +噉=啖 +噐=器 +噑=嗥 +噓=嘘 +噖=琴 +噝=咝 +噠=哒 +噥=哝 +噦=哕 +噭=激 +噯=嗳 +噲=哙 +噴=喷 +噸=吨 +噹=当 +噺=新 +嚀=咛 +嚂=滥 +嚇=吓 +嚌=哜 +嚐=尝 +嚕=噜 +嚗=爆 +嚙=啮 +嚜=墨 +嚠=刘 +嚡=鞋 +嚤=蘑 +嚦=呖 +嚨=咙 +嚮=向 +嚲=亸 +嚳=喾 +嚴=严 +嚶=嘤 +囀=啭 +囁=嗫 +囂=嚣 +囅=冁 +囈=呓 +囉=啰 +囑=嘱 +囓=啮 +囗=口 +囘=回 +囙=因 +囥=亢 +囩=云 +囪=囱 +囬=回 +囮=化 +囯=国 +囸=正 +圅=函 +圇=囵 +國=国 +圍=围 +圎=园 +園=园 +圓=圆 +圖=图 +團=团 +圝=圞 +圤=扑 +圧=庄 +圱=升 +圵=止 +圷=吓 +坆=玫 +坧=石 +坰=垧 +坵=丘 +坿=附 +垇=坳 +垉=咆 +垐=茨 +垜=垛 +垨=守 +垯=达 +垳=行 +垵=埯 +垹=绑 +垿=序 +埐=侵 +埖=花 +埜=野 +埡=垭 +埥=请 +埰=采 +埱=叔 +埳=坎 +執=执 +堅=坚 +堊=垩 +堒=坤 +堔=深 +堖=垴 +堘=塍 +堝=埚 +堦=階 +堯=尧 +報=报 +場=场 +堷=音 +堿=碱 +塆=弯 +塊=块 +塋=茔 +塏=垲 +塒=埘 +塖=乘 +塗=涂 +塚=冢 +塟=葬 +塡=填 +塢=坞 +塤=埙 +塨=恭 +塮=谢 +塲=场 +塵=尘 +塹=堑 +塼=砖 +墊=埝 +墖=塔 +墘=乾 +墛=蔚 +墜=坠 +墪=墩 +墭=盛 +墮=堕 +墳=坟 +墵=坛 +墶=垯 +墻=墙 +墾=垦 +壃=僵 +壄=野 +壇=坛 +壋=垱 +壎=埙 +壓=压 +壖=堧 +壘=垒 +壙=圹 +壚=垆 +壜=坛 +壞=坏 +壟=垅 +壠=垅 +壢=坜 +壩=坝 +壪=塆 +壯=壮 +壺=壶 +壻=婿 +壼=壸 +壽=寿 +壿=蹲 +夀=寿 +夃=孕 +夅=降 +夌=菱 +夗=苑 +夘=卯 +夝=胜 +夠=够 +夢=梦 +夥=伙 +夰=介 +夲=本 +夾=夹 +奐=奂 +奧=奥 +奨=奖 +奩=奁 +奪=夺 +奬=奖 +奮=奋 +奷=奸 +奼=姹 +妀=改 +妏=文 +妑=芭 +妔=坑 +妕=钟 +妝=妆 +妠=呐 +妢=纷 +妬=妒 +妭=拨 +妱=招 +妳=你 +妶=弦 +妷=失 +妸=可 +妺=妹 +妽=申 +姃=征 +姄=民 +姉=姊 +姌=冉 +姍=姗 +姎=央 +姖=巨 +姙=妊 +姟=该 +姠=响 +姦=奸 +姧=歼 +姩=年 +姪=侄 +姵=佩 +姸=妍 +姺=先 +娕=束 +娖=促 +娛=娱 +娝=否 +娦=兵 +娪=语 +娫=延 +娬=武 +娯=娱 +娸=其 +娿=啊 +婁=娄 +婂=锦 +婄=赔 +婇=菜 +婑=矮 +婔=菲 +婖=添 +婜=娶 +婣=姻 +婤=稠 +婥=卓 +婦=妇 +婫=混 +婬=淫 +婭=娅 +婯=丽 +婸=扬 +婹=要 +婼=若 +媈=挥 +媌=苗 +媍=妇 +媔=面 +媗=喧 +媙=威 +媟=谍 +媠=惰 +媣=染 +媥=偏 +媦=胃 +媧=娲 +媨=酋 +媫=婕 +媯=妫 +媴=袁 +媷=辱 +媹=溜 +媼=媪 +媽=妈 +媿=愧 +嫃=真 +嫆=蓉 +嫊=素 +嫋=袅 +嫎=膀 +嫗=妪 +嫙=旋 +嫚=蔓 +嫝=康 +嫟=匿 +嫧=责 +嫰=嫩 +嫲=麻 +嫵=妩 +嫺=娴 +嫻=娴 +嫼=黑 +嫽=撩 +嫿=婳 +嬀=妫 +嬈=娆 +嬋=婵 +嬌=娇 +嬑=意 +嬘=遂 +嬙=嫱 +嬝=袅 +嬡=嫒 +嬤=嬷 +嬪=嫔 +嬭=奶 +嬰=婴 +嬶=鼻 +嬸=婶 +嬾=懒 +嬿=燕 +孃=娘 +孄=栏 +孌=娈 +孒=了 +孡=抬 +孧=幼 +孫=孙 +孶=孳 +學=学 +孼=孽 +孿=孪 +宂=冗 +宖=宏 +宮=宫 +宼=寇 +寀=采 +寃=冤 +寑=寝 +寕=宁 +寢=寝 +實=实 +寧=宁 +審=审 +寫=写 +寬=宽 +寲=疑 +寳=宝 +寵=宠 +寶=宝 +尅=克 +將=将 +專=专 +尋=寻 +對=对 +導=导 +尒=尔 +尙=尚 +尟=鲜 +尠=鲜 +尩=尪 +尫=尪 +尲=尴 +尷=尴 +屆=届 +屍=尸 +屓=屃 +屗=尾 +屙=疴 +屚=漏 +屛=屏 +屜=屉 +屟=屉 +屢=屡 +層=层 +屨=屦 +屬=属 +屭=屃 +屰=逆 +屾=山 +岅=坂 +岆=妖 +岠=拒 +岡=冈 +岥=坡 +岼=坪 +峝=峒 +峩=峨 +峫=邪 +峬=捕 +峮=裙 +峯=峰 +峴=岘 +島=岛 +峸=城 +峽=峡 +崈=宗 +崍=崃 +崐=昆 +崕=崖 +崗=岗 +崙=仑 +崠=岽 +崢=峥 +崣=萎 +崧=嵩 +崫=窟 +崬=岽 +崳=嵛 +崶=封 +崾=腰 +嵐=岚 +嵒=岩 +嵔=畏 +嵗=岁 +嵻=慷 +嵿=顶 +嶁=嵝 +嶃=崭 +嶄=崭 +嶇=岖 +嶒=曾 +嶔=嵚 +嶗=崂 +嶠=峤 +嶢=峣 +嶧=峄 +嶨=峃 +嶮=崄 +嶴=岙 +嶵=罪 +嶶=微 +嶸=嵘 +嶺=岭 +嶼=屿 +嶽=岳 +巋=岿 +巒=峦 +巔=巅 +巗=岩 +巛=川 +巟=荒 +巰=巯 +巵=卮 +巹=卺 +巿=市 +帀=匝 +帉=粉 +帋=纸 +帞=陌 +帥=帅 +師=师 +帬=裙 +帳=帐 +帶=带 +帹=接 +帾=赌 +幀=帧 +幃=帏 +幇=帮 +幈=屏 +幎=幂 +幑=徽 +幗=帼 +幘=帻 +幙=幕 +幚=帮 +幟=帜 +幣=币 +幫=帮 +幬=帱 +幷=并 +幹=干 +幺=么 +幾=几 +広=广 +庅=么 +庝=疼 +庫=库 +庻=庶 +庽=寓 +庿=庙 +廁=厕 +廂=厢 +廄=厩 +廈=厦 +廎=庼 +廐=厩 +廕=荫 +廚=厨 +廜=屠 +廝=厮 +廟=庙 +廠=厂 +廡=庑 +廢=废 +廣=广 +廩=廪 +廬=庐 +廰=厅 +廳=厅 +廵=巡 +廸=迪 +廹=迫 +廻=回 +廼=迺 +弌=壹 +弍=贰 +弒=弑 +弔=吊 +弖=弓 +弚=弟 +弜=弱 +弳=弪 +張=张 +強=强 +彅=简 +彆=别 +彈=弹 +彊=强 +彌=弥 +彎=弯 +彔=录 +彙=汇 +彜=彝 +彞=彝 +彠=彟 +彡=三 +彥=彦 +彫=雕 +彯=飘 +彵=他 +彶=及 +彽=低 +彿=佛 +徃=往 +後=后 +徑=径 +從=从 +徠=徕 +徣=借 +徦=假 +徧=遍 +復=复 +徬=彷 +徳=德 +徵=征 +徹=彻 +忊=订 +忬=舒 +忲=太 +忹=汪 +忼=杭 +怇=矩 +怉=饱 +怌=呸 +怓=努 +怞=油 +怭=必 +怱=匆 +怳=恍 +怵=憷 +怶=披 +怺=咏 +恆=恒 +恉=旨 +恏=好 +恠=怪 +恡=吝 +恥=耻 +悀=涌 +悅=悦 +悇=余 +悈=戒 +悊=哲 +悋=吝 +悘=医 +悙=亨 +悞=悮 +悡=梨 +悢=恨 +悤=匆 +悩=脑 +悪=恶 +悮=误 +悵=怅 +悶=闷 +悽=凄 +惓=倦 +惔=淡 +惡=恶 +惢=蕊 +惥=恿 +惪=德 +惱=恼 +惲=恽 +惷=蠢 +惻=恻 +愅=革 +愙=客 +愛=爱 +愜=惬 +愨=悫 +愬=诉 +愮=瑶 +愰=晃 +愴=怆 +愷=恺 +愺=草 +愽=博 +愾=忾 +慁=恩 +慂=恿 +慄=栗 +慇=殷 +態=态 +慍=愠 +慓=漂 +慘=惨 +慙=惭 +慚=惭 +慛=崔 +慟=恸 +慠=傲 +慣=惯 +慤=悫 +慥=造 +慦=救 +慪=怄 +慫=怂 +慬=懂 +慮=虑 +慲=瞒 +慳=悭 +慴=慑 +慶=庆 +慹=热 +慼=戚 +慽=戚 +慾=欲 +憂=忧 +憅=动 +憇=憩 +憉=彭 +憊=惫 +憐=怜 +憑=凭 +憒=愦 +憕=登 +憖=慭 +憚=惮 +憛=潭 +憜=堕 +憡=策 +憤=愤 +憫=悯 +憮=怃 +憲=宪 +憶=忆 +懃=勤 +懄=勤 +懆=操 +懇=恳 +應=应 +懌=怿 +懍=懔 +懞=蒙 +懟=怼 +懣=懑 +懨=恹 +懪=暴 +懲=惩 +懶=懒 +懷=怀 +懸=悬 +懺=忏 +懼=惧 +懽=欢 +懾=慑 +戀=恋 +戇=戆 +戉=钺 +戓=或 +戔=戋 +戞=戛 +戧=戗 +戨=歌 +戩=戬 +戰=战 +戱=戯 +戲=戏 +戶=户 +戹=厄 +戼=卯 +扂=店 +扆=衣 +扙=丈 +扜=迂 +扝=亏 +扡=扦 +扱=吸 +抝=拗 +抳=拟 +抴=曳 +拋=抛 +拑=钳 +拕=拖 +拚=拼 +拡=扩 +拤=掐 +拹=协 +拾=十 +挌=格 +挘=劣 +挩=捝 +挱=挲 +挵=弄 +挶=局 +挾=挟 +捄=救 +捊=浮 +捨=舍 +捫=扪 +捲=卷 +捳=岳 +掃=扫 +掄=抡 +掗=挜 +掙=挣 +掛=挂 +採=采 +掫=取 +掱=手 +掵=命 +掹=猛 +掽=碰 +揀=拣 +揅=研 +揌=塞 +揑=捏 +揗=循 +揙=编 +揚=扬 +換=换 +揫=揪 +揮=挥 +揵=健 +揷=插 +揹=背 +搆=构 +搇=揿 +搉=榷 +損=损 +搖=摇 +搗=捣 +搣=灭 +搤=扼 +搥=捶 +搧=扇 +搨=拓 +搯=掏 +搵=揾 +搶=抢 +搾=榨 +摀=捂 +摂=摄 +摃=扛 +摋=杀 +摑=掴 +摜=掼 +摟=搂 +摣=揸 +摤=爽 +摯=挚 +摳=抠 +摶=抟 +摺=折 +摻=掺 +摽=标 +撁=牵 +撃=击 +撈=捞 +撏=挦 +撐=撑 +撓=挠 +撚=捻 +撝=㧑 +撟=挢 +撢=掸 +撣=掸 +撥=拨 +撦=扯 +撧=撅 +撫=抚 +撲=扑 +撳=揿 +撴=蹾 +撻=挞 +撽=邀 +撾=挝 +撿=捡 +擁=拥 +擄=掳 +擇=择 +擊=击 +擋=挡 +擏=敬 +擓=㧟 +擔=担 +擕=携 +據=据 +擝=盟 +擠=挤 +擡=抬 +擣=捣 +擧=举 +擬=拟 +擯=摈 +擰=拧 +擱=搁 +擲=掷 +擴=扩 +擷=撷 +擺=摆 +擻=擞 +擼=撸 +擾=扰 +擿=摘 +攃=擦 +攄=摅 +攆=撵 +攋=赖 +攏=拢 +攔=拦 +攖=撄 +攙=搀 +攛=撺 +攜=携 +攝=摄 +攢=攒 +攣=挛 +攤=摊 +攩=挡 +攪=搅 +攬=揽 +攷=考 +敁=掂 +敂=叩 +敍=叙 +敎=教 +敗=败 +敘=叙 +敟=典 +敩=学 +敭=扬 +敵=敌 +數=数 +敺=驱 +斂=敛 +斃=毙 +斈=学 +斉=齐 +斕=斓 +斚=斝 +斬=斩 +斷=断 +於=于 +旂=旗 +旛=幡 +旣=既 +旤=祸 +旪=叶 +旹=时 +旾=春 +昇=升 +昋=吞 +昐=盼 +昜=杨 +昬=昏 +昻=昂 +時=时 +晉=晋 +晎=哄 +晝=昼 +晵=启 +晿=唱 +暀=往 +暈=晕 +暉=晖 +暎=映 +暒=星 +暘=旸 +暠=皓 +暡=翁 +暢=畅 +暫=暂 +暱=昵 +曂=黄 +曃=逮 +曄=晔 +曆=历 +曇=昙 +曉=晓 +曊=费 +曏=向 +曖=暧 +曟=晨 +曠=旷 +曡=叠 +曨=昽 +曬=晒 +曱=甲 +書=书 +朂=最 +會=会 +朓=跳 +朞=期 +朢=望 +朧=胧 +朩=木 +朮=术 +朳=扒 +朶=朵 +杇=圬 +杘=尿 +杧=忙 +東=东 +杴=锨 +杺=心 +枃=匀 +枈=柴 +枒=桠 +枱=台 +枴=拐 +枾=柿 +柂=拖 +柆=垃 +柈=伴 +柭=跋 +柵=栅 +柷=祝 +柸=杯 +柹=柿 +柺=拐 +査=查 +栁=柳 +栆=枣 +栔=契 +栞=刊 +栢=柏 +栤=冰 +栰=筏 +栱=供 +栺=指 +桒=桑 +桚=拶 +桭=振 +桮=杯 +桺=柳 +桿=杆 +梔=栀 +梘=枧 +梚=挽 +條=条 +梟=枭 +梲=棁 +梹=槟 +梽=志 +棃=梨 +棄=弃 +棈=精 +棊=棋 +棌=睬 +棑=排 +棖=枨 +棗=枣 +棟=栋 +棡= +棧=栈 +棩=渊 +棬=桊 +棲=栖 +棴=服 +棶=梾 +椀=碗 +椉=乘 +椏=桠 +椗=碇 +椘=楚 +椨=俯 +椮=渗 +椶=棕 +椾=笺 +楃=握 +楊=杨 +楓=枫 +楛=苦 +楨=桢 +楩=便 +業=业 +楱=奏 +楳=梅 +極=极 +楿=相 +榘=矩 +榦=干 +榪=杩 +榮=荣 +榲=榅 +榿=桤 +槀=槁 +槁=藁 +槃=盘 +構=构 +槍=枪 +槑=呆 +槓=杠 +槕=桌 +槤=梿 +槧=椠 +槨=椁 +槩=概 +槪=概 +槮=椮 +槳=桨 +槶=椢 +槹=槔 +槼=規 +樁=桩 +樂=乐 +樅=枞 +樐=橹 +樑=梁 +樓=楼 +標=标 +樝=楂 +樞=枢 +樣=样 +樭=基 +樸=朴 +樹=树 +樺=桦 +樿=椫 +橆=舞 +橈=桡 +橋=桥 +橓=瞬 +橖=棠 +橜=橛 +機=机 +橢=椭 +橤=蕊 +橫=横 +橰=槔 +橴=紫 +檁=檩 +檇=槜 +檉=柽 +檔=档 +檜=桧 +檝=楫 +檟=槚 +檢=检 +檣=樯 +檤=道 +檭=银 +檮=梼 +檯=台 +檳=槟 +檸=柠 +檻=槛 +檾=苘 +櫂=棹 +櫃=柜 +櫇=颇 +櫈=凳 +櫓=橹 +櫕=替 +櫚=榈 +櫛=栉 +櫝=椟 +櫞=橼 +櫟=栎 +櫥=橱 +櫧=槠 +櫨=栌 +櫪=枥 +櫫=橥 +櫬=榇 +櫱=蘖 +櫳=栊 +櫸=榉 +櫺=棂 +櫻=樱 +欄=栏 +欅=榉 +權=权 +欎=郁 +欏=椤 +欑=攒 +欒=栾 +欖=榄 +欞=棂 +欥=吹 +欵=款 +欽=钦 +歎=叹 +歐=欧 +歔=墟 +歗=啸 +歘=欻 +歛=敛 +歟=欤 +歡=欢 +歭=持 +歮=址 +歯=齿 +歲=岁 +歳=岁 +歴=历 +歷=历 +歸=归 +歿=殁 +殀=夭 +殗=淹 +殘=残 +殙=婚 +殞=殒 +殣=谨 +殤=殇 +殨=㱮 +殫=殚 +殭=僵 +殮=殓 +殯=殡 +殲=歼 +殸=声 +殺=杀 +殻=壳 +殼=壳 +毀=毁 +毃=敲 +毆=殴 +毇=毁 +毉=医 +毐=毒 +毘=毗 +毝=毛 +毣=笔 +毧=绒 +毿=毵 +氂=牦 +氈=毡 +氊=毡 +氌=氇 +氣=气 +氫=氢 +氬=氩 +氳=氲 +氷=冰 +氹=凼 +氾=犯 +氿=酒 +汃=趴 +汈=叼 +汋=勺 +汍=丸 +汎=帆 +汏=大 +汒=茫 +汘=纤 +汙=污 +汚=污 +汢=土 +汥=枝 +汮=均 +汸=坊 +決=决 +汻=许 +沋=优 +沍=冱 +沑=扭 +沒=没 +沕=吻 +沖=冲 +沬=抹 +沰=拓 +沴=珍 +沵=你 +沶=示 +況=况 +泂=炯 +泇=架 +泙=砰 +泚=此 +泝=溯 +泩=生 +泬=穴 +泹=担 +洀=舟 +洂=亦 +洃=灰 +洊=存 +洏=而 +洘=拷 +洝=按 +洣=迷 +洤=全 +洩=泄 +洭=眶 +洶=汹 +洸=光 +洺=名 +洿=夸 +浀=曲 +浄=净 +浉=狮 +浌=伐 +浐=产 +浕=尽 +浗=球 +浛=含 +浢=逗 +浧=逞 +浨=宋 +浭=更 +浵=彤 +浹=浃 +浽=馁 +涃=捆 +涇=泾 +涊=忍 +涍=哮 +涖=莅 +涜=壳 +涥=哼 +涭=授 +涳=空 +涴=碗 +涺=锯 +涻=社 +涼=凉 +涽=昏 +淉=果 +淍=碉 +淒=凄 +淓=芳 +淔=植 +淚=泪 +淛=浙 +淣=倪 +淥=渌 +淨=净 +淩=凌 +淪=沦 +淰=念 +淵=渊 +淶=涞 +淺=浅 +渀=奔 +渁=水 +渇=渴 +渉=涉 +渏=奇 +渓=溪 +渘=揉 +渙=涣 +減=减 +渞=首 +渟=停 +渢=沨 +渦=涡 +渧=蒂 +測=测 +渱=虹 +渶=英 +渻=省 +渾=浑 +湁=拾 +湈=煤 +湊=凑 +湌=餐 +湏=须 +湜=是 +湝=皆 +湞=浈 +湠=碳 +湢=福 +湣=愍 +湤=施 +湥=突 +湧=涌 +湯=汤 +湰=隆 +湴=碰 +湺=保 +湻=淳 +湼=涅 +溇=楼 +溈=沩 +溓=嫌 +溔=糕 +準=准 +溙=泰 +溚=搭 +溜=熘 +溝=沟 +溡=时 +溤=冯 +溫=温 +溮=浉 +溳=涢 +溼=湿 +溿=畔 +滃=嗡 +滄=沧 +滅=灭 +滈=高 +滌=涤 +滎=荥 +滒=哥 +滘=浩 +滙=汇 +滛=淫 +滬=沪 +滭=毕 +滮=彪 +滯=滞 +滲=渗 +滵=蜜 +滷=卤 +滸=浒 +滺=悠 +滻=浐 +滽=庸 +滾=磙 +滿=满 +漁=渔 +漅=巢 +漈=际 +漊=溇 +漑=概 +漚=沤 +漟=堂 +漢=汉 +漣=涟 +漨=逢 +漬=渍 +漲=涨 +漴=崇 +漵=溆 +漷=郭 +漸=渐 +漹=焉 +漻=廖 +漿=浆 +潁=颍 +潄=漱 +潅=罐 +潎=撇 +潐=焦 +潑=泼 +潒=橡 +潔=洁 +潗=集 +潙=沩 +潛=潜 +潠=噀 +潤=润 +潪=智 +潯=浔 +潰=溃 +潵=撒 +潶=嘿 +潷=滗 +潹=森 +潾=磷 +潿=涠 +澀=涩 +澁=涩 +澆=浇 +澇=涝 +澊=尊 +澕=华 +澗=涧 +澠=渑 +澢=挡 +澣=浣 +澤=泽 +澥=懈 +澦=滪 +澩=泶 +澭=雍 +澮=浍 +澱=淀 +澼=辟 +濁=浊 +濃=浓 +濆=愤 +濇=涩 +濐=暑 +濔=沵 +濕=湿 +濘=泞 +濜=浕 +濟=济 +濢=粹 +濤=涛 +濨=磁 +濫=漤 +濰=潍 +濱=滨 +濳=潜 +濶=阔 +濸=呛 +濺=溅 +濼=泺 +濾=滤 +瀅=滢 +瀆=渎 +瀉=泻 +瀋=渖 +瀍=缠 +瀏=浏 +瀕=濒 +瀘=泸 +瀜=融 +瀝=沥 +瀟=潇 +瀠=潆 +瀦=潴 +瀧=泷 +瀨=濑 +瀭=输 +瀲=潋 +瀻=戴 +瀾=澜 +瀿=繁 +灀=霜 +灃=沣 +灄=滠 +灋=法 +灑=洒 +灕=漓 +灘=滩 +灝=灏 +灠=漤 +灡=烂 +灢=囊 +灣=湾 +灤=滦 +灧=滟 +灨=赣 +灩=滟 +災=灾 +炡=政 +炤=照 +炪=出 +為=为 +烄=胶 +烏=乌 +烑=姚 +烖=灾 +烥=臣 +烮=列 +烱=炯 +烴=烃 +烸=梅 +烺=浪 +烾=炎 +焄=君 +焒=吕 +無=无 +煆=煅 +煇=辉 +煉=炼 +煑=煮 +煒=炜 +煕=熙 +煖=暖 +煗=暖 +煙=烟 +煠=炸 +煢=茕 +煥=焕 +煩=烦 +煬=炀 +煭=裂 +煱=锅 +煷=亮 +熅=煴 +熈=熙 +熋=熊 +熒=荧 +熖=焰 +熗=炝 +熱=热 +熲=颎 +熷=增 +熾=炽 +燁=烨 +燄=焰 +燈=灯 +燉=炖 +燐=磷 +燒=烧 +燙=烫 +燜=焖 +營=营 +燦=灿 +燭=烛 +燳=照 +燴=烩 +燻=熏 +燼=烬 +燾=焘 +燿=耀 +爊=熬 +爍=烁 +爐=炉 +爕=燮 +爗=烨 +爘=餐 +爛=烂 +爭=争 +爲=为 +爺=爷 +爾=尔 +爿=丬 +牀=床 +牆=墙 +牋=笺 +牎=窗 +牐=闸 +牓=榜 +牕=窗 +牘=牍 +牠=它 +牴=抵 +牸=字 +牽=牵 +犂=犁 +犇=牛 +犖=荦 +犛=牦 +犠=牺 +犢=犊 +犧=牺 +犼=吼 +狀=状 +狆=中 +狌=牲 +狔=泥 +狚=胆 +狣=挑 +狥=徇 +狪=洞 +狹=狭 +狽=狈 +猂=悍 +猙=狰 +猦=枫 +猨=猿 +猵=遍 +猶=犹 +猻=狲 +獁=犸 +獃=呆 +獄=狱 +獅=狮 +獊=沧 +獌=馒 +獎=奖 +獏=貘 +獓=敖 +獘=毙 +獙=敝 +獞=撞 +獣=兽 +獧=狷 +獨=独 +獪=狯 +獫=猃 +獮=狝 +獰=狞 +獲=获 +獵=猎 +獷=犷 +獸=兽 +獺=獭 +獻=献 +獼=猕 +玀=猡 +玅=妙 +玆=玄 +玙=与 +玞=夫 +玨=珏 +玪=玲 +珆=台 +珒=津 +珓=较 +珪=圭 +珮=佩 +珵=呈 +珶=梯 +珻=悔 +現=现 +琇=锈 +琎=进 +琓=玩 +琖=盏 +琱=雕 +琹=琴 +琺=珐 +琿=珲 +瑆=惺 +瑇=玳 +瑉=珉 +瑋=玮 +瑏=穿 +瑒=玚 +瑝=皇 +瑠=琉 +瑣=琐 +瑤=瑶 +瑩=莹 +瑪=玛 +瑫=滔 +瑯=琅 +瑱=填 +瑲=玱 +瑺=常 +璄=境 +璉=琏 +璔=憎 +璡=琎 +璢=琉 +璣=玑 +璦=瑷 +璪=澡 +璫=珰 +環=环 +璵=玙 +璸=瑸 +璽=玺 +璿=璇 +瓈=璃 +瓊=琼 +瓌=瑰 +瓏=珑 +瓔=璎 +瓚=瓒 +瓟=爬 +甁=瓶 +甆=瓷 +甌=瓯 +甎=砖 +甕=瓮 +甖=罂 +甛=甜 +甞=尝 +產=产 +産=产 +甦=苏 +甯=宁 +甴=由 +甶=田 +甽=圳 +畆=亩 +畊=耕 +畝=亩 +畡=垓 +畢=毕 +畣=答 +畧=略 +畨=番 +畩=依 +畫=画 +畮=亩 +異=异 +畱=留 +畵=画 +當=当 +畼=场 +疇=畴 +疉=叠 +疊=叠 +疍=蛋 +疎=疏 +疒=病 +疧=底 +疺=乏 +疿=痱 +痌=恫 +痐=蛔 +痙=痉 +痠=酸 +痩=瘦 +痲=痳 +痺=痹 +痽=准 +痾=疴 +瘂=痖 +瘉=愈 +瘋=疯 +瘍=疡 +瘓=痪 +瘖=喑 +瘚=撅 +瘞=瘗 +瘡=疮 +瘧=疟 +瘮=瘆 +瘲=疭 +瘺=瘘 +瘻=瘘 +療=疗 +癅=瘤 +癆=痨 +癇=痫 +癉=瘅 +癒=愈 +癘=疠 +癙=鼠 +癟=瘪 +癡=痴 +癢=痒 +癤=疖 +癥=症 +癧=疬 +癩=癞 +癬=癣 +癭=瘿 +癮=瘾 +癰=痈 +癱=瘫 +癲=癫 +癷=罕 +發=发 +皁=皂 +皃=貌 +皐=皋 +皒=俄 +皗=绸 +皚=皑 +皛=白 +皜=皓 +皰=疱 +皷=鼓 +皸=皲 +皺=皱 +盁=盈 +盃=杯 +盇=盍 +盉=盒 +盋=钵 +盌=碗 +盜=盗 +盞=盏 +盡=尽 +監=监 +盤=盘 +盧=卢 +盪=荡 +盬=监 +眀=明 +眎=视 +眏=映 +眡=视 +眥=眦 +眪=丙 +眫=胖 +眾=众 +睋=蛾 +睏=困 +睓=腆 +睜=睁 +睞=睐 +睠=眷 +睪=睾 +睲=腥 +瞇=眯 +瞐=晶 +瞖=翳 +瞘=眍 +瞜=䁖 +瞞=瞒 +瞮=澈 +瞶=瞆 +瞼=睑 +矁=瞅 +矓=眬 +矙=瞰 +矚=瞩 +矯=矫 +矴=碇 +矼=缸 +矽=硅 +砡=玉 +砲=炮 +砽=拥 +硏=研 +硜=硁 +硤=硖 +硧=桶 +硨=砗 +硯=砚 +碁=棋 +碕=埼 +碙=刚 +碩=硕 +碪=砧 +碭=砀 +碸=砜 +確=确 +碼=码 +磆=猾 +磍=瞎 +磎=溪 +磑=硙 +磚=砖 +磟=碌 +磠=硵 +磣=碜 +磧=碛 +磯=矶 +磽=硗 +礃=掌 +礄=硚 +礆=硷 +礎=础 +礙=碍 +礦=矿 +礪=砺 +礫=砾 +礬=矾 +礮=炮 +礱=砻 +礶=罐 +祐=右 +祕=秘 +祘=算 +祿=禄 +禍=祸 +禎=祯 +禕=祎 +禞=篙 +禡=祃 +禢=塌 +禦=御 +禩=祀 +禪=禅 +禮=礼 +禰=祢 +禱=祷 +禸=内 +禿=秃 +秇=执 +秈=籼 +秊=年 +秌=秋 +秏=耗 +秐=耘 +秔=粳 +秖=祇 +秝=禾 +秡=泼 +秥=拈 +秱=桐 +稅=税 +稈=秆 +稉=粳 +稜=棱 +稟=禀 +稤=掠 +稬=糯 +稭=秸 +種=种 +稱=称 +稲=蹈 +稵=滋 +稺=稚 +稾=稿 +穀=谷 +穅=糠 +穉=稚 +穌=稣 +積=积 +穎=颖 +穏=稳 +穠=秾 +穡=穑 +穢=秽 +穤=糯 +穨=颓 +穩=稳 +穫=获 +穭=稆 +穽=阱 +窂=牢 +窉=柄 +窓=窗 +窩=窝 +窪=洼 +窮=穷 +窯=窑 +窰=窑 +窵=窎 +窶=窭 +窷=聊 +窺=窥 +窻=窗 +窾=款 +竄=窜 +竅=窍 +竇=窦 +竈=灶 +竊=窃 +竒=奇 +竚=伫 +竝=并 +竢=俟 +竪=竖 +竲=蹭 +競=竞 +竾=篪 +笀=芒 +笁=工 +笗=冬 +笣=包 +笩=代 +笵=范 +筃=茵 +筆=笔 +筍=笋 +筎=茹 +筗=忠 +筞=策 +筧=笕 +筩=筒 +筭=算 +筯=箸 +筴=䇲 +筺=筐 +箁=菩 +箇=个 +箋=笺 +箌=倒 +箎=篪 +箏=筝 +箒=帚 +箘=菌 +箚=札 +箛=孤 +箠=垂 +箥=玻 +箶=胡 +箹=约 +節=节 +範=范 +築=筑 +篋=箧 +篔=筼 +篛=箬 +篜=蒸 +篠=筱 +篤=笃 +篨=除 +篩=筛 +篲=彗 +篳=筚 +簀=箦 +簃=移 +簆=筘 +簍=篓 +簑=蓑 +簒=篡 +簘=萧 +簞=箪 +簡=简 +簣=篑 +簫=箫 +簮=簪 +簰=牌 +簷=檐 +簹=筜 +簽=签 +簾=帘 +籃=篮 +籌=筹 +籐=藤 +籙=箓 +籛=篯 +籜=箨 +籟=籁 +籠=笼 +籤=签 +籨=奁 +籩=笾 +籪=簖 +籬=篱 +籮=箩 +籲=吁 +籿=村 +粀=杖 +粃=秕 +粄=饭 +粅=物 +粦=磷 +粧=妆 +粩=姥 +粵=粤 +糉=粽 +糊=煳 +糘=稼 +糝=糁 +糞=粪 +糧=粮 +糱=糵 +糲=粝 +糴=籴 +糵=孽 +糶=粜 +糸=纟 +糹=纟 +糼=攻 +糾=纠 +紀=纪 +紁=叉 +紂=纣 +紃=驯 +約=约 +紅=红 +紆=纡 +紇=纥 +紈=纨 +紉=纫 +紋=纹 +納=纳 +紐=纽 +紓=纾 +純=纯 +紕=纰 +紖=纼 +紗=纱 +紘=纮 +紙=纸 +級=级 +紛=纷 +紜=纭 +紝=纴 +紡=纺 +紥=扎 +紬=䌷 +紮=扎 +細=细 +紱=绂 +紲=绁 +紳=绅 +紵=纻 +紹=绍 +紺=绀 +紼=绋 +紿=绐 +絀=绌 +終=终 +絃=弦 +組=组 +絅=䌹 +絆=绊 +絎=绗 +絏=绁 +結=结 +絒=酬 +絕=绝 +絛=绦 +絝=绔 +絞=绞 +絡=络 +絢=绚 +給=给 +絨=绒 +絪=姻 +絰=绖 +統=统 +絲=丝 +絳=绛 +絶=绝 +絸=茧 +絹=绢 +綁=绑 +綃=绡 +綆=绠 +綈=绨 +綉=绣 +綌=绤 +綏=绥 +綑=捆 +經=经 +綜=综 +綞=缍 +綠=绿 +綢=绸 +綣=绻 +綫=线 +綬=绶 +維=维 +綯=绹 +綰=绾 +綱=纲 +網=网 +綳=绷 +綴=缀 +綵=彩 +綸=纶 +綹=绺 +綺=绮 +綻=绽 +綽=绰 +綾=绫 +綿=绵 +緄=绲 +緇=缁 +緊=紧 +緋=绯 +緐=繁 +緑=绿 +緒=绪 +緓=绬 +緔=绱 +緗=缃 +緘=缄 +緙=缂 +線=线 +緜=绵 +緝=缉 +緞=缎 +締=缔 +緡=缗 +緣=缘 +緥=褓 +緦=缌 +編=编 +緩=缓 +緬=缅 +緯=纬 +緱=缑 +緲=缈 +練=练 +緶=缏 +緹=缇 +緻=致 +縂=总 +縈=萦 +縉=缙 +縊=缢 +縋=缒 +縐=绉 +縑=缣 +縕=缊 +縗=缞 +縚=绦 +縛=缚 +縝=缜 +縞=缟 +縟=缛 +縣=县 +縧=绦 +縨=幌 +縫=缝 +縭=缡 +縮=缩 +縱=纵 +縲=缧 +縳=䌸 +縵=缦 +縶=絷 +縷=缕 +縹=缥 +總=总 +績=绩 +繃=绷 +繅=缫 +繆=缪 +繈=襁 +繒=缯 +織=织 +繕=缮 +繖=伞 +繚=缭 +繞=绕 +繡=绣 +繢=缋 +繦=襁 +繩=绳 +繪=绘 +繫=系 +繭=茧 +繮=缰 +繯=缳 +繰=缲 +繳=缴 +繸=䍁 +繹=绎 +繺=煞 +繼=继 +繽=缤 +繾=缱 +纇=颣 +纈=缬 +纊=纩 +續=续 +纍=累 +纏=缠 +纓=缨 +纖=纤 +纘=缵 +纜=缆 +缞=衰 +缽=钵 +缾=瓶 +罁=缸 +罇=樽 +罈=坛 +罌=罂 +罎=坛 +罏=垆 +罓=冈 +罞=茅 +罣=挂 +罰=罚 +罵=骂 +罷=罢 +罸=罚 +羅=罗 +羆=罴 +羈=羁 +羋=芈 +羕=漾 +羗=羌 +羙=美 +羢=绒 +羣=群 +羥=羟 +羨=羡 +義=义 +羱=源 +羴=膻 +羶=膻 +翄=翅 +習=习 +翫=玩 +翬=翚 +翶=翱 +翹=翘 +翺=翱 +翽=翙 +耈=耇 +耉=耇 +耡=锄 +耬=耧 +耮=耢 +聅=联 +聖=圣 +聙=睛 +聞=闻 +聯=联 +聰=聪 +聲=声 +聳=耸 +聵=聩 +聶=聂 +職=职 +聹=聍 +聼=听 +聽=听 +聾=聋 +肅=肃 +肎=肯 +肐=胳 +肔=池 +肗=汝 +肧=胚 +肬=疣 +肻=肯 +胒=尼 +胕=附 +胷=胸 +脃=脆 +脅=胁 +脇=胁 +脈=脉 +脊=嵴 +脕=晚 +脗=吻 +脛=胫 +脣=唇 +脫=脱 +脹=胀 +腁=胼 +腄=捶 +腎=肾 +腖=胨 +腡=脶 +腦=脑 +腫=肿 +腳=脚 +腷=逼 +腸=肠 +膁=肷 +膃=腽 +膆=嗉 +膓=肠 +膕=腘 +膚=肤 +膠=胶 +膤=雪 +膩=腻 +膽=胆 +膾=脍 +膿=脓 +臈=腊 +臉=脸 +臋=臀 +臍=脐 +臏=膑 +臒=癯 +臕=膘 +臘=腊 +臙=胭 +臚=胪 +臝=裸 +臟=脏 +臠=脔 +臢=臜 +臥=卧 +臨=临 +臯=皋 +臱=旁 +臸=至 +臺=台 +舃=舄 +與=与 +興=兴 +舉=举 +舊=旧 +舎=舍 +舖=铺 +舗=铺 +舘=馆 +舙=舌 +舝=辖 +舩=船 +艙=舱 +艢=樯 +艣=橹 +艤=舣 +艦=舰 +艪=橹 +艫=舻 +艱=艰 +艷=艳 +艸=艹 +芉=竿 +芐=下 +芢=仁 +芣=不 +芲=花 +芶=勾 +芻=刍 +苆=切 +苉=匹 +苎=苧 +苐=第 +苝=北 +苧=苎 +苸=呼 +苺=莓 +茐=葱 +茖=各 +茘=荔 +茲=兹 +茿=筑 +荅=答 +荊=荆 +荍=收 +荕=筋 +荖=老 +荝=则 +荢=宇 +荰=杜 +荳=豆 +荴=扶 +荶=吟 +荹=步 +荿=成 +莁=巫 +莂=别 +莇=助 +莈=没 +莊=庄 +莋=做 +莏=抄 +莑=蓬 +莕=荇 +莖=茎 +莢=荚 +莣=忘 +莧=苋 +莮=男 +菈=拉 +菋=味 +菓=果 +菗=抽 +菢=抱 +菦=近 +菭=治 +菮=庚 +華=华 +菴=庵 +菸=烟 +菿=到 +萇=苌 +萉=肥 +萊=莱 +萚=择 +萠=萌 +萣=定 +萪=科 +萫=香 +萬=万 +萭=万 +萯=负 +萲=萱 +萵=莴 +萷=削 +萹=篇 +萺=冒 +萿=活 +葀=括 +葁=姜 +葃=昨 +葉=叶 +葒=荭 +葓=洪 +葠=参 +葢=盖 +葤=荮 +葦=苇 +葮=锻 +葯=药 +葰=所 +葲=泉 +葷=荤 +葾=怨 +葿=眉 +蒄=冠 +蒓=莼 +蒔=莳 +蒛=缺 +蒝=愿 +蒞=莅 +蒢=滁 +蒤=途 +蒩=租 +蒼=苍 +蓀=荪 +蓅=流 +蓆=席 +蓈=榔 +蓋=盖 +蓒=轩 +蓕=桂 +蓙=座 +蓜=配 +蓡=參 +蓢=廊 +蓧=莜 +蓮=莲 +蓯=苁 +蓱=萍 +蓳=董 +蓴=莼 +蓷=推 +蓸=曹 +蓽=荜 +蔀=部 +蔂=累 +蔆=菱 +蔉=滚 +蔋=淑 +蔍=鹿 +蔎=设 +蔔=卜 +蔕=蒂 +蔘=参 +蔞=蒌 +蔠=终 +蔣=蒋 +蔥=葱 +蔦=茑 +蔭=荫 +蔵=藏 +蕁=荨 +蕅=藕 +蕆=蒇 +蕋=蕊 +蕎=荞 +蕏=猪 +蕐=哗 +蕒=荬 +蕓=芸 +蕔=报 +蕕=莸 +蕗=露 +蕘=荛 +蕚=萼 +蕜=悲 +蕝=绝 +蕢=蒉 +蕥=雅 +蕩=荡 +蕪=芜 +蕭=萧 +蕯=萨 +蕶=零 +蕷=蓣 +蕿=萱 +薀=蕰 +薈=荟 +薊=蓟 +薌=芗 +薑=姜 +薔=蔷 +薘=荙 +薟=莶 +薦=荐 +薩=萨 +薴=苧 +薵=筹 +薺=荠 +藂=聚 +藅=罚 +藍=蓝 +藎=荩 +藙=毅 +藝=艺 +藞=磊 +藥=药 +藪=薮 +藴=蕴 +藶=苈 +藷=薯 +藹=蔼 +藺=蔺 +藼=萱 +蘀=萚 +蘂=蕊 +蘄=蕲 +蘆=芦 +蘇=苏 +蘊=蕴 +蘋=苹 +蘐=萱 +蘓=苏 +蘚=藓 +蘞=蔹 +蘢=茏 +蘤=花 +蘭=兰 +蘶=巍 +蘺=蓠 +蘿=萝 +虆=蔂 +處=处 +虖=呼 +虛=虚 +虜=虏 +號=号 +虧=亏 +虯=虬 +虵=蛇 +蚘=蛔 +蚡=鼢 +蚦=蚺 +蛕=蛔 +蛧=网 +蛫=跪 +蛬=蚕 +蛺=蛱 +蛻=蜕 +蜆=蚬 +蜋=螂 +蜖=蛔 +蜨=蝶 +蜯=蚌 +蜺=霓 +蝂=版 +蝕=蚀 +蝟=猬 +蝦=虾 +蝨=虱 +蝯=猿 +蝱=虻 +蝸=蜗 +螄=蛳 +螎=融 +螘=蚁 +螙=蠹 +螞=蚂 +螡=蚊 +螢=萤 +螻=蝼 +螾=蚓 +螿=螀 +蟁=蚊 +蟄=蛰 +蟇=蟆 +蟈=蝈 +蟎=螨 +蟣=虮 +蟬=蝉 +蟯=蛲 +蟲=虫 +蟶=蛏 +蟻=蚁 +蠅=蝇 +蠆=虿 +蠍=蝎 +蠏=蟹 +蠐=蛴 +蠑=蝾 +蠒=茧 +蠔=蚝 +蠟=蜡 +蠣=蛎 +蠧=蠹 +蠨=蟏 +蠭=蜂 +蠱=蛊 +蠶=蚕 +蠻=蛮 +衂=衄 +衆=众 +衇=脉 +衒=炫 +術=术 +衕=同 +衖=弄 +衚=胡 +衛=卫 +衝=冲 +衞=卫 +衹=只 +衺=邪 +袉=鸵 +袑=绍 +袓=祖 +袞=衮 +袵=衽 +裊=袅 +裌=夹 +裏=里 +裑=身 +補=补 +裝=装 +裠=裙 +裡=里 +裩=裈 +製=制 +褃=裉 +複=复 +褌=裈 +褘=袆 +褭=袅 +褲=裤 +褳=裢 +褸=褛 +褻=亵 +襃=褒 +襆=幞 +襇=裥 +襉=裥 +襍=杂 +襏=袯 +襖=袄 +襝=裣 +襠=裆 +襤=褴 +襪=袜 +襬=摆 +襯=衬 +襲=袭 +襴=襕 +覀=西 +覇=霸 +覈=核 +覊=羁 +見=见 +覎=觃 +規=规 +覓=觅 +覔=觅 +視=视 +覘=觇 +覡=觋 +覥=觍 +覦=觎 +覩=睹 +親=亲 +覬=觊 +覯=觏 +覰=觑 +覲=觐 +覷=觑 +覺=觉 +覽=览 +覿=觌 +觀=观 +觔=斤 +觝=抵 +觧=解 +觴=觞 +觶=觯 +觸=触 +訁=讠 +訂=订 +訃=讣 +計=计 +訊=讯 +訌=讧 +討=讨 +訐=讦 +訒=讱 +訓=训 +訕=讪 +訖=讫 +託=讬 +記=记 +訛=讹 +訝=讶 +訟=讼 +訢=䜣 +訣=诀 +訤=驳 +訥=讷 +訩=讻 +訪=访 +訬=吵 +設=设 +許=许 +訴=诉 +訶=诃 +訷=伸 +診=诊 +註=注 +証=证 +詁=诂 +詆=诋 +詎=讵 +詐=诈 +詒=诒 +詔=诏 +評=评 +詖=诐 +詗=诇 +詘=诎 +詛=诅 +詞=词 +詠=咏 +詡=诩 +詢=询 +詣=诣 +試=试 +詧=察 +詩=诗 +詫=诧 +詬=诟 +詭=诡 +詮=诠 +詰=诘 +話=话 +該=该 +詳=详 +詵=诜 +詶=州 +詻=洛 +詼=诙 +詿=诖 +誄=诔 +誅=诛 +誆=诓 +誇=夸 +誌=志 +認=认 +誑=诳 +誒=诶 +誕=诞 +誖=悖 +誘=诱 +誚=诮 +語=语 +誠=诚 +誡=诫 +誣=诬 +誤=误 +誥=诰 +誦=诵 +誧=哺 +誨=诲 +說=说 +説=说 +誯=昌 +誰=谁 +課=课 +誶=谇 +誹=诽 +誼=谊 +誾=訚 +調=调 +諂=谄 +諄=谆 +諆=棋 +談=谈 +諉=诿 +請=请 +諍=诤 +諏=诹 +諐=愆 +諑=诼 +諒=谅 +論=论 +諗=谂 +諛=谀 +諜=谍 +諝=谞 +諞=谝 +諟=堤 +諠=喧 +諡=谥 +諢=诨 +諤=谔 +諦=谛 +諧=谐 +諨=幅 +諫=谏 +諭=谕 +諮=谘 +諱=讳 +諳=谙 +諴=诚 +諶=谌 +諷=讽 +諸=诸 +諺=谚 +諼=谖 +諾=诺 +謀=谋 +謁=谒 +謂=谓 +謄=誊 +謅=诌 +謊=谎 +謌=歌 +謍=誉 +謎=谜 +謐=谧 +謔=谑 +謖=谡 +謗=谤 +謙=谦 +謚=谥 +講=讲 +謝=谢 +謠=谣 +謡=谣 +謨=谟 +謩=谟 +謫=谪 +謬=谬 +謭=谫 +謳=讴 +謸=傲 +謹=谨 +謾=谩 +謿=嘲 +譁=哗 +譆=嘻 +證=证 +譌=讹 +譎=谲 +譏=讥 +譒=播 +譔=撰 +譖=谮 +識=识 +譙=谯 +譚=谭 +譜=谱 +譟=噪 +譫=谵 +譭=毁 +譯=译 +議=议 +譴=谴 +護=护 +譸=诪 +譽=誉 +譾=谫 +讀=读 +讁=谪 +讅=审 +變=变 +讋=詟 +讌=宴 +讎=雠 +讐=雠 +讒=谗 +讓=让 +讕=谰 +讖=谶 +讚=赞 +讜=谠 +讞=谳 +谉=审 +谘=咨 +豈=岂 +豎=竖 +豐=丰 +豓=艳 +豔=艳 +豞=狗 +豩=逐 +豬=猪 +豶=豮 +貍=狸 +貓=猫 +貛=獾 +貝=贝 +貞=贞 +貟=贠 +負=负 +財=财 +貢=贡 +貧=贫 +貨=货 +販=贩 +貪=贪 +貫=贯 +責=责 +貯=贮 +貰=贳 +貲=赀 +貳=贰 +貴=贵 +貶=贬 +買=买 +貸=贷 +貺=贶 +費=费 +貼=贴 +貽=贻 +貿=贸 +賀=贺 +賁=贲 +賂=赂 +賃=赁 +賄=贿 +賅=赅 +資=资 +賈=贾 +賉=恤 +賊=贼 +賍=赃 +賑=赈 +賒=赊 +賓=宾 +賕=赇 +賗=串 +賙=赒 +賚=赉 +賛=赞 +賜=赐 +賞=赏 +賠=赔 +賡=赓 +賢=贤 +賣=卖 +賤=贱 +賦=赋 +賧=赕 +質=质 +賫=赍 +賬=账 +賭=赌 +賴=赖 +賵=赗 +賷=赍 +賸=剩 +賺=赚 +賻=赙 +購=购 +賽=赛 +賾=赜 +贄=贽 +贅=赘 +贇=赟 +贈=赠 +贊=赞 +贋=赝 +贍=赡 +贏=赢 +贐=赆 +贑=贛 +贓=赃 +贔=赑 +贖=赎 +贗=赝 +贛=赣 +贜=赃 +赑=贝 +赬=赪 +赽=块 +趂=趁 +趉=走 +趐=翅 +趕=赶 +趙=赵 +趚=速 +趦=趑 +趧=题 +趨=趋 +趫=超 +趬=翘 +趭=瞧 +趲=趱 +跕=沾 +跡=迹 +跥=跺 +跩=拽 +跴=踩 +跿=陡 +踁=胫 +踐=践 +踡=蜷 +踭=争 +踰=逾 +踴=踊 +蹆=腿 +蹌=跄 +蹍=展 +蹏=蹄 +蹓=溜 +蹔=暂 +蹕=跸 +蹜=宿 +蹟=迹 +蹠=跖 +蹣=蹒 +蹤=踪 +蹧=糟 +蹵=蹴 +蹺=跷 +躂=跶 +躉=趸 +躊=踌 +躋=跻 +躍=跃 +躑=踯 +躒=跞 +躓=踬 +躕=蹰 +躚=跹 +躡=蹑 +躥=蹿 +躦=躜 +躪=躏 +躭=耽 +躱=躲 +躳=躬 +躶=裸 +軀=躯 +軆=体 +車=车 +軋=轧 +軌=轨 +軍=军 +軑=轪 +軒=轩 +軔=轫 +軛=轭 +軟=软 +軤=轷 +軫=轸 +軲=轱 +軸=轴 +軹=轵 +軺=轺 +軻=轲 +軼=轶 +軾=轼 +較=较 +輅=辂 +輇=辁 +輈=辀 +載=载 +輊=轾 +輒=辄 +輓=挽 +輔=辅 +輕=轻 +輙=辄 +輛=辆 +輜=辎 +輝=辉 +輞=辋 +輟=辍 +輥=辊 +輦=辇 +輩=辈 +輪=轮 +輬=辌 +輭=软 +輯=辑 +輳=辏 +輸=输 +輻=辐 +輾=辗 +輿=舆 +轀=辒 +轂=毂 +轄=辖 +轅=辕 +轆=辘 +轉=转 +轍=辙 +轎=轿 +轔=辚 +轟=轰 +轡=辔 +轢=轹 +轤=轳 +辠=罪 +辢=辣 +辤=辞 +辦=办 +辧=辨 +辭=辞 +辮=辫 +辯=辩 +農=农 +辳=农 +辴=冁 +迀=干 +迆=迤 +迉=尸 +迊=迎 +迋=逛 +迖=达 +迡=呢 +迣=世 +迯=逃 +迴=回 +迻=移 +逈=迥 +逕=迳 +這=这 +連=连 +逥=回 +逩=奔 +逬=迸 +週=周 +進=进 +逷=逖 +逺=远 +遉=侦 +遊=游 +運=运 +過=过 +達=达 +違=违 +遖=南 +遙=遥 +遜=逊 +遝=沓 +遞=递 +遠=远 +遡=溯 +遦=惯 +適=适 +遯=遁 +遲=迟 +遶=绕 +遷=迁 +選=选 +遺=遗 +遼=辽 +邁=迈 +還=还 +邇=迩 +邊=边 +邏=逻 +邐=逦 +郉=邢 +郟=郏 +郤=郄 +郰=邓 +郵=邮 +鄆=郓 +鄉=乡 +鄒=邹 +鄔=邬 +鄖=郧 +鄧=邓 +鄭=郑 +鄰=邻 +鄲=郸 +鄴=邺 +鄶=郐 +鄺=邝 +酇=酂 +酈=郦 +酔=醉 +酧=酬 +酨=栽 +醃=腌 +醕=醇 +醖=酝 +醜=丑 +醞=酝 +醣=糖 +醫=医 +醬=酱 +醯=酰 +醱=酦 +醻=酬 +醼=宴 +醿=醾 +釀=酿 +釁=衅 +釃=酾 +釅=酽 +釋=释 +釐=厘 +釒=钅 +釓=钆 +釔=钇 +釕=钌 +釗=钊 +釘=钉 +釙=钋 +針=针 +釡=斧 +釢=乃 +釣=钓 +釤=钐 +釦=扣 +釧=钏 +釩=钒 +釬=焊 +釭=肛 +釵=钗 +釷=钍 +釹=钕 +釺=钎 +釿=斤 +鈀=钯 +鈁=钫 +鈃=钘 +鈄=钭 +鈅=钥 +鈆=铅 +鈈=钚 +鈉=钠 +鈍=钝 +鈎=钩 +鈐=钤 +鈑=钣 +鈒=钑 +鈔=钞 +鈕=钮 +鈞=钧 +鈣=钙 +鈥=钬 +鈦=钛 +鈧=钪 +鈫=纹 +鈮=铌 +鈰=铈 +鈳=钶 +鈴=铃 +鈷=钴 +鈸=钹 +鈹=铍 +鈺=钰 +鈽=钸 +鈾=铀 +鈿=钿 +鉀=钾 +鉄=铁 +鉅=钜 +鉆=钻 +鉈=铊 +鉉=铉 +鉋=铇 +鉍=铋 +鉏=锄 +鉑=铂 +鉕=钷 +鉗=钳 +鉚=铆 +鉛=铅 +鉞=钺 +鉢=钵 +鉤=钩 +鉦=钲 +鉬=钼 +鉭=钽 +鉮=神 +鉲=卡 +鉶=铏 +鉸=铰 +鉺=铒 +鉻=铬 +鉽=式 +鉿=铪 +銀=银 +銃=铳 +銅=铜 +銍=铚 +銑=铣 +銓=铨 +銕=铁 +銖=铢 +銘=铭 +銚=铫 +銛=铦 +銜=衔 +銠=铑 +銣=铷 +銥=铱 +銦=铟 +銨=铵 +銩=铥 +銪=铕 +銫=铯 +銬=铐 +銰=艾 +銱=铞 +銲=焊 +銳=锐 +銷=销 +銹=锈 +銻=锑 +銼=锉 +鋁=铝 +鋂=镅 +鋃=锒 +鋅=锌 +鋇=钡 +鋌=铤 +鋏=铗 +鋒=锋 +鋖=妥 +鋙=铻 +鋝=锊 +鋟=锓 +鋣=铘 +鋤=锄 +鋥=锃 +鋦=锔 +鋨=锇 +鋩=铓 +鋪=铺 +鋭=锐 +鋮=铖 +鋯=锆 +鋰=锂 +鋱=铽 +鋶=锍 +鋸=锯 +鋼=钢 +鋽=掉 +錁=锞 +錄=录 +錆=锖 +錇=锫 +錈=锩 +錏=铔 +錐=锥 +錒=锕 +錕=锟 +錘=锤 +錙=锱 +錚=铮 +錛=锛 +錞=醇 +錟=锬 +錠=锭 +錡=锜 +錢=钱 +錦=锦 +錨=锚 +錩=锠 +錫=锡 +錮=锢 +錯=错 +録=录 +錳=锰 +錶=表 +錸=铼 +錼=镎 +鍀=锝 +鍁=锨 +鍃=锪 +鍆=钔 +鍇=锴 +鍈=锳 +鍋=锅 +鍍=镀 +鍔=锷 +鍘=铡 +鍚=钖 +鍛=锻 +鍠=锽 +鍤=锸 +鍥=锲 +鍩=锘 +鍫=锹 +鍬=锹 +鍰=锾 +鍳=鉴 +鍴=端 +鍵=键 +鍶=锶 +鍺=锗 +鍼=针 +鍾=锺 +鎂=镁 +鎄=锿 +鎅=界 +鎇=镅 +鎊=镑 +鎌=镰 +鎍=索 +鎔=镕 +鎖=锁 +鎗=枪 +鎘=镉 +鎚=锤 +鎛=镈 +鎟=桑 +鎡=镃 +鎢=钨 +鎣=蓥 +鎦=镏 +鎧=铠 +鎩=铩 +鎪=锼 +鎬=镐 +鎮=镇 +鎰=镒 +鎲=镋 +鎳=镍 +鎵=镓 +鎸=镌 +鎹=送 +鎻=锁 +鎿=镎 +鏃=镞 +鏇=镟 +鏈=链 +鏌=镆 +鏍=镙 +鏐=镠 +鏑=镝 +鏗=铿 +鏘=锵 +鏜=镗 +鏝=镘 +鏞=镛 +鏟=铲 +鏡=镜 +鏢=镖 +鏤=镂 +鏨=錾 +鏰=镚 +鏵=铧 +鏷=镤 +鏹=镪 +鏽=锈 +鐃=铙 +鐋=铴 +鐐=镣 +鐒=铹 +鐓=镦 +鐔=镡 +鐘=钟 +鐙=镫 +鐝=镢 +鐠=镨 +鐦=锎 +鐧=锏 +鐨=镄 +鐫=镌 +鐮=镰 +鐰=糙 +鐲=镯 +鐳=镭 +鐴=避 +鐵=铁 +鐶=镮 +鐸=铎 +鐺=铛 +鐿=镱 +鑀=锿 +鑄=铸 +鑊=镬 +鑌=镔 +鑑=鉴 +鑒=鉴 +鑔=镲 +鑕=锧 +鑚=钻 +鑛=矿 +鑞=镴 +鑠=铄 +鑣=镳 +鑤=刨 +鑥=镥 +鑭=镧 +鑰=钥 +鑱=镵 +鑲=镶 +鑵=罐 +鑷=镊 +鑹=镩 +鑼=锣 +鑽=钻 +鑾=銮 +鑿=凿 +钁=镢 +钂=镋 +钜=鉅 +铇=刨 +镚=崩 +镟=碹 +镵=馋 +長=长 +門=门 +閁=闪 +閂=闩 +閃=闪 +閄=门 +閆=闫 +閈=闬 +閉=闭 +開=开 +閌=闶 +閎=闳 +閏=闰 +閑=闲 +閒=闲 +間=间 +閔=闵 +閘=闸 +閙=闹 +閞=开 +閡=阂 +関=关 +閣=阁 +閥=阀 +閨=闺 +閩=闽 +閫=阃 +閬=阆 +閭=闾 +閱=阅 +閲=阅 +閶=阊 +閷=刹 +閹=阉 +閻=阎 +閼=阏 +閽=阍 +閾=阈 +閿=阌 +闃=阒 +闆=板 +闈=闱 +闊=阔 +闋=阕 +闌=阑 +闍=阇 +闐=阗 +闒=阘 +闓=闿 +闔=阖 +闕=阙 +闖=闯 +闚=窥 +關=关 +闝=嫖 +闞=阚 +闠=阓 +闡=阐 +闢=辟 +闤=阛 +闥=闼 +阣=吃 +阨=厄 +阪=坂 +阬=坑 +阯=址 +陏=隋 +陗=峭 +陘=陉 +陝=陕 +陣=阵 +陥=馅 +陰=阴 +陳=陈 +陸=陆 +険=险 +陻=堙 +陼=堵 +陽=阳 +隂=阴 +隄=堤 +隉=陧 +隊=队 +階=阶 +隕=陨 +隖=坞 +際=际 +隟=隙 +隢=饶 +隣=邻 +隨=随 +險=险 +隱=隐 +隴=陇 +隷=隶 +隸=隶 +隻=只 +雋=隽 +雖=虽 +雙=双 +雛=雏 +雜=杂 +雝=雍 +雞=鸡 +離=离 +難=难 +雲=云 +電=电 +霚=雾 +霛=灵 +霡=脉 +霢=霡 +霤=溜 +霧=雾 +霩=廓 +霽=霁 +靂=雳 +靃=霍 +靄=霭 +靆=叇 +靈=灵 +靉=叆 +靚=靓 +靜=静 +靣=面 +靦=腼 +靨=靥 +靭=韧 +靱=韧 +鞀=鼗 +鞉=鼗 +鞌=鞍 +鞏=巩 +鞝=绱 +鞵=鞋 +鞽=鞒 +韁=缰 +韃=鞑 +韈=袜 +韉=鞯 +韋=韦 +韌=韧 +韍=韨 +韓=韩 +韙=韪 +韜=韬 +韝=鞴 +韞=韫 +韤=袜 +韮=韭 +韻=韵 +響=响 +頁=页 +頂=顶 +頃=顷 +項=项 +順=顺 +頇=顸 +須=须 +頊=顼 +頌=颂 +頎=颀 +頏=颃 +預=预 +頑=顽 +頒=颁 +頓=顿 +頗=颇 +領=领 +頙=项 +頜=颌 +頟=额 +頡=颉 +頤=颐 +頦=颏 +頭=头 +頮=颒 +頰=颊 +頲=颋 +頴=颕 +頷=颔 +頸=颈 +頹=颓 +頻=频 +頼=赖 +頽=颓 +顆=颗 +顋=腮 +題=题 +額=额 +顎=颚 +顏=颜 +顒=颙 +顓=颛 +顔=颜 +願=愿 +顙=颡 +顛=颠 +類=类 +顢=颟 +顥=颢 +顦=憔 +顧=顾 +顫=颤 +顬=颥 +顯=显 +顰=颦 +顱=颅 +顳=颞 +顴=颧 +颕=颖 +風=风 +颩=风 +颭=飐 +颮=飑 +颯=飒 +颱=台 +颳=刮 +颶=飓 +颸=飔 +颺=飏 +颻=飖 +颼=飕 +飀=飗 +飃=飘 +飄=飘 +飆=飚 +飈=飚 +飚=飙 +飛=飞 +飜=翻 +飠=饣 +飢=饥 +飣=饤 +飤=饲 +飥=饦 +飩=饨 +飪=饪 +飫=饫 +飭=饬 +飮=饮 +飯=饭 +飱=飧 +飲=饮 +飴=饴 +飺=糍 +飼=饲 +飽=饱 +飾=饰 +飿=饳 +餀=哎 +餁=饪 +餃=饺 +餄=饸 +餅=饼 +餈=糍 +餉=饷 +養=养 +餌=饵 +餎=饹 +餏=饻 +餑=饽 +餒=馁 +餓=饿 +餕=馂 +餖=饾 +餘=馀 +餚=肴 +餛=馄 +餜=馃 +餞=饯 +餡=馅 +餧=喂 +館=馆 +餬=糊 +餱=糇 +餳=饧 +餵=喂 +餶=馉 +餷=馇 +餹=糖 +餺=馎 +餻=糕 +餼=饩 +餽=馈 +餾=馏 +餿=馊 +饁=馌 +饃=馍 +饅=馒 +饈=馐 +饉=馑 +饊=馓 +饋=馈 +饌=馔 +饍=膳 +饑=饥 +饒=饶 +饗=飨 +饜=餍 +饝=馍 +饞=馋 +饟=饷 +饢=馕 +饤=盯 +馀=余 +馬=马 +馭=驭 +馮=冯 +馱=驮 +馳=驰 +馴=驯 +馶=驶 +馹=驲 +馿=驴 +駁=驳 +駆=驱 +駈=驱 +駐=驻 +駑=驽 +駒=驹 +駔=驵 +駕=驾 +駘=骀 +駙=驸 +駛=驶 +駝=驼 +駞=驼 +駟=驷 +駡=骂 +駢=骈 +駦=藤 +駭=骇 +駮=驳 +駰=骃 +駱=骆 +駸=骎 +駿=骏 +騁=骋 +騂=骍 +騅=骓 +騌=骔 +騍=骒 +騎=骑 +騏=骐 +騐=验 +騒=骚 +験=验 +騖=骛 +騗=骗 +騙=骗 +騣=鬃 +騤=骙 +騧=䯄 +騫=骞 +騭=骘 +騮=骝 +騰=腾 +騶=驺 +騷=骚 +騸=骟 +騾=骡 +驀=蓦 +驁=骜 +驂=骖 +驃=骠 +驄=骢 +驅=驱 +驊=骅 +驌=骕 +驍=骁 +驏=骣 +驕=骄 +驗=验 +驘=骡 +驚=惊 +驛=驿 +驟=骤 +驢=驴 +驤=骧 +驥=骥 +驦=骦 +驪=骊 +驫=骉 +骉=马 +骔=鬃 +骯=肮 +骼=胳 +骾=鲠 +髈=膀 +髊=搓 +髏=髅 +髒=脏 +體=体 +髕=髌 +髖=髋 +髠=髡 +髣=仿 +髥=髯 +髩=鬓 +髮=发 +髴=佛 +鬀=剃 +鬁=疬 +鬂=鬓 +鬆=松 +鬉=鬃 +鬍=胡 +鬚=须 +鬢=鬓 +鬥=斗 +鬦=斗 +鬧=闹 +鬨=闹 +鬩=阋 +鬪=斗 +鬭=斗 +鬮=阄 +鬰=郁 +鬱=郁 +鬴=釜 +魊=蜮 +魎=魉 +魘=魇 +魚=鱼 +魛=鱽 +魢=鱾 +魨=鲀 +魯=鲁 +魴=鲂 +魷=鱿 +魺=鲄 +鮁=鲅 +鮃=鲆 +鮊=鲌 +鮋=鲉 +鮍=鲏 +鮎=鲇 +鮐=鲐 +鮑=鲍 +鮒=鲋 +鮓=鲊 +鮚=鲒 +鮜=鲘 +鮝=鲞 +鮞=鲕 +鮟=安 +鮦=鲖 +鮪=鲔 +鮫=鲛 +鮭=鲑 +鮮=鲜 +鮳=鲓 +鮶=鲪 +鮺=鲝 +鯀=鲧 +鯁=鲠 +鯇=鲩 +鯉=鲤 +鯊=鲨 +鯒=鲬 +鯔=鲻 +鯕=鲯 +鯖=鲭 +鯗=鲞 +鯛=鲷 +鯝=鲴 +鯡=鲱 +鯢=鲵 +鯤=鲲 +鯧=鲳 +鯨=鲸 +鯪=鲮 +鯫=鲰 +鯰=鲶 +鯴=鲺 +鯵=鲹 +鯷=鳀 +鯽=鲫 +鯿=鳊 +鰁=鳈 +鰂=鲗 +鰃=鳂 +鰈=鲽 +鰉=鳇 +鰌=鳅 +鰍=鳅 +鰏=鲾 +鰐=鳄 +鰒=鳆 +鰓=鳃 +鰛=鳁 +鰜=鳒 +鰟=鳑 +鰠=鳋 +鰣=鲥 +鰥=鳏 +鰨=鳎 +鰩=鳐 +鰭=鳍 +鰮=鳁 +鰱=鲢 +鰲=鳌 +鰳=鳓 +鰵=鳘 +鰷=鲦 +鰹=鲣 +鰺=鲹 +鰻=鳗 +鰼=鳛 +鰾=鳔 +鱂=鳉 +鱅=鳙 +鱈=鳕 +鱉=鳖 +鱏=鲟 +鱒=鳟 +鱓=鳝 +鱔=鳝 +鱖=鳜 +鱗=鳞 +鱘=鲟 +鱝=鲼 +鱟=鲎 +鱠=鲙 +鱣=鳣 +鱤=鳡 +鱧=鳢 +鱨=鲿 +鱭=鲚 +鱯=鳠 +鱷=鳄 +鱸=鲈 +鱺=鲡 +鱻=鲜 +鳥=鸟 +鳧=凫 +鳩=鸠 +鳬=凫 +鳯=凤 +鳲=鸤 +鳳=凤 +鳴=鸣 +鳶=鸢 +鳾=䴓 +鴆=鸩 +鴇=鸨 +鴈=雁 +鴉=鸦 +鴒=鸰 +鴕=鸵 +鴛=鸳 +鴝=鸲 +鴞=鸮 +鴟=鸱 +鴣=鸪 +鴦=鸯 +鴨=鸭 +鴬=鸴 +鴯=鸸 +鴰=鸹 +鴴=鸻 +鴷=䴕 +鴻=鸿 +鴿=鸽 +鵁=䴔 +鵂=鸺 +鵃=鸼 +鵐=鹀 +鵑=鹃 +鵒=鹆 +鵓=鹁 +鵜=鹈 +鵝=鹅 +鵞=鹅 +鵠=鹄 +鵡=鹉 +鵪=鹌 +鵬=鹏 +鵮=鹐 +鵯=鹎 +鵰=雕 +鵲=鹊 +鵶=鸦 +鵷=鹓 +鵾=鹍 +鶄=䴖 +鶇=鸫 +鶉=鹑 +鶊=鹒 +鶏=鸡 +鶓=鹋 +鶖=鹙 +鶘=鹕 +鶚=鹗 +鶡=鹖 +鶤=鹍 +鶥=鹛 +鶩=鹜 +鶪=䴗 +鶬=鸧 +鶯=莺 +鶲=鹟 +鶴=鹤 +鶹=鹠 +鶺=鹡 +鶻=鹘 +鶼=鹣 +鶿=鹚 +鷀=鹚 +鷁=鹢 +鷂=鹞 +鷄=鸡 +鷈=䴘 +鷊=鹝 +鷓=鹧 +鷖=鹥 +鷗=鸥 +鷙=鸷 +鷚=鹨 +鷥=鸶 +鷦=鹪 +鷫=鹔 +鷯=鹩 +鷰=燕 +鷲=鹫 +鷳=鹇 +鷴=鹇 +鷸=鹬 +鷹=鹰 +鷺=鹭 +鷽=鸴 +鷿=䴙 +鸇=鹯 +鸌=鹱 +鸎=莺 +鸏=鹲 +鸕=鸬 +鸘=鹴 +鸚=鹦 +鸛=鹳 +鸝=鹂 +鸞=鸾 +鹵=卤 +鹹=咸 +鹺=鹾 +鹻=碱 +鹼=硷 +鹽=盐 +麁=粗 +麅=狍 +麐=麟 +麕=麇 +麗=丽 +麞=獐 +麤=粗 +麥=麦 +麩=麸 +麪=面 +麵=面 +麼=么 +麽=么 +黃=黄 +黌=黉 +點=点 +黨=党 +黲=黪 +黴=霉 +黶=黡 +黷=黩 +黽=黾 +黿=鼋 +鼂=鼌 +鼃=蛙 +鼇=鳌 +鼈=鳖 +鼉=鼍 +鼔=鼓 +鼡=用 +鼦=貂 +鼴=鼹 +齇=齄 +齊=齐 +齋=斋 +齎=赍 +齏=齑 +齒=齿 +齔=龀 +齕=龁 +齗=龂 +齙=龅 +齜=龇 +齟=龃 +齠=龆 +齡=龄 +齦=龈 +齧=啮 +齩=咬 +齪=龊 +齬=龉 +齰=醋 +齲=龋 +齶=腭 +齷=龌 +龍=龙 +龎=厐 +龐=庞 +龔=龚 +龕=龛 +龜=龟 +龞=鳖 +龢=和 +︰=﹕ +︵=《 +︶=》 +︷=《 +︸=》 +︹=《 +︺=》 +︻=《 +︼=》 +︽=《 +︾=》 +︿=《 +﹀=》 +﹁=《 +﹂=》 +﹃=《 +﹄=》 +﹝=《 +﹞=》 +﹢=+ +﹤=《 +﹦== +﹩=$ +﹪=% +﹫=@ +!=! +?=? +/=/ +、=, +%=% +(=( +)=) +,=, +.=. +0=0 +1=1 +2=2 +3=3 +4=4 +5=5 +6=6 +7=7 +8=8 +9=9 +A=a +B=b +C=c +D=d +E=e +F=f +G=g +H=h +I=i +J=j +K=k +L=l +M=m +N=n +O=o +P=p +Q=q +R=r +S=s +T=t +U=u +V=v +W=w +X=x +Y=y +Z=z +a=a +b=b +c=c +d=d +e=e +f=f +g=g +h=h +i=i +j=j +k=k +l=l +m=m +n=n +o=o +p=p +q=q +r=r +s=s +t=t +u=u +v=v +w=w +x=x +y=y +z=z +º=0 +¹=1 +²=2 +³=3 +⁴=4 +⁵=5 +⁶=6 +⁷=7 +⁸=8 +⁹=9 +₀=0 +₁=1 +₂=2 +₃=3 +₄=4 +₅=5 +₆=6 +₇=7 +₈=8 +₉=9 +ⁿ=n +:=: +"=" +#=# +$=$ +&=& +'=' +*=* ++=+ +-=- +;=; +<=《 +=== +>=》 +@=@ +[=《 +\=\ +]=》 +^=^ +_=_ +`=` +{=《 +|=| +}=》 +~=~ diff --git a/launchers/standalone/src/main/resources/data/dictionary/other/TagPKU98.csv b/launchers/standalone/src/main/resources/data/dictionary/other/TagPKU98.csv new file mode 100644 index 000000000..c9268b302 --- /dev/null +++ b/launchers/standalone/src/main/resources/data/dictionary/other/TagPKU98.csv @@ -0,0 +1,44 @@ +序号,代码,名称,帮助记忆的诠释,例子及注解 +1,Ag,形语素,形容词性语素。形容词代码为a,语素代码g前面置以A。,绿色/n 似/d 锦/Ag , +2,a,形容词,取英语形容词adjective的第1个字母,[重要/a 步伐/n]NP ,美丽/a ,看似/v 抽象/a , +3,ad,副形词,直接作状语的形容词。形容词代码a和副词代码d并在一起。,[积极/ad 谋求/v]V-ZZ ,幻象/n 易/ad 逝/Vg , +4,an,名形词,具有名词功能的形容词。形容词代码a和名词代码n并在一起。,[外交/n 和/c 安全/an]NP-BL , +5,Bg,区别语素,区别词性语素。区别词代码为b,语素代码g前面置以B。,赤/Ag 橙/Bg 黄/a 绿/a 青/a 蓝/a 紫/a , +6,b,区别词,取汉字“别”的声母。,女/b 司机/n, 金/b 手镯/n, 慢性/b 胃炎/n, 古/b 钱币/n, 副/b 主任/n, 总/b 公司/n单音节区别词和单音节名词或名语素组合,作为一个词,并标以名词词性n。 雄鸡/n, 雌象/n, 女魔/n, 古币/n少数“单音节区别词+双音节词”的结构作为一个词。总书记/n , +7,c,连词,取英语连词conjunction的第1个字母。,合作/vn 与/c 伙伴/n +8,Dg,副语素,副词性语素。副词代码为d,语素代码g前面置以D。,了解/v 甚/Dg 深/a ,煞/Dg 是/v 喜人/a , +9,d,副词,取adverb的第2个字母,因其第1个字母已用于形容词。,进一步/d 发展/v , +10,e,叹词,取英语叹词exclamation的第1个字母。,啊/e ,/w 那/r 金灿灿/z 的/u 麦穗/n , +11,f,方位词,取汉字“方”。,军人/n 的/u 眼睛/n 里/f 不/d 是/v 没有/v 风景/n , +12,h,前接成分,取英语head的第1个字母。,许多/m 非/h 主角/n 人物/n ,办事处/n 的/u “/w 准/h 政府/n ”/w 功能/n 不断/d 加强/v , +13,i,成语,取英语成语idiom的第1个字母。,一言一行/i ,义无反顾/i , +14,j,简称略语,取汉字“简”的声母。,[德/j 外长/n]NP ,文教/j , +15,k,后接成分,后接成分。,少年儿童/l 朋友/n 们/k ,身体/n 健康/a 者/k , +16,l,习用语,习用语尚未成为成语,有点“临时性”,取“临”的声母。,少年儿童/l 朋友/n 们/k ,落到实处/l , +17,Mg,数语素,数词性语素。数词代码为m,语素代码g前面置以M。,甲/Mg 减下/v 的/u 人/n 让/v 乙/Mg 背上/v ,凡/d “/w 寅/Mg 年/n ”/w 中/f 出生/v 的/u 人/n 生肖/n 都/d 属/v 虎/n , +18,m,数词,取英语numeral的第3个字母,n,u已有他用。,1.数量词组应切分为数词和量词。 三/m 个/q, 10/m 公斤/q, 一/m 盒/q 点心/n ,但少数数量词已是词典的登录单位,则不再切分。 一个/m , 一些/m ,2. 基数、序数、小数、分数、百分数一律不予切分,为一个切分单位,标注为 m 。一百二十三/m,20万/m, 123.54/m, 一个/m, 第一/m, 第三十五/m, 20%/m, 三分之二/m, 千分之三十/m, 几十/m 人/n, 十几万/m 元/q, 第一百零一/m 个/q ,3. 约数,前加副词、形容词或后加“来、多、左右”等助数词的应予分开。约/d 一百/m 多/m 万/m,仅/d 一百/m 个/q, 四十/m 来/m 个/q,二十/m 余/m 只/q, 十几/m 个/q,三十/m 左右/m ,两个数词相连的及“成百”、“上千”等则不予切分。五六/m 年/q, 七八/m 天/q,十七八/m 岁/q, 成百/m 学生/n,上千/m 人/n, 4.表序关系的“数+名”结构,应予切分。二/m 连/n , 三/m 部/n , +19,Ng,名语素,名词性语素。名词代码为n,语素代码g前面置以N。,出/v 过/u 两/m 天/q 差/Ng, 理/v 了/u 一/m 次/q 发/Ng, +20,n,名词,取英语名词noun的第1个字母。,(参见 动词--v)岗位/n , 城市/n , 机会/n ,她/r 是/v 责任/n 编辑/n , +21,nr,人名,名词代码n和“人(ren)”的声母并在一起。,1. 汉族人及与汉族起名方式相同的非汉族人的姓和名单独切分,并分别标注为nr。张/nr 仁伟/nr, 欧阳/nr 修/nr, 阮/nr 志雄/nr, 朴/nr 贞爱/nr汉族人除有单姓和复姓外,还有双姓,即有的女子出嫁后,在原来的姓上加上丈夫的姓。如:陈方安生。这种情况切分、标注为:陈/nr 方/nr 安生/nr;唐姜氏,切分、标注为:唐/nr 姜氏/nr。2. 姓名后的职务、职称或称呼要分开。江/nr 主席/n, 小平/nr 同志/n, 江/nr 总书记/n,张/nr 教授/n, 王/nr 部长/n, 陈/nr 老总/n, 李/nr 大娘/n, 刘/nr 阿姨/n, 龙/nr 姑姑/n3. 对人的简称、尊称等若为两个字,则合为一个切分单位,并标以nr。老张/nr, 大李/nr, 小郝/nr, 郭老/nr, 陈总/nr4. 明显带排行的亲属称谓要切分开,分不清楚的则不切开。三/m 哥/n, 大婶/n, 大/a 女儿/n, 大哥/n, 小弟/n, 老爸/n5. 一些著名作者的或不易区分姓和名的笔名通常作为一个切分单位。鲁迅/nr, 茅盾/nr, 巴金/nr, 三毛/nr, 琼瑶/nr, 白桦/nr6. 外国人或少数民族的译名(包括日本人的姓名)不予切分,标注为nr。克林顿/nr, 叶利钦/nr, 才旦卓玛/nr, 小林多喜二/nr, 北研二/nr,华盛顿/nr, 爱因斯坦/nr有些西方人的姓名中有小圆点,也不分开。卡尔·马克思/nr +22,ns,地名,名词代码n和处所词代码s并在一起。,(参见2。短语标记说明--NS)安徽/ns,深圳/ns,杭州/ns,拉萨/ns,哈尔滨/ns, 呼和浩特/ns, 乌鲁木齐/ns,长江/ns,黄海/ns,太平洋/ns, 泰山/ns, 华山/ns,亚洲/ns, 海南岛/ns,太湖/ns,白洋淀/ns, 俄罗斯/ns,哈萨克斯坦/ns,彼得堡/ns, 伏尔加格勒/ns 1. 国名不论长短,作为一个切分单位。中国/ns, 中华人民共和国/ns, 日本国/ns, 美利坚合众国/ns, 美国/ns2. 地名后有“省”、“市”、“县”、“区”、“乡”、“镇”、“村”、“旗”、“州”、“都”、“府”、“道”等单字的行政区划名称时,不切分开,作为一个切分单位。四川省/ns, 天津市/ns,景德镇/ns沙市市/ns, 牡丹江市/ns,正定县/ns,海淀区/ns, 通州区/ns,东升乡/ns, 双桥镇/ns 南化村/ns,华盛顿州/ns,俄亥俄州/ns,东京都/ns, 大阪府/ns,北海道/ns, 长野县/ns,开封府/ns,宣城县/ns3. 地名后的行政区划有两个以上的汉字,则将地名同行政区划名称切开,不过要将地名同行政区划名称用方括号括起来,并标以短语NS。[芜湖/ns 专区/n] NS,[宣城/ns 地区/n]ns,[内蒙古/ns 自治区/n]NS,[深圳/ns 特区/n]NS, [厦门/ns 经济/n 特区/n]NS, [香港/ns 特别/a 行政区/n]NS,[香港/ns 特区/n]NS, [华盛顿/ns 特区/n]NS,4. 地名后有表示地形地貌的一个字的普通名词,如“江、河、山、洋、海、岛、峰、湖”等,不予切分。鸭绿江/ns,亚马逊河/ns, 喜马拉雅山/ns, 珠穆朗玛峰/ns,地中海/ns,大西洋/ns,洞庭湖/ns, 塞普路斯岛/ns 5. 地名后接的表示地形地貌的普通名词若有两个以上汉字,则应切开。然后将地名同该普通名词标成短语NS。[台湾/ns 海峡/n]NS,[华北/ns 平原/n]NS,[帕米尔/ns 高原/n]NS, [南沙/ns 群岛/n]NS,[京东/ns 大/a 峡谷/n]NS [横断/b 山脉/n]NS6.地名后有表示自然区划的一个字的普通名词,如“ 街,路,道,巷,里,町,庄,村,弄,堡”等,不予切分。 中关村/ns,长安街/ns,学院路/ns, 景德镇/ns, 吴家堡/ns, 庞各庄/ns, 三元里/ns,彼得堡/ns, 北菜市巷/ns, 7.地名后接的表示自然区划的普通名词若有两个以上汉字,则应切开。然后将地名同自然区划名词标成短语NS。[米市/ns 大街/n]NS, [蒋家/nz 胡同/n]NS , [陶然亭/ns 公园/n]NS , 8. 大小地名相连时的标注方式为:北京市/ns 海淀区/ns 海淀镇/ns [南/f 大街/n]NS [蒋家/nz 胡同/n]NS 24/m 号/q , +23,nt,机构团体,“团”的声母为t,名词代码n和t并在一起。,(参见2。短语标记说明--NT)联合国/nt,中共中央/nt,国务院/nt, 北京大学/nt1.大多数团体、机构、组织的专有名称一般是短语型的,较长,且含有地名或人名等专名,再组合,标注为短语NT。[中国/ns 计算机/n 学会/n]NT, [香港/ns 钟表业/n 总会/n]NT, [烟台/ns 大学/n]NT, [香港/ns 理工大学/n]NT, [华东/ns 理工大学/n]NT,[合肥/ns 师范/n 学院/n]NT, [北京/ns 图书馆/n]NT, [富士通/nz 株式会社/n]NT, [香山/ns 植物园/n]NT, [安娜/nz 美容院/n]NT,[上海/ns 手表/n 厂/n]NT, [永和/nz 烧饼铺/n]NT,[北京/ns 国安/nz 队/n]NT,2. 对于在国际或中国范围内的知名的唯一的团体、机构、组织的名称即使前面没有专名,也标为nt或NT。联合国/nt,国务院/nt,外交部/nt, 财政部/nt,教育部/nt, 国防部/nt,[世界/n 贸易/n 组织/n]NT, [国家/n 教育/vn 委员会/n]NT,[信息/n 产业/n 部/n]NT,[全国/n 信息/n 技术/n 标准化/vn 委员会/n]NT,[全国/n 总/b 工会/n]NT,[全国/n 人民/n 代表/n 大会/n]NT,美国的“国务院”,其他国家的“外交部、财政部、教育部”,必须在其所属国的国名之后出现时,才联合标注为NT。[美国/ns 国务院/n]NT,[法国/ns 外交部/n]NT,[美/j 国会/n]NT,日本有些政府机构名称很特别,无论是否出现在“日本”国名之后都标为nt。[日本/ns 外务省/nt]NT,[日/j 通产省/nt]NT通产省/nt 3. 前后相连有上下位关系的团体机构组织名称的处理方式如下:[联合国/nt 教科文/j 组织/n]NT, [中国/ns 银行/n 北京/ns 分行/n]NT,[河北省/ns 正定县/ns 西平乐乡/ns 南化村/ns 党支部/n]NT, 当下位名称含有专名(如“北京/ns 分行/n”、“南化村/ns 党支部/n”、“昌平/ns 分校/n”)时,也可脱离前面的上位名称单独标注为NT。[中国/ns 银行/n]NT [北京/ns 分行/n]NT,北京大学/nt [昌平/ns 分校/n]NT,4. 团体、机构、组织名称中用圆括号加注简称时:[宝山/ns 钢铁/n (/w 宝钢/j )/w 总/b 公司/n]NT,[宝山/ns 钢铁/n 总/b 公司/n]NT,(/w 宝钢/j )/w +24,nx,外文字符,外文字符。,A/nx 公司/n ,B/nx 先生/n ,X/nx 君/Ng ,24/m K/nx 镀金/n ,C/nx 是/v 光速/n ,Windows98/nx ,PentiumIV/nx ,I LOVE THIS GAME/nx , +25,nz,其他专名,“专”的声母的第1个字母为z,名词代码n和z并在一起。,(参见2。短语标记说明--NZ)除人名、国名、地名、团体、机构、组织以外的其他专有名词都标以nz。满族/nz,俄罗斯族/nz,汉语/nz,罗马利亚语/nz, 捷克语/nz,中文/nz, 英文/nz, 满人/nz, 哈萨克人/nz, 诺贝尔奖/nz, 茅盾奖/nz, 1.包含专有名称(或简称)的交通线,标以nz;短语型的,标为NZ。津浦路/nz, 石太线/nz, [京/j 九/j 铁路/n]NZ, [京/j 津/j 高速/b 公路/n]NZ, 2. 历史上重要事件、运动等专有名称一般是短语型的,按短语型专有名称处理,标以NZ。[卢沟桥/ns 事件/n]NZ, [西安/ns 事变/n]NZ,[五四/t 运动/n]NZ, [明治/nz 维新/n]NZ,[甲午/t 战争/n]NZ,3.专有名称后接多音节的名词,如“语言”、“文学”、“文化”、“方式”、“精神”等,失去专指性,则应分开。欧洲/ns 语言/n, 法国/ns 文学/n, 西方/ns 文化/n, 贝多芬/nr 交响乐/n, 雷锋/nr 精神/n, 美国/ns 方式/n,日本/ns 料理/n, 宋朝/t 古董/n 4. 商标(包括专名及后接的“牌”、“型”等)是专指的,标以nz,但其后所接的商品仍标以普通名词n。康师傅/nr 方便面/n, 中华牌/nz 香烟/n, 牡丹III型/nz 电视机/n, 联想/nz 电脑/n, 鳄鱼/nz 衬衣/n, 耐克/nz 鞋/n5. 以序号命名的名称一般不认为是专有名称。2/m 号/q 国道/n ,十一/m 届/q 三中全会/j如果前面有专名,合起来作为短语型专名。[中国/ns 101/m 国道/n]NZ, [中共/j 十一/m 届/q 三中全会/j]NZ,6. 书、报、杂志、文档、报告、协议、合同等的名称通常有书名号加以标识,不作为专有名词。由于这些名字往往较长,名字本身按常规处理。《/w 宁波/ns 日报/n 》/w ,《/w 鲁迅/nr 全集/n 》/w,中华/nz 读书/vn 报/n, 杜甫/nr 诗选/n,少数书名、报刊名等专有名称,则不切分。红楼梦/nz, 人民日报/nz,儒林外史/nz 7. 当有些专名无法分辨它们是人名还是地名或机构名时,暂标以nz。[巴黎/ns 贝尔希/nz 体育馆/n]NT,其中“贝尔希”只好暂标为nz。 +26,o,拟声词,取英语拟声词onomatopoeia的第1个字母。,哈哈/o 一/m 笑/v ,装载机/n 隆隆/o 推进/v , +27,p,介词,取英语介词prepositional的第1个字母。,对/p 子孙后代/n 负责/v ,以/p 煤/n 养/v 农/Ng ,为/p 治理/v 荒山/n 服务/v , 把/p 青年/n 推/v 上/v 了/u 领导/vn 岗位/n , +28,q,量词,取英语quantity的第1个字母。,(参见数词m)首/m 批/q ,一/m 年/q , +29,Rg,代语素,代词性语素。代词代码为r,在语素的代码g前面置以R。,读者/n 就/d 是/v 这/r 两/m 棵/q 小树/n 扎根/v 于/p 斯/Rg 、/w 成长/v 于/p 斯/Rg 的/u 肥田/n 沃土/n , +30,r,代词,取英语代词pronoun的第2个字母,因p已用于介词。,单音节代词“本”、“每”、“各”、“诸”后接单音节名词时,和后接的单音节名词合为代词;当后接双音节名词时,应予切分。本报/r, 每人/r, 本社/r, 本/r 地区/n, 各/r 部门/n +31,s,处所词,取英语space的第1个字母。,家里/s 的/u 电脑/n 都/d 联通/v 了/u 国际/n 互联网/n ,西部/s 交通/n 咽喉/n , +32,Tg,时语素,时间词性语素。时间词代码为t,在语素的代码g前面置以T。,3日/t 晚/Tg 在/p 总统府/n 发表/v 声明/n ,尊重/v 现/Tg 执政/vn 当局/n 的/u 权威/n , +33,t,时间词,取英语time的第1个字母。,1. 年月日时分秒,按年、月、日、时、分、秒切分,标注为t 。1997年/t 3月/t 19日/t 下午/t 2时/t 18分/t若数字后无表示时间的“年、月、日、时、分、秒”等的标为数词m。1998/m 中文/n 信息/n 处理/vn 国际/n 会议/n 2. 历史朝代的名称虽然有专有名词的性质,仍标注为t。西周/t, 秦朝/t, 东汉/t, 南北朝/t, 清代/t“牛年、虎年”等一律不予切分,标注为:牛年/t, 虎年/t, 甲午年/t, 甲午/t 战争/n, 庚子/t 赔款/n, 戊戌/t 变法/n +34,u,助词,取英语助词auxiliary。,[[俄罗斯/ns 和/c 北约/j]NP-BL 之间/f [战略/n 伙伴/n 关系/n]NP 的/u 建立/vn]NP 填平/v 了/u [[欧洲/ns 安全/a 政治/n]NP 的/u 鸿沟/n]NP +35,Vg,动语素,动词性语素。动词代码为v。在语素的代码g前面置以V。,洗/v 了/u 一个/m 舒舒服服/z 的/u 澡/Vg +36,v,动词,取英语动词verb的第一个字母。,(参见 名词--n)[[[欧盟/j 扩大/v]S 的/u [历史性/n 决定/n]NP]NP 和/c [北约/j 开放/v]S]NP-BL [为/p [创建/v [一/m 种/q 新/a 的/u 欧洲/ns 安全/a 格局/n]NP]VP-SBI]PP-MD [奠定/v 了/u 基础/n]V-SBI ,, +37,vd,副动词,直接作状语的动词。动词和副词的代码并在一起。,形势/n 会/v 持续/vd 好转/v ,认为/v 是/v 电话局/n 收/v 错/vd 了/u 费/n , +38,vn,名动词,指具有名词功能的动词。动词和名词的代码并在一起。,引起/v 人们/n 的/u 关注/vn 和/c 思考/vn ,收费/vn 电话/n 的/u 号码/n , +39,w,标点符号,,”/w :/w +40,x,非语素字,非语素字只是一个符号,字母x通常用于代表未知数、符号。, +41,Yg,语气语素,语气词性语素。语气词代码为y。在语素的代码g前面置以Y。,唯/d 大力/d 者/k 能/v 致/v 之/u 耳/Yg +42,y,语气词,取汉字“语”的声母。,会/v 泄露/v 用户/n 隐私/n 吗/y ,又/d 何在/v 呢/y ? +43,z,状态词,取汉字“状”的声母的前一个字母。,取得/v 扎扎实实/z 的/u 突破性/n 进展/vn ,四季/n 常青/z 的/u 热带/n 树木/n ,短短/z 几/m 年/q 间, \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/data/version.txt b/launchers/standalone/src/main/resources/data/version.txt new file mode 100644 index 000000000..6a126f402 --- /dev/null +++ b/launchers/standalone/src/main/resources/data/version.txt @@ -0,0 +1 @@ +1.7.5 diff --git a/launchers/standalone/src/main/resources/db/data-h2.sql b/launchers/standalone/src/main/resources/db/data-h2.sql new file mode 100644 index 000000000..61413b07d --- /dev/null +++ b/launchers/standalone/src/main/resources/db/data-h2.sql @@ -0,0 +1,1070 @@ +-- chat data +insert into s2_user (id, `name`, password, display_name, email) values (1, 'admin','admin','admin','admin@xx.com'); +insert into s2_user (id, `name`, password, display_name, email) values (2, 'jack','123456','jack','jack@xx.com'); +insert into s2_user (id, `name`, password, display_name, email) values (3, 'tom','123456','tom','tom@xx.com'); +insert into s2_user (id, `name`, password, display_name, email) values (4, 'lucy','123456','lucy','lucy@xx.com'); + +insert into s2_chat_config (`id` ,`domain_id` ,`default_metrics`,`visibility`,`entity_info` ,`dictionary_info`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (1,1,'[{"metricId":1,"unit":7,"period":"DAY"}]','{"blackDimIdList":[],"blackMetricIdList":[]}','{"entityIds":[2],"names":["用户","用户姓名"],"detailData":{"dimensionIds":[1,2],"metricIds":[2]}}','[{"itemId":1,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":2,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":3,"type":"DIMENSION","blackList":[],"isDictInfo":true}]','2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); + +insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (1, '超音数访问统计','2023-06-10 10:00:52.495','2023-06-10 10:00:52','admin','您好,欢迎使用内容智能小Q','0','0'); +insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (2, '用户访问统计','2023-06-10 10:01:04.528','2023-06-10 10:01:04','admin','您好,欢迎使用内容智能小Q','0','0'); + +insert into s2_chat_context (chat_id, modified_at , `user`, `query_text`, `semantic_parse` ,ext_data) VALUES(1, '2023-06-10 10:40:49.877', 'admin', '访问', '{"queryMode":"METRIC_ORDERBY","aggType":"NONE","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"nativeQuery":false}', 'admin'); +insert into s2_chat_context (chat_id, modified_at , `user`, `query_text`, `semantic_parse` ,ext_data) VALUES(2, '2023-06-10 10:42:02.184', 'null', '访问', '{"queryMode":"METRIC_ORDERBY","aggType":"NONE","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"nativeQuery":false}', 'null'); + +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(1, '2023-06-10 10:39:55.178', '超音数 访问次数', 'admin',0,1,'{"queryMode":"METRIC_DOMAIN","querySql":"SELECT `sys_imp_date` , `pv` FROM ( SELECT `sys_imp_date` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` FROM ( SELECT `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_f370` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_DOMAIN","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","pv":11},{"sys_imp_date":"2023-06-04","pv":14},{"sys_imp_date":"2023-06-05","pv":1},{"sys_imp_date":"2023-06-06","pv":19},{"sys_imp_date":"2023-06-07","pv":18},{"sys_imp_date":"2023-06-08","pv":24},{"sys_imp_date":"2023-06-09","pv":23}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(2, '2023-06-10 10:40:12.259', '按页面', 'admin',0,1,'{"queryMode":"METRIC_ORDERBY","querySql":"SELECT `sys_imp_date` , `page` , `pv` FROM ( SELECT `sys_imp_date` , `page` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` , `page` FROM ( SELECT `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` , `page` AS `page` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_ecf5` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` , `page` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"页面","type":"VARCHAR","nameEn":"page","showType":"CATEGORY","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_ORDERBY","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","page":"p1","pv":2},{"sys_imp_date":"2023-06-03","page":"p2","pv":3},{"sys_imp_date":"2023-06-03","page":"p3","pv":2},{"sys_imp_date":"2023-06-03","page":"p4","pv":1},{"sys_imp_date":"2023-06-03","page":"p5","pv":3},{"sys_imp_date":"2023-06-04","page":"p1","pv":3},{"sys_imp_date":"2023-06-04","page":"p2","pv":1},{"sys_imp_date":"2023-06-04","page":"p3","pv":2},{"sys_imp_date":"2023-06-04","page":"p4","pv":4},{"sys_imp_date":"2023-06-04","page":"p5","pv":4}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(3, '2023-06-10 10:40:49.877', '访问', 'admin',0,1,'{"queryMode":"METRIC_ORDERBY","querySql":"SELECT `sys_imp_date` , `page` , `uv` , `pv` FROM ( SELECT `sys_imp_date` , `page` , `s2_pv_uv_statis_uv` AS `uv` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT COUNT ( DISTINCT `s2_pv_uv_statis_uv` ) AS `s2_pv_uv_statis_uv` , SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` , `page` FROM ( SELECT `uv` AS `s2_pv_uv_statis_uv` , `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` , `page` AS `page` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_022c` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` , `page` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"页面","type":"VARCHAR","nameEn":"page","showType":"CATEGORY","authorized":true},{"name":"访问人数","type":"BIGINT","nameEn":"uv","showType":"NUMBER","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_ORDERBY","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","page":"p1","uv":2,"pv":2},{"sys_imp_date":"2023-06-03","page":"p2","uv":3,"pv":3},{"sys_imp_date":"2023-06-03","page":"p3","uv":2,"pv":2},{"sys_imp_date":"2023-06-03","page":"p4","uv":1,"pv":1},{"sys_imp_date":"2023-06-03","page":"p5","uv":3,"pv":3},{"sys_imp_date":"2023-06-04","page":"p1","uv":2,"pv":3},{"sys_imp_date":"2023-06-04","page":"p2","uv":1,"pv":1},{"sys_imp_date":"2023-06-04","page":"p3","uv":2,"pv":2},{"sys_imp_date":"2023-06-04","page":"p4","uv":3,"pv":4},{"sys_imp_date":"2023-06-04","page":"p5","uv":3,"pv":4}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(4, '2023-06-10 10:41:18.589','alice 访问次数','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `pv` FROM ( SELECT `sys_imp_date` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` FROM ( SELECT `user_name` , `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_b825` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","pv":2},{"sys_imp_date":"2023-06-04","pv":2},{"sys_imp_date":"2023-06-06","pv":2},{"sys_imp_date":"2023-06-07","pv":2},{"sys_imp_date":"2023-06-08","pv":5},{"sys_imp_date":"2023-06-09","pv":2}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(5, '2023-06-10 10:41:48.211','停留时长','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(6, '2023-06-10 10:42:02.184','访问','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); + + +-- semantic data +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 , domain_id, `name`, biz_name, description, database_id ,datasource_detail, created_at, created_by, updated_at, updated_by ) VALUES(1, 1, '停留时长统计', 's2_stay_time_statis', '停留时长统计', 1, '{"dimensions":[{"bizName":"imp_date","dateFormat":"yyyy-MM-dd","expr":"imp_date","isCreateDimension":0,"type":"time","typeParams":{"isPrimary":"true","timeGranularity":"day"}},{"bizName":"page","dateFormat":"yyyy-MM-dd","expr":"page","isCreateDimension":0,"type":"categorical"}],"identifiers":[{"bizName":"user_name","name":"用户名","type":"primary"}],"measures":[{"agg":"sum","bizName":"s2_stay_time_statis_stay_hours","expr":"stay_hours","isCreateMetric":1,"name":"停留时长"}],"queryType":"sql_query","sqlQuery":"SELECT imp_date, page,user_name,stay_hours FROM s2_stay_time_statis"}', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource (id , domain_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 , domain_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_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(1, 1, 1, 2, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(2, 1, 1, 3, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(3, 1, 2, 3, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(1, 1, 3, '部门', 'department', '部门', 1, 0, 'categorical', NULL, 'department', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(2, 1, 1, '用户名', 'user_name', '用户名', 1, 0, 'primary', NULL, 'user_name', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(3, 1, 2, '页面', 'page', '页面', 1, 2, 'categorical', NULL, 'page', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_domain (id, `name`, biz_name, parent_id, status, created_at, created_by, updated_at, updated_by, `admin`, admin_org, is_open, viewer, view_org) VALUES(1, '超音数', 'supersonic', 0, 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', 'admin', '', 0, 'admin,tom,jack', 'admin' ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(1, 1, '停留时长', 'stay_hours', '停留时长', 1, 2, 'expr', '{"expr":"s2_stay_time_statis_stay_hours","measures":[{"agg":"sum","expr":"stay_hours","isCreateMetric":1,"datasourceId":1,"bizName":"s2_stay_time_statis_stay_hours","name":"s2_stay_time_statis_stay_hours"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(2, 1, '访问次数', 'pv', '访问次数', 1, 0, 'expr', ' {"expr":"s2_pv_uv_statis_pv","measures":[{"agg":"sum","bizName":"s2_pv_uv_statis_pv","datasourceId":2,"expr":"pv","isCreateMetric":1,"name":"s2_pv_uv_statis_pv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(3, 1, '访问人数', 'uv', '访问人数', 1, 0, 'expr', ' {"expr":"s2_pv_uv_statis_uv","measures":[{"agg":"count_distinct","bizName":"s2_pv_uv_statis_uv","datasourceId":2,"expr":"uv","isCreateMetric":1,"name":"s2_pv_uv_statis_uv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); + +insert into s2_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, '{"domainId":"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, '{"domainId":"1","name":"tom_sales_permission","groupId":2,"authRules":[{"metrics":["stay_hours"],"dimensions":["page"]}],"dimensionFilters":["department in (''sales'')"],"dimensionFilterDescription":"开通 tom sales部门权限", "authorizedUsers":["tom"],"authorizedDepartmentIds":[]}'); + + +-- 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'); + +---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 ('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_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 new file mode 100644 index 000000000..e75454e90 --- /dev/null +++ b/launchers/standalone/src/main/resources/db/schema-h2.sql @@ -0,0 +1,341 @@ +-- 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 + `semantic_parse` LONGVARCHAR DEFAULT NULL , -- parse data + `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`) +) ; + + +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 '', + PRIMARY KEY (`question_id`) +); + + + +CREATE TABLE IF NOT EXISTS `s2_chat_config` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_id` INT DEFAULT NULL , + `default_metrics` varchar(655) DEFAULT NULL, + `visibility` varchar(655) , -- invisible dimension metric information + `entity_info` varchar(655) , + `dictionary_info` varchar(655) , -- dictionary-related dimension setting information + `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_dictionary` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_id` INT NOT NULL , + `dim_value_infos` LONGVARCHAR , -- dimension value setting information + `created_at` TIMESTAMP NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_by` varchar(100) DEFAULT 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`), + UNIQUE (domain_id) + ); +COMMENT ON TABLE s2_dictionary IS 'dictionary configuration information table'; + + +CREATE TABLE IF NOT EXISTS `s2_dictionary_task` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL , -- task name + `description` varchar(255) , + `command`LONGVARCHAR NOT NULL , -- task Request Parameters + `command_md5` varchar(255) NOT NULL , -- task Request Parameters md5 + `status` INT NOT NULL , -- the final status of the task + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP , + `created_by` varchar(100) NOT NULL , + `progress` DOUBLE default 0.00 , -- task real-time progress + `elapsed_ms` bigINT DEFAULT NULL , -- the task takes time in milliseconds + `message` LONGVARCHAR , -- remark related information + PRIMARY KEY (`id`) +); +COMMENT ON TABLE s2_dictionary_task IS 'dictionary task information table'; + + +create table s2_user +( + id INT AUTO_INCREMENT, + name varchar(100) not null, + display_name varchar(100) null, + password varchar(100) null, + email varchar(100) null, + PRIMARY KEY (`id`) +); +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 , + `is_unique` INT DEFAULT NULL , -- 0 is non-unique, 1 is unique + `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 `s2_database` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `description` varchar(500) 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, + `domain_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), + PRIMARY KEY (`group_id`) +); + +CREATE TABLE IF NOT EXISTS `s2_metric` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_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 , + `created_at` TIMESTAMP 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`) + ); +COMMENT ON TABLE s2_metric IS 'metric information table'; + + +CREATE TABLE IF NOT EXISTS `s2_dimension` ( + `id` INT NOT NULL AUTO_INCREMENT , + `domain_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 , + `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, + PRIMARY KEY (`id`) + ); +COMMENT ON TABLE s2_dimension IS 'dimension information table'; + +create table s2_datasource_rela +( + id INT AUTO_INCREMENT, + domain_id INT null, + datasource_from INT null, + datasource_to INT null, + join_key varchar(100) null, + created_at TIMESTAMP null, + created_by varchar(100) null, + updated_at TIMESTAMP null, + updated_by varchar(100) null, + PRIMARY KEY (`id`) +); +COMMENT ON TABLE s2_datasource_rela IS 'data source association table'; + +create table s2_view_info +( + id INT auto_increment, + domain_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_by varchar(100) not null +); +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 + `domain_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 , + `domain_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 , + `status` INT NOT NULL , + `elapsed_ms` bigINT DEFAULT NULL , + PRIMARY KEY (`id`) + ); +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 , + `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'; + + +-------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 + ); +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 + ); +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, + `stay_hours` DOUBLE NOT NULL, + `page` varchar(200) NOT NULL + ); +COMMENT ON TABLE s2_stay_time_statis IS 's2_stay_time_statis_info'; + + + + + + diff --git a/launchers/standalone/src/main/resources/hanlp.properties b/launchers/standalone/src/main/resources/hanlp.properties new file mode 100644 index 000000000..9d91904eb --- /dev/null +++ b/launchers/standalone/src/main/resources/hanlp.properties @@ -0,0 +1,2 @@ +root=. +CustomDictionaryPath=data/dictionary/custom/DimValue_1_1.txt;data/dictionary/custom/DimValue_1_2.txt;data/dictionary/custom/DimValue_1_3.txt; \ No newline at end of file diff --git a/launchers/standalone/src/main/resources/logback-spring.xml b/launchers/standalone/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..810eda9b3 --- /dev/null +++ b/launchers/standalone/src/main/resources/logback-spring.xml @@ -0,0 +1,93 @@ + + + logback + + + + + + + %d{HH:mm:ss} [%thread] %-5level %logger{36} %line - %msg%n + + + + + + ${LOG_PATH}/info.${LOG_APPNAME}.log + + + + ${LOG_PATH}/info.${LOG_APPNAME}.%d{yyyy-MM-dd}.log.gz + + 30 + + + + + + UTF-8 + %d [%thread] %-5level [%X{TRACE_ID}] %logger{36} %line - %msg%n + + + + + + + Error + + + ${LOG_PATH}/error.${LOG_APPNAME}.log + + + + ${LOG_PATH}/error.${LOG_APPNAME}.%d{yyyy-MM-dd}.log.gz + + 90 + + + + + + UTF-8 + %d [%thread] %-5level [%X{TRACE_ID}] %logger{36} %line - %msg%n + + + + + + + + + + + + ${LOG_PATH}/serviceinfo.${LOG_APPNAME}.log + + + + ${LOG_PATH}/serviceinfo.${LOG_APPNAME}.%d{yyyy-MM-dd}.log.gz + + 30 + + + + + + UTF-8 + %d [%thread] %-5level [%X{TRACE_ID}] %logger{36} %line - %msg%n + + + + + + + \ No newline at end of file diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/db/MybatisConfig.java b/launchers/standalone/src/test/java/com/tencent/supersonic/db/MybatisConfig.java new file mode 100644 index 000000000..f3428741a --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/db/MybatisConfig.java @@ -0,0 +1,31 @@ +package com.tencent.supersonic.db; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import javax.sql.DataSource; + + +@Configuration +@MapperScan(value = "com.tencent.supersonic", annotationClass = Mapper.class) +public class MybatisConfig { + + private static final String MAPPER_LOCATION = "classpath*:mapper/**/*.xml"; + + @Bean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { + SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); + org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); + configuration.setMapUnderscoreToCamelCase(true); + bean.setConfiguration(configuration); + bean.setDataSource(dataSource); + + bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION)); + return bean.getObject(); + } +} diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/test/QueryIntegrationTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/test/QueryIntegrationTest.java new file mode 100644 index 000000000..14bf6ff77 --- /dev/null +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/test/QueryIntegrationTest.java @@ -0,0 +1,371 @@ +package com.tencent.supersonic.test; + +import com.tencent.supersonic.StandaloneLauncher; +import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.chat.api.pojo.Filter; +import com.tencent.supersonic.chat.api.request.QueryContextReq; +import com.tencent.supersonic.chat.api.response.QueryResultResp; +import com.tencent.supersonic.chat.application.query.MetricCompare; +import com.tencent.supersonic.chat.application.query.MetricDomain; +import com.tencent.supersonic.chat.application.query.MetricFilter; +import com.tencent.supersonic.chat.application.query.MetricGroupBy; +import com.tencent.supersonic.chat.domain.service.ChatService; +import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.common.pojo.SchemaItem; +import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import com.tencent.supersonic.chat.domain.service.QueryService; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = StandaloneLauncher.class) +@ActiveProfiles("local") +public class QueryIntegrationTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(QueryIntegrationTest.class); + + @Autowired + private ChatService chatService; + + @Autowired + @Qualifier("chatQueryService") + private QueryService queryService; + + //case:alice的访问次数,queryMode:METRIC_FILTER, + @Test + public void queryTest1() { + QueryContextReq queryContextReq = getQueryContextReq("alice的访问次数"); + try { + QueryResultResp queryResultResp = queryService.executeQuery(queryContextReq); + LOGGER.info("QueryResultResp queryResultResp:{}", queryResultResp); + //assert queryState + Assert.assertEquals(queryResultResp.getQueryState(), 0); + //assert queryMode + Assert.assertEquals(queryResultResp.getQueryMode(), MetricFilter.QUERY_MODE); + //assert aggType + Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); + //assert 主题域Id + assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); + + //assert 指标 + Set metrics = queryResultResp.getChatContext().getMetrics(); + SchemaItem schemaItemMetric = new SchemaItem(); + schemaItemMetric.setId(2L); + schemaItemMetric.setName("访问次数"); + schemaItemMetric.setBizName("pv"); + Boolean metricExist = false; + for (SchemaItem schemaItem : metrics) { + if (schemaItem.getId().equals(schemaItemMetric.getId()) && + schemaItem.getName().equals(schemaItemMetric.getName()) && + schemaItem.getBizName().equals(schemaItemMetric.getBizName())) { + metricExist = true; + } + } + assertThat(metricExist).isEqualTo(true); + + //assert 维度 + Set dimensions = queryResultResp.getChatContext().getDimensions(); + SchemaItem schemaItemDimension = new SchemaItem(); + schemaItemDimension.setBizName("sys_imp_date"); + Boolean dimensionExist = false; + for (SchemaItem schemaItem : dimensions) { + if (schemaItem.getBizName().equals(schemaItemDimension.getBizName())) { + dimensionExist = true; + } + } + assertThat(dimensionExist).isEqualTo(true); + + //assert 维度filter + Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); + Filter dimensionFilter = new Filter(); + dimensionFilter.setBizName("user_name"); + dimensionFilter.setOperator(FilterOperatorEnum.EQUALS); + dimensionFilter.setValue("alice"); + dimensionFilter.setName("用户名"); + dimensionFilter.setElementID(2L); + Boolean dimensionFilterExist = false; + for (Filter filter : dimensionFilters) { + if (filter.getBizName().equals(dimensionFilter.getBizName()) && + filter.getOperator().equals(dimensionFilter.getOperator()) && + filter.getValue().equals(dimensionFilter.getValue()) && + filter.getElementID().equals(dimensionFilter.getElementID()) && + filter.getName().equals(dimensionFilter.getName())) { + dimensionFilterExist = true; + } + } + assertThat(dimensionFilterExist).isEqualTo(true); + + //assert 时间filter + DateConf dateInfo = new DateConf(); + dateInfo.setUnit(7); + dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); + dateInfo.setPeriod("DAY"); + Boolean timeFilterExist = + queryResultResp.getChatContext().getDateInfo().getUnit().equals(dateInfo.getUnit()) && + queryResultResp.getChatContext().getDateInfo().getDateMode().equals(dateInfo.getDateMode()) + && + queryResultResp.getChatContext().getDateInfo().getPeriod().equals(dateInfo.getPeriod()); + assertThat(timeFilterExist).isEqualTo(true); + + //assert nativeQuery + assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); + + } catch (Exception e) { + + } + } + + //case:超音数的访问次数,queryMode:METRIC_DOMAIN + @Test + public void queryTest2() { + QueryContextReq queryContextReq = getQueryContextReq("超音数的访问次数"); + try { + QueryResultResp queryResultResp = queryService.executeQuery(queryContextReq); + LOGGER.info("QueryResultResp queryResultResp:{}", queryResultResp); + //assert queryState + Assert.assertEquals(queryResultResp.getQueryState(), 0); + //assert queryMode + Assert.assertEquals(queryResultResp.getQueryMode(), MetricDomain.QUERY_MODE); + //assert aggType + Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); + //assert 主题域Id + assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); + + //assert 指标 + Set metrics = queryResultResp.getChatContext().getMetrics(); + SchemaItem schemaItemMetric = new SchemaItem(); + schemaItemMetric.setId(2L); + schemaItemMetric.setName("访问次数"); + schemaItemMetric.setBizName("pv"); + Boolean metricExist = false; + for (SchemaItem schemaItem : metrics) { + if (schemaItem.getId().equals(schemaItemMetric.getId()) && + schemaItem.getName().equals(schemaItemMetric.getName()) && + schemaItem.getBizName().equals(schemaItemMetric.getBizName())) { + metricExist = true; + } + } + assertThat(metricExist).isEqualTo(true); + + //assert 维度 + Set dimensions = queryResultResp.getChatContext().getDimensions(); + SchemaItem schemaItemDimension = new SchemaItem(); + schemaItemDimension.setBizName("sys_imp_date"); + Boolean dimensionExist = false; + for (SchemaItem schemaItem : dimensions) { + if (schemaItem.getBizName().equals(schemaItemDimension.getBizName())) { + dimensionExist = true; + } + } + assertThat(dimensionExist).isEqualTo(true); + + //assert 时间filter + DateConf dateInfo = new DateConf(); + dateInfo.setUnit(7); + dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); + dateInfo.setPeriod("DAY"); + Boolean timeFilterExist = + queryResultResp.getChatContext().getDateInfo().getUnit().equals(dateInfo.getUnit()) && + queryResultResp.getChatContext().getDateInfo().getDateMode().equals(dateInfo.getDateMode()) + && + queryResultResp.getChatContext().getDateInfo().getPeriod().equals(dateInfo.getPeriod()); + assertThat(timeFilterExist).isEqualTo(true); + + //assert nativeQuery + assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); + + } catch (Exception e) { + + } + } + + + //case:超音数各部门的访问次数,queryMode:METRIC_GROUPBY + @Test + public void queryTest3() { + QueryContextReq queryContextReq = getQueryContextReq("超音数各部门的访问次数"); + try { + QueryResultResp queryResultResp = queryService.executeQuery(queryContextReq); + LOGGER.info("QueryResultResp queryResultResp:{}", queryResultResp); + //assert queryState + Assert.assertEquals(queryResultResp.getQueryState(), 0); + //assert queryMode + Assert.assertEquals(queryResultResp.getQueryMode(), MetricGroupBy.QUERY_MODE); + //assert aggType + Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); + //assert 主题域Id + assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); + + //assert 指标 + Set metrics = queryResultResp.getChatContext().getMetrics(); + SchemaItem schemaItemMetric = new SchemaItem(); + schemaItemMetric.setId(2L); + schemaItemMetric.setName("访问次数"); + schemaItemMetric.setBizName("pv"); + Boolean metricExist = false; + for (SchemaItem schemaItem : metrics) { + if (schemaItem.getId().equals(schemaItemMetric.getId()) && + schemaItem.getName().equals(schemaItemMetric.getName()) && + schemaItem.getBizName().equals(schemaItemMetric.getBizName())) { + metricExist = true; + } + } + assertThat(metricExist).isEqualTo(true); + + //assert 维度 + Set dimensions = queryResultResp.getChatContext().getDimensions(); + SchemaItem schemaItemDimension = new SchemaItem(); + schemaItemDimension.setBizName("sys_imp_date"); + Boolean dimensionExist = false; + for (SchemaItem schemaItem : dimensions) { + if (schemaItem.getBizName().equals(schemaItemDimension.getBizName())) { + dimensionExist = true; + } + } + assertThat(dimensionExist).isEqualTo(true); + + SchemaItem schemaItemDimension1 = new SchemaItem(); + schemaItemDimension1.setBizName("department"); + schemaItemDimension1.setName("部门"); + schemaItemDimension1.setId(1L); + Boolean dimensionExist1 = false; + for (SchemaItem schemaItem : dimensions) { + if (schemaItem.getBizName().equals(schemaItemDimension1.getBizName()) && + schemaItem.getId().equals(schemaItemDimension1.getId()) && + schemaItem.getName().equals(schemaItemDimension1.getName())) { + dimensionExist1 = true; + } + } + assertThat(dimensionExist1).isEqualTo(true); + + //assert 时间filter + DateConf dateInfo = new DateConf(); + dateInfo.setUnit(7); + dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); + dateInfo.setPeriod("DAY"); + Boolean timeFilterExist = + queryResultResp.getChatContext().getDateInfo().getUnit().equals(dateInfo.getUnit()) && + queryResultResp.getChatContext().getDateInfo().getDateMode().equals(dateInfo.getDateMode()) + && + queryResultResp.getChatContext().getDateInfo().getPeriod().equals(dateInfo.getPeriod()); + assertThat(timeFilterExist).isEqualTo(true); + + //assert nativeQuery + assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); + + } catch (Exception e) { + + } + } + + + //case:对比alice和lucy的访问次数,queryMode:METRIC_COMPARE + @Test + public void queryTest4() { + QueryContextReq queryContextReq = getQueryContextReq("对比alice和lucy的访问次数"); + try { + QueryResultResp queryResultResp = queryService.executeQuery(queryContextReq); + LOGGER.info("QueryResultResp queryResultResp:{}", queryResultResp); + //assert queryState + Assert.assertEquals(queryResultResp.getQueryState(), 0); + //assert queryMode + Assert.assertEquals(queryResultResp.getQueryMode(), MetricCompare.QUERY_MODE); + //assert aggType + Assert.assertEquals(queryResultResp.getChatContext().getAggType(), null); + //assert 主题域Id + assertThat(queryResultResp.getChatContext().getDomainId()).isEqualTo(1L); + + //assert 指标 + Set metrics = queryResultResp.getChatContext().getMetrics(); + SchemaItem schemaItemMetric = new SchemaItem(); + schemaItemMetric.setId(2L); + schemaItemMetric.setName("访问次数"); + schemaItemMetric.setBizName("pv"); + Boolean metricExist = false; + for (SchemaItem schemaItem : metrics) { + if (schemaItem.getId().equals(schemaItemMetric.getId()) && + schemaItem.getName().equals(schemaItemMetric.getName()) && + schemaItem.getBizName().equals(schemaItemMetric.getBizName())) { + metricExist = true; + } + } + assertThat(metricExist).isEqualTo(true); + + //assert 维度 + Set dimensions = queryResultResp.getChatContext().getDimensions(); + SchemaItem schemaItemDimension = new SchemaItem(); + schemaItemDimension.setBizName("sys_imp_date"); + Boolean dimensionExist = false; + for (SchemaItem schemaItem : dimensions) { + if (schemaItem.getBizName().equals(schemaItemDimension.getBizName())) { + dimensionExist = true; + } + } + assertThat(dimensionExist).isEqualTo(true); + + //assert 维度filter + Set dimensionFilters = queryResultResp.getChatContext().getDimensionFilters(); + Filter dimensionFilter = new Filter(); + dimensionFilter.setBizName("user_name"); + dimensionFilter.setOperator(FilterOperatorEnum.IN); + List list = new ArrayList<>(); + list.add("alice"); + list.add("lucy"); + dimensionFilter.setValue(list); + dimensionFilter.setName("用户名"); + dimensionFilter.setElementID(2L); + Boolean dimensionFilterExist = false; + for (Filter 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())) { + dimensionFilterExist = true; + } + } + assertThat(dimensionFilterExist).isEqualTo(true); + + //assert 时间filter + DateConf dateInfo = new DateConf(); + dateInfo.setUnit(7); + dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS); + dateInfo.setPeriod("DAY"); + Boolean timeFilterExist = + queryResultResp.getChatContext().getDateInfo().getUnit().equals(dateInfo.getUnit()) && + queryResultResp.getChatContext().getDateInfo().getDateMode().equals(dateInfo.getDateMode()) + && + queryResultResp.getChatContext().getDateInfo().getPeriod().equals(dateInfo.getPeriod()); + assertThat(timeFilterExist).isEqualTo(true); + + //assert nativeQuery + assertThat(queryResultResp.getChatContext().getNativeQuery()).isEqualTo(false); + + } catch (Exception e) { + + } + } + + public QueryContextReq getQueryContextReq(String query) { + QueryContextReq queryContextReq = new QueryContextReq(); + queryContextReq.setQueryText(query);//"alice的访问次数" + queryContextReq.setChatId(1); + queryContextReq.setUser(new User(1L, "admin", "admin", "admin@email")); + return queryContextReq; + } + +} diff --git a/launchers/standalone/src/test/resources/META-INF/spring.factories b/launchers/standalone/src/test/resources/META-INF/spring.factories new file mode 100644 index 000000000..bc01631d4 --- /dev/null +++ b/launchers/standalone/src/test/resources/META-INF/spring.factories @@ -0,0 +1,23 @@ +com.tencent.supersonic.chat.api.component.SchemaMapper=\ + com.tencent.supersonic.chat.application.mapper.HanlpSchemaMapper + +com.tencent.supersonic.chat.api.component.SemanticParser=\ + com.tencent.supersonic.chat.application.parser.DomainSemanticParser, \ + com.tencent.supersonic.chat.application.parser.TimeSemanticParser, \ + com.tencent.supersonic.chat.application.parser.AggregateSemanticParser +# com.tencent.supersonic.chat.application.parser.LLMSemanticParser + +com.tencent.supersonic.chat.api.component.QueryProcessor=\ + com.tencent.supersonic.chat.application.processor.SemanticQueryProcessor + +com.tencent.supersonic.chat.api.component.SemanticLayer=\ + com.tencent.supersonic.chat.infrastructure.semantic.LocalSemanticLayerImpl + +com.tencent.supersonic.chat.application.query.QuerySelector=\ + com.tencent.supersonic.chat.application.query.HeuristicQuerySelector + +com.tencent.supersonic.chat.application.query.DomainResolver=\ + com.tencent.supersonic.chat.application.query.HeuristicDomainResolver + +com.tencent.supersonic.auth.authentication.domain.interceptor.AuthenticationInterceptor=\ + com.tencent.supersonic.auth.authentication.domain.interceptor.DefaultAuthenticationInterceptor diff --git a/launchers/standalone/src/test/resources/application-local.yaml b/launchers/standalone/src/test/resources/application-local.yaml new file mode 100644 index 000000000..4c029c184 --- /dev/null +++ b/launchers/standalone/src/test/resources/application-local.yaml @@ -0,0 +1,28 @@ +spring: + h2: + console: + path: /h2-console/chat + # enabled web + enabled: true + datasource: + driver-class-name: org.h2.Driver + schema: classpath:db/schema-h2.sql + data: classpath:db/data-h2.sql + url: jdbc:h2:mem:semantic;DATABASE_TO_UPPER=false + username: root + password: semantic + +server: + port: 9080 + +authentication: + enable: false + exclude: + path: /api/auth/user/register,/api/auth/user/login + +semantic: + url: + prefix: http://127.0.0.1:9081 + +mybatis: + mapper-locations=classpath:mappers/custom/*.xml,classpath*:/mappers/*.xml diff --git a/launchers/standalone/src/test/resources/application.yaml b/launchers/standalone/src/test/resources/application.yaml new file mode 100644 index 000000000..83b731d26 --- /dev/null +++ b/launchers/standalone/src/test/resources/application.yaml @@ -0,0 +1,7 @@ +spring: + profiles: + active: local + application: + name: chat +mybatis: + mapper-locations=classpath:mappers/custom/*.xml,classpath*:/mappers/*.xml diff --git a/launchers/standalone/src/test/resources/data/README.url b/launchers/standalone/src/test/resources/data/README.url new file mode 100644 index 000000000..e37374f27 --- /dev/null +++ b/launchers/standalone/src/test/resources/data/README.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=https://github.com/hankcs/HanLP/ diff --git a/launchers/standalone/src/test/resources/data/dictionary/CoreNatureDictionary.mini.txt b/launchers/standalone/src/test/resources/data/dictionary/CoreNatureDictionary.mini.txt new file mode 100644 index 000000000..6014daa6e --- /dev/null +++ b/launchers/standalone/src/test/resources/data/dictionary/CoreNatureDictionary.mini.txt @@ -0,0 +1,3 @@ +龚 nr 1 +龛 ng 1 +龛影 n 1 \ No newline at end of file diff --git a/launchers/standalone/src/test/resources/data/dictionary/CoreNatureDictionary.ngram.mini.txt b/launchers/standalone/src/test/resources/data/dictionary/CoreNatureDictionary.ngram.mini.txt new file mode 100644 index 000000000..562f7f1cc --- /dev/null +++ b/launchers/standalone/src/test/resources/data/dictionary/CoreNatureDictionary.ngram.mini.txt @@ -0,0 +1,4 @@ +买@水果 1 +然后@来 1 +我@遗忘 10 +遗忘@我 10 \ No newline at end of file diff --git a/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_1.txt b/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_1.txt new file mode 100644 index 000000000..c21ae2edb --- /dev/null +++ b/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_1.txt @@ -0,0 +1,5 @@ +hr _1_1 876 +sales _1_1 872 +marketing _1_1 310 +strategy _1_1 360 +sales _1_1 500 \ No newline at end of file diff --git a/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_2.txt b/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_2.txt new file mode 100644 index 000000000..e0570f4b0 --- /dev/null +++ b/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_2.txt @@ -0,0 +1,7 @@ +tom _1_2 52 +alice _1_2 47 +lucy _1_2 31 +dean _1_2 36 +john _1_2 50 +jack _1_2 38 +admin _1_2 70 \ No newline at end of file diff --git a/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_3.txt b/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_3.txt new file mode 100644 index 000000000..f519c23fb --- /dev/null +++ b/launchers/standalone/src/test/resources/data/dictionary/custom/DimValue_1_3.txt @@ -0,0 +1,6 @@ +p1 _1_3 52 +p2 _1_3 47 +p3 _1_3 31 +p4 _1_3 36 +p5 _1_3 50 +p6 _1_3 38 \ No newline at end of file diff --git a/launchers/standalone/src/test/resources/data/dictionary/other/CharTable.txt b/launchers/standalone/src/test/resources/data/dictionary/other/CharTable.txt new file mode 100644 index 000000000..a66a33e07 --- /dev/null +++ b/launchers/standalone/src/test/resources/data/dictionary/other/CharTable.txt @@ -0,0 +1,4890 @@ += +A=a +B=b +C=c +D=d +E=e +F=f +G=g +H=h +I=i +J=j +K=k +L=l +M=m +N=n +O=o +P=p +Q=q +R=r +S=s +T=t +U=u +V=v +W=w +X=x +Y=y +Z=z +[=《 +]=》 +{=《 +}=》 + = +«=《 +»=》 +“=" +”=" +•=· +‹=《 +›=》 +①=一 +②=二 +③=三 +④=四 +⑤=五 +⑥=六 +⑦=七 +⑧=八 +⑨=九 +⑩=十 +〈=《 +〉=》 +「=“ +」=” +『=‘ +』=’ +【=《 +】=》 +〔=《 +〕=》 +〖=《 +〗=" +〝=" +〞=" +と=之 +ふ=子 +ル=儿 +ㄖ=日 +丟=丢 +両=两 +並=并 +丼=井 +乁=乙 +乗=乘 +乧=斗 +乷=沙 +乹=乾 +乾=干 +亀=龟 +亁=乾 +亂=乱 +亙=亘 +亝=斋 +亞=亚 +亯=享 +亱=夜 +亷=廉 +亾=亡 +仈=八 +仏=佛 +仛=托 +仩=上 +仯=秒 +仴=月 +仸=袄 +仹=丰 +仺=仓 +伕=夫 +伖=友 +伝=传 +伮=奴 +佀=侣 +佇=伫 +佋=召 +佔=占 +佘=畲 +佡=仙 +佪=徊 +佱=企 +佲=铭 +併=并 +佷=很 +佹=危 +佽=次 +侀=型 +來=来 +侇=姨 +侎=眯 +侓=律 +侖=仑 +侢=再 +侶=侣 +侷=局 +侹=廷 +俁=俣 +係=系 +俆=徐 +俔=伣 +俠=侠 +俢=修 +俥=伡 +俬=私 +俻=备 +俽=欣 +倀=伥 +倁=蜘 +倂=并 +倆=俩 +倈=俫 +倉=仓 +個=个 +倐=倏 +們=们 +倖=幸 +倞=京 +倣=仿 +倫=伦 +倳=事 +倶=具 +倸=睬 +倹=俭 +倻=椰 +倽=啥 +偅=重 +偉=伟 +偓=屋 +偘=侃 +偡=湛 +偢=秋 +偪=逼 +偲=思 +側=侧 +偵=侦 +偸=偷 +偺=咱 +偽=伪 +傑=杰 +傓=扇 +傖=伧 +傘=伞 +備=备 +傚=效 +傢=家 +傪=参 +傭=佣 +傯=偬 +傳=传 +傴=伛 +債=债 +傷=伤 +傹=镜 +傾=倾 +僂=偻 +僅=仅 +僉=佥 +僊=仙 +働=動 +僐=善 +僑=侨 +僒=窘 +僕=仆 +僜=澄 +僞=伪 +僟=机 +僥=侥 +僨=偾 +僮=童 +僱=雇 +價=价 +僽=愁 +儀=仪 +儁=俊 +儂=侬 +億=亿 +儈=侩 +儉=俭 +儌=侥 +儐=傧 +儔=俦 +儕=侪 +儘=尽 +償=偿 +優=优 +儭=亲 +儲=储 +儵=倏 +儷=俪 +儸=箩 +儹=攒 +儺=傩 +儻=傥 +儼=俨 +兇=凶 +兌=兑 +兎=兔 +兒=儿 +兗=兖 +兠=兜 +內=内 +兩=两 +兯=节 +兲=天 +兿=艺 +冄=冉 +冇=没 +冊=册 +冋=回 +冐=冒 +冨=富 +冩=写 +冪=幂 +冴=讶 +冺=泯 +凂=免 +凃=涂 +凅=固 +凈=净 +凊=清 +凍=冻 +凗=摧 +凘=斯 +凜=凛 +凞=熙 +凢=几 +凣=凡 +処=处 +凧=巾 +凱=凯 +凲=兼 +凴=凭 +凾=涵 +刄=刃 +刅=办 +刋=刊 +別=别 +刦=劫 +刧=劫 +刪=删 +刴=剁 +刼=劫 +剄=刭 +則=则 +剋=克 +剎=刹 +剏=创 +剗=刬 +剘=期 +剙=創 +剛=刚 +剝=剥 +剨=割 +剮=剐 +剳=劄 +剴=剀 +創=创 +剷=铲 +剹=戮 +剼=删 +劃=划 +劄=札 +劇=剧 +劈=噼 +劉=刘 +劊=刽 +劌=刿 +劍=剑 +劑=剂 +劒=剑 +劦=力 +効=效 +勁=劲 +勄=敏 +勅=敕 +勌=倦 +動=动 +勗=勖 +務=务 +勛=勋 +勝=胜 +勞=劳 +勠=戮 +勢=势 +勦=剿 +勧=劝 +勩=勚 +勱=劢 +勳=勋 +勵=励 +勸=劝 +勻=匀 +勼=九 +匄=亡 +匊=菊 +匋=掏 +匑=躬 +匢=勿 +匨=壮 +匬=愈 +匭=匦 +匯=汇 +匱=匮 +匲=奁 +匳=奁 +匴=算 +匵=椟 +匼=合 +匽=宴 +區=区 +卂=汛 +卆=杂 +協=协 +卙=甚 +卛=率 +卬=仰 +卲=邵 +卹=恤 +卻=却 +卽=即 +厊=芽 +厐=庞 +厔=室 +厗=辛 +厙=厍 +厛=听 +厞=匪 +厠=厕 +厡=原 +厤=历 +厫=廒 +厭=厌 +厯=历 +厰=厂 +厲=厉 +厴=厣 +厷=公 +厾=去 +參=参 +叄=叁 +収=收 +叒=双 +叚=假 +叜=叟 +叡=睿 +叢=丛 +叧=另 +叺=入 +吂=盲 +吒=咤 +吘=午 +吚=咿 +吢=吣 +吳=吴 +吶=呐 +吷=决 +吿=告 +呁=钧 +呂=吕 +呉=吴 +呌=叫 +呎=迟 +呞=司 +呪=咒 +呮=只 +呱=哌 +呴=句 +呺=号 +咊=和 +咑=打 +咓=瓦 +咗=左 +咜=它 +咟=百 +咮=珠 +咰=询 +咷=啕 +咼=呙 +哃=同 +哋=的 +哠=告 +員=员 +哢=咔 +哣=痘 +哬=呵 +哯=现 +哴=琅 +哾=悦 +唂=谷 +唄=呗 +唍=完 +唎=例 +唕=唣 +唘=启 +唚=吣 +唡=俩 +唥=冷 +唦=砂 +唫=金 +唰=刷 +唵=俺 +唶=锡 +唸=念 +唻=来 +唽=析 +啇=商 +啌=控 +啍=享 +啎=忤 +問=问 +啑=捷 +啓=启 +啗=啖 +啘=婉 +啚=鄙 +啝=和 +啞=哑 +啟=启 +啢=唡 +啣=衔 +啨=晴 +啩=挂 +啱=岩 +啴=单 +喎=㖞 +喐=郁 +喒=咱 +喖=枯 +喚=唤 +喥=度 +喦=岩 +喪=丧 +喫=吃 +喬=乔 +單=单 +喰=食 +喲=哟 +営=宫 +喼=急 +嗁=啼 +嗆=呛 +嗇=啬 +嗊=唝 +嗎=吗 +嗏=茶 +嗐=害 +嗗=骨 +嗚=呜 +嗛=谦 +嗩=唢 +嗬=呵 +嗱=拿 +嗶=哔 +嗹=莲 +嗻=遮 +嗼=摸 +嘂=叫 +嘄=鸣 +嘆=叹 +嘋=教 +嘍=喽 +嘓=啯 +嘔=呕 +嘖=啧 +嘗=尝 +嘙=婆 +嘚=得 +嘜=唛 +嘠=嘎 +嘢=野 +嘩=哗 +嘫=然 +嘮=唠 +嘯=啸 +嘰=叽 +嘵=哓 +嘸=呒 +嘽=啴 +噂=遵 +噅=咴 +噉=啖 +噐=器 +噑=嗥 +噓=嘘 +噖=琴 +噝=咝 +噠=哒 +噥=哝 +噦=哕 +噭=激 +噯=嗳 +噲=哙 +噴=喷 +噸=吨 +噹=当 +噺=新 +嚀=咛 +嚂=滥 +嚇=吓 +嚌=哜 +嚐=尝 +嚕=噜 +嚗=爆 +嚙=啮 +嚜=墨 +嚠=刘 +嚡=鞋 +嚤=蘑 +嚦=呖 +嚨=咙 +嚮=向 +嚲=亸 +嚳=喾 +嚴=严 +嚶=嘤 +囀=啭 +囁=嗫 +囂=嚣 +囅=冁 +囈=呓 +囉=啰 +囑=嘱 +囓=啮 +囗=口 +囘=回 +囙=因 +囥=亢 +囩=云 +囪=囱 +囬=回 +囮=化 +囯=国 +囸=正 +圅=函 +圇=囵 +國=国 +圍=围 +圎=园 +園=园 +圓=圆 +圖=图 +團=团 +圝=圞 +圤=扑 +圧=庄 +圱=升 +圵=止 +圷=吓 +坆=玫 +坧=石 +坰=垧 +坵=丘 +坿=附 +垇=坳 +垉=咆 +垐=茨 +垜=垛 +垨=守 +垯=达 +垳=行 +垵=埯 +垹=绑 +垿=序 +埐=侵 +埖=花 +埜=野 +埡=垭 +埥=请 +埰=采 +埱=叔 +埳=坎 +執=执 +堅=坚 +堊=垩 +堒=坤 +堔=深 +堖=垴 +堘=塍 +堝=埚 +堦=階 +堯=尧 +報=报 +場=场 +堷=音 +堿=碱 +塆=弯 +塊=块 +塋=茔 +塏=垲 +塒=埘 +塖=乘 +塗=涂 +塚=冢 +塟=葬 +塡=填 +塢=坞 +塤=埙 +塨=恭 +塮=谢 +塲=场 +塵=尘 +塹=堑 +塼=砖 +墊=埝 +墖=塔 +墘=乾 +墛=蔚 +墜=坠 +墪=墩 +墭=盛 +墮=堕 +墳=坟 +墵=坛 +墶=垯 +墻=墙 +墾=垦 +壃=僵 +壄=野 +壇=坛 +壋=垱 +壎=埙 +壓=压 +壖=堧 +壘=垒 +壙=圹 +壚=垆 +壜=坛 +壞=坏 +壟=垅 +壠=垅 +壢=坜 +壩=坝 +壪=塆 +壯=壮 +壺=壶 +壻=婿 +壼=壸 +壽=寿 +壿=蹲 +夀=寿 +夃=孕 +夅=降 +夌=菱 +夗=苑 +夘=卯 +夝=胜 +夠=够 +夢=梦 +夥=伙 +夰=介 +夲=本 +夾=夹 +奐=奂 +奧=奥 +奨=奖 +奩=奁 +奪=夺 +奬=奖 +奮=奋 +奷=奸 +奼=姹 +妀=改 +妏=文 +妑=芭 +妔=坑 +妕=钟 +妝=妆 +妠=呐 +妢=纷 +妬=妒 +妭=拨 +妱=招 +妳=你 +妶=弦 +妷=失 +妸=可 +妺=妹 +妽=申 +姃=征 +姄=民 +姉=姊 +姌=冉 +姍=姗 +姎=央 +姖=巨 +姙=妊 +姟=该 +姠=响 +姦=奸 +姧=歼 +姩=年 +姪=侄 +姵=佩 +姸=妍 +姺=先 +娕=束 +娖=促 +娛=娱 +娝=否 +娦=兵 +娪=语 +娫=延 +娬=武 +娯=娱 +娸=其 +娿=啊 +婁=娄 +婂=锦 +婄=赔 +婇=菜 +婑=矮 +婔=菲 +婖=添 +婜=娶 +婣=姻 +婤=稠 +婥=卓 +婦=妇 +婫=混 +婬=淫 +婭=娅 +婯=丽 +婸=扬 +婹=要 +婼=若 +媈=挥 +媌=苗 +媍=妇 +媔=面 +媗=喧 +媙=威 +媟=谍 +媠=惰 +媣=染 +媥=偏 +媦=胃 +媧=娲 +媨=酋 +媫=婕 +媯=妫 +媴=袁 +媷=辱 +媹=溜 +媼=媪 +媽=妈 +媿=愧 +嫃=真 +嫆=蓉 +嫊=素 +嫋=袅 +嫎=膀 +嫗=妪 +嫙=旋 +嫚=蔓 +嫝=康 +嫟=匿 +嫧=责 +嫰=嫩 +嫲=麻 +嫵=妩 +嫺=娴 +嫻=娴 +嫼=黑 +嫽=撩 +嫿=婳 +嬀=妫 +嬈=娆 +嬋=婵 +嬌=娇 +嬑=意 +嬘=遂 +嬙=嫱 +嬝=袅 +嬡=嫒 +嬤=嬷 +嬪=嫔 +嬭=奶 +嬰=婴 +嬶=鼻 +嬸=婶 +嬾=懒 +嬿=燕 +孃=娘 +孄=栏 +孌=娈 +孒=了 +孡=抬 +孧=幼 +孫=孙 +孶=孳 +學=学 +孼=孽 +孿=孪 +宂=冗 +宖=宏 +宮=宫 +宼=寇 +寀=采 +寃=冤 +寑=寝 +寕=宁 +寢=寝 +實=实 +寧=宁 +審=审 +寫=写 +寬=宽 +寲=疑 +寳=宝 +寵=宠 +寶=宝 +尅=克 +將=将 +專=专 +尋=寻 +對=对 +導=导 +尒=尔 +尙=尚 +尟=鲜 +尠=鲜 +尩=尪 +尫=尪 +尲=尴 +尷=尴 +屆=届 +屍=尸 +屓=屃 +屗=尾 +屙=疴 +屚=漏 +屛=屏 +屜=屉 +屟=屉 +屢=屡 +層=层 +屨=屦 +屬=属 +屭=屃 +屰=逆 +屾=山 +岅=坂 +岆=妖 +岠=拒 +岡=冈 +岥=坡 +岼=坪 +峝=峒 +峩=峨 +峫=邪 +峬=捕 +峮=裙 +峯=峰 +峴=岘 +島=岛 +峸=城 +峽=峡 +崈=宗 +崍=崃 +崐=昆 +崕=崖 +崗=岗 +崙=仑 +崠=岽 +崢=峥 +崣=萎 +崧=嵩 +崫=窟 +崬=岽 +崳=嵛 +崶=封 +崾=腰 +嵐=岚 +嵒=岩 +嵔=畏 +嵗=岁 +嵻=慷 +嵿=顶 +嶁=嵝 +嶃=崭 +嶄=崭 +嶇=岖 +嶒=曾 +嶔=嵚 +嶗=崂 +嶠=峤 +嶢=峣 +嶧=峄 +嶨=峃 +嶮=崄 +嶴=岙 +嶵=罪 +嶶=微 +嶸=嵘 +嶺=岭 +嶼=屿 +嶽=岳 +巋=岿 +巒=峦 +巔=巅 +巗=岩 +巛=川 +巟=荒 +巰=巯 +巵=卮 +巹=卺 +巿=市 +帀=匝 +帉=粉 +帋=纸 +帞=陌 +帥=帅 +師=师 +帬=裙 +帳=帐 +帶=带 +帹=接 +帾=赌 +幀=帧 +幃=帏 +幇=帮 +幈=屏 +幎=幂 +幑=徽 +幗=帼 +幘=帻 +幙=幕 +幚=帮 +幟=帜 +幣=币 +幫=帮 +幬=帱 +幷=并 +幹=干 +幺=么 +幾=几 +広=广 +庅=么 +庝=疼 +庫=库 +庻=庶 +庽=寓 +庿=庙 +廁=厕 +廂=厢 +廄=厩 +廈=厦 +廎=庼 +廐=厩 +廕=荫 +廚=厨 +廜=屠 +廝=厮 +廟=庙 +廠=厂 +廡=庑 +廢=废 +廣=广 +廩=廪 +廬=庐 +廰=厅 +廳=厅 +廵=巡 +廸=迪 +廹=迫 +廻=回 +廼=迺 +弌=壹 +弍=贰 +弒=弑 +弔=吊 +弖=弓 +弚=弟 +弜=弱 +弳=弪 +張=张 +強=强 +彅=简 +彆=别 +彈=弹 +彊=强 +彌=弥 +彎=弯 +彔=录 +彙=汇 +彜=彝 +彞=彝 +彠=彟 +彡=三 +彥=彦 +彫=雕 +彯=飘 +彵=他 +彶=及 +彽=低 +彿=佛 +徃=往 +後=后 +徑=径 +從=从 +徠=徕 +徣=借 +徦=假 +徧=遍 +復=复 +徬=彷 +徳=德 +徵=征 +徹=彻 +忊=订 +忬=舒 +忲=太 +忹=汪 +忼=杭 +怇=矩 +怉=饱 +怌=呸 +怓=努 +怞=油 +怭=必 +怱=匆 +怳=恍 +怵=憷 +怶=披 +怺=咏 +恆=恒 +恉=旨 +恏=好 +恠=怪 +恡=吝 +恥=耻 +悀=涌 +悅=悦 +悇=余 +悈=戒 +悊=哲 +悋=吝 +悘=医 +悙=亨 +悞=悮 +悡=梨 +悢=恨 +悤=匆 +悩=脑 +悪=恶 +悮=误 +悵=怅 +悶=闷 +悽=凄 +惓=倦 +惔=淡 +惡=恶 +惢=蕊 +惥=恿 +惪=德 +惱=恼 +惲=恽 +惷=蠢 +惻=恻 +愅=革 +愙=客 +愛=爱 +愜=惬 +愨=悫 +愬=诉 +愮=瑶 +愰=晃 +愴=怆 +愷=恺 +愺=草 +愽=博 +愾=忾 +慁=恩 +慂=恿 +慄=栗 +慇=殷 +態=态 +慍=愠 +慓=漂 +慘=惨 +慙=惭 +慚=惭 +慛=崔 +慟=恸 +慠=傲 +慣=惯 +慤=悫 +慥=造 +慦=救 +慪=怄 +慫=怂 +慬=懂 +慮=虑 +慲=瞒 +慳=悭 +慴=慑 +慶=庆 +慹=热 +慼=戚 +慽=戚 +慾=欲 +憂=忧 +憅=动 +憇=憩 +憉=彭 +憊=惫 +憐=怜 +憑=凭 +憒=愦 +憕=登 +憖=慭 +憚=惮 +憛=潭 +憜=堕 +憡=策 +憤=愤 +憫=悯 +憮=怃 +憲=宪 +憶=忆 +懃=勤 +懄=勤 +懆=操 +懇=恳 +應=应 +懌=怿 +懍=懔 +懞=蒙 +懟=怼 +懣=懑 +懨=恹 +懪=暴 +懲=惩 +懶=懒 +懷=怀 +懸=悬 +懺=忏 +懼=惧 +懽=欢 +懾=慑 +戀=恋 +戇=戆 +戉=钺 +戓=或 +戔=戋 +戞=戛 +戧=戗 +戨=歌 +戩=戬 +戰=战 +戱=戯 +戲=戏 +戶=户 +戹=厄 +戼=卯 +扂=店 +扆=衣 +扙=丈 +扜=迂 +扝=亏 +扡=扦 +扱=吸 +抝=拗 +抳=拟 +抴=曳 +拋=抛 +拑=钳 +拕=拖 +拚=拼 +拡=扩 +拤=掐 +拹=协 +拾=十 +挌=格 +挘=劣 +挩=捝 +挱=挲 +挵=弄 +挶=局 +挾=挟 +捄=救 +捊=浮 +捨=舍 +捫=扪 +捲=卷 +捳=岳 +掃=扫 +掄=抡 +掗=挜 +掙=挣 +掛=挂 +採=采 +掫=取 +掱=手 +掵=命 +掹=猛 +掽=碰 +揀=拣 +揅=研 +揌=塞 +揑=捏 +揗=循 +揙=编 +揚=扬 +換=换 +揫=揪 +揮=挥 +揵=健 +揷=插 +揹=背 +搆=构 +搇=揿 +搉=榷 +損=损 +搖=摇 +搗=捣 +搣=灭 +搤=扼 +搥=捶 +搧=扇 +搨=拓 +搯=掏 +搵=揾 +搶=抢 +搾=榨 +摀=捂 +摂=摄 +摃=扛 +摋=杀 +摑=掴 +摜=掼 +摟=搂 +摣=揸 +摤=爽 +摯=挚 +摳=抠 +摶=抟 +摺=折 +摻=掺 +摽=标 +撁=牵 +撃=击 +撈=捞 +撏=挦 +撐=撑 +撓=挠 +撚=捻 +撝=㧑 +撟=挢 +撢=掸 +撣=掸 +撥=拨 +撦=扯 +撧=撅 +撫=抚 +撲=扑 +撳=揿 +撴=蹾 +撻=挞 +撽=邀 +撾=挝 +撿=捡 +擁=拥 +擄=掳 +擇=择 +擊=击 +擋=挡 +擏=敬 +擓=㧟 +擔=担 +擕=携 +據=据 +擝=盟 +擠=挤 +擡=抬 +擣=捣 +擧=举 +擬=拟 +擯=摈 +擰=拧 +擱=搁 +擲=掷 +擴=扩 +擷=撷 +擺=摆 +擻=擞 +擼=撸 +擾=扰 +擿=摘 +攃=擦 +攄=摅 +攆=撵 +攋=赖 +攏=拢 +攔=拦 +攖=撄 +攙=搀 +攛=撺 +攜=携 +攝=摄 +攢=攒 +攣=挛 +攤=摊 +攩=挡 +攪=搅 +攬=揽 +攷=考 +敁=掂 +敂=叩 +敍=叙 +敎=教 +敗=败 +敘=叙 +敟=典 +敩=学 +敭=扬 +敵=敌 +數=数 +敺=驱 +斂=敛 +斃=毙 +斈=学 +斉=齐 +斕=斓 +斚=斝 +斬=斩 +斷=断 +於=于 +旂=旗 +旛=幡 +旣=既 +旤=祸 +旪=叶 +旹=时 +旾=春 +昇=升 +昋=吞 +昐=盼 +昜=杨 +昬=昏 +昻=昂 +時=时 +晉=晋 +晎=哄 +晝=昼 +晵=启 +晿=唱 +暀=往 +暈=晕 +暉=晖 +暎=映 +暒=星 +暘=旸 +暠=皓 +暡=翁 +暢=畅 +暫=暂 +暱=昵 +曂=黄 +曃=逮 +曄=晔 +曆=历 +曇=昙 +曉=晓 +曊=费 +曏=向 +曖=暧 +曟=晨 +曠=旷 +曡=叠 +曨=昽 +曬=晒 +曱=甲 +書=书 +朂=最 +會=会 +朓=跳 +朞=期 +朢=望 +朧=胧 +朩=木 +朮=术 +朳=扒 +朶=朵 +杇=圬 +杘=尿 +杧=忙 +東=东 +杴=锨 +杺=心 +枃=匀 +枈=柴 +枒=桠 +枱=台 +枴=拐 +枾=柿 +柂=拖 +柆=垃 +柈=伴 +柭=跋 +柵=栅 +柷=祝 +柸=杯 +柹=柿 +柺=拐 +査=查 +栁=柳 +栆=枣 +栔=契 +栞=刊 +栢=柏 +栤=冰 +栰=筏 +栱=供 +栺=指 +桒=桑 +桚=拶 +桭=振 +桮=杯 +桺=柳 +桿=杆 +梔=栀 +梘=枧 +梚=挽 +條=条 +梟=枭 +梲=棁 +梹=槟 +梽=志 +棃=梨 +棄=弃 +棈=精 +棊=棋 +棌=睬 +棑=排 +棖=枨 +棗=枣 +棟=栋 +棡= +棧=栈 +棩=渊 +棬=桊 +棲=栖 +棴=服 +棶=梾 +椀=碗 +椉=乘 +椏=桠 +椗=碇 +椘=楚 +椨=俯 +椮=渗 +椶=棕 +椾=笺 +楃=握 +楊=杨 +楓=枫 +楛=苦 +楨=桢 +楩=便 +業=业 +楱=奏 +楳=梅 +極=极 +楿=相 +榘=矩 +榦=干 +榪=杩 +榮=荣 +榲=榅 +榿=桤 +槀=槁 +槁=藁 +槃=盘 +構=构 +槍=枪 +槑=呆 +槓=杠 +槕=桌 +槤=梿 +槧=椠 +槨=椁 +槩=概 +槪=概 +槮=椮 +槳=桨 +槶=椢 +槹=槔 +槼=規 +樁=桩 +樂=乐 +樅=枞 +樐=橹 +樑=梁 +樓=楼 +標=标 +樝=楂 +樞=枢 +樣=样 +樭=基 +樸=朴 +樹=树 +樺=桦 +樿=椫 +橆=舞 +橈=桡 +橋=桥 +橓=瞬 +橖=棠 +橜=橛 +機=机 +橢=椭 +橤=蕊 +橫=横 +橰=槔 +橴=紫 +檁=檩 +檇=槜 +檉=柽 +檔=档 +檜=桧 +檝=楫 +檟=槚 +檢=检 +檣=樯 +檤=道 +檭=银 +檮=梼 +檯=台 +檳=槟 +檸=柠 +檻=槛 +檾=苘 +櫂=棹 +櫃=柜 +櫇=颇 +櫈=凳 +櫓=橹 +櫕=替 +櫚=榈 +櫛=栉 +櫝=椟 +櫞=橼 +櫟=栎 +櫥=橱 +櫧=槠 +櫨=栌 +櫪=枥 +櫫=橥 +櫬=榇 +櫱=蘖 +櫳=栊 +櫸=榉 +櫺=棂 +櫻=樱 +欄=栏 +欅=榉 +權=权 +欎=郁 +欏=椤 +欑=攒 +欒=栾 +欖=榄 +欞=棂 +欥=吹 +欵=款 +欽=钦 +歎=叹 +歐=欧 +歔=墟 +歗=啸 +歘=欻 +歛=敛 +歟=欤 +歡=欢 +歭=持 +歮=址 +歯=齿 +歲=岁 +歳=岁 +歴=历 +歷=历 +歸=归 +歿=殁 +殀=夭 +殗=淹 +殘=残 +殙=婚 +殞=殒 +殣=谨 +殤=殇 +殨=㱮 +殫=殚 +殭=僵 +殮=殓 +殯=殡 +殲=歼 +殸=声 +殺=杀 +殻=壳 +殼=壳 +毀=毁 +毃=敲 +毆=殴 +毇=毁 +毉=医 +毐=毒 +毘=毗 +毝=毛 +毣=笔 +毧=绒 +毿=毵 +氂=牦 +氈=毡 +氊=毡 +氌=氇 +氣=气 +氫=氢 +氬=氩 +氳=氲 +氷=冰 +氹=凼 +氾=犯 +氿=酒 +汃=趴 +汈=叼 +汋=勺 +汍=丸 +汎=帆 +汏=大 +汒=茫 +汘=纤 +汙=污 +汚=污 +汢=土 +汥=枝 +汮=均 +汸=坊 +決=决 +汻=许 +沋=优 +沍=冱 +沑=扭 +沒=没 +沕=吻 +沖=冲 +沬=抹 +沰=拓 +沴=珍 +沵=你 +沶=示 +況=况 +泂=炯 +泇=架 +泙=砰 +泚=此 +泝=溯 +泩=生 +泬=穴 +泹=担 +洀=舟 +洂=亦 +洃=灰 +洊=存 +洏=而 +洘=拷 +洝=按 +洣=迷 +洤=全 +洩=泄 +洭=眶 +洶=汹 +洸=光 +洺=名 +洿=夸 +浀=曲 +浄=净 +浉=狮 +浌=伐 +浐=产 +浕=尽 +浗=球 +浛=含 +浢=逗 +浧=逞 +浨=宋 +浭=更 +浵=彤 +浹=浃 +浽=馁 +涃=捆 +涇=泾 +涊=忍 +涍=哮 +涖=莅 +涜=壳 +涥=哼 +涭=授 +涳=空 +涴=碗 +涺=锯 +涻=社 +涼=凉 +涽=昏 +淉=果 +淍=碉 +淒=凄 +淓=芳 +淔=植 +淚=泪 +淛=浙 +淣=倪 +淥=渌 +淨=净 +淩=凌 +淪=沦 +淰=念 +淵=渊 +淶=涞 +淺=浅 +渀=奔 +渁=水 +渇=渴 +渉=涉 +渏=奇 +渓=溪 +渘=揉 +渙=涣 +減=减 +渞=首 +渟=停 +渢=沨 +渦=涡 +渧=蒂 +測=测 +渱=虹 +渶=英 +渻=省 +渾=浑 +湁=拾 +湈=煤 +湊=凑 +湌=餐 +湏=须 +湜=是 +湝=皆 +湞=浈 +湠=碳 +湢=福 +湣=愍 +湤=施 +湥=突 +湧=涌 +湯=汤 +湰=隆 +湴=碰 +湺=保 +湻=淳 +湼=涅 +溇=楼 +溈=沩 +溓=嫌 +溔=糕 +準=准 +溙=泰 +溚=搭 +溜=熘 +溝=沟 +溡=时 +溤=冯 +溫=温 +溮=浉 +溳=涢 +溼=湿 +溿=畔 +滃=嗡 +滄=沧 +滅=灭 +滈=高 +滌=涤 +滎=荥 +滒=哥 +滘=浩 +滙=汇 +滛=淫 +滬=沪 +滭=毕 +滮=彪 +滯=滞 +滲=渗 +滵=蜜 +滷=卤 +滸=浒 +滺=悠 +滻=浐 +滽=庸 +滾=磙 +滿=满 +漁=渔 +漅=巢 +漈=际 +漊=溇 +漑=概 +漚=沤 +漟=堂 +漢=汉 +漣=涟 +漨=逢 +漬=渍 +漲=涨 +漴=崇 +漵=溆 +漷=郭 +漸=渐 +漹=焉 +漻=廖 +漿=浆 +潁=颍 +潄=漱 +潅=罐 +潎=撇 +潐=焦 +潑=泼 +潒=橡 +潔=洁 +潗=集 +潙=沩 +潛=潜 +潠=噀 +潤=润 +潪=智 +潯=浔 +潰=溃 +潵=撒 +潶=嘿 +潷=滗 +潹=森 +潾=磷 +潿=涠 +澀=涩 +澁=涩 +澆=浇 +澇=涝 +澊=尊 +澕=华 +澗=涧 +澠=渑 +澢=挡 +澣=浣 +澤=泽 +澥=懈 +澦=滪 +澩=泶 +澭=雍 +澮=浍 +澱=淀 +澼=辟 +濁=浊 +濃=浓 +濆=愤 +濇=涩 +濐=暑 +濔=沵 +濕=湿 +濘=泞 +濜=浕 +濟=济 +濢=粹 +濤=涛 +濨=磁 +濫=漤 +濰=潍 +濱=滨 +濳=潜 +濶=阔 +濸=呛 +濺=溅 +濼=泺 +濾=滤 +瀅=滢 +瀆=渎 +瀉=泻 +瀋=渖 +瀍=缠 +瀏=浏 +瀕=濒 +瀘=泸 +瀜=融 +瀝=沥 +瀟=潇 +瀠=潆 +瀦=潴 +瀧=泷 +瀨=濑 +瀭=输 +瀲=潋 +瀻=戴 +瀾=澜 +瀿=繁 +灀=霜 +灃=沣 +灄=滠 +灋=法 +灑=洒 +灕=漓 +灘=滩 +灝=灏 +灠=漤 +灡=烂 +灢=囊 +灣=湾 +灤=滦 +灧=滟 +灨=赣 +灩=滟 +災=灾 +炡=政 +炤=照 +炪=出 +為=为 +烄=胶 +烏=乌 +烑=姚 +烖=灾 +烥=臣 +烮=列 +烱=炯 +烴=烃 +烸=梅 +烺=浪 +烾=炎 +焄=君 +焒=吕 +無=无 +煆=煅 +煇=辉 +煉=炼 +煑=煮 +煒=炜 +煕=熙 +煖=暖 +煗=暖 +煙=烟 +煠=炸 +煢=茕 +煥=焕 +煩=烦 +煬=炀 +煭=裂 +煱=锅 +煷=亮 +熅=煴 +熈=熙 +熋=熊 +熒=荧 +熖=焰 +熗=炝 +熱=热 +熲=颎 +熷=增 +熾=炽 +燁=烨 +燄=焰 +燈=灯 +燉=炖 +燐=磷 +燒=烧 +燙=烫 +燜=焖 +營=营 +燦=灿 +燭=烛 +燳=照 +燴=烩 +燻=熏 +燼=烬 +燾=焘 +燿=耀 +爊=熬 +爍=烁 +爐=炉 +爕=燮 +爗=烨 +爘=餐 +爛=烂 +爭=争 +爲=为 +爺=爷 +爾=尔 +爿=丬 +牀=床 +牆=墙 +牋=笺 +牎=窗 +牐=闸 +牓=榜 +牕=窗 +牘=牍 +牠=它 +牴=抵 +牸=字 +牽=牵 +犂=犁 +犇=牛 +犖=荦 +犛=牦 +犠=牺 +犢=犊 +犧=牺 +犼=吼 +狀=状 +狆=中 +狌=牲 +狔=泥 +狚=胆 +狣=挑 +狥=徇 +狪=洞 +狹=狭 +狽=狈 +猂=悍 +猙=狰 +猦=枫 +猨=猿 +猵=遍 +猶=犹 +猻=狲 +獁=犸 +獃=呆 +獄=狱 +獅=狮 +獊=沧 +獌=馒 +獎=奖 +獏=貘 +獓=敖 +獘=毙 +獙=敝 +獞=撞 +獣=兽 +獧=狷 +獨=独 +獪=狯 +獫=猃 +獮=狝 +獰=狞 +獲=获 +獵=猎 +獷=犷 +獸=兽 +獺=獭 +獻=献 +獼=猕 +玀=猡 +玅=妙 +玆=玄 +玙=与 +玞=夫 +玨=珏 +玪=玲 +珆=台 +珒=津 +珓=较 +珪=圭 +珮=佩 +珵=呈 +珶=梯 +珻=悔 +現=现 +琇=锈 +琎=进 +琓=玩 +琖=盏 +琱=雕 +琹=琴 +琺=珐 +琿=珲 +瑆=惺 +瑇=玳 +瑉=珉 +瑋=玮 +瑏=穿 +瑒=玚 +瑝=皇 +瑠=琉 +瑣=琐 +瑤=瑶 +瑩=莹 +瑪=玛 +瑫=滔 +瑯=琅 +瑱=填 +瑲=玱 +瑺=常 +璄=境 +璉=琏 +璔=憎 +璡=琎 +璢=琉 +璣=玑 +璦=瑷 +璪=澡 +璫=珰 +環=环 +璵=玙 +璸=瑸 +璽=玺 +璿=璇 +瓈=璃 +瓊=琼 +瓌=瑰 +瓏=珑 +瓔=璎 +瓚=瓒 +瓟=爬 +甁=瓶 +甆=瓷 +甌=瓯 +甎=砖 +甕=瓮 +甖=罂 +甛=甜 +甞=尝 +產=产 +産=产 +甦=苏 +甯=宁 +甴=由 +甶=田 +甽=圳 +畆=亩 +畊=耕 +畝=亩 +畡=垓 +畢=毕 +畣=答 +畧=略 +畨=番 +畩=依 +畫=画 +畮=亩 +異=异 +畱=留 +畵=画 +當=当 +畼=场 +疇=畴 +疉=叠 +疊=叠 +疍=蛋 +疎=疏 +疒=病 +疧=底 +疺=乏 +疿=痱 +痌=恫 +痐=蛔 +痙=痉 +痠=酸 +痩=瘦 +痲=痳 +痺=痹 +痽=准 +痾=疴 +瘂=痖 +瘉=愈 +瘋=疯 +瘍=疡 +瘓=痪 +瘖=喑 +瘚=撅 +瘞=瘗 +瘡=疮 +瘧=疟 +瘮=瘆 +瘲=疭 +瘺=瘘 +瘻=瘘 +療=疗 +癅=瘤 +癆=痨 +癇=痫 +癉=瘅 +癒=愈 +癘=疠 +癙=鼠 +癟=瘪 +癡=痴 +癢=痒 +癤=疖 +癥=症 +癧=疬 +癩=癞 +癬=癣 +癭=瘿 +癮=瘾 +癰=痈 +癱=瘫 +癲=癫 +癷=罕 +發=发 +皁=皂 +皃=貌 +皐=皋 +皒=俄 +皗=绸 +皚=皑 +皛=白 +皜=皓 +皰=疱 +皷=鼓 +皸=皲 +皺=皱 +盁=盈 +盃=杯 +盇=盍 +盉=盒 +盋=钵 +盌=碗 +盜=盗 +盞=盏 +盡=尽 +監=监 +盤=盘 +盧=卢 +盪=荡 +盬=监 +眀=明 +眎=视 +眏=映 +眡=视 +眥=眦 +眪=丙 +眫=胖 +眾=众 +睋=蛾 +睏=困 +睓=腆 +睜=睁 +睞=睐 +睠=眷 +睪=睾 +睲=腥 +瞇=眯 +瞐=晶 +瞖=翳 +瞘=眍 +瞜=䁖 +瞞=瞒 +瞮=澈 +瞶=瞆 +瞼=睑 +矁=瞅 +矓=眬 +矙=瞰 +矚=瞩 +矯=矫 +矴=碇 +矼=缸 +矽=硅 +砡=玉 +砲=炮 +砽=拥 +硏=研 +硜=硁 +硤=硖 +硧=桶 +硨=砗 +硯=砚 +碁=棋 +碕=埼 +碙=刚 +碩=硕 +碪=砧 +碭=砀 +碸=砜 +確=确 +碼=码 +磆=猾 +磍=瞎 +磎=溪 +磑=硙 +磚=砖 +磟=碌 +磠=硵 +磣=碜 +磧=碛 +磯=矶 +磽=硗 +礃=掌 +礄=硚 +礆=硷 +礎=础 +礙=碍 +礦=矿 +礪=砺 +礫=砾 +礬=矾 +礮=炮 +礱=砻 +礶=罐 +祐=右 +祕=秘 +祘=算 +祿=禄 +禍=祸 +禎=祯 +禕=祎 +禞=篙 +禡=祃 +禢=塌 +禦=御 +禩=祀 +禪=禅 +禮=礼 +禰=祢 +禱=祷 +禸=内 +禿=秃 +秇=执 +秈=籼 +秊=年 +秌=秋 +秏=耗 +秐=耘 +秔=粳 +秖=祇 +秝=禾 +秡=泼 +秥=拈 +秱=桐 +稅=税 +稈=秆 +稉=粳 +稜=棱 +稟=禀 +稤=掠 +稬=糯 +稭=秸 +種=种 +稱=称 +稲=蹈 +稵=滋 +稺=稚 +稾=稿 +穀=谷 +穅=糠 +穉=稚 +穌=稣 +積=积 +穎=颖 +穏=稳 +穠=秾 +穡=穑 +穢=秽 +穤=糯 +穨=颓 +穩=稳 +穫=获 +穭=稆 +穽=阱 +窂=牢 +窉=柄 +窓=窗 +窩=窝 +窪=洼 +窮=穷 +窯=窑 +窰=窑 +窵=窎 +窶=窭 +窷=聊 +窺=窥 +窻=窗 +窾=款 +竄=窜 +竅=窍 +竇=窦 +竈=灶 +竊=窃 +竒=奇 +竚=伫 +竝=并 +竢=俟 +竪=竖 +竲=蹭 +競=竞 +竾=篪 +笀=芒 +笁=工 +笗=冬 +笣=包 +笩=代 +笵=范 +筃=茵 +筆=笔 +筍=笋 +筎=茹 +筗=忠 +筞=策 +筧=笕 +筩=筒 +筭=算 +筯=箸 +筴=䇲 +筺=筐 +箁=菩 +箇=个 +箋=笺 +箌=倒 +箎=篪 +箏=筝 +箒=帚 +箘=菌 +箚=札 +箛=孤 +箠=垂 +箥=玻 +箶=胡 +箹=约 +節=节 +範=范 +築=筑 +篋=箧 +篔=筼 +篛=箬 +篜=蒸 +篠=筱 +篤=笃 +篨=除 +篩=筛 +篲=彗 +篳=筚 +簀=箦 +簃=移 +簆=筘 +簍=篓 +簑=蓑 +簒=篡 +簘=萧 +簞=箪 +簡=简 +簣=篑 +簫=箫 +簮=簪 +簰=牌 +簷=檐 +簹=筜 +簽=签 +簾=帘 +籃=篮 +籌=筹 +籐=藤 +籙=箓 +籛=篯 +籜=箨 +籟=籁 +籠=笼 +籤=签 +籨=奁 +籩=笾 +籪=簖 +籬=篱 +籮=箩 +籲=吁 +籿=村 +粀=杖 +粃=秕 +粄=饭 +粅=物 +粦=磷 +粧=妆 +粩=姥 +粵=粤 +糉=粽 +糊=煳 +糘=稼 +糝=糁 +糞=粪 +糧=粮 +糱=糵 +糲=粝 +糴=籴 +糵=孽 +糶=粜 +糸=纟 +糹=纟 +糼=攻 +糾=纠 +紀=纪 +紁=叉 +紂=纣 +紃=驯 +約=约 +紅=红 +紆=纡 +紇=纥 +紈=纨 +紉=纫 +紋=纹 +納=纳 +紐=纽 +紓=纾 +純=纯 +紕=纰 +紖=纼 +紗=纱 +紘=纮 +紙=纸 +級=级 +紛=纷 +紜=纭 +紝=纴 +紡=纺 +紥=扎 +紬=䌷 +紮=扎 +細=细 +紱=绂 +紲=绁 +紳=绅 +紵=纻 +紹=绍 +紺=绀 +紼=绋 +紿=绐 +絀=绌 +終=终 +絃=弦 +組=组 +絅=䌹 +絆=绊 +絎=绗 +絏=绁 +結=结 +絒=酬 +絕=绝 +絛=绦 +絝=绔 +絞=绞 +絡=络 +絢=绚 +給=给 +絨=绒 +絪=姻 +絰=绖 +統=统 +絲=丝 +絳=绛 +絶=绝 +絸=茧 +絹=绢 +綁=绑 +綃=绡 +綆=绠 +綈=绨 +綉=绣 +綌=绤 +綏=绥 +綑=捆 +經=经 +綜=综 +綞=缍 +綠=绿 +綢=绸 +綣=绻 +綫=线 +綬=绶 +維=维 +綯=绹 +綰=绾 +綱=纲 +網=网 +綳=绷 +綴=缀 +綵=彩 +綸=纶 +綹=绺 +綺=绮 +綻=绽 +綽=绰 +綾=绫 +綿=绵 +緄=绲 +緇=缁 +緊=紧 +緋=绯 +緐=繁 +緑=绿 +緒=绪 +緓=绬 +緔=绱 +緗=缃 +緘=缄 +緙=缂 +線=线 +緜=绵 +緝=缉 +緞=缎 +締=缔 +緡=缗 +緣=缘 +緥=褓 +緦=缌 +編=编 +緩=缓 +緬=缅 +緯=纬 +緱=缑 +緲=缈 +練=练 +緶=缏 +緹=缇 +緻=致 +縂=总 +縈=萦 +縉=缙 +縊=缢 +縋=缒 +縐=绉 +縑=缣 +縕=缊 +縗=缞 +縚=绦 +縛=缚 +縝=缜 +縞=缟 +縟=缛 +縣=县 +縧=绦 +縨=幌 +縫=缝 +縭=缡 +縮=缩 +縱=纵 +縲=缧 +縳=䌸 +縵=缦 +縶=絷 +縷=缕 +縹=缥 +總=总 +績=绩 +繃=绷 +繅=缫 +繆=缪 +繈=襁 +繒=缯 +織=织 +繕=缮 +繖=伞 +繚=缭 +繞=绕 +繡=绣 +繢=缋 +繦=襁 +繩=绳 +繪=绘 +繫=系 +繭=茧 +繮=缰 +繯=缳 +繰=缲 +繳=缴 +繸=䍁 +繹=绎 +繺=煞 +繼=继 +繽=缤 +繾=缱 +纇=颣 +纈=缬 +纊=纩 +續=续 +纍=累 +纏=缠 +纓=缨 +纖=纤 +纘=缵 +纜=缆 +缞=衰 +缽=钵 +缾=瓶 +罁=缸 +罇=樽 +罈=坛 +罌=罂 +罎=坛 +罏=垆 +罓=冈 +罞=茅 +罣=挂 +罰=罚 +罵=骂 +罷=罢 +罸=罚 +羅=罗 +羆=罴 +羈=羁 +羋=芈 +羕=漾 +羗=羌 +羙=美 +羢=绒 +羣=群 +羥=羟 +羨=羡 +義=义 +羱=源 +羴=膻 +羶=膻 +翄=翅 +習=习 +翫=玩 +翬=翚 +翶=翱 +翹=翘 +翺=翱 +翽=翙 +耈=耇 +耉=耇 +耡=锄 +耬=耧 +耮=耢 +聅=联 +聖=圣 +聙=睛 +聞=闻 +聯=联 +聰=聪 +聲=声 +聳=耸 +聵=聩 +聶=聂 +職=职 +聹=聍 +聼=听 +聽=听 +聾=聋 +肅=肃 +肎=肯 +肐=胳 +肔=池 +肗=汝 +肧=胚 +肬=疣 +肻=肯 +胒=尼 +胕=附 +胷=胸 +脃=脆 +脅=胁 +脇=胁 +脈=脉 +脊=嵴 +脕=晚 +脗=吻 +脛=胫 +脣=唇 +脫=脱 +脹=胀 +腁=胼 +腄=捶 +腎=肾 +腖=胨 +腡=脶 +腦=脑 +腫=肿 +腳=脚 +腷=逼 +腸=肠 +膁=肷 +膃=腽 +膆=嗉 +膓=肠 +膕=腘 +膚=肤 +膠=胶 +膤=雪 +膩=腻 +膽=胆 +膾=脍 +膿=脓 +臈=腊 +臉=脸 +臋=臀 +臍=脐 +臏=膑 +臒=癯 +臕=膘 +臘=腊 +臙=胭 +臚=胪 +臝=裸 +臟=脏 +臠=脔 +臢=臜 +臥=卧 +臨=临 +臯=皋 +臱=旁 +臸=至 +臺=台 +舃=舄 +與=与 +興=兴 +舉=举 +舊=旧 +舎=舍 +舖=铺 +舗=铺 +舘=馆 +舙=舌 +舝=辖 +舩=船 +艙=舱 +艢=樯 +艣=橹 +艤=舣 +艦=舰 +艪=橹 +艫=舻 +艱=艰 +艷=艳 +艸=艹 +芉=竿 +芐=下 +芢=仁 +芣=不 +芲=花 +芶=勾 +芻=刍 +苆=切 +苉=匹 +苎=苧 +苐=第 +苝=北 +苧=苎 +苸=呼 +苺=莓 +茐=葱 +茖=各 +茘=荔 +茲=兹 +茿=筑 +荅=答 +荊=荆 +荍=收 +荕=筋 +荖=老 +荝=则 +荢=宇 +荰=杜 +荳=豆 +荴=扶 +荶=吟 +荹=步 +荿=成 +莁=巫 +莂=别 +莇=助 +莈=没 +莊=庄 +莋=做 +莏=抄 +莑=蓬 +莕=荇 +莖=茎 +莢=荚 +莣=忘 +莧=苋 +莮=男 +菈=拉 +菋=味 +菓=果 +菗=抽 +菢=抱 +菦=近 +菭=治 +菮=庚 +華=华 +菴=庵 +菸=烟 +菿=到 +萇=苌 +萉=肥 +萊=莱 +萚=择 +萠=萌 +萣=定 +萪=科 +萫=香 +萬=万 +萭=万 +萯=负 +萲=萱 +萵=莴 +萷=削 +萹=篇 +萺=冒 +萿=活 +葀=括 +葁=姜 +葃=昨 +葉=叶 +葒=荭 +葓=洪 +葠=参 +葢=盖 +葤=荮 +葦=苇 +葮=锻 +葯=药 +葰=所 +葲=泉 +葷=荤 +葾=怨 +葿=眉 +蒄=冠 +蒓=莼 +蒔=莳 +蒛=缺 +蒝=愿 +蒞=莅 +蒢=滁 +蒤=途 +蒩=租 +蒼=苍 +蓀=荪 +蓅=流 +蓆=席 +蓈=榔 +蓋=盖 +蓒=轩 +蓕=桂 +蓙=座 +蓜=配 +蓡=參 +蓢=廊 +蓧=莜 +蓮=莲 +蓯=苁 +蓱=萍 +蓳=董 +蓴=莼 +蓷=推 +蓸=曹 +蓽=荜 +蔀=部 +蔂=累 +蔆=菱 +蔉=滚 +蔋=淑 +蔍=鹿 +蔎=设 +蔔=卜 +蔕=蒂 +蔘=参 +蔞=蒌 +蔠=终 +蔣=蒋 +蔥=葱 +蔦=茑 +蔭=荫 +蔵=藏 +蕁=荨 +蕅=藕 +蕆=蒇 +蕋=蕊 +蕎=荞 +蕏=猪 +蕐=哗 +蕒=荬 +蕓=芸 +蕔=报 +蕕=莸 +蕗=露 +蕘=荛 +蕚=萼 +蕜=悲 +蕝=绝 +蕢=蒉 +蕥=雅 +蕩=荡 +蕪=芜 +蕭=萧 +蕯=萨 +蕶=零 +蕷=蓣 +蕿=萱 +薀=蕰 +薈=荟 +薊=蓟 +薌=芗 +薑=姜 +薔=蔷 +薘=荙 +薟=莶 +薦=荐 +薩=萨 +薴=苧 +薵=筹 +薺=荠 +藂=聚 +藅=罚 +藍=蓝 +藎=荩 +藙=毅 +藝=艺 +藞=磊 +藥=药 +藪=薮 +藴=蕴 +藶=苈 +藷=薯 +藹=蔼 +藺=蔺 +藼=萱 +蘀=萚 +蘂=蕊 +蘄=蕲 +蘆=芦 +蘇=苏 +蘊=蕴 +蘋=苹 +蘐=萱 +蘓=苏 +蘚=藓 +蘞=蔹 +蘢=茏 +蘤=花 +蘭=兰 +蘶=巍 +蘺=蓠 +蘿=萝 +虆=蔂 +處=处 +虖=呼 +虛=虚 +虜=虏 +號=号 +虧=亏 +虯=虬 +虵=蛇 +蚘=蛔 +蚡=鼢 +蚦=蚺 +蛕=蛔 +蛧=网 +蛫=跪 +蛬=蚕 +蛺=蛱 +蛻=蜕 +蜆=蚬 +蜋=螂 +蜖=蛔 +蜨=蝶 +蜯=蚌 +蜺=霓 +蝂=版 +蝕=蚀 +蝟=猬 +蝦=虾 +蝨=虱 +蝯=猿 +蝱=虻 +蝸=蜗 +螄=蛳 +螎=融 +螘=蚁 +螙=蠹 +螞=蚂 +螡=蚊 +螢=萤 +螻=蝼 +螾=蚓 +螿=螀 +蟁=蚊 +蟄=蛰 +蟇=蟆 +蟈=蝈 +蟎=螨 +蟣=虮 +蟬=蝉 +蟯=蛲 +蟲=虫 +蟶=蛏 +蟻=蚁 +蠅=蝇 +蠆=虿 +蠍=蝎 +蠏=蟹 +蠐=蛴 +蠑=蝾 +蠒=茧 +蠔=蚝 +蠟=蜡 +蠣=蛎 +蠧=蠹 +蠨=蟏 +蠭=蜂 +蠱=蛊 +蠶=蚕 +蠻=蛮 +衂=衄 +衆=众 +衇=脉 +衒=炫 +術=术 +衕=同 +衖=弄 +衚=胡 +衛=卫 +衝=冲 +衞=卫 +衹=只 +衺=邪 +袉=鸵 +袑=绍 +袓=祖 +袞=衮 +袵=衽 +裊=袅 +裌=夹 +裏=里 +裑=身 +補=补 +裝=装 +裠=裙 +裡=里 +裩=裈 +製=制 +褃=裉 +複=复 +褌=裈 +褘=袆 +褭=袅 +褲=裤 +褳=裢 +褸=褛 +褻=亵 +襃=褒 +襆=幞 +襇=裥 +襉=裥 +襍=杂 +襏=袯 +襖=袄 +襝=裣 +襠=裆 +襤=褴 +襪=袜 +襬=摆 +襯=衬 +襲=袭 +襴=襕 +覀=西 +覇=霸 +覈=核 +覊=羁 +見=见 +覎=觃 +規=规 +覓=觅 +覔=觅 +視=视 +覘=觇 +覡=觋 +覥=觍 +覦=觎 +覩=睹 +親=亲 +覬=觊 +覯=觏 +覰=觑 +覲=觐 +覷=觑 +覺=觉 +覽=览 +覿=觌 +觀=观 +觔=斤 +觝=抵 +觧=解 +觴=觞 +觶=觯 +觸=触 +訁=讠 +訂=订 +訃=讣 +計=计 +訊=讯 +訌=讧 +討=讨 +訐=讦 +訒=讱 +訓=训 +訕=讪 +訖=讫 +託=讬 +記=记 +訛=讹 +訝=讶 +訟=讼 +訢=䜣 +訣=诀 +訤=驳 +訥=讷 +訩=讻 +訪=访 +訬=吵 +設=设 +許=许 +訴=诉 +訶=诃 +訷=伸 +診=诊 +註=注 +証=证 +詁=诂 +詆=诋 +詎=讵 +詐=诈 +詒=诒 +詔=诏 +評=评 +詖=诐 +詗=诇 +詘=诎 +詛=诅 +詞=词 +詠=咏 +詡=诩 +詢=询 +詣=诣 +試=试 +詧=察 +詩=诗 +詫=诧 +詬=诟 +詭=诡 +詮=诠 +詰=诘 +話=话 +該=该 +詳=详 +詵=诜 +詶=州 +詻=洛 +詼=诙 +詿=诖 +誄=诔 +誅=诛 +誆=诓 +誇=夸 +誌=志 +認=认 +誑=诳 +誒=诶 +誕=诞 +誖=悖 +誘=诱 +誚=诮 +語=语 +誠=诚 +誡=诫 +誣=诬 +誤=误 +誥=诰 +誦=诵 +誧=哺 +誨=诲 +說=说 +説=说 +誯=昌 +誰=谁 +課=课 +誶=谇 +誹=诽 +誼=谊 +誾=訚 +調=调 +諂=谄 +諄=谆 +諆=棋 +談=谈 +諉=诿 +請=请 +諍=诤 +諏=诹 +諐=愆 +諑=诼 +諒=谅 +論=论 +諗=谂 +諛=谀 +諜=谍 +諝=谞 +諞=谝 +諟=堤 +諠=喧 +諡=谥 +諢=诨 +諤=谔 +諦=谛 +諧=谐 +諨=幅 +諫=谏 +諭=谕 +諮=谘 +諱=讳 +諳=谙 +諴=诚 +諶=谌 +諷=讽 +諸=诸 +諺=谚 +諼=谖 +諾=诺 +謀=谋 +謁=谒 +謂=谓 +謄=誊 +謅=诌 +謊=谎 +謌=歌 +謍=誉 +謎=谜 +謐=谧 +謔=谑 +謖=谡 +謗=谤 +謙=谦 +謚=谥 +講=讲 +謝=谢 +謠=谣 +謡=谣 +謨=谟 +謩=谟 +謫=谪 +謬=谬 +謭=谫 +謳=讴 +謸=傲 +謹=谨 +謾=谩 +謿=嘲 +譁=哗 +譆=嘻 +證=证 +譌=讹 +譎=谲 +譏=讥 +譒=播 +譔=撰 +譖=谮 +識=识 +譙=谯 +譚=谭 +譜=谱 +譟=噪 +譫=谵 +譭=毁 +譯=译 +議=议 +譴=谴 +護=护 +譸=诪 +譽=誉 +譾=谫 +讀=读 +讁=谪 +讅=审 +變=变 +讋=詟 +讌=宴 +讎=雠 +讐=雠 +讒=谗 +讓=让 +讕=谰 +讖=谶 +讚=赞 +讜=谠 +讞=谳 +谉=审 +谘=咨 +豈=岂 +豎=竖 +豐=丰 +豓=艳 +豔=艳 +豞=狗 +豩=逐 +豬=猪 +豶=豮 +貍=狸 +貓=猫 +貛=獾 +貝=贝 +貞=贞 +貟=贠 +負=负 +財=财 +貢=贡 +貧=贫 +貨=货 +販=贩 +貪=贪 +貫=贯 +責=责 +貯=贮 +貰=贳 +貲=赀 +貳=贰 +貴=贵 +貶=贬 +買=买 +貸=贷 +貺=贶 +費=费 +貼=贴 +貽=贻 +貿=贸 +賀=贺 +賁=贲 +賂=赂 +賃=赁 +賄=贿 +賅=赅 +資=资 +賈=贾 +賉=恤 +賊=贼 +賍=赃 +賑=赈 +賒=赊 +賓=宾 +賕=赇 +賗=串 +賙=赒 +賚=赉 +賛=赞 +賜=赐 +賞=赏 +賠=赔 +賡=赓 +賢=贤 +賣=卖 +賤=贱 +賦=赋 +賧=赕 +質=质 +賫=赍 +賬=账 +賭=赌 +賴=赖 +賵=赗 +賷=赍 +賸=剩 +賺=赚 +賻=赙 +購=购 +賽=赛 +賾=赜 +贄=贽 +贅=赘 +贇=赟 +贈=赠 +贊=赞 +贋=赝 +贍=赡 +贏=赢 +贐=赆 +贑=贛 +贓=赃 +贔=赑 +贖=赎 +贗=赝 +贛=赣 +贜=赃 +赑=贝 +赬=赪 +赽=块 +趂=趁 +趉=走 +趐=翅 +趕=赶 +趙=赵 +趚=速 +趦=趑 +趧=题 +趨=趋 +趫=超 +趬=翘 +趭=瞧 +趲=趱 +跕=沾 +跡=迹 +跥=跺 +跩=拽 +跴=踩 +跿=陡 +踁=胫 +踐=践 +踡=蜷 +踭=争 +踰=逾 +踴=踊 +蹆=腿 +蹌=跄 +蹍=展 +蹏=蹄 +蹓=溜 +蹔=暂 +蹕=跸 +蹜=宿 +蹟=迹 +蹠=跖 +蹣=蹒 +蹤=踪 +蹧=糟 +蹵=蹴 +蹺=跷 +躂=跶 +躉=趸 +躊=踌 +躋=跻 +躍=跃 +躑=踯 +躒=跞 +躓=踬 +躕=蹰 +躚=跹 +躡=蹑 +躥=蹿 +躦=躜 +躪=躏 +躭=耽 +躱=躲 +躳=躬 +躶=裸 +軀=躯 +軆=体 +車=车 +軋=轧 +軌=轨 +軍=军 +軑=轪 +軒=轩 +軔=轫 +軛=轭 +軟=软 +軤=轷 +軫=轸 +軲=轱 +軸=轴 +軹=轵 +軺=轺 +軻=轲 +軼=轶 +軾=轼 +較=较 +輅=辂 +輇=辁 +輈=辀 +載=载 +輊=轾 +輒=辄 +輓=挽 +輔=辅 +輕=轻 +輙=辄 +輛=辆 +輜=辎 +輝=辉 +輞=辋 +輟=辍 +輥=辊 +輦=辇 +輩=辈 +輪=轮 +輬=辌 +輭=软 +輯=辑 +輳=辏 +輸=输 +輻=辐 +輾=辗 +輿=舆 +轀=辒 +轂=毂 +轄=辖 +轅=辕 +轆=辘 +轉=转 +轍=辙 +轎=轿 +轔=辚 +轟=轰 +轡=辔 +轢=轹 +轤=轳 +辠=罪 +辢=辣 +辤=辞 +辦=办 +辧=辨 +辭=辞 +辮=辫 +辯=辩 +農=农 +辳=农 +辴=冁 +迀=干 +迆=迤 +迉=尸 +迊=迎 +迋=逛 +迖=达 +迡=呢 +迣=世 +迯=逃 +迴=回 +迻=移 +逈=迥 +逕=迳 +這=这 +連=连 +逥=回 +逩=奔 +逬=迸 +週=周 +進=进 +逷=逖 +逺=远 +遉=侦 +遊=游 +運=运 +過=过 +達=达 +違=违 +遖=南 +遙=遥 +遜=逊 +遝=沓 +遞=递 +遠=远 +遡=溯 +遦=惯 +適=适 +遯=遁 +遲=迟 +遶=绕 +遷=迁 +選=选 +遺=遗 +遼=辽 +邁=迈 +還=还 +邇=迩 +邊=边 +邏=逻 +邐=逦 +郉=邢 +郟=郏 +郤=郄 +郰=邓 +郵=邮 +鄆=郓 +鄉=乡 +鄒=邹 +鄔=邬 +鄖=郧 +鄧=邓 +鄭=郑 +鄰=邻 +鄲=郸 +鄴=邺 +鄶=郐 +鄺=邝 +酇=酂 +酈=郦 +酔=醉 +酧=酬 +酨=栽 +醃=腌 +醕=醇 +醖=酝 +醜=丑 +醞=酝 +醣=糖 +醫=医 +醬=酱 +醯=酰 +醱=酦 +醻=酬 +醼=宴 +醿=醾 +釀=酿 +釁=衅 +釃=酾 +釅=酽 +釋=释 +釐=厘 +釒=钅 +釓=钆 +釔=钇 +釕=钌 +釗=钊 +釘=钉 +釙=钋 +針=针 +釡=斧 +釢=乃 +釣=钓 +釤=钐 +釦=扣 +釧=钏 +釩=钒 +釬=焊 +釭=肛 +釵=钗 +釷=钍 +釹=钕 +釺=钎 +釿=斤 +鈀=钯 +鈁=钫 +鈃=钘 +鈄=钭 +鈅=钥 +鈆=铅 +鈈=钚 +鈉=钠 +鈍=钝 +鈎=钩 +鈐=钤 +鈑=钣 +鈒=钑 +鈔=钞 +鈕=钮 +鈞=钧 +鈣=钙 +鈥=钬 +鈦=钛 +鈧=钪 +鈫=纹 +鈮=铌 +鈰=铈 +鈳=钶 +鈴=铃 +鈷=钴 +鈸=钹 +鈹=铍 +鈺=钰 +鈽=钸 +鈾=铀 +鈿=钿 +鉀=钾 +鉄=铁 +鉅=钜 +鉆=钻 +鉈=铊 +鉉=铉 +鉋=铇 +鉍=铋 +鉏=锄 +鉑=铂 +鉕=钷 +鉗=钳 +鉚=铆 +鉛=铅 +鉞=钺 +鉢=钵 +鉤=钩 +鉦=钲 +鉬=钼 +鉭=钽 +鉮=神 +鉲=卡 +鉶=铏 +鉸=铰 +鉺=铒 +鉻=铬 +鉽=式 +鉿=铪 +銀=银 +銃=铳 +銅=铜 +銍=铚 +銑=铣 +銓=铨 +銕=铁 +銖=铢 +銘=铭 +銚=铫 +銛=铦 +銜=衔 +銠=铑 +銣=铷 +銥=铱 +銦=铟 +銨=铵 +銩=铥 +銪=铕 +銫=铯 +銬=铐 +銰=艾 +銱=铞 +銲=焊 +銳=锐 +銷=销 +銹=锈 +銻=锑 +銼=锉 +鋁=铝 +鋂=镅 +鋃=锒 +鋅=锌 +鋇=钡 +鋌=铤 +鋏=铗 +鋒=锋 +鋖=妥 +鋙=铻 +鋝=锊 +鋟=锓 +鋣=铘 +鋤=锄 +鋥=锃 +鋦=锔 +鋨=锇 +鋩=铓 +鋪=铺 +鋭=锐 +鋮=铖 +鋯=锆 +鋰=锂 +鋱=铽 +鋶=锍 +鋸=锯 +鋼=钢 +鋽=掉 +錁=锞 +錄=录 +錆=锖 +錇=锫 +錈=锩 +錏=铔 +錐=锥 +錒=锕 +錕=锟 +錘=锤 +錙=锱 +錚=铮 +錛=锛 +錞=醇 +錟=锬 +錠=锭 +錡=锜 +錢=钱 +錦=锦 +錨=锚 +錩=锠 +錫=锡 +錮=锢 +錯=错 +録=录 +錳=锰 +錶=表 +錸=铼 +錼=镎 +鍀=锝 +鍁=锨 +鍃=锪 +鍆=钔 +鍇=锴 +鍈=锳 +鍋=锅 +鍍=镀 +鍔=锷 +鍘=铡 +鍚=钖 +鍛=锻 +鍠=锽 +鍤=锸 +鍥=锲 +鍩=锘 +鍫=锹 +鍬=锹 +鍰=锾 +鍳=鉴 +鍴=端 +鍵=键 +鍶=锶 +鍺=锗 +鍼=针 +鍾=锺 +鎂=镁 +鎄=锿 +鎅=界 +鎇=镅 +鎊=镑 +鎌=镰 +鎍=索 +鎔=镕 +鎖=锁 +鎗=枪 +鎘=镉 +鎚=锤 +鎛=镈 +鎟=桑 +鎡=镃 +鎢=钨 +鎣=蓥 +鎦=镏 +鎧=铠 +鎩=铩 +鎪=锼 +鎬=镐 +鎮=镇 +鎰=镒 +鎲=镋 +鎳=镍 +鎵=镓 +鎸=镌 +鎹=送 +鎻=锁 +鎿=镎 +鏃=镞 +鏇=镟 +鏈=链 +鏌=镆 +鏍=镙 +鏐=镠 +鏑=镝 +鏗=铿 +鏘=锵 +鏜=镗 +鏝=镘 +鏞=镛 +鏟=铲 +鏡=镜 +鏢=镖 +鏤=镂 +鏨=錾 +鏰=镚 +鏵=铧 +鏷=镤 +鏹=镪 +鏽=锈 +鐃=铙 +鐋=铴 +鐐=镣 +鐒=铹 +鐓=镦 +鐔=镡 +鐘=钟 +鐙=镫 +鐝=镢 +鐠=镨 +鐦=锎 +鐧=锏 +鐨=镄 +鐫=镌 +鐮=镰 +鐰=糙 +鐲=镯 +鐳=镭 +鐴=避 +鐵=铁 +鐶=镮 +鐸=铎 +鐺=铛 +鐿=镱 +鑀=锿 +鑄=铸 +鑊=镬 +鑌=镔 +鑑=鉴 +鑒=鉴 +鑔=镲 +鑕=锧 +鑚=钻 +鑛=矿 +鑞=镴 +鑠=铄 +鑣=镳 +鑤=刨 +鑥=镥 +鑭=镧 +鑰=钥 +鑱=镵 +鑲=镶 +鑵=罐 +鑷=镊 +鑹=镩 +鑼=锣 +鑽=钻 +鑾=銮 +鑿=凿 +钁=镢 +钂=镋 +钜=鉅 +铇=刨 +镚=崩 +镟=碹 +镵=馋 +長=长 +門=门 +閁=闪 +閂=闩 +閃=闪 +閄=门 +閆=闫 +閈=闬 +閉=闭 +開=开 +閌=闶 +閎=闳 +閏=闰 +閑=闲 +閒=闲 +間=间 +閔=闵 +閘=闸 +閙=闹 +閞=开 +閡=阂 +関=关 +閣=阁 +閥=阀 +閨=闺 +閩=闽 +閫=阃 +閬=阆 +閭=闾 +閱=阅 +閲=阅 +閶=阊 +閷=刹 +閹=阉 +閻=阎 +閼=阏 +閽=阍 +閾=阈 +閿=阌 +闃=阒 +闆=板 +闈=闱 +闊=阔 +闋=阕 +闌=阑 +闍=阇 +闐=阗 +闒=阘 +闓=闿 +闔=阖 +闕=阙 +闖=闯 +闚=窥 +關=关 +闝=嫖 +闞=阚 +闠=阓 +闡=阐 +闢=辟 +闤=阛 +闥=闼 +阣=吃 +阨=厄 +阪=坂 +阬=坑 +阯=址 +陏=隋 +陗=峭 +陘=陉 +陝=陕 +陣=阵 +陥=馅 +陰=阴 +陳=陈 +陸=陆 +険=险 +陻=堙 +陼=堵 +陽=阳 +隂=阴 +隄=堤 +隉=陧 +隊=队 +階=阶 +隕=陨 +隖=坞 +際=际 +隟=隙 +隢=饶 +隣=邻 +隨=随 +險=险 +隱=隐 +隴=陇 +隷=隶 +隸=隶 +隻=只 +雋=隽 +雖=虽 +雙=双 +雛=雏 +雜=杂 +雝=雍 +雞=鸡 +離=离 +難=难 +雲=云 +電=电 +霚=雾 +霛=灵 +霡=脉 +霢=霡 +霤=溜 +霧=雾 +霩=廓 +霽=霁 +靂=雳 +靃=霍 +靄=霭 +靆=叇 +靈=灵 +靉=叆 +靚=靓 +靜=静 +靣=面 +靦=腼 +靨=靥 +靭=韧 +靱=韧 +鞀=鼗 +鞉=鼗 +鞌=鞍 +鞏=巩 +鞝=绱 +鞵=鞋 +鞽=鞒 +韁=缰 +韃=鞑 +韈=袜 +韉=鞯 +韋=韦 +韌=韧 +韍=韨 +韓=韩 +韙=韪 +韜=韬 +韝=鞴 +韞=韫 +韤=袜 +韮=韭 +韻=韵 +響=响 +頁=页 +頂=顶 +頃=顷 +項=项 +順=顺 +頇=顸 +須=须 +頊=顼 +頌=颂 +頎=颀 +頏=颃 +預=预 +頑=顽 +頒=颁 +頓=顿 +頗=颇 +領=领 +頙=项 +頜=颌 +頟=额 +頡=颉 +頤=颐 +頦=颏 +頭=头 +頮=颒 +頰=颊 +頲=颋 +頴=颕 +頷=颔 +頸=颈 +頹=颓 +頻=频 +頼=赖 +頽=颓 +顆=颗 +顋=腮 +題=题 +額=额 +顎=颚 +顏=颜 +顒=颙 +顓=颛 +顔=颜 +願=愿 +顙=颡 +顛=颠 +類=类 +顢=颟 +顥=颢 +顦=憔 +顧=顾 +顫=颤 +顬=颥 +顯=显 +顰=颦 +顱=颅 +顳=颞 +顴=颧 +颕=颖 +風=风 +颩=风 +颭=飐 +颮=飑 +颯=飒 +颱=台 +颳=刮 +颶=飓 +颸=飔 +颺=飏 +颻=飖 +颼=飕 +飀=飗 +飃=飘 +飄=飘 +飆=飚 +飈=飚 +飚=飙 +飛=飞 +飜=翻 +飠=饣 +飢=饥 +飣=饤 +飤=饲 +飥=饦 +飩=饨 +飪=饪 +飫=饫 +飭=饬 +飮=饮 +飯=饭 +飱=飧 +飲=饮 +飴=饴 +飺=糍 +飼=饲 +飽=饱 +飾=饰 +飿=饳 +餀=哎 +餁=饪 +餃=饺 +餄=饸 +餅=饼 +餈=糍 +餉=饷 +養=养 +餌=饵 +餎=饹 +餏=饻 +餑=饽 +餒=馁 +餓=饿 +餕=馂 +餖=饾 +餘=馀 +餚=肴 +餛=馄 +餜=馃 +餞=饯 +餡=馅 +餧=喂 +館=馆 +餬=糊 +餱=糇 +餳=饧 +餵=喂 +餶=馉 +餷=馇 +餹=糖 +餺=馎 +餻=糕 +餼=饩 +餽=馈 +餾=馏 +餿=馊 +饁=馌 +饃=馍 +饅=馒 +饈=馐 +饉=馑 +饊=馓 +饋=馈 +饌=馔 +饍=膳 +饑=饥 +饒=饶 +饗=飨 +饜=餍 +饝=馍 +饞=馋 +饟=饷 +饢=馕 +饤=盯 +馀=余 +馬=马 +馭=驭 +馮=冯 +馱=驮 +馳=驰 +馴=驯 +馶=驶 +馹=驲 +馿=驴 +駁=驳 +駆=驱 +駈=驱 +駐=驻 +駑=驽 +駒=驹 +駔=驵 +駕=驾 +駘=骀 +駙=驸 +駛=驶 +駝=驼 +駞=驼 +駟=驷 +駡=骂 +駢=骈 +駦=藤 +駭=骇 +駮=驳 +駰=骃 +駱=骆 +駸=骎 +駿=骏 +騁=骋 +騂=骍 +騅=骓 +騌=骔 +騍=骒 +騎=骑 +騏=骐 +騐=验 +騒=骚 +験=验 +騖=骛 +騗=骗 +騙=骗 +騣=鬃 +騤=骙 +騧=䯄 +騫=骞 +騭=骘 +騮=骝 +騰=腾 +騶=驺 +騷=骚 +騸=骟 +騾=骡 +驀=蓦 +驁=骜 +驂=骖 +驃=骠 +驄=骢 +驅=驱 +驊=骅 +驌=骕 +驍=骁 +驏=骣 +驕=骄 +驗=验 +驘=骡 +驚=惊 +驛=驿 +驟=骤 +驢=驴 +驤=骧 +驥=骥 +驦=骦 +驪=骊 +驫=骉 +骉=马 +骔=鬃 +骯=肮 +骼=胳 +骾=鲠 +髈=膀 +髊=搓 +髏=髅 +髒=脏 +體=体 +髕=髌 +髖=髋 +髠=髡 +髣=仿 +髥=髯 +髩=鬓 +髮=发 +髴=佛 +鬀=剃 +鬁=疬 +鬂=鬓 +鬆=松 +鬉=鬃 +鬍=胡 +鬚=须 +鬢=鬓 +鬥=斗 +鬦=斗 +鬧=闹 +鬨=闹 +鬩=阋 +鬪=斗 +鬭=斗 +鬮=阄 +鬰=郁 +鬱=郁 +鬴=釜 +魊=蜮 +魎=魉 +魘=魇 +魚=鱼 +魛=鱽 +魢=鱾 +魨=鲀 +魯=鲁 +魴=鲂 +魷=鱿 +魺=鲄 +鮁=鲅 +鮃=鲆 +鮊=鲌 +鮋=鲉 +鮍=鲏 +鮎=鲇 +鮐=鲐 +鮑=鲍 +鮒=鲋 +鮓=鲊 +鮚=鲒 +鮜=鲘 +鮝=鲞 +鮞=鲕 +鮟=安 +鮦=鲖 +鮪=鲔 +鮫=鲛 +鮭=鲑 +鮮=鲜 +鮳=鲓 +鮶=鲪 +鮺=鲝 +鯀=鲧 +鯁=鲠 +鯇=鲩 +鯉=鲤 +鯊=鲨 +鯒=鲬 +鯔=鲻 +鯕=鲯 +鯖=鲭 +鯗=鲞 +鯛=鲷 +鯝=鲴 +鯡=鲱 +鯢=鲵 +鯤=鲲 +鯧=鲳 +鯨=鲸 +鯪=鲮 +鯫=鲰 +鯰=鲶 +鯴=鲺 +鯵=鲹 +鯷=鳀 +鯽=鲫 +鯿=鳊 +鰁=鳈 +鰂=鲗 +鰃=鳂 +鰈=鲽 +鰉=鳇 +鰌=鳅 +鰍=鳅 +鰏=鲾 +鰐=鳄 +鰒=鳆 +鰓=鳃 +鰛=鳁 +鰜=鳒 +鰟=鳑 +鰠=鳋 +鰣=鲥 +鰥=鳏 +鰨=鳎 +鰩=鳐 +鰭=鳍 +鰮=鳁 +鰱=鲢 +鰲=鳌 +鰳=鳓 +鰵=鳘 +鰷=鲦 +鰹=鲣 +鰺=鲹 +鰻=鳗 +鰼=鳛 +鰾=鳔 +鱂=鳉 +鱅=鳙 +鱈=鳕 +鱉=鳖 +鱏=鲟 +鱒=鳟 +鱓=鳝 +鱔=鳝 +鱖=鳜 +鱗=鳞 +鱘=鲟 +鱝=鲼 +鱟=鲎 +鱠=鲙 +鱣=鳣 +鱤=鳡 +鱧=鳢 +鱨=鲿 +鱭=鲚 +鱯=鳠 +鱷=鳄 +鱸=鲈 +鱺=鲡 +鱻=鲜 +鳥=鸟 +鳧=凫 +鳩=鸠 +鳬=凫 +鳯=凤 +鳲=鸤 +鳳=凤 +鳴=鸣 +鳶=鸢 +鳾=䴓 +鴆=鸩 +鴇=鸨 +鴈=雁 +鴉=鸦 +鴒=鸰 +鴕=鸵 +鴛=鸳 +鴝=鸲 +鴞=鸮 +鴟=鸱 +鴣=鸪 +鴦=鸯 +鴨=鸭 +鴬=鸴 +鴯=鸸 +鴰=鸹 +鴴=鸻 +鴷=䴕 +鴻=鸿 +鴿=鸽 +鵁=䴔 +鵂=鸺 +鵃=鸼 +鵐=鹀 +鵑=鹃 +鵒=鹆 +鵓=鹁 +鵜=鹈 +鵝=鹅 +鵞=鹅 +鵠=鹄 +鵡=鹉 +鵪=鹌 +鵬=鹏 +鵮=鹐 +鵯=鹎 +鵰=雕 +鵲=鹊 +鵶=鸦 +鵷=鹓 +鵾=鹍 +鶄=䴖 +鶇=鸫 +鶉=鹑 +鶊=鹒 +鶏=鸡 +鶓=鹋 +鶖=鹙 +鶘=鹕 +鶚=鹗 +鶡=鹖 +鶤=鹍 +鶥=鹛 +鶩=鹜 +鶪=䴗 +鶬=鸧 +鶯=莺 +鶲=鹟 +鶴=鹤 +鶹=鹠 +鶺=鹡 +鶻=鹘 +鶼=鹣 +鶿=鹚 +鷀=鹚 +鷁=鹢 +鷂=鹞 +鷄=鸡 +鷈=䴘 +鷊=鹝 +鷓=鹧 +鷖=鹥 +鷗=鸥 +鷙=鸷 +鷚=鹨 +鷥=鸶 +鷦=鹪 +鷫=鹔 +鷯=鹩 +鷰=燕 +鷲=鹫 +鷳=鹇 +鷴=鹇 +鷸=鹬 +鷹=鹰 +鷺=鹭 +鷽=鸴 +鷿=䴙 +鸇=鹯 +鸌=鹱 +鸎=莺 +鸏=鹲 +鸕=鸬 +鸘=鹴 +鸚=鹦 +鸛=鹳 +鸝=鹂 +鸞=鸾 +鹵=卤 +鹹=咸 +鹺=鹾 +鹻=碱 +鹼=硷 +鹽=盐 +麁=粗 +麅=狍 +麐=麟 +麕=麇 +麗=丽 +麞=獐 +麤=粗 +麥=麦 +麩=麸 +麪=面 +麵=面 +麼=么 +麽=么 +黃=黄 +黌=黉 +點=点 +黨=党 +黲=黪 +黴=霉 +黶=黡 +黷=黩 +黽=黾 +黿=鼋 +鼂=鼌 +鼃=蛙 +鼇=鳌 +鼈=鳖 +鼉=鼍 +鼔=鼓 +鼡=用 +鼦=貂 +鼴=鼹 +齇=齄 +齊=齐 +齋=斋 +齎=赍 +齏=齑 +齒=齿 +齔=龀 +齕=龁 +齗=龂 +齙=龅 +齜=龇 +齟=龃 +齠=龆 +齡=龄 +齦=龈 +齧=啮 +齩=咬 +齪=龊 +齬=龉 +齰=醋 +齲=龋 +齶=腭 +齷=龌 +龍=龙 +龎=厐 +龐=庞 +龔=龚 +龕=龛 +龜=龟 +龞=鳖 +龢=和 +︰=﹕ +︵=《 +︶=》 +︷=《 +︸=》 +︹=《 +︺=》 +︻=《 +︼=》 +︽=《 +︾=》 +︿=《 +﹀=》 +﹁=《 +﹂=》 +﹃=《 +﹄=》 +﹝=《 +﹞=》 +﹢=+ +﹤=《 +﹦== +﹩=$ +﹪=% +﹫=@ +!=! +?=? +/=/ +、=, +%=% +(=( +)=) +,=, +.=. +0=0 +1=1 +2=2 +3=3 +4=4 +5=5 +6=6 +7=7 +8=8 +9=9 +A=a +B=b +C=c +D=d +E=e +F=f +G=g +H=h +I=i +J=j +K=k +L=l +M=m +N=n +O=o +P=p +Q=q +R=r +S=s +T=t +U=u +V=v +W=w +X=x +Y=y +Z=z +a=a +b=b +c=c +d=d +e=e +f=f +g=g +h=h +i=i +j=j +k=k +l=l +m=m +n=n +o=o +p=p +q=q +r=r +s=s +t=t +u=u +v=v +w=w +x=x +y=y +z=z +º=0 +¹=1 +²=2 +³=3 +⁴=4 +⁵=5 +⁶=6 +⁷=7 +⁸=8 +⁹=9 +₀=0 +₁=1 +₂=2 +₃=3 +₄=4 +₅=5 +₆=6 +₇=7 +₈=8 +₉=9 +ⁿ=n +:=: +"=" +#=# +$=$ +&=& +'=' +*=* ++=+ +-=- +;=; +<=《 +=== +>=》 +@=@ +[=《 +\=\ +]=》 +^=^ +_=_ +`=` +{=《 +|=| +}=》 +~=~ diff --git a/launchers/standalone/src/test/resources/data/dictionary/other/TagPKU98.csv b/launchers/standalone/src/test/resources/data/dictionary/other/TagPKU98.csv new file mode 100644 index 000000000..c9268b302 --- /dev/null +++ b/launchers/standalone/src/test/resources/data/dictionary/other/TagPKU98.csv @@ -0,0 +1,44 @@ +序号,代码,名称,帮助记忆的诠释,例子及注解 +1,Ag,形语素,形容词性语素。形容词代码为a,语素代码g前面置以A。,绿色/n 似/d 锦/Ag , +2,a,形容词,取英语形容词adjective的第1个字母,[重要/a 步伐/n]NP ,美丽/a ,看似/v 抽象/a , +3,ad,副形词,直接作状语的形容词。形容词代码a和副词代码d并在一起。,[积极/ad 谋求/v]V-ZZ ,幻象/n 易/ad 逝/Vg , +4,an,名形词,具有名词功能的形容词。形容词代码a和名词代码n并在一起。,[外交/n 和/c 安全/an]NP-BL , +5,Bg,区别语素,区别词性语素。区别词代码为b,语素代码g前面置以B。,赤/Ag 橙/Bg 黄/a 绿/a 青/a 蓝/a 紫/a , +6,b,区别词,取汉字“别”的声母。,女/b 司机/n, 金/b 手镯/n, 慢性/b 胃炎/n, 古/b 钱币/n, 副/b 主任/n, 总/b 公司/n单音节区别词和单音节名词或名语素组合,作为一个词,并标以名词词性n。 雄鸡/n, 雌象/n, 女魔/n, 古币/n少数“单音节区别词+双音节词”的结构作为一个词。总书记/n , +7,c,连词,取英语连词conjunction的第1个字母。,合作/vn 与/c 伙伴/n +8,Dg,副语素,副词性语素。副词代码为d,语素代码g前面置以D。,了解/v 甚/Dg 深/a ,煞/Dg 是/v 喜人/a , +9,d,副词,取adverb的第2个字母,因其第1个字母已用于形容词。,进一步/d 发展/v , +10,e,叹词,取英语叹词exclamation的第1个字母。,啊/e ,/w 那/r 金灿灿/z 的/u 麦穗/n , +11,f,方位词,取汉字“方”。,军人/n 的/u 眼睛/n 里/f 不/d 是/v 没有/v 风景/n , +12,h,前接成分,取英语head的第1个字母。,许多/m 非/h 主角/n 人物/n ,办事处/n 的/u “/w 准/h 政府/n ”/w 功能/n 不断/d 加强/v , +13,i,成语,取英语成语idiom的第1个字母。,一言一行/i ,义无反顾/i , +14,j,简称略语,取汉字“简”的声母。,[德/j 外长/n]NP ,文教/j , +15,k,后接成分,后接成分。,少年儿童/l 朋友/n 们/k ,身体/n 健康/a 者/k , +16,l,习用语,习用语尚未成为成语,有点“临时性”,取“临”的声母。,少年儿童/l 朋友/n 们/k ,落到实处/l , +17,Mg,数语素,数词性语素。数词代码为m,语素代码g前面置以M。,甲/Mg 减下/v 的/u 人/n 让/v 乙/Mg 背上/v ,凡/d “/w 寅/Mg 年/n ”/w 中/f 出生/v 的/u 人/n 生肖/n 都/d 属/v 虎/n , +18,m,数词,取英语numeral的第3个字母,n,u已有他用。,1.数量词组应切分为数词和量词。 三/m 个/q, 10/m 公斤/q, 一/m 盒/q 点心/n ,但少数数量词已是词典的登录单位,则不再切分。 一个/m , 一些/m ,2. 基数、序数、小数、分数、百分数一律不予切分,为一个切分单位,标注为 m 。一百二十三/m,20万/m, 123.54/m, 一个/m, 第一/m, 第三十五/m, 20%/m, 三分之二/m, 千分之三十/m, 几十/m 人/n, 十几万/m 元/q, 第一百零一/m 个/q ,3. 约数,前加副词、形容词或后加“来、多、左右”等助数词的应予分开。约/d 一百/m 多/m 万/m,仅/d 一百/m 个/q, 四十/m 来/m 个/q,二十/m 余/m 只/q, 十几/m 个/q,三十/m 左右/m ,两个数词相连的及“成百”、“上千”等则不予切分。五六/m 年/q, 七八/m 天/q,十七八/m 岁/q, 成百/m 学生/n,上千/m 人/n, 4.表序关系的“数+名”结构,应予切分。二/m 连/n , 三/m 部/n , +19,Ng,名语素,名词性语素。名词代码为n,语素代码g前面置以N。,出/v 过/u 两/m 天/q 差/Ng, 理/v 了/u 一/m 次/q 发/Ng, +20,n,名词,取英语名词noun的第1个字母。,(参见 动词--v)岗位/n , 城市/n , 机会/n ,她/r 是/v 责任/n 编辑/n , +21,nr,人名,名词代码n和“人(ren)”的声母并在一起。,1. 汉族人及与汉族起名方式相同的非汉族人的姓和名单独切分,并分别标注为nr。张/nr 仁伟/nr, 欧阳/nr 修/nr, 阮/nr 志雄/nr, 朴/nr 贞爱/nr汉族人除有单姓和复姓外,还有双姓,即有的女子出嫁后,在原来的姓上加上丈夫的姓。如:陈方安生。这种情况切分、标注为:陈/nr 方/nr 安生/nr;唐姜氏,切分、标注为:唐/nr 姜氏/nr。2. 姓名后的职务、职称或称呼要分开。江/nr 主席/n, 小平/nr 同志/n, 江/nr 总书记/n,张/nr 教授/n, 王/nr 部长/n, 陈/nr 老总/n, 李/nr 大娘/n, 刘/nr 阿姨/n, 龙/nr 姑姑/n3. 对人的简称、尊称等若为两个字,则合为一个切分单位,并标以nr。老张/nr, 大李/nr, 小郝/nr, 郭老/nr, 陈总/nr4. 明显带排行的亲属称谓要切分开,分不清楚的则不切开。三/m 哥/n, 大婶/n, 大/a 女儿/n, 大哥/n, 小弟/n, 老爸/n5. 一些著名作者的或不易区分姓和名的笔名通常作为一个切分单位。鲁迅/nr, 茅盾/nr, 巴金/nr, 三毛/nr, 琼瑶/nr, 白桦/nr6. 外国人或少数民族的译名(包括日本人的姓名)不予切分,标注为nr。克林顿/nr, 叶利钦/nr, 才旦卓玛/nr, 小林多喜二/nr, 北研二/nr,华盛顿/nr, 爱因斯坦/nr有些西方人的姓名中有小圆点,也不分开。卡尔·马克思/nr +22,ns,地名,名词代码n和处所词代码s并在一起。,(参见2。短语标记说明--NS)安徽/ns,深圳/ns,杭州/ns,拉萨/ns,哈尔滨/ns, 呼和浩特/ns, 乌鲁木齐/ns,长江/ns,黄海/ns,太平洋/ns, 泰山/ns, 华山/ns,亚洲/ns, 海南岛/ns,太湖/ns,白洋淀/ns, 俄罗斯/ns,哈萨克斯坦/ns,彼得堡/ns, 伏尔加格勒/ns 1. 国名不论长短,作为一个切分单位。中国/ns, 中华人民共和国/ns, 日本国/ns, 美利坚合众国/ns, 美国/ns2. 地名后有“省”、“市”、“县”、“区”、“乡”、“镇”、“村”、“旗”、“州”、“都”、“府”、“道”等单字的行政区划名称时,不切分开,作为一个切分单位。四川省/ns, 天津市/ns,景德镇/ns沙市市/ns, 牡丹江市/ns,正定县/ns,海淀区/ns, 通州区/ns,东升乡/ns, 双桥镇/ns 南化村/ns,华盛顿州/ns,俄亥俄州/ns,东京都/ns, 大阪府/ns,北海道/ns, 长野县/ns,开封府/ns,宣城县/ns3. 地名后的行政区划有两个以上的汉字,则将地名同行政区划名称切开,不过要将地名同行政区划名称用方括号括起来,并标以短语NS。[芜湖/ns 专区/n] NS,[宣城/ns 地区/n]ns,[内蒙古/ns 自治区/n]NS,[深圳/ns 特区/n]NS, [厦门/ns 经济/n 特区/n]NS, [香港/ns 特别/a 行政区/n]NS,[香港/ns 特区/n]NS, [华盛顿/ns 特区/n]NS,4. 地名后有表示地形地貌的一个字的普通名词,如“江、河、山、洋、海、岛、峰、湖”等,不予切分。鸭绿江/ns,亚马逊河/ns, 喜马拉雅山/ns, 珠穆朗玛峰/ns,地中海/ns,大西洋/ns,洞庭湖/ns, 塞普路斯岛/ns 5. 地名后接的表示地形地貌的普通名词若有两个以上汉字,则应切开。然后将地名同该普通名词标成短语NS。[台湾/ns 海峡/n]NS,[华北/ns 平原/n]NS,[帕米尔/ns 高原/n]NS, [南沙/ns 群岛/n]NS,[京东/ns 大/a 峡谷/n]NS [横断/b 山脉/n]NS6.地名后有表示自然区划的一个字的普通名词,如“ 街,路,道,巷,里,町,庄,村,弄,堡”等,不予切分。 中关村/ns,长安街/ns,学院路/ns, 景德镇/ns, 吴家堡/ns, 庞各庄/ns, 三元里/ns,彼得堡/ns, 北菜市巷/ns, 7.地名后接的表示自然区划的普通名词若有两个以上汉字,则应切开。然后将地名同自然区划名词标成短语NS。[米市/ns 大街/n]NS, [蒋家/nz 胡同/n]NS , [陶然亭/ns 公园/n]NS , 8. 大小地名相连时的标注方式为:北京市/ns 海淀区/ns 海淀镇/ns [南/f 大街/n]NS [蒋家/nz 胡同/n]NS 24/m 号/q , +23,nt,机构团体,“团”的声母为t,名词代码n和t并在一起。,(参见2。短语标记说明--NT)联合国/nt,中共中央/nt,国务院/nt, 北京大学/nt1.大多数团体、机构、组织的专有名称一般是短语型的,较长,且含有地名或人名等专名,再组合,标注为短语NT。[中国/ns 计算机/n 学会/n]NT, [香港/ns 钟表业/n 总会/n]NT, [烟台/ns 大学/n]NT, [香港/ns 理工大学/n]NT, [华东/ns 理工大学/n]NT,[合肥/ns 师范/n 学院/n]NT, [北京/ns 图书馆/n]NT, [富士通/nz 株式会社/n]NT, [香山/ns 植物园/n]NT, [安娜/nz 美容院/n]NT,[上海/ns 手表/n 厂/n]NT, [永和/nz 烧饼铺/n]NT,[北京/ns 国安/nz 队/n]NT,2. 对于在国际或中国范围内的知名的唯一的团体、机构、组织的名称即使前面没有专名,也标为nt或NT。联合国/nt,国务院/nt,外交部/nt, 财政部/nt,教育部/nt, 国防部/nt,[世界/n 贸易/n 组织/n]NT, [国家/n 教育/vn 委员会/n]NT,[信息/n 产业/n 部/n]NT,[全国/n 信息/n 技术/n 标准化/vn 委员会/n]NT,[全国/n 总/b 工会/n]NT,[全国/n 人民/n 代表/n 大会/n]NT,美国的“国务院”,其他国家的“外交部、财政部、教育部”,必须在其所属国的国名之后出现时,才联合标注为NT。[美国/ns 国务院/n]NT,[法国/ns 外交部/n]NT,[美/j 国会/n]NT,日本有些政府机构名称很特别,无论是否出现在“日本”国名之后都标为nt。[日本/ns 外务省/nt]NT,[日/j 通产省/nt]NT通产省/nt 3. 前后相连有上下位关系的团体机构组织名称的处理方式如下:[联合国/nt 教科文/j 组织/n]NT, [中国/ns 银行/n 北京/ns 分行/n]NT,[河北省/ns 正定县/ns 西平乐乡/ns 南化村/ns 党支部/n]NT, 当下位名称含有专名(如“北京/ns 分行/n”、“南化村/ns 党支部/n”、“昌平/ns 分校/n”)时,也可脱离前面的上位名称单独标注为NT。[中国/ns 银行/n]NT [北京/ns 分行/n]NT,北京大学/nt [昌平/ns 分校/n]NT,4. 团体、机构、组织名称中用圆括号加注简称时:[宝山/ns 钢铁/n (/w 宝钢/j )/w 总/b 公司/n]NT,[宝山/ns 钢铁/n 总/b 公司/n]NT,(/w 宝钢/j )/w +24,nx,外文字符,外文字符。,A/nx 公司/n ,B/nx 先生/n ,X/nx 君/Ng ,24/m K/nx 镀金/n ,C/nx 是/v 光速/n ,Windows98/nx ,PentiumIV/nx ,I LOVE THIS GAME/nx , +25,nz,其他专名,“专”的声母的第1个字母为z,名词代码n和z并在一起。,(参见2。短语标记说明--NZ)除人名、国名、地名、团体、机构、组织以外的其他专有名词都标以nz。满族/nz,俄罗斯族/nz,汉语/nz,罗马利亚语/nz, 捷克语/nz,中文/nz, 英文/nz, 满人/nz, 哈萨克人/nz, 诺贝尔奖/nz, 茅盾奖/nz, 1.包含专有名称(或简称)的交通线,标以nz;短语型的,标为NZ。津浦路/nz, 石太线/nz, [京/j 九/j 铁路/n]NZ, [京/j 津/j 高速/b 公路/n]NZ, 2. 历史上重要事件、运动等专有名称一般是短语型的,按短语型专有名称处理,标以NZ。[卢沟桥/ns 事件/n]NZ, [西安/ns 事变/n]NZ,[五四/t 运动/n]NZ, [明治/nz 维新/n]NZ,[甲午/t 战争/n]NZ,3.专有名称后接多音节的名词,如“语言”、“文学”、“文化”、“方式”、“精神”等,失去专指性,则应分开。欧洲/ns 语言/n, 法国/ns 文学/n, 西方/ns 文化/n, 贝多芬/nr 交响乐/n, 雷锋/nr 精神/n, 美国/ns 方式/n,日本/ns 料理/n, 宋朝/t 古董/n 4. 商标(包括专名及后接的“牌”、“型”等)是专指的,标以nz,但其后所接的商品仍标以普通名词n。康师傅/nr 方便面/n, 中华牌/nz 香烟/n, 牡丹III型/nz 电视机/n, 联想/nz 电脑/n, 鳄鱼/nz 衬衣/n, 耐克/nz 鞋/n5. 以序号命名的名称一般不认为是专有名称。2/m 号/q 国道/n ,十一/m 届/q 三中全会/j如果前面有专名,合起来作为短语型专名。[中国/ns 101/m 国道/n]NZ, [中共/j 十一/m 届/q 三中全会/j]NZ,6. 书、报、杂志、文档、报告、协议、合同等的名称通常有书名号加以标识,不作为专有名词。由于这些名字往往较长,名字本身按常规处理。《/w 宁波/ns 日报/n 》/w ,《/w 鲁迅/nr 全集/n 》/w,中华/nz 读书/vn 报/n, 杜甫/nr 诗选/n,少数书名、报刊名等专有名称,则不切分。红楼梦/nz, 人民日报/nz,儒林外史/nz 7. 当有些专名无法分辨它们是人名还是地名或机构名时,暂标以nz。[巴黎/ns 贝尔希/nz 体育馆/n]NT,其中“贝尔希”只好暂标为nz。 +26,o,拟声词,取英语拟声词onomatopoeia的第1个字母。,哈哈/o 一/m 笑/v ,装载机/n 隆隆/o 推进/v , +27,p,介词,取英语介词prepositional的第1个字母。,对/p 子孙后代/n 负责/v ,以/p 煤/n 养/v 农/Ng ,为/p 治理/v 荒山/n 服务/v , 把/p 青年/n 推/v 上/v 了/u 领导/vn 岗位/n , +28,q,量词,取英语quantity的第1个字母。,(参见数词m)首/m 批/q ,一/m 年/q , +29,Rg,代语素,代词性语素。代词代码为r,在语素的代码g前面置以R。,读者/n 就/d 是/v 这/r 两/m 棵/q 小树/n 扎根/v 于/p 斯/Rg 、/w 成长/v 于/p 斯/Rg 的/u 肥田/n 沃土/n , +30,r,代词,取英语代词pronoun的第2个字母,因p已用于介词。,单音节代词“本”、“每”、“各”、“诸”后接单音节名词时,和后接的单音节名词合为代词;当后接双音节名词时,应予切分。本报/r, 每人/r, 本社/r, 本/r 地区/n, 各/r 部门/n +31,s,处所词,取英语space的第1个字母。,家里/s 的/u 电脑/n 都/d 联通/v 了/u 国际/n 互联网/n ,西部/s 交通/n 咽喉/n , +32,Tg,时语素,时间词性语素。时间词代码为t,在语素的代码g前面置以T。,3日/t 晚/Tg 在/p 总统府/n 发表/v 声明/n ,尊重/v 现/Tg 执政/vn 当局/n 的/u 权威/n , +33,t,时间词,取英语time的第1个字母。,1. 年月日时分秒,按年、月、日、时、分、秒切分,标注为t 。1997年/t 3月/t 19日/t 下午/t 2时/t 18分/t若数字后无表示时间的“年、月、日、时、分、秒”等的标为数词m。1998/m 中文/n 信息/n 处理/vn 国际/n 会议/n 2. 历史朝代的名称虽然有专有名词的性质,仍标注为t。西周/t, 秦朝/t, 东汉/t, 南北朝/t, 清代/t“牛年、虎年”等一律不予切分,标注为:牛年/t, 虎年/t, 甲午年/t, 甲午/t 战争/n, 庚子/t 赔款/n, 戊戌/t 变法/n +34,u,助词,取英语助词auxiliary。,[[俄罗斯/ns 和/c 北约/j]NP-BL 之间/f [战略/n 伙伴/n 关系/n]NP 的/u 建立/vn]NP 填平/v 了/u [[欧洲/ns 安全/a 政治/n]NP 的/u 鸿沟/n]NP +35,Vg,动语素,动词性语素。动词代码为v。在语素的代码g前面置以V。,洗/v 了/u 一个/m 舒舒服服/z 的/u 澡/Vg +36,v,动词,取英语动词verb的第一个字母。,(参见 名词--n)[[[欧盟/j 扩大/v]S 的/u [历史性/n 决定/n]NP]NP 和/c [北约/j 开放/v]S]NP-BL [为/p [创建/v [一/m 种/q 新/a 的/u 欧洲/ns 安全/a 格局/n]NP]VP-SBI]PP-MD [奠定/v 了/u 基础/n]V-SBI ,, +37,vd,副动词,直接作状语的动词。动词和副词的代码并在一起。,形势/n 会/v 持续/vd 好转/v ,认为/v 是/v 电话局/n 收/v 错/vd 了/u 费/n , +38,vn,名动词,指具有名词功能的动词。动词和名词的代码并在一起。,引起/v 人们/n 的/u 关注/vn 和/c 思考/vn ,收费/vn 电话/n 的/u 号码/n , +39,w,标点符号,,”/w :/w +40,x,非语素字,非语素字只是一个符号,字母x通常用于代表未知数、符号。, +41,Yg,语气语素,语气词性语素。语气词代码为y。在语素的代码g前面置以Y。,唯/d 大力/d 者/k 能/v 致/v 之/u 耳/Yg +42,y,语气词,取汉字“语”的声母。,会/v 泄露/v 用户/n 隐私/n 吗/y ,又/d 何在/v 呢/y ? +43,z,状态词,取汉字“状”的声母的前一个字母。,取得/v 扎扎实实/z 的/u 突破性/n 进展/vn ,四季/n 常青/z 的/u 热带/n 树木/n ,短短/z 几/m 年/q 间, \ No newline at end of file diff --git a/launchers/standalone/src/test/resources/data/version.txt b/launchers/standalone/src/test/resources/data/version.txt new file mode 100644 index 000000000..6a126f402 --- /dev/null +++ b/launchers/standalone/src/test/resources/data/version.txt @@ -0,0 +1 @@ +1.7.5 diff --git a/launchers/standalone/src/test/resources/db/data-h2.sql b/launchers/standalone/src/test/resources/db/data-h2.sql new file mode 100644 index 000000000..61413b07d --- /dev/null +++ b/launchers/standalone/src/test/resources/db/data-h2.sql @@ -0,0 +1,1070 @@ +-- chat data +insert into s2_user (id, `name`, password, display_name, email) values (1, 'admin','admin','admin','admin@xx.com'); +insert into s2_user (id, `name`, password, display_name, email) values (2, 'jack','123456','jack','jack@xx.com'); +insert into s2_user (id, `name`, password, display_name, email) values (3, 'tom','123456','tom','tom@xx.com'); +insert into s2_user (id, `name`, password, display_name, email) values (4, 'lucy','123456','lucy','lucy@xx.com'); + +insert into s2_chat_config (`id` ,`domain_id` ,`default_metrics`,`visibility`,`entity_info` ,`dictionary_info`,`created_at`,`updated_at`,`created_by`,`updated_by`,`status` ) values (1,1,'[{"metricId":1,"unit":7,"period":"DAY"}]','{"blackDimIdList":[],"blackMetricIdList":[]}','{"entityIds":[2],"names":["用户","用户姓名"],"detailData":{"dimensionIds":[1,2],"metricIds":[2]}}','[{"itemId":1,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":2,"type":"DIMENSION","blackList":[],"isDictInfo":true},{"itemId":3,"type":"DIMENSION","blackList":[],"isDictInfo":true}]','2023-05-24 18:00:00','2023-05-25 11:00:00','admin','admin',1); + +insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (1, '超音数访问统计','2023-06-10 10:00:52.495','2023-06-10 10:00:52','admin','您好,欢迎使用内容智能小Q','0','0'); +insert into s2_chat (chat_id, `chat_name`, create_time, last_time, creator,last_question,is_delete,is_top) values (2, '用户访问统计','2023-06-10 10:01:04.528','2023-06-10 10:01:04','admin','您好,欢迎使用内容智能小Q','0','0'); + +insert into s2_chat_context (chat_id, modified_at , `user`, `query_text`, `semantic_parse` ,ext_data) VALUES(1, '2023-06-10 10:40:49.877', 'admin', '访问', '{"queryMode":"METRIC_ORDERBY","aggType":"NONE","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"nativeQuery":false}', 'admin'); +insert into s2_chat_context (chat_id, modified_at , `user`, `query_text`, `semantic_parse` ,ext_data) VALUES(2, '2023-06-10 10:42:02.184', 'null', '访问', '{"queryMode":"METRIC_ORDERBY","aggType":"NONE","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"nativeQuery":false}', 'null'); + +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(1, '2023-06-10 10:39:55.178', '超音数 访问次数', 'admin',0,1,'{"queryMode":"METRIC_DOMAIN","querySql":"SELECT `sys_imp_date` , `pv` FROM ( SELECT `sys_imp_date` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` FROM ( SELECT `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_f370` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_DOMAIN","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","pv":11},{"sys_imp_date":"2023-06-04","pv":14},{"sys_imp_date":"2023-06-05","pv":1},{"sys_imp_date":"2023-06-06","pv":19},{"sys_imp_date":"2023-06-07","pv":18},{"sys_imp_date":"2023-06-08","pv":24},{"sys_imp_date":"2023-06-09","pv":23}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(2, '2023-06-10 10:40:12.259', '按页面', 'admin',0,1,'{"queryMode":"METRIC_ORDERBY","querySql":"SELECT `sys_imp_date` , `page` , `pv` FROM ( SELECT `sys_imp_date` , `page` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` , `page` FROM ( SELECT `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` , `page` AS `page` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_ecf5` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` , `page` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"页面","type":"VARCHAR","nameEn":"page","showType":"CATEGORY","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_ORDERBY","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","page":"p1","pv":2},{"sys_imp_date":"2023-06-03","page":"p2","pv":3},{"sys_imp_date":"2023-06-03","page":"p3","pv":2},{"sys_imp_date":"2023-06-03","page":"p4","pv":1},{"sys_imp_date":"2023-06-03","page":"p5","pv":3},{"sys_imp_date":"2023-06-04","page":"p1","pv":3},{"sys_imp_date":"2023-06-04","page":"p2","pv":1},{"sys_imp_date":"2023-06-04","page":"p3","pv":2},{"sys_imp_date":"2023-06-04","page":"p4","pv":4},{"sys_imp_date":"2023-06-04","page":"p5","pv":4}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(3, '2023-06-10 10:40:49.877', '访问', 'admin',0,1,'{"queryMode":"METRIC_ORDERBY","querySql":"SELECT `sys_imp_date` , `page` , `uv` , `pv` FROM ( SELECT `sys_imp_date` , `page` , `s2_pv_uv_statis_uv` AS `uv` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT COUNT ( DISTINCT `s2_pv_uv_statis_uv` ) AS `s2_pv_uv_statis_uv` , SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` , `page` FROM ( SELECT `uv` AS `s2_pv_uv_statis_uv` , `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` , `page` AS `page` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_022c` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' ) GROUP BY `sys_imp_date` , `page` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"页面","type":"VARCHAR","nameEn":"page","showType":"CATEGORY","authorized":true},{"name":"访问人数","type":"BIGINT","nameEn":"uv","showType":"NUMBER","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"}},"chatContext":{"queryMode":"METRIC_ORDERBY","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":3,"name":"访问人数","bizName":"uv","status":1,"sensitiveLevel":0},{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"id":3,"name":"页面","bizName":"page","status":1,"sensitiveLevel":0},{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","page":"p1","uv":2,"pv":2},{"sys_imp_date":"2023-06-03","page":"p2","uv":3,"pv":3},{"sys_imp_date":"2023-06-03","page":"p3","uv":2,"pv":2},{"sys_imp_date":"2023-06-03","page":"p4","uv":1,"pv":1},{"sys_imp_date":"2023-06-03","page":"p5","uv":3,"pv":3},{"sys_imp_date":"2023-06-04","page":"p1","uv":2,"pv":3},{"sys_imp_date":"2023-06-04","page":"p2","uv":1,"pv":1},{"sys_imp_date":"2023-06-04","page":"p3","uv":2,"pv":2},{"sys_imp_date":"2023-06-04","page":"p4","uv":3,"pv":4},{"sys_imp_date":"2023-06-04","page":"p5","uv":3,"pv":4}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(4, '2023-06-10 10:41:18.589','alice 访问次数','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `pv` FROM ( SELECT `sys_imp_date` , `s2_pv_uv_statis_pv` AS `pv` FROM ( SELECT SUM ( `s2_pv_uv_statis_pv` ) AS `s2_pv_uv_statis_pv` , `sys_imp_date` FROM ( SELECT `user_name` , `pv` AS `s2_pv_uv_statis_pv` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `user_name` , `page` , 1 AS `pv` , `user_name` AS `uv` FROM `s2_pv_uv_statis` ) AS `s2_pv_uv_statis` ) AS `src00_s2_pv_uv_statis_b825` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_pv_uv_statis_0` ) AS `s2_pv_uv_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"访问次数","type":"BIGINT","nameEn":"pv","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":2,"name":"访问次数","bizName":"pv","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","pv":2},{"sys_imp_date":"2023-06-04","pv":2},{"sys_imp_date":"2023-06-06","pv":2},{"sys_imp_date":"2023-06-07","pv":2},{"sys_imp_date":"2023-06-08","pv":5},{"sys_imp_date":"2023-06-09","pv":2}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(5, '2023-06-10 10:41:48.211','停留时长','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); +insert into s2_chat_query (`question_id`,`create_time`,`query_text`,`user_name`,`query_state`,`chat_id`,`query_response`,`score`,`feedback`) VALUES(6, '2023-06-10 10:42:02.184','访问','admin',0,2,'{"queryMode":"METRIC_FILTER","querySql":"SELECT `sys_imp_date` , `stay_hours` FROM ( SELECT `sys_imp_date` , `s2_stay_time_statis_stay_hours` AS `stay_hours` FROM ( SELECT SUM ( `s2_stay_time_statis_stay_hours` ) AS `s2_stay_time_statis_stay_hours` , `sys_imp_date` FROM ( SELECT `user_name` , `stay_hours` AS `s2_stay_time_statis_stay_hours` , `imp_date` AS `sys_imp_date` FROM ( SELECT `imp_date` , `page` , `user_name` , `stay_hours` FROM `s2_stay_time_statis` ) AS `s2_stay_time_statis` ) AS `src00_s2_stay_time_statis_df18` WHERE ( `sys_imp_date` >= ''2023-06-03'' AND `sys_imp_date` <= ''2023-06-09'' AND `user_name` = ''alice'' ) GROUP BY `sys_imp_date` ) AS `s2_stay_time_statis_0` ) AS `s2_stay_time_statis_1` LIMIT 10","queryState":0,"queryColumns":[{"name":"date","type":"VARCHAR","nameEn":"sys_imp_date","showType":"DATE","authorized":true},{"name":"停留时长","type":"DOUBLE","nameEn":"stay_hours","showType":"NUMBER","authorized":true}],"entityInfo":{"domainInfo":{"itemId":1,"name":"超音数","bizName":"supersonic","words":["用户","用户姓名"],"primaryEntityBizName":"user_name"},"dimensions":[{"itemId":1,"name":"部门","bizName":"department","value":"sales"},{"itemId":2,"name":"用户名","bizName":"user_name","value":"alice"}],"metrics":[{"itemId":2,"name":"访问次数","bizName":"pv","value":"2"}],"entityId":"alice"},"chatContext":{"queryMode":"METRIC_FILTER","domainId":1,"domainName":"超音数","entity":0,"metrics":[{"id":1,"name":"停留时长","bizName":"stay_hours","status":1,"sensitiveLevel":0}],"dimensions":[{"bizName":"sys_imp_date","status":1,"sensitiveLevel":0}],"dimensionFilters":[{"bizName":"user_name","name":"用户名","operator":"=","value":"alice","elementID":2}],"metricFilters":[],"orders":[],"dateInfo":{"dateMode":"RECENT_UNITS","startDate":"2023-06-03","endDate":"2023-06-09","dateList":[],"unit":7,"period":"DAY"},"limit":10,"nativeQuery":false},"queryResults":[{"sys_imp_date":"2023-06-03","stay_hours":0.5963801306980994},{"sys_imp_date":"2023-06-04","stay_hours":1.5120376931855422},{"sys_imp_date":"2023-06-06","stay_hours":3.7790223355266317},{"sys_imp_date":"2023-06-07","stay_hours":0.8654528466186735},{"sys_imp_date":"2023-06-08","stay_hours":0.9796159603778489},{"sys_imp_date":"2023-06-09","stay_hours":0.6705580511822682}]}',0,''); + + +-- semantic data +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 , domain_id, `name`, biz_name, description, database_id ,datasource_detail, created_at, created_by, updated_at, updated_by ) VALUES(1, 1, '停留时长统计', 's2_stay_time_statis', '停留时长统计', 1, '{"dimensions":[{"bizName":"imp_date","dateFormat":"yyyy-MM-dd","expr":"imp_date","isCreateDimension":0,"type":"time","typeParams":{"isPrimary":"true","timeGranularity":"day"}},{"bizName":"page","dateFormat":"yyyy-MM-dd","expr":"page","isCreateDimension":0,"type":"categorical"}],"identifiers":[{"bizName":"user_name","name":"用户名","type":"primary"}],"measures":[{"agg":"sum","bizName":"s2_stay_time_statis_stay_hours","expr":"stay_hours","isCreateMetric":1,"name":"停留时长"}],"queryType":"sql_query","sqlQuery":"SELECT imp_date, page,user_name,stay_hours FROM s2_stay_time_statis"}', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource (id , domain_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 , domain_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_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(1, 1, 1, 2, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(2, 1, 1, 3, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_datasource_rela (id , domain_id, `datasource_from`, datasource_to, join_key, created_at, created_by, updated_at, updated_by ) VALUES(3, 1, 2, 3, 'user_name', '2023-05-25 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin'); +insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(1, 1, 3, '部门', 'department', '部门', 1, 0, 'categorical', NULL, 'department', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(2, 1, 1, '用户名', 'user_name', '用户名', 1, 0, 'primary', NULL, 'user_name', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_dimension (id , domain_id, datasource_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, expr, created_at, created_by, updated_at, updated_by, semantic_type) VALUES(3, 1, 2, '页面', 'page', '页面', 1, 2, 'categorical', NULL, 'page', '2023-05-24 00:00:00', 'admin', '2023-05-25 00:00:00', 'admin', 'CATEGORY'); +insert into s2_domain (id, `name`, biz_name, parent_id, status, created_at, created_by, updated_at, updated_by, `admin`, admin_org, is_open, viewer, view_org) VALUES(1, '超音数', 'supersonic', 0, 1, '2023-05-24 00:00:00', 'admin', '2023-05-24 00:00:00', 'admin', 'admin', '', 0, 'admin,tom,jack', 'admin' ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(1, 1, '停留时长', 'stay_hours', '停留时长', 1, 2, 'expr', '{"expr":"s2_stay_time_statis_stay_hours","measures":[{"agg":"sum","expr":"stay_hours","isCreateMetric":1,"datasourceId":1,"bizName":"s2_stay_time_statis_stay_hours","name":"s2_stay_time_statis_stay_hours"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(2, 1, '访问次数', 'pv', '访问次数', 1, 0, 'expr', ' {"expr":"s2_pv_uv_statis_pv","measures":[{"agg":"sum","bizName":"s2_pv_uv_statis_pv","datasourceId":2,"expr":"pv","isCreateMetric":1,"name":"s2_pv_uv_statis_pv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); +insert into s2_metric (id, domain_id, `name`, biz_name, description, status, sensitive_level, `type`, type_params, created_at, created_by, updated_at, updated_by, data_format_type, data_format) VALUES(3, 1, '访问人数', 'uv', '访问人数', 1, 0, 'expr', ' {"expr":"s2_pv_uv_statis_uv","measures":[{"agg":"count_distinct","bizName":"s2_pv_uv_statis_uv","datasourceId":2,"expr":"uv","isCreateMetric":1,"name":"s2_pv_uv_statis_uv"}]}' , '2023-05-24 17:00:00', 'admin', '2023-05-25 00:00:00', 'admin', NULL, NULL ); + +insert into s2_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, '{"domainId":"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, '{"domainId":"1","name":"tom_sales_permission","groupId":2,"authRules":[{"metrics":["stay_hours"],"dimensions":["page"]}],"dimensionFilters":["department in (''sales'')"],"dimensionFilterDescription":"开通 tom sales部门权限", "authorizedUsers":["tom"],"authorizedDepartmentIds":[]}'); + + +-- 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'); + +---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 ('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_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/test/resources/db/schema-h2.sql b/launchers/standalone/src/test/resources/db/schema-h2.sql new file mode 100644 index 000000000..e75454e90 --- /dev/null +++ b/launchers/standalone/src/test/resources/db/schema-h2.sql @@ -0,0 +1,341 @@ +-- 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 + `semantic_parse` LONGVARCHAR DEFAULT NULL , -- parse data + `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`) +) ; + + +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 '', + PRIMARY KEY (`question_id`) +); + + + +CREATE TABLE IF NOT EXISTS `s2_chat_config` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_id` INT DEFAULT NULL , + `default_metrics` varchar(655) DEFAULT NULL, + `visibility` varchar(655) , -- invisible dimension metric information + `entity_info` varchar(655) , + `dictionary_info` varchar(655) , -- dictionary-related dimension setting information + `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_dictionary` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_id` INT NOT NULL , + `dim_value_infos` LONGVARCHAR , -- dimension value setting information + `created_at` TIMESTAMP NOT NULL , + `updated_at` TIMESTAMP NOT NULL , + `created_by` varchar(100) NOT NULL , + `updated_by` varchar(100) DEFAULT 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`), + UNIQUE (domain_id) + ); +COMMENT ON TABLE s2_dictionary IS 'dictionary configuration information table'; + + +CREATE TABLE IF NOT EXISTS `s2_dictionary_task` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL , -- task name + `description` varchar(255) , + `command`LONGVARCHAR NOT NULL , -- task Request Parameters + `command_md5` varchar(255) NOT NULL , -- task Request Parameters md5 + `status` INT NOT NULL , -- the final status of the task + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP , + `created_by` varchar(100) NOT NULL , + `progress` DOUBLE default 0.00 , -- task real-time progress + `elapsed_ms` bigINT DEFAULT NULL , -- the task takes time in milliseconds + `message` LONGVARCHAR , -- remark related information + PRIMARY KEY (`id`) +); +COMMENT ON TABLE s2_dictionary_task IS 'dictionary task information table'; + + +create table s2_user +( + id INT AUTO_INCREMENT, + name varchar(100) not null, + display_name varchar(100) null, + password varchar(100) null, + email varchar(100) null, + PRIMARY KEY (`id`) +); +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 , + `is_unique` INT DEFAULT NULL , -- 0 is non-unique, 1 is unique + `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 `s2_database` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_id` INT NOT NULL , + `name` varchar(255) NOT NULL , + `description` varchar(500) 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, + `domain_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), + PRIMARY KEY (`group_id`) +); + +CREATE TABLE IF NOT EXISTS `s2_metric` ( + `id` INT NOT NULL AUTO_INCREMENT, + `domain_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 , + `created_at` TIMESTAMP 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`) + ); +COMMENT ON TABLE s2_metric IS 'metric information table'; + + +CREATE TABLE IF NOT EXISTS `s2_dimension` ( + `id` INT NOT NULL AUTO_INCREMENT , + `domain_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 , + `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, + PRIMARY KEY (`id`) + ); +COMMENT ON TABLE s2_dimension IS 'dimension information table'; + +create table s2_datasource_rela +( + id INT AUTO_INCREMENT, + domain_id INT null, + datasource_from INT null, + datasource_to INT null, + join_key varchar(100) null, + created_at TIMESTAMP null, + created_by varchar(100) null, + updated_at TIMESTAMP null, + updated_by varchar(100) null, + PRIMARY KEY (`id`) +); +COMMENT ON TABLE s2_datasource_rela IS 'data source association table'; + +create table s2_view_info +( + id INT auto_increment, + domain_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_by varchar(100) not null +); +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 + `domain_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 , + `domain_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 , + `status` INT NOT NULL , + `elapsed_ms` bigINT DEFAULT NULL , + PRIMARY KEY (`id`) + ); +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 , + `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'; + + +-------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 + ); +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 + ); +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, + `stay_hours` DOUBLE NOT NULL, + `page` varchar(200) NOT NULL + ); +COMMENT ON TABLE s2_stay_time_statis IS 's2_stay_time_statis_info'; + + + + + + diff --git a/launchers/standalone/src/test/resources/hanlp.properties b/launchers/standalone/src/test/resources/hanlp.properties new file mode 100644 index 000000000..9d91904eb --- /dev/null +++ b/launchers/standalone/src/test/resources/hanlp.properties @@ -0,0 +1,2 @@ +root=. +CustomDictionaryPath=data/dictionary/custom/DimValue_1_1.txt;data/dictionary/custom/DimValue_1_2.txt;data/dictionary/custom/DimValue_1_3.txt; \ No newline at end of file diff --git a/launchers/standalone/src/test/resources/logback-spring.xml b/launchers/standalone/src/test/resources/logback-spring.xml new file mode 100644 index 000000000..810eda9b3 --- /dev/null +++ b/launchers/standalone/src/test/resources/logback-spring.xml @@ -0,0 +1,93 @@ + + + logback + + + + + + + %d{HH:mm:ss} [%thread] %-5level %logger{36} %line - %msg%n + + + + + + ${LOG_PATH}/info.${LOG_APPNAME}.log + + + + ${LOG_PATH}/info.${LOG_APPNAME}.%d{yyyy-MM-dd}.log.gz + + 30 + + + + + + UTF-8 + %d [%thread] %-5level [%X{TRACE_ID}] %logger{36} %line - %msg%n + + + + + + + Error + + + ${LOG_PATH}/error.${LOG_APPNAME}.log + + + + ${LOG_PATH}/error.${LOG_APPNAME}.%d{yyyy-MM-dd}.log.gz + + 90 + + + + + + UTF-8 + %d [%thread] %-5level [%X{TRACE_ID}] %logger{36} %line - %msg%n + + + + + + + + + + + + ${LOG_PATH}/serviceinfo.${LOG_APPNAME}.log + + + + ${LOG_PATH}/serviceinfo.${LOG_APPNAME}.%d{yyyy-MM-dd}.log.gz + + 30 + + + + + + UTF-8 + %d [%thread] %-5level [%X{TRACE_ID}] %logger{36} %line - %msg%n + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index a7b34fd6a..7e6c4be5a 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 2.5.1 1.34.0 1.23.0 - 0.5-SNAPSHOT + 0.6-SNAPSHOT diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/MetricTypeEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/MetricTypeEnum.java index 87e612136..09674c884 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/MetricTypeEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/MetricTypeEnum.java @@ -3,15 +3,7 @@ package com.tencent.supersonic.semantic.api.core.enums; public enum MetricTypeEnum { - EXPR("expr"); + ATOMIC, + DERIVED - private String name; - - MetricTypeEnum(String name) { - this.name = name; - } - - public String getName() { - return name; - } } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/OperatorEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/OperatorEnum.java index 7b302ccea..3a37f9a31 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/OperatorEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/OperatorEnum.java @@ -19,12 +19,12 @@ public enum OperatorEnum { UNKNOWN("UNKNOWN"); + private String operator; + OperatorEnum(String operator) { this.operator = operator; } - private String operator; - public String getOperator() { return operator; } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeBackEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeBackEnum.java index 7f1a1d5fb..942f02ee3 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeBackEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeBackEnum.java @@ -14,14 +14,6 @@ public enum QueryTypeBackEnum { this.state = state; } - public String getValue() { - return value; - } - - public Integer getState() { - return state; - } - public static QueryTypeBackEnum of(String src) { for (QueryTypeBackEnum operatorEnum : QueryTypeBackEnum.values()) { if (src.toUpperCase().contains(operatorEnum.value)) { @@ -31,5 +23,13 @@ public enum QueryTypeBackEnum { return null; } + public String getValue() { + return value; + } + + public Integer getState() { + return state; + } + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeEnum.java index d53f04ab6..0cfa26322 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/QueryTypeEnum.java @@ -12,10 +12,6 @@ public enum QueryTypeEnum { this.value = value; } - public String getValue() { - return value; - } - public static QueryTypeEnum of(String src) { for (QueryTypeEnum operatorEnum : QueryTypeEnum.values()) { if (src.toUpperCase().contains(operatorEnum.value)) { @@ -25,5 +21,9 @@ public enum QueryTypeEnum { return null; } + public String getValue() { + return value; + } + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/TimeDimensionEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/TimeDimensionEnum.java index 92f827271..0ad46bca3 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/TimeDimensionEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/enums/TimeDimensionEnum.java @@ -18,11 +18,11 @@ public enum TimeDimensionEnum { this.name = name; } - public String getName() { - return name; - } - public static List getNameList() { return Arrays.stream(TimeDimensionEnum.values()).map(TimeDimensionEnum::getName).collect(Collectors.toList()); } + + public String getName() { + return name; + } } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/MetricTypeParams.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/MetricTypeParams.java index e32356833..b97bf56f8 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/MetricTypeParams.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/MetricTypeParams.java @@ -1,12 +1,13 @@ package com.tencent.supersonic.semantic.api.core.pojo; import java.util.List; +import com.google.common.collect.Lists; import lombok.Data; @Data public class MetricTypeParams { - private List measures; + private List measures = Lists.newArrayList(); private String expr; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryColumn.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryColumn.java index 9adc33066..6fa981635 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryColumn.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/pojo/QueryColumn.java @@ -15,12 +15,12 @@ public class QueryColumn { private String showType; private Boolean authorized = true; - public void setType(String type) { - this.type = type == null ? null : type; - } - public QueryColumn(String nameEn, String type) { this.type = type; this.nameEn = nameEn; } + + public void setType(String type) { + this.type = type == null ? null : type; + } } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatabaseReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatabaseReq.java index cefb5e929..1924d91ed 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatabaseReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatabaseReq.java @@ -1,5 +1,6 @@ package com.tencent.supersonic.semantic.api.core.request; +import com.tencent.supersonic.semantic.api.core.enums.DataTypeEnum; import lombok.Data; import org.apache.commons.lang3.StringUtils; @@ -7,7 +8,6 @@ import org.apache.commons.lang3.StringUtils; @Data public class DatabaseReq { - private Long id; private Long domainId; @@ -34,6 +34,10 @@ public class DatabaseReq { if (StringUtils.isNotBlank(url)) { return url; } + if (type.equalsIgnoreCase(DataTypeEnum.MYSQL.getFeature())) { + return String.format("jdbc:%s://%s:%s?sessionVariables=sql_mode='IGNORE_SPACE'&allowMultiQueries=true", + type, host, port); + } return String.format("jdbc:%s://%s:%s", type, host, port); } } \ No newline at end of file diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceReq.java index 460cfbde7..bcfeb3363 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DatasourceReq.java @@ -19,7 +19,7 @@ public class DatasourceReq extends SchemaItem { private String sqlQuery; - private String sqlTable; + private String tableQuery; private Long domainId; diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DimensionReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DimensionReq.java index 36262f079..31a101129 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DimensionReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/DimensionReq.java @@ -3,6 +3,7 @@ package com.tencent.supersonic.semantic.api.core.request; import com.tencent.supersonic.common.pojo.SchemaItem; import javax.validation.constraints.NotNull; import lombok.Data; +import java.util.List; @Data public class DimensionReq extends SchemaItem { @@ -20,5 +21,9 @@ public class DimensionReq extends SchemaItem { //DATE ID CATEGORY private String semanticType = "CATEGORY"; + private String alias; + + private List defaultValues; + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricBaseReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricBaseReq.java index b77d317cd..fcea10637 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricBaseReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricBaseReq.java @@ -10,4 +10,6 @@ public class MetricBaseReq extends SchemaItem { private Long domainId; + private String alias; + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricReq.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricReq.java index d38937129..b7f6cf337 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricReq.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/request/MetricReq.java @@ -1,12 +1,31 @@ package com.tencent.supersonic.semantic.api.core.request; +import com.tencent.supersonic.semantic.api.core.enums.MetricTypeEnum; +import com.tencent.supersonic.semantic.api.core.pojo.Measure; import com.tencent.supersonic.semantic.api.core.pojo.MetricTypeParams; import lombok.Data; +import java.util.List; @Data public class MetricReq extends MetricBaseReq { + private MetricTypeEnum metricType; + private MetricTypeParams typeParams; + public MetricTypeEnum getMetricType() { + if (metricType != null) { + return metricType; + } + List measureList = typeParams.getMeasures(); + if (measureList.size() > 1) { + return MetricTypeEnum.DERIVED; + } + if (measureList.size() == 1 && typeParams.getExpr().trim().equalsIgnoreCase(measureList.get(0).getBizName())) { + return MetricTypeEnum.ATOMIC; + } + throw new RuntimeException("measure can not be none"); + } + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimensionResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimensionResp.java index e1dca29e6..38a0ce7a1 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimensionResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DimensionResp.java @@ -3,6 +3,7 @@ package com.tencent.supersonic.semantic.api.core.response; import com.tencent.supersonic.common.pojo.SchemaItem; import lombok.Data; +import java.util.List; @Data @@ -24,5 +25,9 @@ public class DimensionResp extends SchemaItem { //DATE ID CATEGORY private String semanticType; + private String alias; + + private List defaultValues; + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainResp.java index 1d21f2b8c..e0b8689e4 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/DomainResp.java @@ -23,5 +23,9 @@ public class DomainResp extends SchemaItem { private Integer isOpen = 0; + private Integer dimensionCnt; + + private Integer metricCnt; + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricResp.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricResp.java index f9bc22c58..c3dfb0295 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricResp.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/core/response/MetricResp.java @@ -14,16 +14,18 @@ public class MetricResp extends SchemaItem { private String domainName; - //measure_proxy ratio expr cumulative derived + //ATOMIC DERIVED private String type; private MetricTypeParams typeParams; private String fullPath; - private String dataFormatType; private DataFormat dataFormat; + private String alias; + + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/enums/FilterOperatorEnum.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/enums/FilterOperatorEnum.java index a1bb243a7..fd6823f37 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/enums/FilterOperatorEnum.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/enums/FilterOperatorEnum.java @@ -26,11 +26,6 @@ public enum FilterOperatorEnum { this.value = value; } - @JsonValue - public String getValue() { - return value; - } - @JsonCreator public static FilterOperatorEnum getSqlOperator(String type) { for (FilterOperatorEnum operatorEnum : FilterOperatorEnum.values()) { @@ -41,5 +36,10 @@ public enum FilterOperatorEnum { return null; } + @JsonValue + public String getValue() { + return value; + } + } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Criterion.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Criterion.java index 8436b4bcc..162779ba1 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Criterion.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Criterion.java @@ -20,6 +20,26 @@ public class Criterion { private String dataType; + public Criterion(String column, FilterOperatorEnum operator, Object value, String dataType) { + super(); + this.column = column; + this.operator = operator; + this.value = value; + this.dataType = dataType; + + if (FilterOperatorEnum.BETWEEN.name().equals(operator) || FilterOperatorEnum.IN.name().equals(operator) + || FilterOperatorEnum.NOT_IN.name().equals(operator)) { + this.values = (List) value; + } + } + + public boolean isNeedApostrophe() { + return Arrays.stream(StringDataType.values()) + .filter(value -> this.dataType.equalsIgnoreCase(value.getType())).findFirst() + .isPresent(); + } + + public enum NumericDataType { TINYINT("TINYINT"), SMALLINT("SMALLINT"), @@ -43,6 +63,7 @@ public class Criterion { } } + public enum StringDataType { VARCHAR("VARCHAR"), STRING("STRING"), @@ -59,25 +80,4 @@ public class Criterion { } - public Criterion(String column, FilterOperatorEnum operator, Object value, String dataType) { - super(); - this.column = column; - this.operator = operator; - this.value = value; - this.dataType = dataType; - - if (FilterOperatorEnum.BETWEEN.name().equals(operator) || FilterOperatorEnum.IN.name().equals(operator) - || FilterOperatorEnum.NOT_IN.name().equals(operator)) { - this.values = (List) value; - } - } - - - public boolean isNeedApostrophe() { - return Arrays.stream(StringDataType.values()) - .filter(value -> this.dataType.equalsIgnoreCase(value.getType())).findFirst() - .isPresent(); - } - - } diff --git a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Filter.java b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Filter.java index 8ea40b380..9c3d2506e 100644 --- a/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Filter.java +++ b/semantic/api/src/main/java/com/tencent/supersonic/semantic/api/query/pojo/Filter.java @@ -13,19 +13,11 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class Filter { - public enum Relation { - FILTER, OR, AND - } - private Relation relation = Relation.FILTER; private String bizName; - private String name; - private FilterOperatorEnum operator; - private Object value; - private List children; public Filter(String bizName, FilterOperatorEnum operator, Object value) { @@ -34,7 +26,6 @@ public class Filter { this.value = value; } - public Filter(Relation relation, String bizName, FilterOperatorEnum operator, Object value) { this.relation = relation; this.bizName = bizName; @@ -60,4 +51,8 @@ public class Filter { sb.append('}'); return sb.toString(); } + + public enum Relation { + FILTER, OR, AND + } } \ No newline at end of file diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatabaseServiceImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatabaseServiceImpl.java index 3c1060008..c61bdf965 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatabaseServiceImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatabaseServiceImpl.java @@ -5,6 +5,8 @@ import com.tencent.supersonic.semantic.api.core.request.DatabaseReq; import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; +import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptor; +import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptorFactory; import com.tencent.supersonic.semantic.core.domain.dataobject.DatabaseDO; import com.tencent.supersonic.semantic.core.domain.repository.DatabaseRepository; import com.tencent.supersonic.semantic.core.domain.utils.DatabaseConverter; @@ -24,9 +26,8 @@ import org.springframework.stereotype.Service; @Service public class DatabaseServiceImpl implements DatabaseService { - private DatabaseRepository databaseRepository; - private final SqlUtils sqlUtils; + private DatabaseRepository databaseRepository; public DatabaseServiceImpl(DatabaseRepository databaseRepository, SqlUtils sqlUtils) { this.databaseRepository = databaseRepository; @@ -53,6 +54,7 @@ public class DatabaseServiceImpl implements DatabaseService { return DatabaseConverter.convert(databaseDO); } + @Override public DatabaseResp getDatabase(Long id) { DatabaseDO databaseDO = databaseRepository.getDatabase(id); @@ -74,8 +76,6 @@ public class DatabaseServiceImpl implements DatabaseService { @Override public QueryResultWithSchemaResp executeSql(String sql, DatabaseResp databaseResp) { - - SqlUtils sqlUtils = this.sqlUtils.init(databaseResp); return queryWithColumns(sql, databaseResp); } @@ -93,7 +93,7 @@ public class DatabaseServiceImpl implements DatabaseService { private QueryResultWithSchemaResp queryWithColumns(String sql, DatabaseResp databaseResp) { QueryResultWithSchemaResp queryResultWithColumns = new QueryResultWithSchemaResp(); SqlUtils sqlUtils = this.sqlUtils.init(databaseResp); - log.info("query SQL: {}" , sql); + log.info("query SQL: {}", sql); sqlUtils.queryInternal(sql, queryResultWithColumns); return queryResultWithColumns; } @@ -103,4 +103,31 @@ public class DatabaseServiceImpl implements DatabaseService { return databaseDOS.stream().findFirst(); } + @Override + public QueryResultWithSchemaResp getDbNames(Long id) { + DatabaseResp databaseResp = getDatabase(id); + EngineAdaptor engineAdaptor = EngineAdaptorFactory.getEngineAdaptor(databaseResp.getType()); + String metaQueryTpl = engineAdaptor.getDbMetaQueryTpl(); + return queryWithColumns(metaQueryTpl, databaseResp); + } + + @Override + public QueryResultWithSchemaResp getTables(Long id, String db) { + DatabaseResp databaseResp = getDatabase(id); + EngineAdaptor engineAdaptor = EngineAdaptorFactory.getEngineAdaptor(databaseResp.getType()); + String metaQueryTpl = engineAdaptor.getTableMetaQueryTpl(); + String metaQuerySql = String.format(metaQueryTpl, db); + return queryWithColumns(metaQuerySql, databaseResp); + } + + + @Override + public QueryResultWithSchemaResp getColumns(Long id, String db, String table) { + DatabaseResp databaseResp = getDatabase(id); + EngineAdaptor engineAdaptor = EngineAdaptorFactory.getEngineAdaptor(databaseResp.getType()); + String metaQueryTpl = engineAdaptor.getColumnMetaQueryTpl(); + String metaQuerySql = String.format(metaQueryTpl, db, table); + return queryWithColumns(metaQuerySql, databaseResp); + } + } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatasourceServiceImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatasourceServiceImpl.java index a9f59430f..139b92f6c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatasourceServiceImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DatasourceServiceImpl.java @@ -63,8 +63,6 @@ public class DatasourceServiceImpl implements DatasourceService { private DatasourceRepository datasourceRepository; - private DatasourceYamlManager datasourceYamlManager; - private DatabaseService databaseService; private DimensionService dimensionService; @@ -73,19 +71,13 @@ public class DatasourceServiceImpl implements DatasourceService { private DateInfoRepository dateInfoRepository; - private DomainService domainService; - public DatasourceServiceImpl(DatasourceRepository datasourceRepository, - DatasourceYamlManager datasourceYamlManager, - DomainService domainService, DatabaseService databaseService, @Lazy DimensionService dimensionService, @Lazy MetricService metricService, DateInfoRepository dateInfoRepository) { - this.domainService = domainService; this.datasourceRepository = datasourceRepository; - this.datasourceYamlManager = datasourceYamlManager; this.databaseService = databaseService; this.dimensionService = dimensionService; this.metricService = metricService; @@ -107,10 +99,6 @@ public class DatasourceServiceImpl implements DatasourceService { datasource.setId(datasourceDesc.getId()); batchCreateDimension(datasource, user); batchCreateMetric(datasource, user); - List dimensionDescsExist = dimensionService.getDimensionsByDatasource(datasource.getId()); - DatabaseResp databaseResp = databaseService.getDatabase(datasource.getDatabaseId()); - datasourceYamlManager.generateYamlFile(datasource, databaseResp, - domainService.getDomainFullPath(datasource.getDomainId()), dimensionDescsExist); return datasourceDesc; } @@ -124,10 +112,6 @@ public class DatasourceServiceImpl implements DatasourceService { batchCreateDimension(datasource, user); batchCreateMetric(datasource, user); - List dimensionDescsExist = dimensionService.getDimensionsByDatasource(datasource.getId()); - DatabaseResp databaseResp = databaseService.getDatabase(datasource.getDatabaseId()); - datasourceYamlManager.generateYamlFile(datasource, databaseResp, - domainService.getDomainFullPath(datasource.getDomainId()), dimensionDescsExist); DatasourceDO datasourceDO = updateDatasource(datasource, user); return DatasourceConverter.convert(datasourceDO); } @@ -207,8 +191,6 @@ public class DatasourceServiceImpl implements DatasourceService { } - - private void preCheck(DatasourceReq datasourceReq) { List dims = datasourceReq.getDimensions(); if (CollectionUtils.isEmpty(dims)) { @@ -245,8 +227,6 @@ public class DatasourceServiceImpl implements DatasourceService { } - - @Override public Map getDatasourceMap() { Map map = new HashMap<>(); @@ -264,9 +244,16 @@ public class DatasourceServiceImpl implements DatasourceService { if (datasourceDO == null) { return; } + checkDelete(datasourceDO.getDomainId(), id); datasourceRepository.deleteDatasource(id); - datasourceYamlManager.deleteYamlFile(datasourceDO.getBizName(), - domainService.getDomainFullPath(datasourceDO.getDomainId())); + } + + private void checkDelete(Long domainId, Long datasourceId) { + List metricResps = metricService.getMetrics(domainId, datasourceId); + List dimensionResps = dimensionService.getDimensionsByDatasource(datasourceId); + if (!CollectionUtils.isEmpty(metricResps) || !CollectionUtils.isEmpty(dimensionResps)) { + throw new RuntimeException("exist dimension or metric on this datasource, please check"); + } } @@ -315,6 +302,7 @@ public class DatasourceServiceImpl implements DatasourceService { } + @Override public ItemDateResp getDateDate(ItemDateFilter dimension, ItemDateFilter metric) { List itemDates = new ArrayList<>(); List dimensions = dateInfoRepository.getDateInfos(dimension); @@ -355,10 +343,10 @@ public class DatasourceServiceImpl implements DatasourceService { String startDate1 = item.getStartDate(); String endDate1 = item.getEndDate(); List unavailableDateList1 = item.getUnavailableDateList(); - if (Strings.isNotEmpty(startDate1) && startDate1.compareTo(startDate) < 0) { + if (Strings.isNotEmpty(startDate1) && startDate1.compareTo(startDate) > 0) { startDate = startDate1; } - if (Strings.isNotEmpty(endDate1) && startDate1.compareTo(endDate1) > 0) { + if (Strings.isNotEmpty(endDate1) && endDate1.compareTo(endDate) < 0) { endDate = endDate1; } if (!CollectionUtils.isEmpty(unavailableDateList1)) { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DimensionServiceImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DimensionServiceImpl.java index 7a4f98f97..3fcfdf0d4 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DimensionServiceImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DimensionServiceImpl.java @@ -11,7 +11,6 @@ import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; import com.tencent.supersonic.semantic.api.core.response.DimensionResp; import com.tencent.supersonic.common.enums.SensitiveLevelEnum; import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; -import com.tencent.supersonic.semantic.core.domain.manager.DimensionYamlManager; import com.tencent.supersonic.semantic.core.domain.repository.DimensionRepository; import com.tencent.supersonic.semantic.core.domain.utils.DimensionConverter; import com.tencent.supersonic.semantic.core.domain.DatasourceService; @@ -19,7 +18,6 @@ import com.tencent.supersonic.semantic.core.domain.DimensionService; import com.tencent.supersonic.semantic.core.domain.DomainService; import com.tencent.supersonic.semantic.core.domain.pojo.Dimension; import com.tencent.supersonic.semantic.core.domain.pojo.DimensionFilter; - import java.util.HashMap; import java.util.List; import java.util.Map; @@ -37,59 +35,54 @@ public class DimensionServiceImpl implements DimensionService { private DimensionRepository dimensionRepository; - private DimensionYamlManager dimensionYamlManager; - private DatasourceService datasourceService; private DomainService domainService; public DimensionServiceImpl(DimensionRepository dimensionRepository, - DimensionYamlManager dimensionYamlManager, DomainService domainService, DatasourceService datasourceService) { this.domainService = domainService; this.dimensionRepository = dimensionRepository; - this.dimensionYamlManager = dimensionYamlManager; this.datasourceService = datasourceService; } @Override - public void createDimension(DimensionReq dimensionReq, User user) throws Exception { + public void createDimension(DimensionReq dimensionReq, User user) { checkExist(Lists.newArrayList(dimensionReq)); Dimension dimension = DimensionConverter.convert(dimensionReq); log.info("[create dimension] object:{}", JSONObject.toJSONString(dimension)); - saveDimensionAndGenerateYaml(dimension, user); + dimension.createdBy(user.getName()); + saveDimension(dimension); } @Override - public void createDimensionBatch(List dimensionReqs, User user) throws Exception { + public void createDimensionBatch(List dimensionReqs, User user) { if (CollectionUtils.isEmpty(dimensionReqs)) { return; } Long domainId = dimensionReqs.get(0).getDomainId(); - List dimensionDescs = getDimensions(domainId); - Map dimensionDescMap = dimensionDescs.stream() + List dimensionResps = getDimensions(domainId); + Map dimensionRespMap = dimensionResps.stream() .collect(Collectors.toMap(DimensionResp::getBizName, a -> a, (k1, k2) -> k1)); List dimensions = dimensionReqs.stream().map(DimensionConverter::convert) .collect(Collectors.toList()); List dimensionToInsert = dimensions.stream() - .filter(dimension -> !dimensionDescMap.containsKey(dimension.getBizName())) + .filter(dimension -> !dimensionRespMap.containsKey(dimension.getBizName())) .collect(Collectors.toList()); log.info("[create dimension] object:{}", JSONObject.toJSONString(dimensions)); saveDimensionBatch(dimensionToInsert, user); - generateYamlFile(dimensions.get(0).getDatasourceId(), dimensions.get(0).getDomainId()); } @Override - public void updateDimension(DimensionReq dimensionReq, User user) throws Exception { + public void updateDimension(DimensionReq dimensionReq, User user) { Dimension dimension = DimensionConverter.convert(dimensionReq); dimension.updatedBy(user.getName()); log.info("[update dimension] object:{}", JSONObject.toJSONString(dimension)); updateDimension(dimension); - generateYamlFile(dimension.getDatasourceId(), dimension.getDomainId()); } protected void updateDimension(Dimension dimension) { @@ -100,13 +93,13 @@ public class DimensionServiceImpl implements DimensionService { @Override public DimensionResp getDimension(String bizName, Long domainId) { - List dimensionDescs = getDimensions(domainId); - if (CollectionUtils.isEmpty(dimensionDescs)) { + List dimensionResps = getDimensions(domainId); + if (CollectionUtils.isEmpty(dimensionResps)) { return null; } - for (DimensionResp dimensionDesc : dimensionDescs) { - if (dimensionDesc.getBizName().equalsIgnoreCase(bizName)) { - return dimensionDesc; + for (DimensionResp dimensionResp : dimensionResps) { + if (dimensionResp.getBizName().equalsIgnoreCase(bizName)) { + return dimensionResp; } } return null; @@ -132,16 +125,16 @@ public class DimensionServiceImpl implements DimensionService { @Override public List getDimensions(List ids) { - List dimensionDescs = Lists.newArrayList(); + List dimensionResps = Lists.newArrayList(); List dimensionDOS = dimensionRepository.getDimensionListByIds(ids); Map fullDomainPathMap = domainService.getDomainFullPath(); if (!CollectionUtils.isEmpty(dimensionDOS)) { - dimensionDescs = dimensionDOS.stream() - .map(dimensionDO -> DimensionConverter.convert2DimensionDesc(dimensionDO, fullDomainPathMap, + dimensionResps = dimensionDOS.stream() + .map(dimensionDO -> DimensionConverter.convert2DimensionResp(dimensionDO, fullDomainPathMap, new HashMap<>())) .collect(Collectors.toList()); } - return dimensionDescs; + return dimensionResps; } @Override @@ -149,52 +142,46 @@ public class DimensionServiceImpl implements DimensionService { return convertList(getDimensionDOS(domainId), datasourceService.getDatasourceMap()); } - - public List getDimensionList(Long datasourceId) { - List dimensions = Lists.newArrayList(); - List dimensionDOS = dimensionRepository.getDimensionListOfDatasource(datasourceId); - if (!CollectionUtils.isEmpty(dimensionDOS)) { - dimensions = dimensionDOS.stream().map(DimensionConverter::convert2Dimension).collect(Collectors.toList()); - } - return dimensions; + @Override + public List getDimensions() { + return convertList(getDimensionDOS(), datasourceService.getDatasourceMap()); } @Override public List getDimensionsByDatasource(Long datasourceId) { - List dimensionDescs = Lists.newArrayList(); + List dimensionResps = Lists.newArrayList(); List dimensionDOS = dimensionRepository.getDimensionListOfDatasource(datasourceId); if (!CollectionUtils.isEmpty(dimensionDOS)) { - dimensionDescs = dimensionDOS.stream() - .map(dimensionDO -> DimensionConverter.convert2DimensionDesc(dimensionDO, new HashMap<>(), + dimensionResps = dimensionDOS.stream() + .map(dimensionDO -> DimensionConverter.convert2DimensionResp(dimensionDO, new HashMap<>(), new HashMap<>())) .collect(Collectors.toList()); } - return dimensionDescs; + return dimensionResps; } private List convertList(List dimensionDOS, - Map datasourceDescMap) { - List dimensionDescs = Lists.newArrayList(); + Map datasourceRespMap) { + List dimensionResps = Lists.newArrayList(); Map fullDomainPathMap = domainService.getDomainFullPath(); if (!CollectionUtils.isEmpty(dimensionDOS)) { - dimensionDescs = dimensionDOS.stream() - .map(dimensionDO -> DimensionConverter.convert2DimensionDesc(dimensionDO, fullDomainPathMap, - datasourceDescMap)) + dimensionResps = dimensionDOS.stream() + .map(dimensionDO -> DimensionConverter.convert2DimensionResp(dimensionDO, fullDomainPathMap, + datasourceRespMap)) .collect(Collectors.toList()); } - return dimensionDescs; + return dimensionResps; } - @Override public List getHighSensitiveDimension(Long domainId) { - List dimensionDescs = getDimensions(domainId); - if (CollectionUtils.isEmpty(dimensionDescs)) { - return dimensionDescs; + List dimensionResps = getDimensions(domainId); + if (CollectionUtils.isEmpty(dimensionResps)) { + return dimensionResps; } - return dimensionDescs.stream() - .filter(dimensionDesc -> SensitiveLevelEnum.HIGH.getCode().equals(dimensionDesc.getSensitiveLevel())) + return dimensionResps.stream() + .filter(dimensionResp -> SensitiveLevelEnum.HIGH.getCode().equals(dimensionResp.getSensitiveLevel())) .collect(Collectors.toList()); } @@ -203,13 +190,17 @@ public class DimensionServiceImpl implements DimensionService { return dimensionRepository.getDimensionListOfDomain(domainId); } + protected List getDimensionDOS() { + return dimensionRepository.getDimensionList(); + } + @Override public List getAllHighSensitiveDimension() { - List dimensionDescs = Lists.newArrayList(); + List dimensionResps = Lists.newArrayList(); List dimensionDOS = dimensionRepository.getAllDimensionList(); if (CollectionUtils.isEmpty(dimensionDOS)) { - return dimensionDescs; + return dimensionResps; } return convertList(dimensionDOS.stream() .filter(dimensionDO -> SensitiveLevelEnum.HIGH.getCode().equals(dimensionDO.getSensitiveLevel())) @@ -217,8 +208,7 @@ public class DimensionServiceImpl implements DimensionService { } - //保存并获取自增ID - private void saveDimension(Dimension dimension) { + public void saveDimension(Dimension dimension) { DimensionDO dimensionDO = DimensionConverter.convert2DimensionDO(dimension); log.info("[save dimension] dimensionDO:{}", JSONObject.toJSONString(dimensionDO)); dimensionRepository.createDimension(dimensionDO); @@ -238,52 +228,30 @@ public class DimensionServiceImpl implements DimensionService { } - - @Override - public void deleteDimension(Long id) throws Exception { + public void deleteDimension(Long id) { DimensionDO dimensionDO = dimensionRepository.getDimensionById(id); if (dimensionDO == null) { throw new RuntimeException(String.format("the dimension %s not exist", id)); } dimensionRepository.deleteDimension(id); - generateYamlFile(dimensionDO.getDatasourceId(), dimensionDO.getDomainId()); - } - - protected void generateYamlFile(Long datasourceId, Long domainId) throws Exception { - String datasourceBizName = datasourceService.getSourceBizNameById(datasourceId); - List dimensionList = getDimensionList(datasourceId); - String fullPath = domainService.getDomainFullPath(domainId); - dimensionYamlManager.generateYamlFile(dimensionList, fullPath, datasourceBizName); } private void checkExist(List dimensionReqs) { Long domainId = dimensionReqs.get(0).getDomainId(); - List dimensionDescs = getDimensions(domainId); + List dimensionResps = getDimensions(domainId); for (DimensionReq dimensionReq : dimensionReqs) { - for (DimensionResp dimensionDesc : dimensionDescs) { - if (dimensionDesc.getName().equalsIgnoreCase(dimensionReq.getBizName())) { + for (DimensionResp dimensionResp : dimensionResps) { + if (dimensionResp.getName().equalsIgnoreCase(dimensionReq.getBizName())) { throw new RuntimeException(String.format("exist same dimension name:%s", dimensionReq.getName())); } - if (dimensionDesc.getBizName().equalsIgnoreCase(dimensionReq.getBizName())) { + if (dimensionResp.getBizName().equalsIgnoreCase(dimensionReq.getBizName())) { throw new RuntimeException( String.format("exist same dimension bizName:%s", dimensionReq.getBizName())); } } } - } - - private void saveDimensionAndGenerateYaml(Dimension dimension, User user) throws Exception { - dimension.createdBy(user.getName()); - saveDimension(dimension); - generateYamlFile(dimension.getDatasourceId(), dimension.getDomainId()); - } - - - - - } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DomainServiceImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DomainServiceImpl.java index 8f0f151bd..9e081b645 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DomainServiceImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/DomainServiceImpl.java @@ -3,24 +3,25 @@ package com.tencent.supersonic.semantic.core.application; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.common.util.mapper.BeanMapper; import com.tencent.supersonic.semantic.api.core.request.DomainReq; import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; import com.tencent.supersonic.semantic.api.core.request.DomainUpdateReq; +import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp; import com.tencent.supersonic.semantic.api.core.response.DimensionResp; import com.tencent.supersonic.semantic.api.core.response.DomainResp; import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; import com.tencent.supersonic.semantic.api.core.response.MetricResp; import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp; -import com.tencent.supersonic.common.util.mapper.BeanMapper; -import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; -import com.tencent.supersonic.semantic.core.domain.repository.DomainRepository; -import com.tencent.supersonic.semantic.core.domain.utils.DomainConvert; +import com.tencent.supersonic.semantic.core.domain.DatasourceService; import com.tencent.supersonic.semantic.core.domain.DimensionService; import com.tencent.supersonic.semantic.core.domain.DomainService; import com.tencent.supersonic.semantic.core.domain.MetricService; +import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; import com.tencent.supersonic.semantic.core.domain.pojo.Domain; - +import com.tencent.supersonic.semantic.core.domain.repository.DomainRepository; +import com.tencent.supersonic.semantic.core.domain.utils.DomainConvert; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -42,14 +43,15 @@ public class DomainServiceImpl implements DomainService { private final DomainRepository domainRepository; private final MetricService metricService; private final DimensionService dimensionService; + private final DatasourceService datasourceService; - public DomainServiceImpl(DomainRepository domainRepository, - @Lazy MetricService metricService, - @Lazy DimensionService dimensionService) { + public DomainServiceImpl(DomainRepository domainRepository, @Lazy MetricService metricService, + @Lazy DimensionService dimensionService, @Lazy DatasourceService datasourceService) { this.domainRepository = domainRepository; this.metricService = metricService; this.dimensionService = dimensionService; + this.datasourceService = datasourceService; } @@ -80,9 +82,20 @@ public class DomainServiceImpl implements DomainService { @Override public void deleteDomain(Long id) { + checkDelete(id); domainRepository.deleteDomain(id); } + private void checkDelete(Long id) { + List metricResps = metricService.getMetrics(id); + List dimensionResps = dimensionService.getDimensions(id); + List datasourceResps = datasourceService.getDatasourceList(id); + if (!CollectionUtils.isEmpty(metricResps) || !CollectionUtils.isEmpty(datasourceResps) + || !CollectionUtils.isEmpty(dimensionResps)) { + throw new RuntimeException("exist datasource, dimension or metric in this domain, please check"); + } + } + @Override public String getDomainBizName(Long id) { if (id == null) { @@ -99,7 +112,7 @@ public class DomainServiceImpl implements DomainService { @Override public List getDomainList() { - return convertList(domainRepository.getDomainList()); + return convertList(domainRepository.getDomainList(), new HashMap<>(), new HashMap<>()); } @@ -115,7 +128,11 @@ public class DomainServiceImpl implements DomainService { List domainDOS = domainRepository.getDomainList(); List orgIds = Lists.newArrayList(); log.info("orgIds:{},userName:{}", orgIds, userName); - return convertList(domainDOS).stream() + Map> metricDomainMap = metricService.getMetrics().stream() + .collect(Collectors.groupingBy(MetricResp::getDomainId)); + Map> dimensionDomainMap = dimensionService.getDimensions().stream() + .collect(Collectors.groupingBy(DimensionResp::getDomainId)); + return convertList(domainDOS, metricDomainMap, dimensionDomainMap).stream() .filter(domainDesc -> checkAdminPermission(orgIds, userName, domainDesc)) .collect(Collectors.toList()); } @@ -125,7 +142,7 @@ public class DomainServiceImpl implements DomainService { List domainDOS = domainRepository.getDomainList(); List orgIds = Lists.newArrayList(); log.info("orgIds:{},userName:{}", orgIds, userName); - return convertList(domainDOS).stream() + return convertList(domainDOS, new HashMap<>(), new HashMap<>()).stream() .filter(domainDesc -> checkViewerPermission(orgIds, userName, domainDesc)) .collect(Collectors.toList()); } @@ -160,23 +177,23 @@ public class DomainServiceImpl implements DomainService { } - private List convertList(List domainDOS) { + private List convertList(List domainDOS, Map> metricDomainMap, + Map> dimensionDomainMap) { List domainDescs = Lists.newArrayList(); if (CollectionUtils.isEmpty(domainDOS)) { return domainDescs; } Map fullDomainPathMap = getDomainFullPath(); + return domainDOS.stream() - .map(domainDO -> DomainConvert.convert(domainDO, fullDomainPathMap)) + .map(domainDO -> DomainConvert.convert(domainDO, fullDomainPathMap, dimensionDomainMap, + metricDomainMap)) .collect(Collectors.toList()); } - - @Override public Map getDomainMap() { - return getDomainList().stream().collect(Collectors.toMap(DomainResp::getId, a -> a, (k1, k2) -> k1)); } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/MetricServiceImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/MetricServiceImpl.java index 8a5bdf5e4..2f9d3f8f6 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/MetricServiceImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/application/MetricServiceImpl.java @@ -13,7 +13,6 @@ import com.tencent.supersonic.semantic.api.core.response.DomainResp; import com.tencent.supersonic.semantic.api.core.response.MetricResp; import com.tencent.supersonic.common.enums.SensitiveLevelEnum; import com.tencent.supersonic.semantic.core.domain.dataobject.MetricDO; -import com.tencent.supersonic.semantic.core.domain.manager.MetricYamlManager; import com.tencent.supersonic.semantic.core.domain.pojo.MetricFilter; import com.tencent.supersonic.semantic.core.domain.repository.MetricRepository; import com.tencent.supersonic.semantic.core.domain.utils.MetricConverter; @@ -27,6 +26,7 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -38,30 +38,26 @@ public class MetricServiceImpl implements MetricService { private MetricRepository metricRepository; - private MetricYamlManager metricYamlManager; - private DomainService domainService; public MetricServiceImpl(MetricRepository metricRepository, - MetricYamlManager metricYamlManager, DomainService domainService) { this.domainService = domainService; this.metricRepository = metricRepository; - this.metricYamlManager = metricYamlManager; } @Override - public void creatExprMetric(MetricReq metricReq, User user) throws Exception { + public void creatExprMetric(MetricReq metricReq, User user) { checkExist(Lists.newArrayList(metricReq)); Metric metric = MetricConverter.convert(metricReq); metric.createdBy(user.getName()); log.info("[create metric] object:{}", JSONObject.toJSONString(metric)); - saveMetricAndGenerateYaml(metric); + saveMetric(metric); } @Override - public void createMetricBatch(List metricReqs, User user) throws Exception { + public void createMetricBatch(List metricReqs, User user) { if (CollectionUtils.isEmpty(metricReqs)) { return; } @@ -74,8 +70,6 @@ public class MetricServiceImpl implements MetricService { .filter(metric -> !metricDescMap.containsKey(metric.getBizName())).collect(Collectors.toList()); log.info("[insert metric] object:{}", JSONObject.toJSONString(metricToInsert)); saveMetricBatch(metricToInsert, user); - - generateYamlFile(metrics.get(0).getDomainId()); } @@ -84,6 +78,11 @@ public class MetricServiceImpl implements MetricService { return convertList(metricRepository.getMetricList(domainId)); } + @Override + public List getMetrics() { + return convertList(metricRepository.getMetricList()); + } + @Override public List getMetrics(Long domainId, Long datasourceId) { List metricResps = convertList(metricRepository.getMetricList(domainId)); @@ -136,27 +135,15 @@ public class MetricServiceImpl implements MetricService { } @Override - public void updateExprMetric(MetricReq metricReq, User user) throws Exception { + public void updateExprMetric(MetricReq metricReq, User user) { preCheckMetric(metricReq); Metric metric = MetricConverter.convert(metricReq); metric.updatedBy(user.getName()); log.info("[update metric] object:{}", JSONObject.toJSONString(metric)); updateMetric(metric); - generateYamlFile(metric.getDomainId()); } - public List getMetricList(Long domainId) { - List metrics = Lists.newArrayList(); - List metricDOS = metricRepository.getMetricList(domainId); - if (!CollectionUtils.isEmpty(metricDOS)) { - metrics = metricDOS.stream().map(MetricConverter::convert2Metric).collect(Collectors.toList()); - } - return metrics; - } - - - //保存并获取自增ID public void saveMetric(Metric metric) { MetricDO metricDO = MetricConverter.convert2MetricDO(metric); log.info("[save metric] metricDO:{}", JSONObject.toJSONString(metricDO)); @@ -205,20 +192,12 @@ public class MetricServiceImpl implements MetricService { } @Override - public void deleteMetric(Long id) throws Exception { + public void deleteMetric(Long id) { MetricDO metricDO = metricRepository.getMetricById(id); if (metricDO == null) { throw new RuntimeException(String.format("the metric %s not exist", id)); } metricRepository.deleteMetric(id); - generateYamlFile(metricDO.getDomainId()); - } - - protected void generateYamlFile(Long domainId) throws Exception { - List metrics = getMetricList(domainId); - String fullPath = domainService.getDomainFullPath(domainId); - String domainBizName = domainService.getDomainBizName(domainId); - metricYamlManager.generateYamlFile(metrics, fullPath, domainBizName); } @@ -232,21 +211,14 @@ public class MetricServiceImpl implements MetricService { metricRepository.createMetricBatch(metricDOS); } - private void saveMetricAndGenerateYaml(Metric metric) throws Exception { - saveMetric(metric); - generateYamlFile(metric.getDomainId()); - } - - - private void preCheckMetric(MetricReq exprMetricReq) { - - MetricTypeParams typeParams = exprMetricReq.getTypeParams(); + private void preCheckMetric(MetricReq metricReq) { + MetricTypeParams typeParams = metricReq.getTypeParams(); List measures = typeParams.getMeasures(); if (CollectionUtils.isEmpty(measures)) { throw new RuntimeException("measure can not be none"); } - for (Measure measure : measures) { - measure.setExpr(null); + if (StringUtils.isBlank(typeParams.getExpr())) { + throw new RuntimeException("expr can not be blank"); } } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatabaseService.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatabaseService.java index fb0f56867..85f30a730 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatabaseService.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DatabaseService.java @@ -24,4 +24,9 @@ public interface DatabaseService { QueryResultWithSchemaResp queryWithColumns(SqlParserResp sqlParser); + QueryResultWithSchemaResp getDbNames(Long id); + + QueryResultWithSchemaResp getTables(Long id, String db); + + QueryResultWithSchemaResp getColumns(Long id, String db, String table); } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DimensionService.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DimensionService.java index 2c131f38e..8dbe47ddb 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DimensionService.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/DimensionService.java @@ -13,6 +13,8 @@ public interface DimensionService { List getDimensions(Long domainId); + List getDimensions(); + DimensionResp getDimension(String bizName, Long domainId); void createDimension(DimensionReq dimensionReq, User user) throws Exception; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/MetricService.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/MetricService.java index 233362919..a4c764470 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/MetricService.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/MetricService.java @@ -13,6 +13,8 @@ public interface MetricService { List getMetrics(Long domainId); + List getMetrics(); + List getMetrics(Long domainId, Long datasourceId); void creatExprMetric(MetricReq metricReq, User user) throws Exception; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/ClickHouseAdaptor.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/ClickHouseAdaptor.java index 7d917085c..b03758ceb 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/ClickHouseAdaptor.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/ClickHouseAdaptor.java @@ -27,4 +27,22 @@ public class ClickHouseAdaptor extends EngineAdaptor { return column; } + @Override + public String getDbMetaQueryTpl() { + return " " + + " select " + + " name from system.databases " + + " where name not in('_temporary_and_external_tables','benchmark','default','system');"; + } + + @Override + public String getTableMetaQueryTpl() { + return "select name from system.tables where database = '%s';"; + } + + @Override + public String getColumnMetaQueryTpl() { + return "select name,type as dataType, comment from system.columns where database = '%s' and table='%s'"; + } + } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptor.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptor.java index d85efd74b..be5635330 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptor.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/EngineAdaptor.java @@ -7,4 +7,9 @@ public abstract class EngineAdaptor { public abstract String getDateFormat(String dateType, String dateFormat, String column); + public abstract String getColumnMetaQueryTpl(); + + public abstract String getDbMetaQueryTpl(); + + public abstract String getTableMetaQueryTpl(); } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/MysqlAdaptor.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/MysqlAdaptor.java index 2bdc882e0..1e6fc0073 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/MysqlAdaptor.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/adaptor/engineadapter/MysqlAdaptor.java @@ -18,7 +18,7 @@ public class MysqlAdaptor extends EngineAdaptor { } else if (TimeDimensionEnum.WEEK.name().equalsIgnoreCase(dateType)) { return "to_monday(from_unixtime(unix_timestamp(%s), 'yyyy-MM-dd'))".replace("%s", column); } else { - return "from_unixtime(unix_timestamp(%s), 'yyyy-MM-dd')".replace("%s", column); + return "date_format(str_to_date(%s, '%Y%m%d'),'%Y-%m-%d')".replace("%s", column); } } else if (dateFormat.equalsIgnoreCase(Constants.DAY_FORMAT)) { if (TimeDimensionEnum.MONTH.name().equalsIgnoreCase(dateType)) { @@ -33,4 +33,21 @@ public class MysqlAdaptor extends EngineAdaptor { } + @Override + public String getDbMetaQueryTpl() { + return "select distinct TABLE_SCHEMA from information_schema.tables where TABLE_SCHEMA not in ('information_schema','mysql','performance_schema','sys');"; + } + + @Override + public String getTableMetaQueryTpl() { + return "select TABLE_NAME from information_schema.tables where TABLE_SCHEMA = '%s';"; + } + + @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'"; + } + + } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDOExample.java index 3521334bd..916ba9322 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatabaseDOExample.java @@ -38,13 +38,6 @@ public class DatabaseDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class DatabaseDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class DatabaseDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class DatabaseDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class DatabaseDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class DatabaseDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_database null */ @@ -812,38 +812,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; @@ -879,5 +847,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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDOExample.java index 22331f4e8..f8b87fbd4 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceDOExample.java @@ -38,13 +38,6 @@ public class DatasourceDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class DatasourceDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class DatasourceDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class DatasourceDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class DatasourceDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class DatasourceDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_datasource null */ @@ -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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDOExample.java index 09378686a..f4264d58d 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DatasourceRelaDOExample.java @@ -38,13 +38,6 @@ public class DatasourceRelaDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class DatasourceRelaDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class DatasourceRelaDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class DatasourceRelaDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class DatasourceRelaDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class DatasourceRelaDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_datasource_rela null */ @@ -787,38 +787,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; @@ -854,5 +822,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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDOExample.java index 3065b92e0..ff9cbb1c5 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryDOExample.java @@ -38,13 +38,6 @@ public class DictionaryDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class DictionaryDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class DictionaryDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class DictionaryDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class DictionaryDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class DictionaryDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_dictionary null */ @@ -792,38 +792,6 @@ public class DictionaryDOExample { 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 DictionaryDOExample { 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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDOExample.java index 94aa5bc87..d8548809c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DictionaryTaskDOExample.java @@ -37,13 +37,6 @@ public class DictionaryTaskDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -54,8 +47,8 @@ public class DictionaryTaskDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -65,6 +58,13 @@ public class DictionaryTaskDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -116,13 +116,6 @@ public class DictionaryTaskDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -133,8 +126,8 @@ public class DictionaryTaskDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -144,6 +137,13 @@ public class DictionaryTaskDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_dictionary_task null */ @@ -461,38 +461,6 @@ public class DictionaryTaskDOExample { 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; @@ -528,5 +496,37 @@ public class DictionaryTaskDOExample { 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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDO.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDO.java index a406d5362..eec2ef285 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDO.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDO.java @@ -74,6 +74,16 @@ public class DimensionDO { */ private String semanticType; + /** + * + */ + private String alias; + + /** + * default values of dimension when query + */ + private String defaultValues; + /** * 类型参数 */ @@ -336,6 +346,38 @@ public class DimensionDO { this.semanticType = semanticType == null ? null : semanticType.trim(); } + /** + * @return alias + */ + public String getAlias() { + return alias; + } + + /** + * @param alias + */ + public void setAlias(String alias) { + this.alias = alias == null ? null : alias.trim(); + } + + /** + * default values of dimension when query + * + * @return default_values default values of dimension when query + */ + public String getDefaultValues() { + return defaultValues; + } + + /** + * default values of dimension when query + * + * @param defaultValues default values of dimension when query + */ + public void setDefaultValues(String defaultValues) { + this.defaultValues = defaultValues == null ? null : defaultValues.trim(); + } + /** * 类型参数 * diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOExample.java index 435277083..32ebe9944 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DimensionDOExample.java @@ -38,13 +38,6 @@ public class DimensionDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class DimensionDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class DimensionDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class DimensionDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class DimensionDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class DimensionDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_dimension null */ @@ -665,6 +665,11 @@ public class DimensionDOExample { return (Criteria) this; } + public Criteria andSensitiveLevelGreaterThanOrEqualTo(Integer value) { + addCriterion("sensitive_level >=", value, "sensitiveLevel"); + return (Criteria) this; + } + public Criteria andSensitiveLevelLessThan(Integer value) { addCriterion("sensitive_level <", value, "sensitiveLevel"); return (Criteria) this; @@ -1094,6 +1099,146 @@ public class DimensionDOExample { addCriterion("semantic_type not between", value1, value2, "semanticType"); return (Criteria) this; } + + public Criteria andAliasIsNull() { + addCriterion("alias is null"); + return (Criteria) this; + } + + public Criteria andAliasIsNotNull() { + addCriterion("alias is not null"); + return (Criteria) this; + } + + public Criteria andAliasEqualTo(String value) { + addCriterion("alias =", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotEqualTo(String value) { + addCriterion("alias <>", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasGreaterThan(String value) { + addCriterion("alias >", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasGreaterThanOrEqualTo(String value) { + addCriterion("alias >=", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasLessThan(String value) { + addCriterion("alias <", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasLessThanOrEqualTo(String value) { + addCriterion("alias <=", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasLike(String value) { + addCriterion("alias like", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotLike(String value) { + addCriterion("alias not like", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasIn(List values) { + addCriterion("alias in", values, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotIn(List values) { + addCriterion("alias not in", values, "alias"); + return (Criteria) this; + } + + public Criteria andAliasBetween(String value1, String value2) { + addCriterion("alias between", value1, value2, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotBetween(String value1, String value2) { + addCriterion("alias not between", value1, value2, "alias"); + return (Criteria) this; + } + + public Criteria andDefaultValuesIsNull() { + addCriterion("default_values is null"); + return (Criteria) this; + } + + public Criteria andDefaultValuesIsNotNull() { + addCriterion("default_values is not null"); + return (Criteria) this; + } + + public Criteria andDefaultValuesEqualTo(String value) { + addCriterion("default_values =", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesNotEqualTo(String value) { + addCriterion("default_values <>", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesGreaterThan(String value) { + addCriterion("default_values >", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesGreaterThanOrEqualTo(String value) { + addCriterion("default_values >=", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesLessThan(String value) { + addCriterion("default_values <", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesLessThanOrEqualTo(String value) { + addCriterion("default_values <=", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesLike(String value) { + addCriterion("default_values like", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesNotLike(String value) { + addCriterion("default_values not like", value, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesIn(List values) { + addCriterion("default_values in", values, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesNotIn(List values) { + addCriterion("default_values not in", values, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesBetween(String value1, String value2) { + addCriterion("default_values between", value1, value2, "defaultValues"); + return (Criteria) this; + } + + public Criteria andDefaultValuesNotBetween(String value1, String value2) { + addCriterion("default_values not between", value1, value2, "defaultValues"); + return (Criteria) this; + } } /** @@ -1127,38 +1272,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; @@ -1194,5 +1307,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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDOExample.java index 7443f3ea9..37e67289c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainDOExample.java @@ -38,13 +38,6 @@ public class DomainDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class DomainDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class DomainDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class DomainDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class DomainDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class DomainDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_domain null */ @@ -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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDOExample.java index c1be45ec9..df30d4ae2 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/DomainExtendDOExample.java @@ -38,13 +38,6 @@ public class DomainExtendDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class DomainExtendDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class DomainExtendDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class DomainExtendDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class DomainExtendDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class DomainExtendDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_domain_extend null */ @@ -727,38 +727,6 @@ public class DomainExtendDOExample { 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; @@ -794,5 +762,37 @@ public class DomainExtendDOExample { 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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDO.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDO.java index 709e3cff3..9e52c7009 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDO.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDO.java @@ -74,6 +74,11 @@ public class MetricDO { */ private String dataFormat; + /** + * + */ + private String alias; + /** * 类型参数 */ @@ -327,6 +332,20 @@ public class MetricDO { this.dataFormat = dataFormat == null ? null : dataFormat.trim(); } + /** + * @return alias + */ + public String getAlias() { + return alias; + } + + /** + * @param alias + */ + public void setAlias(String alias) { + this.alias = alias == null ? null : alias.trim(); + } + /** * 类型参数 * diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDOExample.java index a3989229a..fa9afb69e 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/MetricDOExample.java @@ -38,13 +38,6 @@ public class MetricDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class MetricDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class MetricDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class MetricDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class MetricDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class MetricDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_metric null */ @@ -605,6 +605,11 @@ public class MetricDOExample { return (Criteria) this; } + public Criteria andSensitiveLevelGreaterThanOrEqualTo(Integer value) { + addCriterion("sensitive_level >=", value, "sensitiveLevel"); + return (Criteria) this; + } + public Criteria andSensitiveLevelLessThan(Integer value) { addCriterion("sensitive_level <", value, "sensitiveLevel"); return (Criteria) this; @@ -990,6 +995,11 @@ public class MetricDOExample { return (Criteria) this; } + public Criteria andDataFormatTypeGreaterThanOrEqualTo(String value) { + addCriterion("data_format_type >=", value, "dataFormatType"); + return (Criteria) this; + } + public Criteria andDataFormatTypeLessThan(String value) { addCriterion("data_format_type <", value, "dataFormatType"); return (Criteria) this; @@ -1099,6 +1109,76 @@ public class MetricDOExample { addCriterion("data_format not between", value1, value2, "dataFormat"); return (Criteria) this; } + + public Criteria andAliasIsNull() { + addCriterion("alias is null"); + return (Criteria) this; + } + + public Criteria andAliasIsNotNull() { + addCriterion("alias is not null"); + return (Criteria) this; + } + + public Criteria andAliasEqualTo(String value) { + addCriterion("alias =", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotEqualTo(String value) { + addCriterion("alias <>", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasGreaterThan(String value) { + addCriterion("alias >", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasGreaterThanOrEqualTo(String value) { + addCriterion("alias >=", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasLessThan(String value) { + addCriterion("alias <", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasLessThanOrEqualTo(String value) { + addCriterion("alias <=", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasLike(String value) { + addCriterion("alias like", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotLike(String value) { + addCriterion("alias not like", value, "alias"); + return (Criteria) this; + } + + public Criteria andAliasIn(List values) { + addCriterion("alias in", values, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotIn(List values) { + addCriterion("alias not in", values, "alias"); + return (Criteria) this; + } + + public Criteria andAliasBetween(String value1, String value2) { + addCriterion("alias between", value1, value2, "alias"); + return (Criteria) this; + } + + public Criteria andAliasNotBetween(String value1, String value2) { + addCriterion("alias not between", value1, value2, "alias"); + return (Criteria) this; + } } /** @@ -1132,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; @@ -1199,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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDOExample.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDOExample.java index 9ad4570a2..f37588017 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDOExample.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/dataobject/ViewInfoDOExample.java @@ -38,13 +38,6 @@ public class ViewInfoDOExample { oredCriteria = new ArrayList(); } - /** - * @mbg.generated - */ - public void setOrderByClause(String orderByClause) { - this.orderByClause = orderByClause; - } - /** * @mbg.generated */ @@ -55,8 +48,8 @@ public class ViewInfoDOExample { /** * @mbg.generated */ - public void setDistinct(boolean distinct) { - this.distinct = distinct; + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; } /** @@ -66,6 +59,13 @@ public class ViewInfoDOExample { return distinct; } + /** + * @mbg.generated + */ + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + /** * @mbg.generated */ @@ -117,13 +117,6 @@ public class ViewInfoDOExample { distinct = false; } - /** - * @mbg.generated - */ - public void setLimitStart(Integer limitStart) { - this.limitStart = limitStart; - } - /** * @mbg.generated */ @@ -134,8 +127,8 @@ public class ViewInfoDOExample { /** * @mbg.generated */ - public void setLimitEnd(Integer limitEnd) { - this.limitEnd = limitEnd; + public void setLimitStart(Integer limitStart) { + this.limitStart = limitStart; } /** @@ -145,6 +138,13 @@ public class ViewInfoDOExample { return limitEnd; } + /** + * @mbg.generated + */ + public void setLimitEnd(Integer limitEnd) { + this.limitEnd = limitEnd; + } + /** * s2_view_info null */ @@ -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/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DatasourceYamlManager.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DatasourceYamlManager.java index 002104f16..e0e50816b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DatasourceYamlManager.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DatasourceYamlManager.java @@ -10,66 +10,22 @@ import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; import com.tencent.supersonic.semantic.api.core.pojo.yaml.IdentifyYamlTpl; import com.tencent.supersonic.semantic.api.core.pojo.yaml.MeasureYamlTpl; import com.tencent.supersonic.semantic.api.core.response.DatabaseResp; -import com.tencent.supersonic.semantic.api.core.response.DimensionResp; -import com.tencent.supersonic.common.enums.TypeEnums; -import com.tencent.supersonic.common.util.yaml.YamlUtils; import com.tencent.supersonic.semantic.core.domain.utils.SysTimeDimensionBuilder; import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptor; import com.tencent.supersonic.semantic.core.domain.adaptor.engineadapter.EngineAdaptorFactory; import com.tencent.supersonic.semantic.core.domain.pojo.Datasource; import com.tencent.supersonic.semantic.core.domain.pojo.DatasourceQueryEnum; - -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; @Service @Slf4j public class DatasourceYamlManager { - - private YamlManager yamlManager; - - public DatasourceYamlManager(YamlManager yamlManager) { - this.yamlManager = yamlManager; - } - - - public void generateYamlFile(Datasource datasource, DatabaseResp databaseResp, String fullPath, - List dimensionDescsExist) throws Exception { - if (!CollectionUtils.isEmpty(dimensionDescsExist)) { - List dimensionBizNames = dimensionDescsExist.stream().map(DimensionResp::getBizName) - .collect(Collectors.toList()); - datasource.getDatasourceDetail().getDimensions() - .removeIf(dim -> dimensionBizNames.contains(dim.getBizName())); - } - String yamlStr = convert2YamlStr(datasource, databaseResp); - log.info("generate yaml str :{} from datasource:{} full path:{}", yamlStr, datasource, fullPath); - yamlManager.generateYamlFile(yamlStr, fullPath, getYamlName(datasource.getBizName())); - } - - public void deleteYamlFile(String datasourceBizName, String fullPath) throws Exception { - log.info("delete datasource yaml :{} ,fullPath:{}", datasourceBizName, fullPath); - yamlManager.deleteYamlFile(fullPath, getYamlName(datasourceBizName)); - } - - public String getYamlName(String name) { - return String.format("%s_%s", name, TypeEnums.DATASOURCE.getName()); - } - - public static String convert2YamlStr(Datasource datasource, DatabaseResp databaseResp) { - DatasourceYamlTpl datasourceYamlTpl = convert2YamlObj(datasource, databaseResp); - Map rootMap = new HashMap<>(); - rootMap.put("data_source", datasourceYamlTpl); - return YamlUtils.toYamlWithoutNull(rootMap); - } - public static DatasourceYamlTpl convert2YamlObj(Datasource datasource, DatabaseResp databaseResp) { DatasourceDetail datasourceDetail = datasource.getDatasourceDetail(); EngineAdaptor engineAdaptor = EngineAdaptorFactory.getEngineAdaptor(databaseResp.getType()); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DimensionYamlManager.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DimensionYamlManager.java index 4f335352e..ffec920ee 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DimensionYamlManager.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/DimensionYamlManager.java @@ -21,44 +21,6 @@ import org.springframework.util.CollectionUtils; public class DimensionYamlManager { - private YamlManager yamlManager; - - public DimensionYamlManager(YamlManager yamlManager) { - this.yamlManager = yamlManager; - } - - - public void generateYamlFile(List dimensions, String fullPath, String datasourceBizName) - throws Exception { - String yamlStr = convert2YamlStr(dimensions, datasourceBizName); - log.info("generate yaml str :{} from metric:{} full path:{}", yamlStr, dimensions, fullPath); - yamlManager.generateYamlFile(yamlStr, fullPath, getYamlName(datasourceBizName)); - } - - public String getYamlName(String name) { - return String.format("%s_%s", name, TypeEnums.DIMENSION.getName()); - } - - public static String convert2YamlStr(List dimensions, String datasourceBizName) { - if (CollectionUtils.isEmpty(dimensions)) { - return ""; - } - List dimensionYamlTpls = dimensions.stream() - .filter(dimension -> !dimension.getType().equalsIgnoreCase("primary")) - .map(DimensionConverter::convert2DimensionYamlTpl).collect(Collectors.toList()); - if (CollectionUtils.isEmpty(dimensionYamlTpls)) { - return ""; - } - Map dataMap = new HashMap<>(); - dataMap.put("source", datasourceBizName); - dataMap.put("dimensions", dimensionYamlTpls); - - Map rootMap = new HashMap<>(); - rootMap.put("dimension", dataMap); - return YamlUtils.toYamlWithoutNull(rootMap); - - } - public static List convert2DimensionYaml(List dimensions) { if (CollectionUtils.isEmpty(dimensions)) { return new ArrayList<>(); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/MetricYamlManager.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/MetricYamlManager.java index 3496c10cc..6a3b570ce 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/MetricYamlManager.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/MetricYamlManager.java @@ -1,17 +1,12 @@ package com.tencent.supersonic.semantic.core.domain.manager; import com.tencent.supersonic.semantic.api.core.pojo.yaml.MetricYamlTpl; -import com.tencent.supersonic.common.enums.TypeEnums; -import com.tencent.supersonic.common.util.yaml.YamlUtils; import com.tencent.supersonic.semantic.core.domain.pojo.Metric; import com.tencent.supersonic.semantic.core.domain.utils.MetricConverter; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; @Slf4j @@ -19,37 +14,6 @@ import org.springframework.util.CollectionUtils; public class MetricYamlManager { - private YamlManager yamlManager; - - public MetricYamlManager(YamlManager yamlManager) { - this.yamlManager = yamlManager; - } - - - public void generateYamlFile(List metrics, String fullPath, String domainBizName) throws Exception { - String yamlStr = convert2YamlStr(metrics); - log.info("generate yaml str :{} from metric:{} full path:{}", yamlStr, metrics, fullPath); - yamlManager.generateYamlFile(yamlStr, fullPath, getYamlName(domainBizName)); - } - - public String getYamlName(String name) { - return String.format("%s_%s", name, TypeEnums.METRIC.getName()); - } - - public static String convert2YamlStr(List metrics) { - if (CollectionUtils.isEmpty(metrics)) { - return ""; - } - StringBuilder yamlBuilder = new StringBuilder(); - for (Metric metric : metrics) { - MetricYamlTpl metricYamlTpl = MetricConverter.convert2MetricYamlTpl(metric); - Map rootMap = new HashMap<>(); - rootMap.put("metric", metricYamlTpl); - yamlBuilder.append(YamlUtils.toYamlWithoutNull(rootMap)).append("\n"); - } - return yamlBuilder.toString(); - } - public static List convert2YamlObj(List metrics) { List metricYamlTpls = new ArrayList<>(); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/YamlManager.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/YamlManager.java deleted file mode 100644 index b85a9d0d1..000000000 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/manager/YamlManager.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.tencent.supersonic.semantic.core.domain.manager; - - -import com.tencent.supersonic.common.constant.Constants; -import com.tencent.supersonic.semantic.core.domain.config.YamlConfig; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FileUtils; -import org.springframework.stereotype.Service; - - -@Slf4j -@Service -public class YamlManager { - - - protected final YamlConfig yamlConfig; - -// private final ParserService parserService; - - - public YamlManager(YamlConfig yamlConfig -// , @Lazy ParserService parserService - ) { - this.yamlConfig = yamlConfig; -// this.parserService = parserService; - } - - public void generateYamlFile(String yamlStr, String path, String name) throws Exception { - String localPath = generateLocalYamlPath(path, name); - File file = createMetaYamlFile(localPath); - FileUtils.writeStringToFile(file, yamlStr, StandardCharsets.UTF_8); -// parserService.reloadModels(path); - - } - - public void deleteYamlFile(String path, String fileName) { - String localPath = generateLocalYamlPath(path, fileName); - deleteMetaYamlFile(localPath); - } - - private File createMetaYamlFile(String fullPath) throws IOException { - File file = new File(fullPath); - if (file.getParentFile().mkdirs() && file.createNewFile()) { - log.info("File :{} created: " + fullPath); - } else { - log.warn("File:{} create failed.", fullPath); - } - return file; - } - - private void deleteMetaYamlFile(String fullPath) { - File file = new File(fullPath); - if (file.delete()) { - log.info("File :{} deleted: " + fullPath); - } else { - log.info("File :{} delete failed: " + fullPath); - } - } - - private String generateLocalYamlPath(String path, String name) { - return yamlConfig.getmetaYamlFileDir() + path + name + Constants.YAML_FILES_SUFFIX; - } -} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Dimension.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Dimension.java index 871abfb7f..ba024e60a 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Dimension.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Dimension.java @@ -3,7 +3,7 @@ package com.tencent.supersonic.semantic.core.domain.pojo; import com.tencent.supersonic.common.pojo.SchemaItem; import lombok.Data; - +import java.util.List; @Data public class Dimension extends SchemaItem { @@ -15,9 +15,12 @@ public class Dimension extends SchemaItem { private Long domainId; - private Long datasourceId; private String semanticType; + private String alias; + + private List defaultValues; + } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/JdbcDataSource.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/JdbcDataSource.java index a73d834d3..74aaaa59c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/JdbcDataSource.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/JdbcDataSource.java @@ -29,42 +29,9 @@ import org.springframework.stereotype.Component; @Component public class JdbcDataSource { - @Bean(name = "wallConfig") - WallConfig wallConfig() { - WallConfig config = new WallConfig(); - config.setDeleteAllow(false); - config.setUpdateAllow(false); - config.setInsertAllow(false); - config.setReplaceAllow(false); - config.setMergeAllow(false); - config.setTruncateAllow(false); - config.setCreateTableAllow(false); - config.setAlterTableAllow(false); - config.setDropTableAllow(false); - config.setCommentAllow(true); - config.setUseAllow(false); - config.setDescribeAllow(false); - config.setShowAllow(false); - config.setSelectWhereAlwayTrueCheck(false); - config.setSelectHavingAlwayTrueCheck(false); - config.setSelectUnionCheck(false); - config.setConditionDoubleConstAllow(true); - config.setConditionAndAlwayTrueAllow(true); - config.setConditionAndAlwayFalseAllow(true); - return config; - } - - @Bean(name = "wallFilter") - @DependsOn("wallConfig") - WallFilter wallFilter(WallConfig wallConfig) { - WallFilter wfilter = new WallFilter(); - wfilter.setConfig(wallConfig); - return wfilter; - } - - @Autowired - WallFilter wallFilter; - + private static final Object lockLock = new Object(); + private static volatile Map dataSourceMap = new ConcurrentHashMap<>(); + private static volatile Map dataSourceLockMap = new ConcurrentHashMap<>(); @Value("${source.lock-time:30}") @Getter protected Long lockTime; @@ -136,10 +103,41 @@ public class JdbcDataSource { @Value("${source.filters:'stat'}") @Getter protected String filters; + @Autowired + WallFilter wallFilter; - private static volatile Map dataSourceMap = new ConcurrentHashMap<>(); - private static volatile Map dataSourceLockMap = new ConcurrentHashMap<>(); - private static final Object lockLock = new Object(); + @Bean(name = "wallConfig") + WallConfig wallConfig() { + WallConfig config = new WallConfig(); + config.setDeleteAllow(false); + config.setUpdateAllow(false); + config.setInsertAllow(false); + config.setReplaceAllow(false); + config.setMergeAllow(false); + config.setTruncateAllow(false); + config.setCreateTableAllow(false); + config.setAlterTableAllow(false); + config.setDropTableAllow(false); + config.setCommentAllow(true); + config.setUseAllow(false); + config.setDescribeAllow(false); + config.setShowAllow(false); + config.setSelectWhereAlwayTrueCheck(false); + config.setSelectHavingAlwayTrueCheck(false); + config.setSelectUnionCheck(false); + config.setConditionDoubleConstAllow(true); + config.setConditionAndAlwayTrueAllow(true); + config.setConditionAndAlwayFalseAllow(true); + return config; + } + + @Bean(name = "wallFilter") + @DependsOn("wallConfig") + WallFilter wallFilter(WallConfig wallConfig) { + WallFilter wfilter = new WallFilter(); + wfilter.setConfig(wallConfig); + return wfilter; + } private Lock getDataSourceLock(String key) { if (dataSourceLockMap.containsKey(key)) { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Metric.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Metric.java index f0aee38d3..fab864d76 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Metric.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/pojo/Metric.java @@ -21,4 +21,6 @@ public class Metric extends SchemaItem { private DataFormat dataFormat; + private String alias; + } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DimensionRepository.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DimensionRepository.java index 4fab4f083..84fe70b2b 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DimensionRepository.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/DimensionRepository.java @@ -18,6 +18,8 @@ public interface DimensionRepository { List getDimensionListOfDomain(Long domainId); + List getDimensionList(); + List getDimensionListByIds(List ids); DimensionDO getDimensionById(Long id); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/MetricRepository.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/MetricRepository.java index 31e735d87..674257fa6 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/MetricRepository.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/repository/MetricRepository.java @@ -17,6 +17,8 @@ public interface MetricRepository { List getMetricList(Long domainId); + List getMetricList(); + List getMetricListByIds(List ids); MetricDO getMetricById(Long id); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatasourceConverter.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatasourceConverter.java index 737972421..520d2c99f 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatasourceConverter.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DatasourceConverter.java @@ -3,6 +3,7 @@ package com.tencent.supersonic.semantic.core.domain.utils; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.semantic.api.core.enums.MetricTypeEnum; import com.tencent.supersonic.semantic.api.core.pojo.DatasourceDetail; import com.tencent.supersonic.semantic.api.core.pojo.Dim; import com.tencent.supersonic.semantic.api.core.pojo.Identify; @@ -111,16 +112,17 @@ public class DatasourceConverter { public static MetricReq convert(Measure measure, Datasource datasource) { measure.setDatasourceId(datasource.getId()); - MetricReq exprMetricReq = new MetricReq(); - exprMetricReq.setName(measure.getName()); - exprMetricReq.setBizName(measure.getBizName().replace(datasource.getBizName() + "_", "")); - exprMetricReq.setDescription(measure.getName()); - exprMetricReq.setDomainId(datasource.getDomainId()); + MetricReq metricReq = new MetricReq(); + metricReq.setName(measure.getName()); + metricReq.setBizName(measure.getBizName().replace(datasource.getBizName() + "_", "")); + metricReq.setDescription(measure.getName()); + metricReq.setDomainId(datasource.getDomainId()); + metricReq.setMetricType(MetricTypeEnum.ATOMIC); MetricTypeParams exprTypeParams = new MetricTypeParams(); exprTypeParams.setExpr(measure.getBizName()); exprTypeParams.setMeasures(Lists.newArrayList(measure)); - exprMetricReq.setTypeParams(exprTypeParams); - return exprMetricReq; + metricReq.setTypeParams(exprTypeParams); + return metricReq; } public static DimensionReq convert(Identify identify, Datasource datasource) { diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DimensionConverter.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DimensionConverter.java index 0fed66215..06b615e94 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DimensionConverter.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DimensionConverter.java @@ -1,5 +1,6 @@ package com.tencent.supersonic.semantic.core.domain.utils; +import com.alibaba.fastjson.JSONObject; import com.tencent.supersonic.semantic.api.core.pojo.yaml.DimensionYamlTpl; import com.tencent.supersonic.semantic.api.core.request.DimensionReq; import com.tencent.supersonic.semantic.api.core.response.DatasourceResp; @@ -22,36 +23,34 @@ public class DimensionConverter { public static DimensionDO convert(DimensionDO dimensionDO, Dimension dimension) { BeanMapper.mapper(dimension, dimensionDO); + dimensionDO.setDefaultValues(JSONObject.toJSONString(dimension.getDefaultValues())); return dimensionDO; } public static DimensionDO convert2DimensionDO(Dimension dimension) { DimensionDO dimensionDO = new DimensionDO(); BeanUtils.copyProperties(dimension, dimensionDO); + dimensionDO.setDefaultValues(JSONObject.toJSONString(dimension.getDefaultValues())); return dimensionDO; } - public static DimensionResp convert2DimensionDesc(DimensionDO dimensionDO, + public static DimensionResp convert2DimensionResp(DimensionDO dimensionDO, Map fullPathMap, - Map datasourceDescMap - ) { - DimensionResp dimensionDesc = new DimensionResp(); - BeanUtils.copyProperties(dimensionDO, dimensionDesc); - dimensionDesc.setFullPath(fullPathMap.get(dimensionDO.getDomainId()) + dimensionDO.getBizName()); - dimensionDesc.setDatasourceId( - datasourceDescMap.getOrDefault(dimensionDesc.getDatasourceId(), new DatasourceResp()).getId()); - dimensionDesc.setDatasourceName( - datasourceDescMap.getOrDefault(dimensionDesc.getDatasourceId(), new DatasourceResp()).getName()); - dimensionDesc.setDatasourceBizName( - datasourceDescMap.getOrDefault(dimensionDesc.getDatasourceId(), new DatasourceResp()).getBizName()); - return dimensionDesc; - } - - public static Dimension convert2Dimension(DimensionDO dimensionDO) { - Dimension dimension = new Dimension(); - BeanUtils.copyProperties(dimensionDO, dimension); - return dimension; + Map datasourceRespMap) { + DimensionResp dimensionResp = new DimensionResp(); + BeanUtils.copyProperties(dimensionDO, dimensionResp); + dimensionResp.setFullPath(fullPathMap.get(dimensionDO.getDomainId()) + dimensionDO.getBizName()); + dimensionResp.setDatasourceId( + datasourceRespMap.getOrDefault(dimensionResp.getDatasourceId(), new DatasourceResp()).getId()); + dimensionResp.setDatasourceName( + datasourceRespMap.getOrDefault(dimensionResp.getDatasourceId(), new DatasourceResp()).getName()); + dimensionResp.setDatasourceBizName( + datasourceRespMap.getOrDefault(dimensionResp.getDatasourceId(), new DatasourceResp()).getBizName()); + if (dimensionDO.getDefaultValues() != null) { + dimensionResp.setDefaultValues(JSONObject.parseObject(dimensionDO.getDefaultValues(), List.class)); + } + return dimensionResp; } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DomainConvert.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DomainConvert.java index b322e8e89..4951d96d8 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DomainConvert.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/DomainConvert.java @@ -4,12 +4,15 @@ package com.tencent.supersonic.semantic.core.domain.utils; import com.google.common.collect.Lists; import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.semantic.api.core.request.DomainReq; +import com.tencent.supersonic.semantic.api.core.response.DimensionResp; import com.tencent.supersonic.semantic.api.core.response.DomainResp; import com.tencent.supersonic.common.enums.StatusEnum; +import com.tencent.supersonic.semantic.api.core.response.MetricResp; import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDO; import com.tencent.supersonic.semantic.core.domain.pojo.Domain; import 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; @@ -38,18 +41,26 @@ public class DomainConvert { } public static DomainResp convert(DomainDO domainDO, Map domainFullPathMap) { - DomainResp domainDesc = new DomainResp(); - BeanUtils.copyProperties(domainDO, domainDesc); - domainDesc.setFullPath(domainFullPathMap.get(domainDO.getId())); - domainDesc.setAdmins(StringUtils.isBlank(domainDO.getAdmin()) + DomainResp domainResp = new DomainResp(); + BeanUtils.copyProperties(domainDO, domainResp); + domainResp.setFullPath(domainFullPathMap.get(domainDO.getId())); + domainResp.setAdmins(StringUtils.isBlank(domainDO.getAdmin()) ? Lists.newArrayList() : Arrays.asList(domainDO.getAdmin().split(","))); - domainDesc.setAdminOrgs(StringUtils.isBlank(domainDO.getAdminOrg()) + domainResp.setAdminOrgs(StringUtils.isBlank(domainDO.getAdminOrg()) ? Lists.newArrayList() : Arrays.asList(domainDO.getAdminOrg().split(","))); - domainDesc.setViewers(StringUtils.isBlank(domainDO.getViewer()) + domainResp.setViewers(StringUtils.isBlank(domainDO.getViewer()) ? Lists.newArrayList() : Arrays.asList(domainDO.getViewer().split(","))); - domainDesc.setViewOrgs(StringUtils.isBlank(domainDO.getViewOrg()) + domainResp.setViewOrgs(StringUtils.isBlank(domainDO.getViewOrg()) ? Lists.newArrayList() : Arrays.asList(domainDO.getViewOrg().split(","))); - return domainDesc; + return domainResp; + } + + public static DomainResp convert(DomainDO domainDO, Map domainFullPathMap, + 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()); + return domainResp; } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/JdbcDataSourceUtils.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/JdbcDataSourceUtils.java index d01a21e0a..10099610e 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/JdbcDataSourceUtils.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/JdbcDataSourceUtils.java @@ -29,10 +29,9 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class JdbcDataSourceUtils { - private JdbcDataSource jdbcDataSource; - @Getter private static Set releaseSourceSet = new HashSet(); + private JdbcDataSource jdbcDataSource; public JdbcDataSourceUtils(JdbcDataSource jdbcDataSource) { this.jdbcDataSource = jdbcDataSource; @@ -57,54 +56,6 @@ public class JdbcDataSourceUtils { return false; } - - public DataSource getDataSource(DatabaseResp databaseResp) throws RuntimeException { - return jdbcDataSource.getDataSource(databaseResp); - } - - public Connection getConnection(DatabaseResp databaseResp) throws RuntimeException { - Connection conn = getConnectionWithRetry(databaseResp); - if (conn == null) { - try { - releaseDataSource(databaseResp); - DataSource dataSource = getDataSource(databaseResp); - return dataSource.getConnection(); - } catch (Exception e) { - log.error("Get connection error, jdbcUrl:{}, e:{}", databaseResp.getUrl(), e); - throw new RuntimeException("Get connection error, jdbcUrl:" + databaseResp.getUrl() - + " you can try again later or reset datasource"); - } - } - return conn; - } - - private Connection getConnectionWithRetry(DatabaseResp databaseResp) { - int rc = 1; - for (; ; ) { - - if (rc > 3) { - return null; - } - - try { - Connection connection = getDataSource(databaseResp).getConnection(); - if (connection != null && connection.isValid(5)) { - return connection; - } - } catch (Exception e) { - log.error("e", e); - } - - try { - Thread.sleep((long) Math.pow(2, rc) * 1000); - } catch (InterruptedException e) { - log.error("e", e); - } - - rc++; - } - } - public static void releaseConnection(Connection connection) { if (null != connection) { try { @@ -177,11 +128,6 @@ public class JdbcDataSourceUtils { throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl); } - - public void releaseDataSource(DatabaseResp databaseResp) { - jdbcDataSource.removeDatasource(databaseResp); - } - public static String getKey(String name, String jdbcUrl, String username, String password, String version, boolean isExt) { @@ -199,4 +145,55 @@ public class JdbcDataSourceUtils { return MD5Util.getMD5(sb.toString(), true, 64); } + + public DataSource getDataSource(DatabaseResp databaseResp) throws RuntimeException { + return jdbcDataSource.getDataSource(databaseResp); + } + + public Connection getConnection(DatabaseResp databaseResp) throws RuntimeException { + Connection conn = getConnectionWithRetry(databaseResp); + if (conn == null) { + try { + releaseDataSource(databaseResp); + DataSource dataSource = getDataSource(databaseResp); + return dataSource.getConnection(); + } catch (Exception e) { + log.error("Get connection error, jdbcUrl:{}, e:{}", databaseResp.getUrl(), e); + throw new RuntimeException("Get connection error, jdbcUrl:" + databaseResp.getUrl() + + " you can try again later or reset datasource"); + } + } + return conn; + } + + private Connection getConnectionWithRetry(DatabaseResp databaseResp) { + int rc = 1; + for (; ; ) { + + if (rc > 3) { + return null; + } + + try { + Connection connection = getDataSource(databaseResp).getConnection(); + if (connection != null && connection.isValid(5)) { + return connection; + } + } catch (Exception e) { + log.error("e", e); + } + + try { + Thread.sleep((long) Math.pow(2, rc) * 1000); + } catch (InterruptedException e) { + log.error("e", e); + } + + rc++; + } + } + + public void releaseDataSource(DatabaseResp databaseResp) { + jdbcDataSource.removeDatasource(databaseResp); + } } \ No newline at end of file diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/MetricConverter.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/MetricConverter.java index 58a6c749b..e251ef844 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/MetricConverter.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/MetricConverter.java @@ -26,7 +26,7 @@ public class MetricConverter { public static Metric convert(MetricReq metricReq) { Metric metric = new Metric(); BeanUtils.copyProperties(metricReq, metric); - metric.setType(MetricTypeEnum.EXPR.getName()); + metric.setType(metricReq.getMetricType().name()); metric.setTypeParams(metricReq.getTypeParams()); return metric; } @@ -75,7 +75,7 @@ public class MetricConverter { return metric; } - + public static MetricYamlTpl convert2MetricYamlTpl(Metric metric) { MetricYamlTpl metricYamlTpl = new MetricYamlTpl(); BeanUtils.copyProperties(metric, metricYamlTpl); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SqlUtils.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SqlUtils.java index e9ecf0d46..98d12bd3c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SqlUtils.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SqlUtils.java @@ -47,6 +47,15 @@ public class SqlUtils { @Getter private JdbcDataSourceUtils jdbcDataSourceUtils; + public SqlUtils() { + + } + + public SqlUtils(DatabaseResp databaseResp) { + this.databaseResp = databaseResp; + this.dataTypeEnum = DataTypeEnum.urlOf(databaseResp.getUrl()); + } + public SqlUtils init(DatabaseResp databaseResp) { //todo Password decryption return SqlUtilsBuilder @@ -62,16 +71,6 @@ public class SqlUtils { .build(); } - public SqlUtils() { - - } - - public SqlUtils(DatabaseResp databaseResp) { - this.databaseResp = databaseResp; - this.dataTypeEnum = DataTypeEnum.urlOf(databaseResp.getUrl()); - } - - public List> execute(String sql) throws ServerException { try { List> list = jdbcTemplate().queryForList(sql); @@ -97,7 +96,6 @@ public class SqlUtils { JdbcDataSourceUtils.releaseConnection(connection); } DataSource dataSource = jdbcDataSourceUtils.getDataSource(databaseResp); - JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.setDatabaseProductName(databaseResp.getName()); jdbcTemplate.setFetchSize(500); @@ -232,4 +230,4 @@ public class SqlUtils { return sqlUtils; } } -} \ No newline at end of file +} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SysTimeDimensionBuilder.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SysTimeDimensionBuilder.java index e4f6d8981..673358695 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SysTimeDimensionBuilder.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/domain/utils/SysTimeDimensionBuilder.java @@ -23,7 +23,7 @@ public class SysTimeDimensionBuilder { dims.add(generateSysDayDimension(timeDim, engineAdaptor)); dims.add(generateSysWeekDimension(timeDim, engineAdaptor)); dims.add(generateSysMonthDimension(timeDim, engineAdaptor)); - log.info("addSysTimeDimension after:{}, engineAdaptor:{}", dims, engineAdaptor); + log.debug("addSysTimeDimension after:{}, engineAdaptor:{}", dims, engineAdaptor); } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOMapper.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOMapper.java index 594bf7bf0..5f586c637 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOMapper.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DimensionDOMapper.java @@ -3,9 +3,9 @@ package com.tencent.supersonic.semantic.core.infrastructure.mapper; import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDO; import com.tencent.supersonic.semantic.core.domain.dataobject.DimensionDOExample; +import org.apache.ibatis.annotations.Mapper; import java.util.List; -import org.apache.ibatis.annotations.Mapper; @Mapper public interface DimensionDOMapper { @@ -59,4 +59,4 @@ public interface DimensionDOMapper { * @mbg.generated */ int updateByPrimaryKey(DimensionDO record); -} +} \ No newline at end of file diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DomainDOMapper.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DomainDOMapper.java index 965332270..177bc0559 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DomainDOMapper.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/mapper/DomainDOMapper.java @@ -48,4 +48,4 @@ public interface DomainDOMapper { * @mbg.generated */ int updateByPrimaryKey(DomainDO record); -} \ No newline at end of file +} diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatasourceRepositoryImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatasourceRepositoryImpl.java index ccf73ad27..e521c9e3c 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatasourceRepositoryImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DatasourceRepositoryImpl.java @@ -53,7 +53,7 @@ public class DatasourceRepositoryImpl implements DatasourceRepository { public DatasourceDO getDatasourceById(Long id) { return datasourceMapper.selectByPrimaryKey(id); } - + @Override public void deleteDatasource(Long id) { datasourceMapper.deleteByPrimaryKey(id); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DimensionRepositoryImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DimensionRepositoryImpl.java index 4d2a44ed0..eeef1f45a 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DimensionRepositoryImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DimensionRepositoryImpl.java @@ -56,6 +56,12 @@ public class DimensionRepositoryImpl implements DimensionRepository { return dimensionDOMapper.selectByExampleWithBLOBs(dimensionDOExample); } + @Override + public List getDimensionList() { + DimensionDOExample dimensionDOExample = new DimensionDOExample(); + return dimensionDOMapper.selectByExampleWithBLOBs(dimensionDOExample); + } + @Override public List getDimensionListByIds(List ids) { DimensionDOExample dimensionDOExample = new DimensionDOExample(); @@ -86,7 +92,7 @@ public class DimensionRepositoryImpl implements DimensionRepository { dimensionDOExample.getOredCriteria().get(0).andNameLike("%" + dimensionFilter.getName() + "%"); } if (dimensionFilter.getBizName() != null) { - dimensionDOExample.getOredCriteria().get(0).andBizNameEqualTo("%" + dimensionFilter.getBizName() + "%"); + dimensionDOExample.getOredCriteria().get(0).andBizNameLike("%" + dimensionFilter.getBizName() + "%"); } if (dimensionFilter.getCreatedBy() != null) { dimensionDOExample.getOredCriteria().get(0).andCreatedByEqualTo(dimensionFilter.getCreatedBy()); @@ -94,6 +100,9 @@ public class DimensionRepositoryImpl implements DimensionRepository { if (dimensionFilter.getDomainId() != null) { dimensionDOExample.getOredCriteria().get(0).andDomainIdEqualTo(dimensionFilter.getDomainId()); } + if (dimensionFilter.getSensitiveLevel() != null) { + dimensionDOExample.getOredCriteria().get(0).andSensitiveLevelEqualTo(dimensionFilter.getSensitiveLevel()); + } return dimensionDOMapper.selectByExampleWithBLOBs(dimensionDOExample); } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DomainRepositoryImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DomainRepositoryImpl.java index 2ed8285ab..dcea2c7a7 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DomainRepositoryImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/DomainRepositoryImpl.java @@ -5,10 +5,13 @@ import com.tencent.supersonic.semantic.core.domain.dataobject.DomainDOExample; import com.tencent.supersonic.semantic.core.domain.repository.DomainRepository; import com.tencent.supersonic.semantic.core.infrastructure.mapper.DomainDOMapper; import java.util.List; + +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class DomainRepositoryImpl implements DomainRepository { private DomainDOMapper domainDOMapper; diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/MetricRepositoryImpl.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/MetricRepositoryImpl.java index f7c7c67f1..8ff981b45 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/MetricRepositoryImpl.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/infrastructure/repository/MetricRepositoryImpl.java @@ -48,6 +48,12 @@ public class MetricRepositoryImpl implements MetricRepository { return metricDOMapper.selectByExampleWithBLOBs(metricDOExample); } + @Override + public List getMetricList() { + MetricDOExample metricDOExample = new MetricDOExample(); + return metricDOMapper.selectByExampleWithBLOBs(metricDOExample); + } + @Override public List getMetricListByIds(List ids) { MetricDOExample metricDOExample = new MetricDOExample(); diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatabaseController.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatabaseController.java index 290f09851..527684374 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatabaseController.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/DatabaseController.java @@ -59,5 +59,24 @@ public class DatabaseController { return databaseService.executeSql(sqlExecuteReq.getSql(), sqlExecuteReq.getDomainId()); } + @RequestMapping("/getDbNames/{id}") + public QueryResultWithSchemaResp getDbNames(@PathVariable("id") Long id) { + return databaseService.getDbNames(id); + } + + @RequestMapping("/getTables/{id}/{db}") + public QueryResultWithSchemaResp getTables(@PathVariable("id") Long id, + @PathVariable("db") String db) { + return databaseService.getTables(id, db); + } + + + @RequestMapping("/getColumns/{id}/{db}/{table}") + public QueryResultWithSchemaResp getColumns(@PathVariable("id") Long id, + @PathVariable("db") String db, + @PathVariable("table") String table) { + return databaseService.getColumns(id, db, table); + } + } diff --git a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/ViewInfoController.java b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/ViewInfoController.java index 4d01f7e40..d6e1d16d8 100644 --- a/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/ViewInfoController.java +++ b/semantic/core/src/main/java/com/tencent/supersonic/semantic/core/rest/ViewInfoController.java @@ -32,7 +32,7 @@ public class ViewInfoController { @PostMapping("/createOrUpdateViewInfo") public ViewInfoDO createOrUpdateViewInfo(@RequestBody ViewInfoReq viewInfoReq, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return viewInfoServiceImpl.createOrUpdateViewInfo(viewInfoReq, user); } diff --git a/semantic/core/src/main/resources/mapper/DimensionDOMapper.xml b/semantic/core/src/main/resources/mapper/DimensionDOMapper.xml index f24ced025..fa5d52624 100644 --- a/semantic/core/src/main/resources/mapper/DimensionDOMapper.xml +++ b/semantic/core/src/main/resources/mapper/DimensionDOMapper.xml @@ -1,338 +1,341 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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} + + + - - - - id - , domain_id, datasource_id, name, biz_name, description, status, sensitive_level, - type, created_at, created_by, updated_at, updated_by, semantic_type - - - type_params - , expr - - - - - - delete - from s2_dimension - where id = #{id,jdbcType=BIGINT} - - - insert into s2_dimension (id, domain_id, datasource_id, - name, biz_name, description, - status, sensitive_level, type, - created_at, created_by, updated_at, - updated_by, semantic_type, type_params, - expr) - values (#{id,jdbcType=BIGINT}, #{domainId,jdbcType=BIGINT}, #{datasourceId,jdbcType=BIGINT}, - #{name,jdbcType=VARCHAR}, #{bizName,jdbcType=VARCHAR}, - #{description,jdbcType=VARCHAR}, - #{status,jdbcType=INTEGER}, #{sensitiveLevel,jdbcType=INTEGER}, - #{type,jdbcType=VARCHAR}, - #{createdAt,jdbcType=TIMESTAMP}, #{createdBy,jdbcType=VARCHAR}, - #{updatedAt,jdbcType=TIMESTAMP}, - #{updatedBy,jdbcType=VARCHAR}, #{semanticType,jdbcType=VARCHAR}, - #{typeParams,jdbcType=LONGVARCHAR}, - #{expr,jdbcType=LONGVARCHAR}) - - - insert into s2_dimension - - - id, - - - domain_id, - - - datasource_id, - - - name, - - - biz_name, - - - description, - - - status, - - - sensitive_level, - - - type, - - - created_at, - - - created_by, - - - updated_at, - - - updated_by, - - - semantic_type, - - - type_params, - - - expr, - - - - - #{id,jdbcType=BIGINT}, - - - #{domainId,jdbcType=BIGINT}, - - - #{datasourceId,jdbcType=BIGINT}, - - - #{name,jdbcType=VARCHAR}, - - - #{bizName,jdbcType=VARCHAR}, - - - #{description,jdbcType=VARCHAR}, - - - #{status,jdbcType=INTEGER}, - - - #{sensitiveLevel,jdbcType=INTEGER}, - - - #{type,jdbcType=VARCHAR}, - - - #{createdAt,jdbcType=TIMESTAMP}, - - - #{createdBy,jdbcType=VARCHAR}, - - - #{updatedAt,jdbcType=TIMESTAMP}, - - - #{updatedBy,jdbcType=VARCHAR}, - - - #{semanticType,jdbcType=VARCHAR}, - - - #{typeParams,jdbcType=LONGVARCHAR}, - - - #{expr,jdbcType=LONGVARCHAR}, - - - - - - update s2_dimension - - - domain_id = #{domainId,jdbcType=BIGINT}, - - - datasource_id = #{datasourceId,jdbcType=BIGINT}, - - - name = #{name,jdbcType=VARCHAR}, - - - biz_name = #{bizName,jdbcType=VARCHAR}, - - - description = #{description,jdbcType=VARCHAR}, - - - status = #{status,jdbcType=INTEGER}, - - - sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, - - - type = #{type,jdbcType=VARCHAR}, - - - created_at = #{createdAt,jdbcType=TIMESTAMP}, - - - created_by = #{createdBy,jdbcType=VARCHAR}, - - - updated_at = #{updatedAt,jdbcType=TIMESTAMP}, - - - updated_by = #{updatedBy,jdbcType=VARCHAR}, - - - semantic_type = #{semanticType,jdbcType=VARCHAR}, - - - type_params = #{typeParams,jdbcType=LONGVARCHAR}, - - - expr = #{expr,jdbcType=LONGVARCHAR}, - - - where id = #{id,jdbcType=BIGINT} - - - update s2_dimension - set domain_id = #{domainId,jdbcType=BIGINT}, - datasource_id = #{datasourceId,jdbcType=BIGINT}, - name = #{name,jdbcType=VARCHAR}, - biz_name = #{bizName,jdbcType=VARCHAR}, - description = #{description,jdbcType=VARCHAR}, - status = #{status,jdbcType=INTEGER}, - sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, - type = #{type,jdbcType=VARCHAR}, - created_at = #{createdAt,jdbcType=TIMESTAMP}, - created_by = #{createdBy,jdbcType=VARCHAR}, - updated_at = #{updatedAt,jdbcType=TIMESTAMP}, - updated_by = #{updatedBy,jdbcType=VARCHAR}, - semantic_type = #{semanticType,jdbcType=VARCHAR}, - type_params = #{typeParams,jdbcType=LONGVARCHAR}, - expr = #{expr,jdbcType=LONGVARCHAR} - where id = #{id,jdbcType=BIGINT} - - - update s2_dimension - set domain_id = #{domainId,jdbcType=BIGINT}, - datasource_id = #{datasourceId,jdbcType=BIGINT}, - name = #{name,jdbcType=VARCHAR}, - biz_name = #{bizName,jdbcType=VARCHAR}, - description = #{description,jdbcType=VARCHAR}, - status = #{status,jdbcType=INTEGER}, - sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, - type = #{type,jdbcType=VARCHAR}, - created_at = #{createdAt,jdbcType=TIMESTAMP}, - created_by = #{createdBy,jdbcType=VARCHAR}, - updated_at = #{updatedAt,jdbcType=TIMESTAMP}, - updated_by = #{updatedBy,jdbcType=VARCHAR}, - semantic_type = #{semanticType,jdbcType=VARCHAR} - where id = #{id,jdbcType=BIGINT} - + + + + + id, domain_id, datasource_id, name, biz_name, description, status, sensitive_level, + type, created_at, created_by, updated_at, updated_by, semantic_type, alias, default_values + + + type_params, expr + + + + + + delete from s2_dimension + where id = #{id,jdbcType=BIGINT} + + + insert into s2_dimension (id, domain_id, datasource_id, + name, biz_name, description, + status, sensitive_level, type, + created_at, created_by, updated_at, + updated_by, semantic_type, alias, + default_values, type_params, expr + ) + values (#{id,jdbcType=BIGINT}, #{domainId,jdbcType=BIGINT}, #{datasourceId,jdbcType=BIGINT}, + #{name,jdbcType=VARCHAR}, #{bizName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, + #{status,jdbcType=INTEGER}, #{sensitiveLevel,jdbcType=INTEGER}, #{type,jdbcType=VARCHAR}, + #{createdAt,jdbcType=TIMESTAMP}, #{createdBy,jdbcType=VARCHAR}, #{updatedAt,jdbcType=TIMESTAMP}, + #{updatedBy,jdbcType=VARCHAR}, #{semanticType,jdbcType=VARCHAR}, #{alias,jdbcType=VARCHAR}, + #{defaultValues,jdbcType=VARCHAR}, #{typeParams,jdbcType=LONGVARCHAR}, #{expr,jdbcType=LONGVARCHAR} + ) + + + insert into s2_dimension + + + id, + + + domain_id, + + + datasource_id, + + + name, + + + biz_name, + + + description, + + + status, + + + sensitive_level, + + + type, + + + created_at, + + + created_by, + + + updated_at, + + + updated_by, + + + semantic_type, + + + alias, + + + default_values, + + + type_params, + + + expr, + + + + + #{id,jdbcType=BIGINT}, + + + #{domainId,jdbcType=BIGINT}, + + + #{datasourceId,jdbcType=BIGINT}, + + + #{name,jdbcType=VARCHAR}, + + + #{bizName,jdbcType=VARCHAR}, + + + #{description,jdbcType=VARCHAR}, + + + #{status,jdbcType=INTEGER}, + + + #{sensitiveLevel,jdbcType=INTEGER}, + + + #{type,jdbcType=VARCHAR}, + + + #{createdAt,jdbcType=TIMESTAMP}, + + + #{createdBy,jdbcType=VARCHAR}, + + + #{updatedAt,jdbcType=TIMESTAMP}, + + + #{updatedBy,jdbcType=VARCHAR}, + + + #{semanticType,jdbcType=VARCHAR}, + + + #{alias,jdbcType=VARCHAR}, + + + #{defaultValues,jdbcType=VARCHAR}, + + + #{typeParams,jdbcType=LONGVARCHAR}, + + + #{expr,jdbcType=LONGVARCHAR}, + + + + + + update s2_dimension + + + domain_id = #{domainId,jdbcType=BIGINT}, + + + datasource_id = #{datasourceId,jdbcType=BIGINT}, + + + name = #{name,jdbcType=VARCHAR}, + + + biz_name = #{bizName,jdbcType=VARCHAR}, + + + description = #{description,jdbcType=VARCHAR}, + + + status = #{status,jdbcType=INTEGER}, + + + sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, + + + type = #{type,jdbcType=VARCHAR}, + + + created_at = #{createdAt,jdbcType=TIMESTAMP}, + + + created_by = #{createdBy,jdbcType=VARCHAR}, + + + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + + + updated_by = #{updatedBy,jdbcType=VARCHAR}, + + + semantic_type = #{semanticType,jdbcType=VARCHAR}, + + + alias = #{alias,jdbcType=VARCHAR}, + + + default_values = #{defaultValues,jdbcType=VARCHAR}, + + + type_params = #{typeParams,jdbcType=LONGVARCHAR}, + + + expr = #{expr,jdbcType=LONGVARCHAR}, + + + where id = #{id,jdbcType=BIGINT} + + + update s2_dimension + set domain_id = #{domainId,jdbcType=BIGINT}, + datasource_id = #{datasourceId,jdbcType=BIGINT}, + name = #{name,jdbcType=VARCHAR}, + biz_name = #{bizName,jdbcType=VARCHAR}, + description = #{description,jdbcType=VARCHAR}, + status = #{status,jdbcType=INTEGER}, + sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, + type = #{type,jdbcType=VARCHAR}, + created_at = #{createdAt,jdbcType=TIMESTAMP}, + created_by = #{createdBy,jdbcType=VARCHAR}, + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + updated_by = #{updatedBy,jdbcType=VARCHAR}, + semantic_type = #{semanticType,jdbcType=VARCHAR}, + alias = #{alias,jdbcType=VARCHAR}, + default_values = #{defaultValues,jdbcType=VARCHAR}, + type_params = #{typeParams,jdbcType=LONGVARCHAR}, + expr = #{expr,jdbcType=LONGVARCHAR} + where id = #{id,jdbcType=BIGINT} + + + update s2_dimension + set domain_id = #{domainId,jdbcType=BIGINT}, + datasource_id = #{datasourceId,jdbcType=BIGINT}, + name = #{name,jdbcType=VARCHAR}, + biz_name = #{bizName,jdbcType=VARCHAR}, + description = #{description,jdbcType=VARCHAR}, + status = #{status,jdbcType=INTEGER}, + sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, + type = #{type,jdbcType=VARCHAR}, + created_at = #{createdAt,jdbcType=TIMESTAMP}, + created_by = #{createdBy,jdbcType=VARCHAR}, + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + updated_by = #{updatedBy,jdbcType=VARCHAR}, + semantic_type = #{semanticType,jdbcType=VARCHAR}, + alias = #{alias,jdbcType=VARCHAR}, + default_values = #{defaultValues,jdbcType=VARCHAR} + where id = #{id,jdbcType=BIGINT} + \ No newline at end of file diff --git a/semantic/core/src/main/resources/mapper/MetricDOMapper.xml b/semantic/core/src/main/resources/mapper/MetricDOMapper.xml index b4df05687..cb173cc0a 100644 --- a/semantic/core/src/main/resources/mapper/MetricDOMapper.xml +++ b/semantic/core/src/main/resources/mapper/MetricDOMapper.xml @@ -1,324 +1,316 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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} + + + - - - - id - , domain_id, name, biz_name, description, status, sensitive_level, type, created_at, - created_by, updated_at, updated_by, data_format_type, data_format - - - type_params - - - - - - delete - from s2_metric - where id = #{id,jdbcType=BIGINT} - - - insert into s2_metric (id, domain_id, name, - biz_name, description, status, - sensitive_level, type, created_at, - created_by, updated_at, updated_by, - data_format_type, data_format, type_params) - values (#{id,jdbcType=BIGINT}, #{domainId,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, - #{bizName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, - #{status,jdbcType=INTEGER}, - #{sensitiveLevel,jdbcType=INTEGER}, #{type,jdbcType=VARCHAR}, - #{createdAt,jdbcType=TIMESTAMP}, - #{createdBy,jdbcType=VARCHAR}, #{updatedAt,jdbcType=TIMESTAMP}, - #{updatedBy,jdbcType=VARCHAR}, - #{dataFormatType,jdbcType=VARCHAR}, #{dataFormat,jdbcType=VARCHAR}, - #{typeParams,jdbcType=LONGVARCHAR}) - - - insert into s2_metric - - - id, - - - domain_id, - - - name, - - - biz_name, - - - description, - - - status, - - - sensitive_level, - - - type, - - - created_at, - - - created_by, - - - updated_at, - - - updated_by, - - - data_format_type, - - - data_format, - - - type_params, - - - - - #{id,jdbcType=BIGINT}, - - - #{domainId,jdbcType=BIGINT}, - - - #{name,jdbcType=VARCHAR}, - - - #{bizName,jdbcType=VARCHAR}, - - - #{description,jdbcType=VARCHAR}, - - - #{status,jdbcType=INTEGER}, - - - #{sensitiveLevel,jdbcType=INTEGER}, - - - #{type,jdbcType=VARCHAR}, - - - #{createdAt,jdbcType=TIMESTAMP}, - - - #{createdBy,jdbcType=VARCHAR}, - - - #{updatedAt,jdbcType=TIMESTAMP}, - - - #{updatedBy,jdbcType=VARCHAR}, - - - #{dataFormatType,jdbcType=VARCHAR}, - - - #{dataFormat,jdbcType=VARCHAR}, - - - #{typeParams,jdbcType=LONGVARCHAR}, - - - - - - update s2_metric - - - domain_id = #{domainId,jdbcType=BIGINT}, - - - name = #{name,jdbcType=VARCHAR}, - - - biz_name = #{bizName,jdbcType=VARCHAR}, - - - description = #{description,jdbcType=VARCHAR}, - - - status = #{status,jdbcType=INTEGER}, - - - sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, - - - type = #{type,jdbcType=VARCHAR}, - - - created_at = #{createdAt,jdbcType=TIMESTAMP}, - - - created_by = #{createdBy,jdbcType=VARCHAR}, - - - updated_at = #{updatedAt,jdbcType=TIMESTAMP}, - - - updated_by = #{updatedBy,jdbcType=VARCHAR}, - - - data_format_type = #{dataFormatType,jdbcType=VARCHAR}, - - - data_format = #{dataFormat,jdbcType=VARCHAR}, - - - type_params = #{typeParams,jdbcType=LONGVARCHAR}, - - - where id = #{id,jdbcType=BIGINT} - - - update s2_metric - set domain_id = #{domainId,jdbcType=BIGINT}, - name = #{name,jdbcType=VARCHAR}, - biz_name = #{bizName,jdbcType=VARCHAR}, - description = #{description,jdbcType=VARCHAR}, - status = #{status,jdbcType=INTEGER}, - sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, - type = #{type,jdbcType=VARCHAR}, - created_at = #{createdAt,jdbcType=TIMESTAMP}, - created_by = #{createdBy,jdbcType=VARCHAR}, - updated_at = #{updatedAt,jdbcType=TIMESTAMP}, - updated_by = #{updatedBy,jdbcType=VARCHAR}, - data_format_type = #{dataFormatType,jdbcType=VARCHAR}, - data_format = #{dataFormat,jdbcType=VARCHAR}, - type_params = #{typeParams,jdbcType=LONGVARCHAR} - where id = #{id,jdbcType=BIGINT} - - - update s2_metric - set domain_id = #{domainId,jdbcType=BIGINT}, - name = #{name,jdbcType=VARCHAR}, - biz_name = #{bizName,jdbcType=VARCHAR}, - description = #{description,jdbcType=VARCHAR}, - status = #{status,jdbcType=INTEGER}, - sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, - type = #{type,jdbcType=VARCHAR}, - created_at = #{createdAt,jdbcType=TIMESTAMP}, - created_by = #{createdBy,jdbcType=VARCHAR}, - updated_at = #{updatedAt,jdbcType=TIMESTAMP}, - updated_by = #{updatedBy,jdbcType=VARCHAR}, - data_format_type = #{dataFormatType,jdbcType=VARCHAR}, - data_format = #{dataFormat,jdbcType=VARCHAR} - where id = #{id,jdbcType=BIGINT} - + + + + + id, domain_id, name, biz_name, description, status, sensitive_level, type, created_at, + created_by, updated_at, updated_by, data_format_type, data_format, alias + + + type_params + + + + + + delete from s2_metric + where id = #{id,jdbcType=BIGINT} + + + insert into s2_metric (id, domain_id, name, + biz_name, description, status, + sensitive_level, type, created_at, + created_by, updated_at, updated_by, + data_format_type, data_format, alias, + type_params) + values (#{id,jdbcType=BIGINT}, #{domainId,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, + #{bizName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=INTEGER}, + #{sensitiveLevel,jdbcType=INTEGER}, #{type,jdbcType=VARCHAR}, #{createdAt,jdbcType=TIMESTAMP}, + #{createdBy,jdbcType=VARCHAR}, #{updatedAt,jdbcType=TIMESTAMP}, #{updatedBy,jdbcType=VARCHAR}, + #{dataFormatType,jdbcType=VARCHAR}, #{dataFormat,jdbcType=VARCHAR}, #{alias,jdbcType=VARCHAR}, + #{typeParams,jdbcType=LONGVARCHAR}) + + + insert into s2_metric + + + id, + + + domain_id, + + + name, + + + biz_name, + + + description, + + + status, + + + sensitive_level, + + + type, + + + created_at, + + + created_by, + + + updated_at, + + + updated_by, + + + data_format_type, + + + data_format, + + + alias, + + + type_params, + + + + + #{id,jdbcType=BIGINT}, + + + #{domainId,jdbcType=BIGINT}, + + + #{name,jdbcType=VARCHAR}, + + + #{bizName,jdbcType=VARCHAR}, + + + #{description,jdbcType=VARCHAR}, + + + #{status,jdbcType=INTEGER}, + + + #{sensitiveLevel,jdbcType=INTEGER}, + + + #{type,jdbcType=VARCHAR}, + + + #{createdAt,jdbcType=TIMESTAMP}, + + + #{createdBy,jdbcType=VARCHAR}, + + + #{updatedAt,jdbcType=TIMESTAMP}, + + + #{updatedBy,jdbcType=VARCHAR}, + + + #{dataFormatType,jdbcType=VARCHAR}, + + + #{dataFormat,jdbcType=VARCHAR}, + + + #{alias,jdbcType=VARCHAR}, + + + #{typeParams,jdbcType=LONGVARCHAR}, + + + + + + update s2_metric + + + domain_id = #{domainId,jdbcType=BIGINT}, + + + name = #{name,jdbcType=VARCHAR}, + + + biz_name = #{bizName,jdbcType=VARCHAR}, + + + description = #{description,jdbcType=VARCHAR}, + + + status = #{status,jdbcType=INTEGER}, + + + sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, + + + type = #{type,jdbcType=VARCHAR}, + + + created_at = #{createdAt,jdbcType=TIMESTAMP}, + + + created_by = #{createdBy,jdbcType=VARCHAR}, + + + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + + + updated_by = #{updatedBy,jdbcType=VARCHAR}, + + + data_format_type = #{dataFormatType,jdbcType=VARCHAR}, + + + data_format = #{dataFormat,jdbcType=VARCHAR}, + + + alias = #{alias,jdbcType=VARCHAR}, + + + type_params = #{typeParams,jdbcType=LONGVARCHAR}, + + + where id = #{id,jdbcType=BIGINT} + + + update s2_metric + set domain_id = #{domainId,jdbcType=BIGINT}, + name = #{name,jdbcType=VARCHAR}, + biz_name = #{bizName,jdbcType=VARCHAR}, + description = #{description,jdbcType=VARCHAR}, + status = #{status,jdbcType=INTEGER}, + sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, + type = #{type,jdbcType=VARCHAR}, + created_at = #{createdAt,jdbcType=TIMESTAMP}, + created_by = #{createdBy,jdbcType=VARCHAR}, + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + updated_by = #{updatedBy,jdbcType=VARCHAR}, + data_format_type = #{dataFormatType,jdbcType=VARCHAR}, + data_format = #{dataFormat,jdbcType=VARCHAR}, + alias = #{alias,jdbcType=VARCHAR}, + type_params = #{typeParams,jdbcType=LONGVARCHAR} + where id = #{id,jdbcType=BIGINT} + + + update s2_metric + set domain_id = #{domainId,jdbcType=BIGINT}, + name = #{name,jdbcType=VARCHAR}, + biz_name = #{bizName,jdbcType=VARCHAR}, + description = #{description,jdbcType=VARCHAR}, + status = #{status,jdbcType=INTEGER}, + sensitive_level = #{sensitiveLevel,jdbcType=INTEGER}, + type = #{type,jdbcType=VARCHAR}, + created_at = #{createdAt,jdbcType=TIMESTAMP}, + created_by = #{createdBy,jdbcType=VARCHAR}, + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + updated_by = #{updatedBy,jdbcType=VARCHAR}, + data_format_type = #{dataFormatType,jdbcType=VARCHAR}, + data_format = #{dataFormat,jdbcType=VARCHAR}, + alias = #{alias,jdbcType=VARCHAR} + where id = #{id,jdbcType=BIGINT} + \ No newline at end of file diff --git a/semantic/core/src/main/resources/mapper/custom/DateInfoMapper.xml b/semantic/core/src/main/resources/mapper/custom/DateInfoMapper.xml index 467522d96..5df03b47d 100644 --- a/semantic/core/src/main/resources/mapper/custom/DateInfoMapper.xml +++ b/semantic/core/src/main/resources/mapper/custom/DateInfoMapper.xml @@ -32,16 +32,23 @@ diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/ParserServiceImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/ParserServiceImpl.java index cdb124001..9d016d63c 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/ParserServiceImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/ParserServiceImpl.java @@ -12,6 +12,7 @@ import com.tencent.supersonic.semantic.query.domain.parser.dsl.SemanticModel; import java.util.ArrayList; import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -31,7 +32,6 @@ public class ParserServiceImpl implements ParserService { } - @Override public SqlParserResp physicalSql(ParseSqlReq sqlCommend) throws Exception { return parser(sqlCommend); @@ -107,6 +107,9 @@ public class ParserServiceImpl implements ParserService { private String formatWhere(String where) { + if (StringUtils.isEmpty(where)) { + return where; + } return where.replace("\"", "\\\\\""); } } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/QueryServiceImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/QueryServiceImpl.java index 198e889a6..c30c38a7c 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/QueryServiceImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/QueryServiceImpl.java @@ -1,28 +1,31 @@ package com.tencent.supersonic.semantic.query.application; import com.tencent.supersonic.auth.api.authentication.pojo.User; +import com.tencent.supersonic.common.enums.TaskStatusEnum; +import com.tencent.supersonic.common.util.cache.CacheUtils; +import com.tencent.supersonic.common.util.context.ContextUtils; import com.tencent.supersonic.semantic.api.core.pojo.QueryStat; +import com.tencent.supersonic.semantic.api.core.request.DomainSchemaFilterReq; +import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; import com.tencent.supersonic.semantic.api.core.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; import com.tencent.supersonic.semantic.api.query.pojo.Cache; import com.tencent.supersonic.semantic.api.query.request.ItemUseReq; -import com.tencent.supersonic.semantic.api.query.request.MetricReq; import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; -import com.tencent.supersonic.common.enums.TaskStatusEnum; -import com.tencent.supersonic.common.util.cache.CacheUtils; import com.tencent.supersonic.semantic.core.domain.DatabaseService; import com.tencent.supersonic.semantic.query.domain.ParserService; import com.tencent.supersonic.semantic.query.domain.QueryService; +import com.tencent.supersonic.semantic.query.domain.SchemaService; import com.tencent.supersonic.semantic.query.domain.annotation.DataPermission; +import com.tencent.supersonic.semantic.query.domain.utils.QueryReqConverter; import com.tencent.supersonic.semantic.query.domain.utils.QueryStructUtils; import com.tencent.supersonic.semantic.query.domain.utils.StatUtils; - +import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; - import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -37,28 +40,37 @@ public class QueryServiceImpl implements QueryService { private final QueryStructUtils queryStructUtils; private final StatUtils statUtils; private final CacheUtils cacheUtils; + private final QueryReqConverter queryReqConverter; @Value("${query.cache.enable:true}") private Boolean cacheEnable; public QueryServiceImpl(ParserService parserService, - DatabaseService databaseService, - QueryStructUtils queryStructUtils, - StatUtils statUtils, - CacheUtils cacheUtils) { + DatabaseService databaseService, + QueryStructUtils queryStructUtils, + StatUtils statUtils, + CacheUtils cacheUtils, + QueryReqConverter queryReqConverter) { this.parserService = parserService; this.databaseService = databaseService; this.queryStructUtils = queryStructUtils; this.statUtils = statUtils; this.cacheUtils = cacheUtils; + this.queryReqConverter = queryReqConverter; } @Override - public Object queryBySql(QuerySqlReq querySqlCmd) throws Exception { - //TODO QuerySqlCmd---> SqlCommend - MetricReq sqlCommend = new MetricReq(); + public Object queryBySql(QuerySqlReq querySqlCmd, User user) throws Exception { + DomainSchemaFilterReq filter = new DomainSchemaFilterReq(); + List domainIds = new ArrayList<>(); + domainIds.add(querySqlCmd.getDomainId()); + + filter.setDomainIds(domainIds); + SchemaService schemaService = ContextUtils.getBean(SchemaService.class); + List domainSchemas = schemaService.fetchDomainSchema(filter, user); + + SqlParserResp sqlParser = queryReqConverter.convert(querySqlCmd, domainSchemas); - SqlParserResp sqlParser = parserService.physicalSql(sqlCommend); return databaseService.executeSql(sqlParser.getSql(), querySqlCmd.getDomainId()); } @@ -128,5 +140,4 @@ public class QueryServiceImpl implements QueryService { } - } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SchemaServiceImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SchemaServiceImpl.java index 60ab7f9ec..4a82e5b59 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SchemaServiceImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/SchemaServiceImpl.java @@ -38,9 +38,9 @@ public class SchemaServiceImpl implements SchemaService { private final MetricService metricService; public SchemaServiceImpl(QueryService queryService, - DomainService domainService, - DimensionService dimensionService, - MetricService metricService) { + DomainService domainService, + DimensionService dimensionService, + MetricService metricService) { this.queryService = queryService; this.domainService = domainService; this.dimensionService = dimensionService; @@ -52,7 +52,7 @@ public class SchemaServiceImpl implements SchemaService { public List fetchDomainSchema(DomainSchemaFilterReq filter, User user) { List domainSchemaDescList = domainService.fetchDomainSchema(filter, user); List statInfos = queryService.getStatInfo(new ItemUseReq()); - log.info("statInfos:{}", statInfos); + log.debug("statInfos:{}", statInfos); fillCnt(domainSchemaDescList, statInfos); return domainSchemaDescList; @@ -66,7 +66,7 @@ public class SchemaServiceImpl implements SchemaService { itemUseInfo -> itemUseInfo.getType() + AT_SYMBOL + AT_SYMBOL + itemUseInfo.getBizName(), itemUseInfo -> itemUseInfo, (item1, item2) -> item1)); - log.info("typeIdAndStatPair:{}", typeIdAndStatPair); + log.debug("typeIdAndStatPair:{}", typeIdAndStatPair); for (DomainSchemaResp domainSchemaDesc : domainSchemaDescList) { fillDimCnt(domainSchemaDesc, typeIdAndStatPair); fillMetricCnt(domainSchemaDesc, typeIdAndStatPair); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SemanticSchemaManagerImpl.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SemanticSchemaManagerImpl.java index 5585d2678..327ae11bf 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SemanticSchemaManagerImpl.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/application/parser/SemanticSchemaManagerImpl.java @@ -38,18 +38,19 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @Slf4j +@Primary @Service("SemanticSchemaManager") public class SemanticSchemaManagerImpl implements SemanticSchemaManager { - @Autowired - private LoadingCache loadingCache; - private final DatasourceService datasourceService; private final DomainService domainService; + @Autowired + private LoadingCache loadingCache; public SemanticSchemaManagerImpl(DatasourceService datasourceService, @@ -58,62 +59,14 @@ public class SemanticSchemaManagerImpl implements SemanticSchemaManager { this.domainService = domainService; } - - @Override - public SemanticModel reload(String rootPath) { - SemanticModel semanticModel = new SemanticModel(); - semanticModel.setRootPath(rootPath); - Map domainFullPathMap = domainService.getDomainFullPath(); - log.info("domainFullPathMap {}", domainFullPathMap); - Set domainIds = domainFullPathMap.entrySet().stream().filter(e -> e.getValue().startsWith(rootPath)) - .map(e -> e.getKey()).collect(Collectors.toSet()); - if (domainIds.isEmpty()) { - log.error("get domainId empty {}", rootPath); - return semanticModel; - } - Map> dimensionYamlTpls = new HashMap<>(); - List datasourceYamlTpls = new ArrayList<>(); - List metricYamlTpls = new ArrayList<>(); - datasourceService.getModelYamlTplByDomainIds(domainIds, dimensionYamlTpls, datasourceYamlTpls, metricYamlTpls); - if (!datasourceYamlTpls.isEmpty()) { - Map dataSourceMap = datasourceYamlTpls.stream().map(d -> getDatasource(d)) - .collect(Collectors.toMap(DataSource::getName, item -> item)); - semanticModel.setDatasourceMap(dataSourceMap); - } - if (!dimensionYamlTpls.isEmpty()) { - Map> dimensionMap = new HashMap<>(); - for (Map.Entry> entry : dimensionYamlTpls.entrySet()) { - dimensionMap.put(entry.getKey(), getDimensions(entry.getValue())); - } - semanticModel.setDimensionMap(dimensionMap); - } - if (!metricYamlTpls.isEmpty()) { - semanticModel.setMetrics(getMetrics(metricYamlTpls)); - } - return semanticModel; - } - - //private Map semanticSchemaMap = new HashMap<>(); - @Override - public SemanticModel get(String rootPath) throws Exception { - rootPath = formatKey(rootPath); - SemanticModel schema = loadingCache.get(rootPath); - if (schema == null) { - return null; - } - return schema; - } - public static List getMetrics(final List t) { return getMetricsByMetricYamlTpl(t); } - public static List getDimensions(final List t) { return getDimension(t); } - public static DataSource getDatasource(final DatasourceYamlTpl d) { DataSource datasource = new DataSource(); datasource.setSqlQuery(d.getSqlQuery()); @@ -197,7 +150,6 @@ public class SemanticSchemaManagerImpl implements SemanticSchemaManager { return identifies; } - public static void update(SemanticSchema schema, List metric) throws Exception { if (schema != null) { updateMetric(metric, schema.getMetrics()); @@ -273,6 +225,51 @@ public class SemanticSchemaManagerImpl implements SemanticSchemaManager { return key; } + @Override + public SemanticModel reload(String rootPath) { + SemanticModel semanticModel = new SemanticModel(); + semanticModel.setRootPath(rootPath); + Map domainFullPathMap = domainService.getDomainFullPath(); + log.info("domainFullPathMap {}", domainFullPathMap); + Set domainIds = domainFullPathMap.entrySet().stream().filter(e -> e.getValue().startsWith(rootPath)) + .map(e -> e.getKey()).collect(Collectors.toSet()); + if (domainIds.isEmpty()) { + log.error("get domainId empty {}", rootPath); + return semanticModel; + } + Map> dimensionYamlTpls = new HashMap<>(); + List datasourceYamlTpls = new ArrayList<>(); + List metricYamlTpls = new ArrayList<>(); + datasourceService.getModelYamlTplByDomainIds(domainIds, dimensionYamlTpls, datasourceYamlTpls, metricYamlTpls); + if (!datasourceYamlTpls.isEmpty()) { + Map dataSourceMap = datasourceYamlTpls.stream().map(d -> getDatasource(d)) + .collect(Collectors.toMap(DataSource::getName, item -> item)); + semanticModel.setDatasourceMap(dataSourceMap); + } + if (!dimensionYamlTpls.isEmpty()) { + Map> dimensionMap = new HashMap<>(); + for (Map.Entry> entry : dimensionYamlTpls.entrySet()) { + dimensionMap.put(entry.getKey(), getDimensions(entry.getValue())); + } + semanticModel.setDimensionMap(dimensionMap); + } + if (!metricYamlTpls.isEmpty()) { + semanticModel.setMetrics(getMetrics(metricYamlTpls)); + } + return semanticModel; + } + + //private Map semanticSchemaMap = new HashMap<>(); + @Override + public SemanticModel get(String rootPath) throws Exception { + rootPath = formatKey(rootPath); + SemanticModel schema = loadingCache.get(rootPath); + if (schema == null) { + return null; + } + return schema; + } + @Configuration @EnableCaching public class GuavaCacheConfig { diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/QueryService.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/QueryService.java index 57639f440..8415d6940 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/QueryService.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/QueryService.java @@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest; public interface QueryService { - Object queryBySql(QuerySqlReq querySqlCmd) throws Exception; + Object queryBySql(QuerySqlReq querySqlCmd, User user) throws Exception; QueryResultWithSchemaResp queryByStruct(QueryStructReq queryStructCmd, User user) throws Exception; diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/Configuration.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/Configuration.java index 8b42e5ca1..6582a78e2 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/Configuration.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/Configuration.java @@ -27,6 +27,11 @@ public class Configuration { public static RelDataTypeFactory typeFactory = new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT); public static SqlOperatorTable operatorTable = SqlStdOperatorTable.instance(); public static CalciteConnectionConfig config = new CalciteConnectionConfigImpl(configProperties); + public static SqlValidator.Config validatorConfig = SqlValidator.Config.DEFAULT + .withLenientOperatorLookup(config.lenientOperatorLookup()) + .withSqlConformance(SemanticSqlDialect.DEFAULT.getConformance()) + .withDefaultNullCollation(config.defaultNullCollation()) + .withIdentifierExpansion(true); static { configProperties.put(CalciteConnectionProperty.CASE_SENSITIVE.camelName(), Boolean.TRUE.toString()); @@ -34,12 +39,6 @@ public class Configuration { configProperties.put(CalciteConnectionProperty.QUOTED_CASING.camelName(), Casing.TO_LOWER.toString()); } - public static SqlValidator.Config validatorConfig = SqlValidator.Config.DEFAULT - .withLenientOperatorLookup(config.lenientOperatorLookup()) - .withSqlConformance(SemanticSqlDialect.DEFAULT.getConformance()) - .withDefaultNullCollation(config.defaultNullCollation()) - .withIdentifierExpansion(true); - public static SqlParser.Config getParserConfig() { CalciteConnectionConfig config = new CalciteConnectionConfigImpl(configProperties); SqlParser.ConfigBuilder parserConfig = SqlParser.configBuilder(); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/Renderer.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/Renderer.java index 70efc72a7..52f12b384 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/Renderer.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/Renderer.java @@ -25,21 +25,6 @@ public abstract class Renderer { protected TableView tableView = new TableView(); - public void setTable(SqlNode table) { - tableView.setTable(table); - } - - public SqlNode builder() { - return tableView.build(); - } - - public SqlNode builderAs(String alias) throws Exception { - return SemanticNode.buildAs(alias, tableView.build()); - } - - public abstract void render(MetricReq metricCommand, List dataSources, SqlValidatorScope scope, - SemanticSchema schema, boolean nonAgg) throws Exception; - public static Optional getDimensionByName(String name, DataSource datasource) { return datasource.getDimensions().stream().filter(d -> d.getName().equalsIgnoreCase(name)).findFirst(); } @@ -58,7 +43,6 @@ public abstract class Renderer { return datasource.getIdentifiers().stream().filter(i -> i.getName().equalsIgnoreCase(name)).findFirst(); } - public static MetricNode buildMetricNode(String metric, DataSource datasource, SqlValidatorScope scope, SemanticSchema schema, boolean nonAgg, String alias) throws Exception { Optional metricOpt = getMetricByName(metric, schema); @@ -105,4 +89,19 @@ public abstract class Renderer { Set tmp = new HashSet<>(list); return tmp.stream().collect(Collectors.toList()); } + + public void setTable(SqlNode table) { + tableView.setTable(table); + } + + public SqlNode builder() { + return tableView.build(); + } + + public SqlNode builderAs(String alias) throws Exception { + return SemanticNode.buildAs(alias, tableView.build()); + } + + public abstract void render(MetricReq metricCommand, List dataSources, SqlValidatorScope scope, + SemanticSchema schema, boolean nonAgg) throws Exception; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/AggFunctionNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/AggFunctionNode.java index ae1007be3..5b52f1f95 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/AggFunctionNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/AggFunctionNode.java @@ -5,6 +5,13 @@ import org.apache.calcite.sql.validate.SqlValidatorScope; public class AggFunctionNode extends SemanticNode { + public static SqlNode build(String agg, String name, SqlValidatorScope scope) throws Exception { + if (AggFunction.COUNT_DISTINCT.name().equalsIgnoreCase(agg)) { + return parse(AggFunction.COUNT.name() + " ( " + AggFunction.DISTINCT.name() + " " + name + " ) ", scope); + } + return parse(agg + " ( " + name + " ) ", scope); + } + public static enum AggFunction { AVG, COUNT_DISTINCT, @@ -15,12 +22,5 @@ public class AggFunctionNode extends SemanticNode { DISTINCT } - public static SqlNode build(String agg, String name, SqlValidatorScope scope) throws Exception { - if (AggFunction.COUNT_DISTINCT.name().equalsIgnoreCase(agg)) { - return parse(AggFunction.COUNT.name() + " ( " + AggFunction.DISTINCT.name() + " " + name + " ) ", scope); - } - return parse(agg + " ( " + name + " ) ", scope); - } - } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/SemanticNode.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/SemanticNode.java index 51fcc05d4..258105a46 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/SemanticNode.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/node/SemanticNode.java @@ -24,10 +24,6 @@ import org.apache.commons.lang3.StringUtils; public abstract class SemanticNode { - public void accept(Optimization optimization) { - optimization.visit(this); - } - public static SqlNode parse(String expression, SqlValidatorScope scope) throws Exception { SqlParser sqlParser = SqlParser.create(expression, Configuration.getParserConfig()); SqlNode sqlNode = sqlParser.parseExpression(); @@ -77,7 +73,6 @@ public abstract class SemanticNode { return sqlNode instanceof SqlIdentifier; } - public static SqlNode getAlias(SqlNode sqlNode, SqlValidatorScope scope) throws Exception { if (sqlNode instanceof SqlBasicCall) { SqlBasicCall sqlBasicCall = (SqlBasicCall) sqlNode; @@ -117,5 +112,9 @@ public abstract class SemanticNode { return sqlNode; } + public void accept(Optimization optimization) { + optimization.visit(this); + } + } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/JoinRender.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/JoinRender.java index 15bec0241..26ac16d66 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/JoinRender.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/JoinRender.java @@ -90,7 +90,7 @@ public class JoinRender extends Renderer { fieldWhere.add(identify.getName()); } } - TableView tableView = SourceRender.renderOne(false, "", fieldWhere, queryMetrics, queryDimension, + TableView tableView = SourceRender.renderOne("", fieldWhere, queryMetrics, queryDimension, metricCommand.getWhere(), dataSources.get(i), scope, schema, true); log.info("tableView {}", tableView.getTable().toString()); String alias = Constants.JOIN_TABLE_PREFIX + dataSource.getName(); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/SourceRender.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/SourceRender.java index b53579cb1..eaaffbfa1 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/SourceRender.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/convertor/sql/render/SourceRender.java @@ -33,30 +33,7 @@ import org.springframework.util.CollectionUtils; @Slf4j public class SourceRender extends Renderer { - public void render(MetricReq metricCommand, List dataSources, SqlValidatorScope scope, - SemanticSchema schema, boolean nonAgg) throws Exception { - String queryWhere = metricCommand.getWhere(); - Set whereFields = new HashSet<>(); - List fieldWhere = new ArrayList<>(); - if (queryWhere != null && !queryWhere.isEmpty()) { - SqlNode sqlNode = SemanticNode.parse(queryWhere, scope); - FilterNode.getFilterField(sqlNode, whereFields); - fieldWhere = whereFields.stream().collect(Collectors.toList()); - } - if (dataSources.size() == 1) { - DataSource dataSource = dataSources.get(0); - super.tableView = renderOne(false, "", fieldWhere, metricCommand.getMetrics(), - metricCommand.getDimensions(), - metricCommand.getWhere(), dataSource, scope, schema, nonAgg); - return; - } - JoinRender joinRender = new JoinRender(); - joinRender.render(metricCommand, dataSources, scope, schema, nonAgg); - super.tableView = joinRender.getTableView(); - } - - - public static TableView renderOne(boolean addWhere, String alias, List fieldWhere, + public static TableView renderOne(String alias, List fieldWhere, List reqMetrics, List reqDimensions, String queryWhere, DataSource datasource, SqlValidatorScope scope, SemanticSchema schema, boolean nonAgg) throws Exception { @@ -65,10 +42,10 @@ public class SourceRender extends Renderer { List queryMetrics = new ArrayList<>(reqMetrics); List queryDimensions = new ArrayList<>(reqDimensions); if (!fieldWhere.isEmpty()) { - SqlNode sqlNode = SemanticNode.parse(queryWhere, scope); - if (addWhere) { - output.getFilter().add(sqlNode); - } +// SqlNode sqlNode = SemanticNode.parse(queryWhere, scope); +// if (addWhere) { +// output.getFilter().add(sqlNode); +// } Set dimensions = new HashSet<>(); Set metrics = new HashSet<>(); whereDimMetric(fieldWhere, queryMetrics, queryDimensions, datasource, schema, dimensions, metrics); @@ -104,7 +81,6 @@ public class SourceRender extends Renderer { return output; } - private static void buildDimension(String alias, String dimension, DataSource datasource, SemanticSchema schema, boolean nonAgg, TableView dataSet, TableView output, SqlValidatorScope scope) throws Exception { List dimensionList = schema.getDimension().get(datasource.getName()); @@ -160,7 +136,6 @@ public class SourceRender extends Renderer { } } - private static boolean isWhereHasMetric(List fields, DataSource datasource) { Long metricNum = datasource.getMeasures().stream().filter(m -> fields.contains(m.getName().toLowerCase())) .count(); @@ -227,7 +202,6 @@ public class SourceRender extends Renderer { //getWhere(outputSet,fields,queryMetrics,queryDimensions,datasource,scope,schema); } - public static void whereDimMetric(List fields, List queryMetrics, List queryDimensions, DataSource datasource, SemanticSchema schema, Set dimensions, Set metrics) { @@ -291,7 +265,6 @@ public class SourceRender extends Renderer { return false; } - private static void expandWhere(MetricReq metricCommand, TableView tableView, SqlValidatorScope scope) throws Exception { if (metricCommand.getWhere() != null && !metricCommand.getWhere().isEmpty()) { @@ -303,5 +276,27 @@ public class SourceRender extends Renderer { } } + public void render(MetricReq metricCommand, List dataSources, SqlValidatorScope scope, + SemanticSchema schema, boolean nonAgg) throws Exception { + String queryWhere = metricCommand.getWhere(); + Set whereFields = new HashSet<>(); + List fieldWhere = new ArrayList<>(); + if (queryWhere != null && !queryWhere.isEmpty()) { + SqlNode sqlNode = SemanticNode.parse(queryWhere, scope); + FilterNode.getFilterField(sqlNode, whereFields); + fieldWhere = whereFields.stream().collect(Collectors.toList()); + } + if (dataSources.size() == 1) { + DataSource dataSource = dataSources.get(0); + super.tableView = renderOne("", fieldWhere, metricCommand.getMetrics(), + metricCommand.getDimensions(), + metricCommand.getWhere(), dataSource, scope, schema, nonAgg); + return; + } + JoinRender joinRender = new JoinRender(); + joinRender.render(metricCommand, dataSources, scope, schema, nonAgg); + super.tableView = joinRender.getTableView(); + } + } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Dimension.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Dimension.java index 49d553733..a725237a0 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Dimension.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Dimension.java @@ -9,18 +9,13 @@ import lombok.Data; public class Dimension implements SemanticItem { String name; + private String owners; + private String type; + private String expr; + private DimensionTimeTypeParams dimensionTimeTypeParams; @Override public String getName() { return name; } - - - private String owners; - - private String type; - - private String expr; - - private DimensionTimeTypeParams dimensionTimeTypeParams; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Metric.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Metric.java index 9ed6c2f2c..a45d5e2e3 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Metric.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/Metric.java @@ -10,16 +10,12 @@ import lombok.Data; public class Metric implements SemanticItem { private String name; + private List owners; + private String type; + private MetricTypeParams metricTypeParams; @Override public String getName() { return name; } - - - private List owners; - - private String type; - - private MetricTypeParams metricTypeParams; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/SemanticModel.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/SemanticModel.java index e1f9f71cc..cfa886bf7 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/SemanticModel.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/dsl/SemanticModel.java @@ -8,6 +8,7 @@ import lombok.Data; @Data public class SemanticModel { + private String rootPath; private List metrics = new ArrayList<>(); private Map datasourceMap = new HashMap<>(); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/DataSourceTable.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/DataSourceTable.java index b22d87948..f7c070b6e 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/DataSourceTable.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/DataSourceTable.java @@ -39,11 +39,14 @@ public class DataSourceTable extends AbstractTable implements ScannableTable, Tr this.statistic = statistic; } + public static Builder newBuilder(String tableName) { + return new Builder(tableName); + } + public String getTableName() { return tableName; } - @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) { if (rowType == null) { @@ -71,11 +74,6 @@ public class DataSourceTable extends AbstractTable implements ScannableTable, Tr throw new UnsupportedOperationException("Not implemented"); } - public static Builder newBuilder(String tableName) { - return new Builder(tableName); - } - - public RelNode toRel(RelOptTable.ToRelContext toRelContext, RelOptTable relOptTable) { List hint = new ArrayList<>(); return new LogicalTableScan(toRelContext.getCluster(), toRelContext.getCluster().traitSet(), hint, relOptTable); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSchema.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSchema.java index 441f3c880..df6c79a1a 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSchema.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSchema.java @@ -26,6 +26,10 @@ public class SemanticSchema extends AbstractSchema { this.tableMap = tableMap; } + public static Builder newBuilder(String rootPath) { + return new Builder(rootPath); + } + public String getRootPath() { return rootPath; } @@ -40,27 +44,22 @@ public class SemanticSchema extends AbstractSchema { return this; } - public static Builder newBuilder(String rootPath) { - return new Builder(rootPath); + public Map getDatasource() { + return semanticModel.getDatasourceMap(); } - public void setDatasource(Map datasource) { semanticModel.setDatasourceMap(datasource); } - public void setDimension(Map> dimensions) { - semanticModel.setDimensionMap(dimensions); - } - - public Map getDatasource() { - return semanticModel.getDatasourceMap(); - } - public Map> getDimension() { return semanticModel.getDimensionMap(); } + public void setDimension(Map> dimensions) { + semanticModel.setDimensionMap(dimensions); + } + public List getMetrics() { return semanticModel.getMetrics(); } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSqlDialect.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSqlDialect.java index 7a9cd6d40..669fb187e 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSqlDialect.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/parser/schema/SemanticSqlDialect.java @@ -12,7 +12,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class SemanticSqlDialect extends SqlDialect { - private static final SqlConformance tagTdwSqlConformance = new SemanticSqlConformance(); public static final Context DEFAULT_CONTEXT = SqlDialect.EMPTY_CONTEXT .withDatabaseProduct(DatabaseProduct.BIG_QUERY) .withLiteralQuoteString("'") @@ -22,13 +21,37 @@ public class SemanticSqlDialect extends SqlDialect { .withUnquotedCasing(Casing.UNCHANGED) .withQuotedCasing(Casing.UNCHANGED) .withCaseSensitive(false); - public static final SqlDialect DEFAULT = new SemanticSqlDialect(DEFAULT_CONTEXT); + private static final SqlConformance tagTdwSqlConformance = new SemanticSqlConformance(); public SemanticSqlDialect(Context context) { super(context); } + public static void unparseFetchUsingAnsi(SqlWriter writer, @Nullable SqlNode offset, @Nullable SqlNode fetch) { + Preconditions.checkArgument(fetch != null || offset != null); + SqlWriter.Frame fetchFrame; + writer.newlineAndIndent(); + fetchFrame = writer.startList(SqlWriter.FrameTypeEnum.OFFSET); + writer.keyword("LIMIT"); + if (offset != null) { + //writer.keyword("OFFSET"); + offset.unparse(writer, -1, -1); + //writer.keyword("ROWS"); + } + + if (fetch != null) { + //writer.newlineAndIndent(); + //fetchFrame = writer.startList(SqlWriter.FrameTypeEnum.FETCH); + writer.keyword(","); + //writer.keyword("NEXT"); + fetch.unparse(writer, -1, -1); + } + + writer.endList(fetchFrame); + + } + @Override public void quoteStringLiteralUnicode(StringBuilder buf, String val) { buf.append("'"); @@ -36,7 +59,6 @@ public class SemanticSqlDialect extends SqlDialect { buf.append("'"); } - @Override public void quoteStringLiteral(StringBuilder buf, String charsetName, String val) { buf.append(literalQuoteString); @@ -70,28 +92,4 @@ public class SemanticSqlDialect extends SqlDialect { public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, @Nullable SqlNode fetch) { unparseFetchUsingAnsi(writer, offset, fetch); } - - public static void unparseFetchUsingAnsi(SqlWriter writer, @Nullable SqlNode offset, @Nullable SqlNode fetch) { - Preconditions.checkArgument(fetch != null || offset != null); - SqlWriter.Frame fetchFrame; - writer.newlineAndIndent(); - fetchFrame = writer.startList(SqlWriter.FrameTypeEnum.OFFSET); - writer.keyword("LIMIT"); - if (offset != null) { - //writer.keyword("OFFSET"); - offset.unparse(writer, -1, -1); - //writer.keyword("ROWS"); - } - - if (fetch != null) { - //writer.newlineAndIndent(); - //fetchFrame = writer.startList(SqlWriter.FrameTypeEnum.FETCH); - writer.keyword(","); - //writer.keyword("NEXT"); - fetch.unparse(writer, -1, -1); - } - - writer.endList(fetchFrame); - - } } \ No newline at end of file diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/ParserSvrResponse.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/ParserSvrResponse.java index a187e8f2b..70ba1ca3a 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/ParserSvrResponse.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/pojo/ParserSvrResponse.java @@ -10,22 +10,22 @@ public class ParserSvrResponse { return code; } - public String getMsg() { - return msg; - } - - public T getData() { - return data; - } - public void setCode(String code) { this.code = code; } + public String getMsg() { + return msg; + } + public void setMsg(String msg) { this.msg = msg; } + public T getData() { + return data; + } + public void setData(T data) { this.data = data; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DataPermissionAOP.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DataPermissionAOP.java index a46079790..1dc02c8b8 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DataPermissionAOP.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DataPermissionAOP.java @@ -57,26 +57,20 @@ import org.springframework.util.CollectionUtils; @Slf4j public class DataPermissionAOP { - @Autowired - private QueryStructUtils queryStructUtils; - - @Autowired - private AuthService authService; - - @Autowired - private DimensionService dimensionService; - - @Autowired - private MetricService metricService; - - @Autowired - private DomainService domainService; - - @Value("${permission.data.enable:true}") - private Boolean permissionDataEnable; - private static final ObjectMapper MAPPER = new ObjectMapper().setDateFormat( new SimpleDateFormat(Constants.DAY_FORMAT)); + @Autowired + private QueryStructUtils queryStructUtils; + @Autowired + private AuthService authService; + @Autowired + private DimensionService dimensionService; + @Autowired + private MetricService metricService; + @Autowired + private DomainService domainService; + @Value("${permission.data.enable:true}") + private Boolean permissionDataEnable; @Pointcut("@annotation(com.tencent.supersonic.semantic.query.domain.annotation.DataPermission)") public void dataPermissionAOP() { @@ -179,7 +173,7 @@ public class DataPermissionAOP { } private void addPromptInfoInfo(Long domainId, QueryResultWithSchemaResp queryResultWithColumns, - AuthorizedResourceResp authorizedResource) { + AuthorizedResourceResp authorizedResource) { List filters = authorizedResource.getFilters(); if (!CollectionUtils.isEmpty(filters)) { log.debug("dimensionFilters:{}", filters); @@ -258,7 +252,7 @@ public class DataPermissionAOP { } private AuthorizedResourceResp getAuthorizedResource(User user, HttpServletRequest request, Long domainId, - Set sensitiveResReq) { + Set sensitiveResReq) { List resourceReqList = new ArrayList<>(); sensitiveResReq.stream().forEach(res -> resourceReqList.add(new AuthRes(domainId.toString(), res))); QueryAuthResReq queryAuthResReq = new QueryAuthResReq(); @@ -375,7 +369,7 @@ public class DataPermissionAOP { } private void doFilterCheckLogic(QueryStructReq queryStructCmd, Set resAuthName, - Set sensitiveResReq) { + Set sensitiveResReq) { Set resFilterSet = queryStructUtils.getFilterResNameEnExceptInternalCol(queryStructCmd); Set need2Apply = resFilterSet.stream() .filter(res -> !resAuthName.contains(res) && sensitiveResReq.contains(res)).collect(Collectors.toSet()); @@ -405,7 +399,7 @@ public class DataPermissionAOP { private AuthorizedResourceResp fetchAuthRes(HttpServletRequest request, QueryAuthResReq queryAuthResReq) { log.info("Authorization:{}", request.getHeader("Authorization")); log.info("queryAuthResReq:{}", queryAuthResReq); - return authService.queryAuthorizedResources(request, queryAuthResReq); + return authService.queryAuthorizedResources(queryAuthResReq, request); } } \ No newline at end of file diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DateUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DateUtils.java index f9bfc84e1..5030bba88 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DateUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/DateUtils.java @@ -1,14 +1,16 @@ -package com.tencent.supersonic.domain.semantic.query.domain.utils; +package com.tencent.supersonic.semantic.query.domain.utils; import static com.tencent.supersonic.common.constant.Constants.APOSTROPHE; import static com.tencent.supersonic.common.constant.Constants.COMMA; import static com.tencent.supersonic.common.constant.Constants.DAY; import static com.tencent.supersonic.common.constant.Constants.DAY_FORMAT; import static com.tencent.supersonic.common.constant.Constants.MONTH; +import static com.tencent.supersonic.common.constant.Constants.MONTH_FORMAT; +import static com.tencent.supersonic.common.constant.Constants.WEEK; import com.google.common.base.Strings; -import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; import com.tencent.supersonic.common.pojo.DateConf; +import com.tencent.supersonic.semantic.api.core.response.ItemDateResp; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; @@ -29,6 +31,10 @@ public class DateUtils { @Value("${query.parameter.sys.date:sys_imp_date}") private String sysDateCol; + @Value("${query.parameter.sys.month:sys_imp_month}") + private String sysDateMonthCol; + @Value("${query.parameter.sys.month:sys_imp_week}") + private String sysDateWeekCol; public Boolean recentMode(DateConf dateInfo) { if (Objects.nonNull(dateInfo) && DateConf.DateMode.RECENT_UNITS == dateInfo.getDateMode() @@ -125,6 +131,29 @@ public class DateUtils { return String.format("(%s >= '%s' and %s <= '%s')", sysDateCol, start, sysDateCol, dateDate.getEndDate()); } + public String recentMonthStr(ItemDateResp dateDate, DateConf dateInfo) { + String dateFormatStr = MONTH_FORMAT; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormatStr); + LocalDate end = LocalDate.parse(dateDate.getEndDate(), formatter); + String endStr = end.format(formatter); + Integer unit = dateInfo.getUnit() - 1; + String start = end.minusMonths(unit).format(formatter); + return String.format("(%s >= '%s' and %s <= '%s')", sysDateMonthCol, start, sysDateMonthCol, endStr); + } + + public String recentWeekStr(ItemDateResp dateDate, DateConf dateInfo) { + String dateFormatStr = dateDate.getDateFormat(); + if (Strings.isNullOrEmpty(dateFormatStr)) { + dateFormatStr = DAY_FORMAT; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormatStr); + LocalDate end = LocalDate.parse(dateDate.getEndDate(), formatter); + Integer unit = dateInfo.getUnit() - 1; + String start = end.minusDays(unit * 7).format(formatter); + return String.format("(%s >= '%s' and %s <= '%s')", sysDateWeekCol, start, sysDateWeekCol, + dateDate.getEndDate()); + } + private Long getInterval(String startDate, String endDate, String dateFormat, ChronoUnit chronoUnit) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat); try { @@ -142,6 +171,12 @@ public class DateUtils { if (DAY.equalsIgnoreCase(dateInfo.getPeriod())) { return recentDayStr(dateDate, dateInfo); } + if (MONTH.equalsIgnoreCase(dateInfo.getPeriod())) { + return recentMonthStr(dateDate, dateInfo); + } + if (WEEK.equalsIgnoreCase(dateInfo.getPeriod())) { + return recentWeekStr(dateDate, dateInfo); + } return ""; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/ParserCommandConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/ParserCommandConverter.java index a117ee86e..75e166d9c 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/ParserCommandConverter.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/ParserCommandConverter.java @@ -30,12 +30,11 @@ public class ParserCommandConverter { private final ParserService parserService; private final DomainService domainService; private final CalculateConverterAgg calculateCoverterAgg; + private final DimensionService dimensionService; + private final QueryStructUtils queryStructUtils; @Value("${internal.metric.cnt.suffix:internal_cnt}") private String internalMetricNameSuffix; - private final DimensionService dimensionService; - private List calculateCoverters = new LinkedList<>(); - private final QueryStructUtils queryStructUtils; public ParserCommandConverter(ParserService parserService, DomainService domainService, @@ -78,11 +77,14 @@ public class ParserCommandConverter { sqlCommend.setLimit(queryStructCmd.getLimit()); String rootPath = domainService.getDomainFullPath(queryStructCmd.getDomainId()); sqlCommend.setRootPath(rootPath); + + // todo tmp delete // support detail query if (queryStructCmd.getNativeQuery() && CollectionUtils.isEmpty(sqlCommend.getMetrics())) { String internalMetricName = generateInternalMetricName(queryStructCmd); sqlCommend.getMetrics().add(internalMetricName); } + return sqlCommend; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryReqConverter.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryReqConverter.java new file mode 100644 index 000000000..101c278d4 --- /dev/null +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryReqConverter.java @@ -0,0 +1,72 @@ +package com.tencent.supersonic.semantic.query.domain.utils; + +import com.tencent.supersonic.common.util.calcite.SqlParseUtils; +import com.tencent.supersonic.common.util.calcite.SqlParserInfo; +import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp; +import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; +import com.tencent.supersonic.semantic.api.query.pojo.MetricTable; +import com.tencent.supersonic.semantic.api.query.request.ParseSqlReq; +import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; +import com.tencent.supersonic.semantic.core.domain.DomainService; +import com.tencent.supersonic.semantic.query.domain.ParserService; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +@Component +public class QueryReqConverter { + + @Autowired + private DomainService domainService; + + @Autowired + private ParserService parserService; + + public SqlParserResp convert(QuerySqlReq databaseReq, List domainSchemas) throws Exception { + + List tables = new ArrayList<>(); + MetricTable metricTable = new MetricTable(); + String sql = databaseReq.getSql(); + SqlParserInfo sqlParseInfo = SqlParseUtils.getSqlParseInfo(sql); + + List allFields = sqlParseInfo.getAllFields(); + + if (CollectionUtils.isEmpty(domainSchemas)) { + return new SqlParserResp(); + } + + Set dimensions = domainSchemas.get(0).getDimensions().stream() + .map(entry -> entry.getBizName().toLowerCase()) + .collect(Collectors.toSet()); + dimensions.addAll(QueryStructUtils.internalCols); + + Set metrics = domainSchemas.get(0).getMetrics().stream().map(entry -> entry.getBizName().toLowerCase()) + .collect(Collectors.toSet()); + + metricTable.setMetrics(allFields.stream().filter(entry -> metrics.contains(entry.toLowerCase())) + .map(entry -> entry.toLowerCase()).collect(Collectors.toList())); + Set collect = allFields.stream().filter(entry -> dimensions.contains(entry.toLowerCase())) + .map(entry -> entry.toLowerCase()).collect(Collectors.toSet()); + for (String internalCol : QueryStructUtils.internalCols) { + if (sql.contains(internalCol)) { + collect.add(internalCol); + } + } + metricTable.setDimensions(new ArrayList<>(collect)); + metricTable.setAlias(sqlParseInfo.getTableName().toLowerCase()); + tables.add(metricTable); + + ParseSqlReq result = new ParseSqlReq(); + BeanUtils.copyProperties(databaseReq, result); + result.setRootPath(domainService.getDomainFullPath(databaseReq.getDomainId())); + result.setTables(tables); + + return parserService.physicalSql(result); + } + +} diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryStructUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryStructUtils.java index 789cb07ca..6b8c76f64 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryStructUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryStructUtils.java @@ -42,6 +42,8 @@ import org.springframework.util.CollectionUtils; @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 DatabaseService databaseService; private final QueryUtils queryUtils; private final ParserService parserService; @@ -50,16 +52,12 @@ public class QueryStructUtils { private final DimensionService dimensionService; private final MetricService metricService; private final DatasourceService datasourceService; - private final com.tencent.supersonic.domain.semantic.query.domain.utils.DateUtils dateUtils; + private final DateUtils dateUtils; private final SqlFilterUtils sqlFilterUtils; private final CacheUtils cacheUtils; - @Value("${query.cache.enable:true}") private Boolean cacheEnable; - Set internalCols = new HashSet<>( - Arrays.asList("dayno", "plat_sys_var", "sys_imp_date", "sys_imp_week", "sys_imp_month")); - public QueryStructUtils(DatabaseService databaseService, QueryUtils queryUtils, ParserService parserService, @@ -68,7 +66,7 @@ public class QueryStructUtils { DimensionService dimensionService, MetricService metricService, DatasourceService datasourceService, - com.tencent.supersonic.domain.semantic.query.domain.utils.DateUtils dateUtils, + DateUtils dateUtils, SqlFilterUtils sqlFilterUtils, CacheUtils cacheUtils) { this.databaseService = databaseService; @@ -118,7 +116,10 @@ public class QueryStructUtils { queryUtils.checkSqlParse(sqlParser); log.info("sqlParser:{}", sqlParser); - queryUtils.handleDetail(queryStructCmd, sqlParser); + // todo tmp delete + //queryUtils.handleDetail(queryStructCmd, sqlParser); + queryUtils.handleNoMetric(queryStructCmd, sqlParser); + QueryResultWithSchemaResp queryResultWithColumns = databaseService.queryWithColumns(sqlParser); queryUtils.fillItemNameInfo(queryResultWithColumns, queryStructCmd.getDomainId()); diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryUtils.java index 3f46d14ae..a9a851ec0 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/QueryUtils.java @@ -42,6 +42,23 @@ import org.springframework.util.CollectionUtils; public class QueryUtils { private final Set patterns = new HashSet<>(); + private final MetricService metricService; + private final DimensionService dimensionService; + private final ParserCommandConverter parserCommandConverter; + public QueryUtils(MetricService metricService, + DimensionService dimensionService, + @Lazy ParserCommandConverter parserCommandConverter) { + this.metricService = metricService; + this.dimensionService = dimensionService; + this.parserCommandConverter = parserCommandConverter; + } + + private static void addSysTimeDimension(Map namePair, Map nameTypePair) { + for (TimeDimensionEnum timeDimensionEnum : TimeDimensionEnum.values()) { + namePair.put(timeDimensionEnum.getName(), "date"); + nameTypePair.put(timeDimensionEnum.getName(), "DATE"); + } + } @PostConstruct public void fillPattern() { @@ -52,19 +69,6 @@ public class QueryUtils { } } - private final MetricService metricService; - private final DimensionService dimensionService; - private final ParserCommandConverter parserCommandConverter; - - public QueryUtils(MetricService metricService, - DimensionService dimensionService, - @Lazy ParserCommandConverter parserCommandConverter) { - this.metricService = metricService; - this.dimensionService = dimensionService; - this.parserCommandConverter = parserCommandConverter; - } - - public void checkSqlParse(SqlParserResp sqlParser) { if (Strings.isNullOrEmpty(sqlParser.getSql()) || Strings.isNullOrEmpty(sqlParser.getSourceId())) { throw new RuntimeException("parse Exception: " + sqlParser.getErrMsg()); @@ -76,6 +80,23 @@ public class QueryUtils { queryStructCmd.getMetrics()); } + public SqlParserResp handleNoMetric(QueryStructReq queryStructCmd, SqlParserResp sqlParser) { + String sqlRaw = sqlParser.getSql().trim(); + if (Strings.isNullOrEmpty(sqlRaw)) { + throw new RuntimeException("sql is empty or null"); + } + log.info("before handleNoMetric, sql:{}", sqlRaw); + if (isDetailQuery(queryStructCmd)) { + if (queryStructCmd.getMetrics().size() == 0) { + String sql = String.format("select %s from ( %s ) src_no_metric", + queryStructCmd.getGroups().stream().collect(Collectors.joining(",")), sqlRaw); + sqlParser.setSql(sql); + } + } + log.info("after handleNoMetric, sql:{}", sqlParser.getSql()); + return sqlParser; + } + public SqlParserResp handleDetail(QueryStructReq queryStructCmd, SqlParserResp sqlParser) { String sqlRaw = sqlParser.getSql().trim(); if (Strings.isNullOrEmpty(sqlRaw)) { @@ -223,11 +244,4 @@ public class QueryUtils { } return map; } - - private static void addSysTimeDimension(Map namePair, Map nameTypePair) { - for (TimeDimensionEnum timeDimensionEnum : TimeDimensionEnum.values()) { - namePair.put(timeDimensionEnum.getName(), "date"); - nameTypePair.put(timeDimensionEnum.getName(), "DATE"); - } - } } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlGenerateUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlGenerateUtils.java index 3e72267d6..7dff2bc09 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlGenerateUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlGenerateUtils.java @@ -13,13 +13,6 @@ import org.springframework.util.CollectionUtils; @Slf4j public class SqlGenerateUtils { - public String getLimit(QueryStructReq queryStructCmd) { - if (queryStructCmd.getLimit() > 0) { - return " limit " + String.valueOf(queryStructCmd.getLimit()); - } - return ""; - } - public static String getUnionSelect(QueryStructReq queryStructCmd) { StringBuilder sb = new StringBuilder(); int locate = 0; @@ -41,6 +34,12 @@ public class SqlGenerateUtils { return selectSql; } + public String getLimit(QueryStructReq queryStructCmd) { + if (queryStructCmd.getLimit() > 0) { + return " limit " + String.valueOf(queryStructCmd.getLimit()); + } + return ""; + } public String getSelect(QueryStructReq queryStructCmd) { String aggStr = queryStructCmd.getAggregators().stream().map(this::getSelectField) diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlParserUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlParserUtils.java index f70af9dac..19444d578 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlParserUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/SqlParserUtils.java @@ -22,7 +22,7 @@ public class SqlParserUtils { public SqlParserResp getSqlParserWithoutCache(QueryStructReq queryStructCmd) throws Exception { log.info("stat getSqlParser without cache"); - multiSourceJoinUtils.buildJoinPrefix(queryStructCmd); + //multiSourceJoinUtils.buildJoinPrefix(queryStructCmd); SqlParserResp sqlParser = parserCommandConverter.getSqlParser(queryStructCmd); return sqlParser; } diff --git a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/StatUtils.java b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/StatUtils.java index e1aaac99f..88fd39543 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/StatUtils.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/domain/utils/StatUtils.java @@ -25,12 +25,11 @@ import org.springframework.stereotype.Component; @Slf4j public class StatUtils { + private static final TransmittableThreadLocal STATS = new TransmittableThreadLocal<>(); private final StatRepository statRepository; private final SqlFilterUtils sqlFilterUtils; private final ObjectMapper objectMapper = new ObjectMapper(); - private static final TransmittableThreadLocal STATS = new TransmittableThreadLocal<>(); - public StatUtils(StatRepository statRepository, SqlFilterUtils sqlFilterUtils) { 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 d172e0456..080bdf4de 100644 --- a/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/QueryController.java +++ b/semantic/query/src/main/java/com/tencent/supersonic/semantic/query/rest/QueryController.java @@ -2,15 +2,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.query.request.ItemUseReq; -import com.tencent.supersonic.semantic.api.query.request.QueryMultiStructReq; -import com.tencent.supersonic.semantic.api.query.request.QuerySqlReq; -import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; +import com.tencent.supersonic.semantic.api.core.response.SqlParserResp; +import com.tencent.supersonic.semantic.api.query.request.*; import com.tencent.supersonic.semantic.api.query.response.ItemUseResp; +import com.tencent.supersonic.semantic.query.domain.ParserService; import com.tencent.supersonic.semantic.query.domain.QueryService; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -20,17 +20,25 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/semantic/query") +@Slf4j public class QueryController { @Autowired private QueryService queryService; + @Autowired + private ParserService parserService; + @PostMapping("/sql") - public Object queryBySql(@RequestBody QuerySqlReq querySqlReq) throws Exception { - return queryService.queryBySql(querySqlReq); + public Object queryBySql(@RequestBody QuerySqlReq querySqlReq, + HttpServletRequest request, + HttpServletResponse response) throws Exception { + User user = UserHolder.findUser(request, response); + Object queryBySql = queryService.queryBySql(querySqlReq, user); + log.info("queryBySql:{},queryBySql"); + return queryBySql; } - @PostMapping("/struct") public Object queryByStruct(@RequestBody QueryStructReq queryStructReq, HttpServletRequest request, @@ -39,6 +47,14 @@ public class QueryController { return queryService.queryByStruct(queryStructReq, user, request); } + @PostMapping("/struct/parse") + public SqlParserResp parseByStruct(@RequestBody ParseSqlReq parseSqlReq, + HttpServletRequest request, + HttpServletResponse response) throws Exception { + User user = UserHolder.findUser(request, response); + return parserService.physicalSql(parseSqlReq); + } + /** * queryByMultiStruct */ @@ -61,5 +77,4 @@ public class QueryController { return queryService.getStatInfo(itemUseReq); } - } 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 535778426..58f059947 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 @@ -32,8 +32,8 @@ public class SchemaController { @PostMapping public List fetchDomainSchema(@RequestBody DomainSchemaFilterReq filter, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return schemaService.fetchDomainSchema(filter, user); } @@ -45,23 +45,23 @@ public class SchemaController { */ @GetMapping("/domain/list") public List getDomainList(HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return schemaService.getDomainListForAdmin(user); } @PostMapping("/dimension/page") public PageInfo queryDimension(@RequestBody PageDimensionReq pageDimensionCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return schemaService.queryDimension(pageDimensionCmd, user); } @PostMapping("/metric/page") public PageInfo queryMetric(@RequestBody PageMetricReq pageMetricCmd, - HttpServletRequest request, - HttpServletResponse response) { + HttpServletRequest request, + HttpServletResponse response) { User user = UserHolder.findUser(request, response); return schemaService.queryMetric(pageMetricCmd, user); } diff --git a/semantic/query/src/test/java/com/tencent/supersonic/semantic/query/domain/parser/SemanticParserServiceTest.java b/semantic/query/src/test/java/com/tencent/supersonic/semantic/query/domain/parser/SemanticParserServiceTest.java index 2cb63855a..eb5fa8bd2 100644 --- a/semantic/query/src/test/java/com/tencent/supersonic/semantic/query/domain/parser/SemanticParserServiceTest.java +++ b/semantic/query/src/test/java/com/tencent/supersonic/semantic/query/domain/parser/SemanticParserServiceTest.java @@ -47,6 +47,66 @@ class SemanticParserServiceTest { return sqlParser; } + private static void addDepartment(SemanticSchema semanticSchema) { + DatasourceYamlTpl datasource = new DatasourceYamlTpl(); + datasource.setName("user_department"); + datasource.setSourceId(1L); + datasource.setSqlQuery("SELECT imp_date,user_name,department FROM s2_user_department"); + + MeasureYamlTpl measure = new MeasureYamlTpl(); + measure.setAgg("count"); + measure.setName("user_department_internal_cnt"); + measure.setCreateMetric("true"); + measure.setExpr("1"); + List measures = new ArrayList<>(); + measures.add(measure); + + datasource.setMeasures(measures); + + DimensionYamlTpl dimension = new DimensionYamlTpl(); + dimension.setName("sys_imp_date"); + dimension.setExpr("imp_date"); + dimension.setType("time"); + DimensionTimeTypeParamsTpl dimensionTimeTypeParams = new DimensionTimeTypeParamsTpl(); + dimensionTimeTypeParams.setIsPrimary("true"); + dimensionTimeTypeParams.setTimeGranularity("day"); + dimension.setTypeParams(dimensionTimeTypeParams); + List dimensions = new ArrayList<>(); + dimensions.add(dimension); + + DimensionYamlTpl dimension3 = new DimensionYamlTpl(); + dimension3.setName("sys_imp_week"); + dimension3.setExpr("to_monday(from_unixtime(unix_timestamp(imp_date), 'yyyy-MM-dd'))"); + dimension3.setType("time"); + DimensionTimeTypeParamsTpl dimensionTimeTypeParams3 = new DimensionTimeTypeParamsTpl(); + dimensionTimeTypeParams3.setIsPrimary("true"); + dimensionTimeTypeParams3.setTimeGranularity("week"); + dimension3.setTypeParams(dimensionTimeTypeParams3); + dimensions.add(dimension3); + + datasource.setDimensions(dimensions); + + List identifies = new ArrayList<>(); + IdentifyYamlTpl identify = new IdentifyYamlTpl(); + identify.setName("user_name"); + identify.setType("primary"); + identifies.add(identify); + datasource.setIdentifiers(identifies); + + semanticSchema.getDatasource().put("user_department", SemanticSchemaManagerImpl.getDatasource(datasource)); + + DimensionYamlTpl dimension1 = new DimensionYamlTpl(); + dimension1.setExpr("department"); + dimension1.setName("department"); + dimension1.setType("categorical"); + List dimensionYamlTpls = new ArrayList<>(); + dimensionYamlTpls.add(dimension1); + + semanticSchema.getDimension() + .put("user_department", SemanticSchemaManagerImpl.getDimensions(dimensionYamlTpls)); + + } + //@Test public void test() throws Exception { @@ -189,65 +249,4 @@ class SemanticParserServiceTest { } - - - private static void addDepartment(SemanticSchema semanticSchema) { - DatasourceYamlTpl datasource = new DatasourceYamlTpl(); - datasource.setName("user_department"); - datasource.setSourceId(1L); - datasource.setSqlQuery("SELECT imp_date,user_name,department FROM s2_user_department"); - - MeasureYamlTpl measure = new MeasureYamlTpl(); - measure.setAgg("count"); - measure.setName("user_department_internal_cnt"); - measure.setCreateMetric("true"); - measure.setExpr("1"); - List measures = new ArrayList<>(); - measures.add(measure); - - datasource.setMeasures(measures); - - DimensionYamlTpl dimension = new DimensionYamlTpl(); - dimension.setName("sys_imp_date"); - dimension.setExpr("imp_date"); - dimension.setType("time"); - DimensionTimeTypeParamsTpl dimensionTimeTypeParams = new DimensionTimeTypeParamsTpl(); - dimensionTimeTypeParams.setIsPrimary("true"); - dimensionTimeTypeParams.setTimeGranularity("day"); - dimension.setTypeParams(dimensionTimeTypeParams); - List dimensions = new ArrayList<>(); - dimensions.add(dimension); - - DimensionYamlTpl dimension3 = new DimensionYamlTpl(); - dimension3.setName("sys_imp_week"); - dimension3.setExpr("to_monday(from_unixtime(unix_timestamp(imp_date), 'yyyy-MM-dd'))"); - dimension3.setType("time"); - DimensionTimeTypeParamsTpl dimensionTimeTypeParams3 = new DimensionTimeTypeParamsTpl(); - dimensionTimeTypeParams3.setIsPrimary("true"); - dimensionTimeTypeParams3.setTimeGranularity("week"); - dimension3.setTypeParams(dimensionTimeTypeParams3); - dimensions.add(dimension3); - - datasource.setDimensions(dimensions); - - List identifies = new ArrayList<>(); - IdentifyYamlTpl identify = new IdentifyYamlTpl(); - identify.setName("user_name"); - identify.setType("primary"); - identifies.add(identify); - datasource.setIdentifiers(identifies); - - semanticSchema.getDatasource().put("user_department", SemanticSchemaManagerImpl.getDatasource(datasource)); - - DimensionYamlTpl dimension1 = new DimensionYamlTpl(); - dimension1.setExpr("department"); - dimension1.setName("department"); - dimension1.setType("categorical"); - List dimensionYamlTpls = new ArrayList<>(); - dimensionYamlTpls.add(dimension1); - - semanticSchema.getDimension() - .put("user_department", SemanticSchemaManagerImpl.getDimensions(dimensionYamlTpls)); - - } } \ No newline at end of file diff --git a/webapp/packages/chat-sdk/rollup/rollup.umd.config.mjs b/webapp/packages/chat-sdk/rollup/rollup.umd.config.mjs index 062443458..5f408c308 100644 --- a/webapp/packages/chat-sdk/rollup/rollup.umd.config.mjs +++ b/webapp/packages/chat-sdk/rollup/rollup.umd.config.mjs @@ -1,5 +1,5 @@ import basicConfig from './rollup.config.mjs' -import { terser } from '@rollup/plugin-terser' +import { terser } from "@rollup/plugin-terser" import replace from '@rollup/plugin-replace' const config = { diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/style.less b/webapp/packages/chat-sdk/src/components/ChatItem/style.less index 0c9be0830..842a035bd 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/style.less +++ b/webapp/packages/chat-sdk/src/components/ChatItem/style.less @@ -42,7 +42,7 @@ &-typing-bubble { width: fit-content; - padding: 16px !important; + padding: 8px 16px !important; } &-text-bubble { diff --git a/webapp/packages/supersonic-fe/coding_build/build_prd.sh b/webapp/packages/supersonic-fe/coding_build/build_prd.sh index cac545a79..9912dcbab 100644 --- a/webapp/packages/supersonic-fe/coding_build/build_prd.sh +++ b/webapp/packages/supersonic-fe/coding_build/build_prd.sh @@ -6,7 +6,7 @@ if [ $? -ne 0 ]; then exit 1 fi -npm run build +npm run build:inner if [ $? -ne 0 ]; then echo "build failed" exit 1 diff --git a/webapp/packages/supersonic-fe/config/envConfig.ts b/webapp/packages/supersonic-fe/config/envConfig.ts index d28529eca..3ef1ecb6b 100644 --- a/webapp/packages/supersonic-fe/config/envConfig.ts +++ b/webapp/packages/supersonic-fe/config/envConfig.ts @@ -1,2 +1,4 @@ -const ENV_CONFIG = {}; +const ENV_CONFIG = { + tmeAvatarUrl: 'http://tpp.tmeoa.com/photo/48/', +}; export default ENV_CONFIG; diff --git a/webapp/packages/supersonic-fe/src/app.tsx b/webapp/packages/supersonic-fe/src/app.tsx index 7954d1969..2ccfb6ed9 100644 --- a/webapp/packages/supersonic-fe/src/app.tsx +++ b/webapp/packages/supersonic-fe/src/app.tsx @@ -5,12 +5,18 @@ import { history } from 'umi'; import type { RunTimeLayoutConfig } from 'umi'; import RightContent from '@/components/RightContent'; import S2Icon, { ICON } from '@/components/S2Icon'; +import qs from 'qs'; import { queryCurrentUser } from './services/user'; +import { queryToken } from './services/login'; import defaultSettings from '../config/defaultSettings'; import settings from '../config/themeSettings'; +import { deleteUrlQuery } from './utils/utils'; +import { AUTH_TOKEN_KEY, FROM_URL_KEY } from '@/common/constants'; export { request } from './services/request'; import { ROUTE_AUTH_CODES } from '../config/routes'; +const TOKEN_KEY = AUTH_TOKEN_KEY; + const replaceRoute = '/'; const getRuningEnv = async () => { @@ -34,6 +40,25 @@ export const initialStateConfig = { ), }; +const getToken = async () => { + let { search } = window.location; + if (search.length > 0) { + search = search.slice(1); + } + const data = qs.parse(search); + if (data.code) { + try { + const fromUrl = localStorage.getItem(FROM_URL_KEY); + const res = await queryToken(data.code as string); + localStorage.setItem(TOKEN_KEY, res.payload); + const newUrl = deleteUrlQuery(window.location.href, 'code'); + window.location.href = fromUrl || newUrl; + } catch (err) { + console.log(err); + } + } +}; + const getAuthCodes = () => { const { RUN_TYPE, APP_TARGET } = process.env; if (RUN_TYPE === 'local') { @@ -64,6 +89,12 @@ export async function getInitialState(): Promise<{ } catch (error) {} return undefined; }; + const { query } = history.location as any; + const currentToken = query[TOKEN_KEY] || localStorage.getItem(TOKEN_KEY); + + if (window.location.host.includes('tmeoa') && !currentToken) { + await getToken(); + } const currentUser = await fetchUserInfo(); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/ChatSetting.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/ChatSetting.tsx index e05536833..66c62fe16 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/ChatSetting.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/ChatSetting.tsx @@ -1,13 +1,11 @@ -import { Tabs } from 'antd'; +import { Tabs, Popover } from 'antd'; import React, { useEffect, useState } from 'react'; import { connect, Helmet } from 'umi'; import ProjectListTree from './components/ProjectList'; -import EntitySection from './components/Entity/EntitySection'; import styles from './components/style.less'; import type { StateType } from './model'; -import { RightOutlined, LeftOutlined } from '@ant-design/icons'; -import SplitPane from 'react-split-pane'; -import Pane from 'react-split-pane/lib/Pane'; +import { DownOutlined } from '@ant-design/icons'; +import EntitySection from './components/Entity/EntitySection'; import type { Dispatch } from 'umi'; const { TabPane } = Tabs; @@ -17,21 +15,14 @@ type Props = { dispatch: Dispatch; }; -const DEFAULT_LEFT_SIZE = '300px'; - const ChatSetting: React.FC = ({ domainManger, dispatch }) => { window.RUNNING_ENV = 'chat'; - const [collapsed, setCollapsed] = useState(false); - const [leftSize, setLeftSize] = useState(''); const { selectDomainId, selectDomainName } = domainManger; - useEffect(() => { - const semanticLeftCollapsed = localStorage.getItem('semanticLeftCollapsed'); - const semanticLeftSize = - semanticLeftCollapsed === 'true' ? '0px' : localStorage.getItem('semanticLeftSize'); - setCollapsed(semanticLeftCollapsed === 'true'); - setLeftSize(semanticLeftSize || DEFAULT_LEFT_SIZE); - }, []); + const [open, setOpen] = useState(false); + const handleOpenChange = (newOpen: boolean) => { + setOpen(newOpen); + }; useEffect(() => { if (selectDomainId) { dispatch({ @@ -49,64 +40,54 @@ const ChatSetting: React.FC = ({ domainManger, dispatch }) => { } }, [selectDomainId]); - const onCollapse = () => { - const collapsedValue = !collapsed; - setCollapsed(collapsedValue); - localStorage.setItem('semanticLeftCollapsed', String(collapsedValue)); - const semanticLeftSize = collapsedValue ? '0px' : localStorage.getItem('semanticLeftSize'); - const sizeValue = parseInt(semanticLeftSize || '0'); - if (!collapsedValue && sizeValue <= 10) { - setLeftSize(DEFAULT_LEFT_SIZE); - localStorage.setItem('semanticLeftSize', DEFAULT_LEFT_SIZE); - } else { - setLeftSize(semanticLeftSize || DEFAULT_LEFT_SIZE); - } - }; - - useEffect(() => { - const width = document.getElementById('tab'); - const switchWarpper: any = document.getElementById('switch'); - if (width && switchWarpper) { - switchWarpper.style.width = width.offsetWidth * 0.77 + 'px'; - } - }); - return (
- { - localStorage.setItem('semanticLeftSize', size[0]); - setLeftSize(size[0]); - }} - > - -
- -
-
- -
-
- {collapsed ? : } -
-

- {selectDomainName ? `选择的主题域:${selectDomainName}` : '主题域信息'} -

- {selectDomainId ? ( - <> - - - - - - - ) : ( -

请选择项目

- )} -
-
+ {/* 页面改版取消侧边栏转换为popover形式后,因为popover不触发则组件不加载,需要保留原本页面初始化需要ProjectListTree向model中写入首个主题域数据逻辑,在此引入但并不显示 */} +
+ +
+
+

+ { + setOpen(false); + }} + /> + } + trigger="click" + open={open} + onOpenChange={handleOpenChange} + > +
+ + {selectDomainName ? `选择的主题域:${selectDomainName}` : '主题域信息'} + + + + +
+
+

+ {selectDomainId ? ( + <> + + + + + + + ) : ( +

请选择项目

+ )} +
); }; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceBasicForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceBasicForm.tsx index b2ea88092..a887b473e 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceBasicForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceBasicForm.tsx @@ -1,19 +1,102 @@ -import React from 'react'; -import { Form, Input, Spin } from 'antd'; +import React, { useEffect, useState } from 'react'; +import { Form, Input, Spin, Select, message } from 'antd'; import type { FormInstance } from 'antd/lib/form'; +import { getDbNames, getTables } from '../../service'; const FormItem = Form.Item; const { TextArea } = Input; type Props = { isEdit?: boolean; + dataBaseConfig: any; form: FormInstance; tableLoading?: boolean; + mode?: 'normal' | 'fast'; }; -const DataSourceBasicForm: React.FC = ({ isEdit, tableLoading = false }) => { +const DataSourceBasicForm: React.FC = ({ + isEdit, + dataBaseConfig, + tableLoading = false, + mode = 'normal', +}) => { + const [dbNameList, setDbNameList] = useState([]); + const [tableNameList, setTableNameList] = useState([]); + const [currentDbName, setCurrentDbName] = useState(''); + const [currentTableName, setCurrentTableName] = useState(''); + const queryDbNameList = async (databaseId: number) => { + const { code, data, msg } = await getDbNames(databaseId); + if (code === 200) { + const list = data?.resultList || []; + setDbNameList(list); + } else { + message.error(msg); + } + }; + const queryTableNameList = async (databaseName: string) => { + const { code, data, msg } = await getTables(dataBaseConfig.id, databaseName); + if (code === 200) { + const list = data?.resultList || []; + setTableNameList(list); + } else { + message.error(msg); + } + }; + useEffect(() => { + if (dataBaseConfig?.id) { + queryDbNameList(dataBaseConfig.id); + } + }, [dataBaseConfig]); + return ( + {mode === 'fast' && ( + <> + + + + + + + + )} + void; onSubmit?: (dataSourceInfo: any) => void; - scriptColumns: any[]; + scriptColumns?: any[] | undefined; + basicInfoFormMode?: 'normal' | 'fast'; + onDataBaseTableChange?: (tableName: string) => void; }; const { Step } = Steps; @@ -26,30 +33,40 @@ const initFormVal = { }; const DataSourceCreateForm: React.FC = ({ + domainManger, onCancel, createModalVisible, domainId, scriptColumns, - sql, + sql = '', onSubmit, dataSourceItem, + basicInfoFormMode, }) => { const isEdit = !!dataSourceItem?.id; - const [fields, setFields] = useState([]); + const [fields, setFields] = useState([]); const [currentStep, setCurrentStep] = useState(0); const [saveLoading, setSaveLoading] = useState(false); const formValRef = useRef(initFormVal as any); const [form] = Form.useForm(); - const updateFormVal = (val: SaveDataSetForm) => { + const { dataBaseConfig } = domainManger; + const updateFormVal = (val: any) => { formValRef.current = val; }; + const [fieldColumns, setFieldColumns] = useState(scriptColumns || []); + useEffect(() => { + if (scriptColumns) { + setFieldColumns(scriptColumns); + } + }, [scriptColumns]); + const forward = () => setCurrentStep(currentStep + 1); const backward = () => setCurrentStep(currentStep - 1); - const getFieldsClassify = (fieldsList: FieldItem[]) => { + const getFieldsClassify = (fieldsList: any[]) => { const classify = fieldsList.reduce( - (fieldsClassify, item: FieldItem) => { + (fieldsClassify, item: any) => { const { type, bizName, @@ -126,11 +143,13 @@ const DataSourceCreateForm: React.FC = ({ forward(); } else { setSaveLoading(true); + const { dbName, tableName } = submitForm; const queryParams = { ...submitForm, sqlQuery: sql, - databaseId: dataSourceItem.databaseId, - queryType: 'sql_query', + databaseId: dataSourceItem?.databaseId || dataBaseConfig.id, + queryType: basicInfoFormMode === 'fast' ? 'table_query' : 'sql_query', + tableQuery: dbName && tableName ? `${dbName}.${tableName}` : '', domainId, }; const queryDatasource = isEdit ? updateDatasource : createDatasource; @@ -149,8 +168,8 @@ const DataSourceCreateForm: React.FC = ({ } }; - const initFields = (fieldsClassifyList: any[]) => { - const columnFields: any[] = scriptColumns.map((item: any) => { + const initFields = (fieldsClassifyList: any[], columns: any[]) => { + const columnFields: any[] = columns.map((item: any) => { const { type, nameEn } = item; const oldItem = fieldsClassifyList.find((oItem) => oItem.bizName === item.nameEn) || {}; return { @@ -181,13 +200,32 @@ const DataSourceCreateForm: React.FC = ({ }); }; - const initData = () => { + const initData = async () => { + const { queryType, tableQuery } = dataSourceItem.datasourceDetail; + let tableQueryInitValue = {}; + let columns = fieldColumns; + if (queryType === 'table_query') { + const tableQueryString = tableQuery || ''; + const [dbName, tableName] = tableQueryString.split('.'); + columns = await queryTableColumnList(dbName, tableName); + tableQueryInitValue = { + dbName, + tableName, + }; + } + formatterInitData(columns, tableQueryInitValue); + }; + + const formatterInitData = (columns: any[], extendParams: Record = {}) => { const { id, name, bizName, description, datasourceDetail } = dataSourceItem as any; + const { dimensions, identifiers, measures } = datasourceDetail; const initValue = { id, name, bizName, description, + ...extendParams, + // ...tableQueryInitValue, }; const editInitFormVal = { ...formValRef.current, @@ -195,20 +233,19 @@ const DataSourceCreateForm: React.FC = ({ }; updateFormVal(editInitFormVal); form.setFieldsValue(initValue); - const { dimensions, identifiers, measures } = datasourceDetail; const formatFields = [ ...formatterDimensions(dimensions || []), ...(identifiers || []), ...formatterMeasures(measures || []), ]; - initFields(formatFields); + initFields(formatFields, columns); }; useEffect(() => { if (isEdit) { initData(); } else { - initFields([]); + initFields([], fieldColumns); } }, [dataSourceItem]); @@ -227,11 +264,42 @@ const DataSourceCreateForm: React.FC = ({ setFields(result); }; + const queryTableColumnList = async (dbName: string, tableName: string) => { + if (!dataBaseConfig?.id) { + return; + } + const { code, data, msg } = await getColumns(dataBaseConfig.id, dbName, tableName); + if (code === 200) { + const list = data?.resultList || []; + // setTableNameList(list); + const columns = list.map((item: any) => { + const { dataType, name } = item; + return { + nameEn: name, + type: dataType, + }; + }); + // setFields(columns); + initFields([], columns); + setFieldColumns(columns); + return columns; + } else { + message.error(msg); + } + }; + const renderContent = () => { if (currentStep === 1) { return ; } - return ; + return ( + + ); }; const renderFooter = () => { @@ -280,6 +348,13 @@ const DataSourceCreateForm: React.FC = ({ initialValues={{ ...formValRef.current, }} + onValuesChange={(value, values) => { + const { tableName } = value; + const { dbName } = values; + if (tableName) { + queryTableColumnList(dbName, tableName); + } + }} className={styles.form} > {renderContent()} @@ -288,4 +363,6 @@ const DataSourceCreateForm: React.FC = ({ ); }; -export default DataSourceCreateForm; +export default connect(({ domainManger }: { domainManger: StateType }) => ({ + domainManger, +}))(DataSourceCreateForm); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlDetail.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlDetail.tsx index 3cac2ced9..42ec92ef4 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlDetail.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlDetail.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { Button, Table, message, Tooltip, Space, Dropdown } from 'antd'; import SplitPane from 'react-split-pane'; import Pane from 'react-split-pane/lib/Pane'; +import { connect } from 'umi'; import sqlFormatter from 'sql-formatter'; import { FullscreenOutlined, @@ -15,10 +16,12 @@ import { import { isFunction } from 'lodash'; import FullScreen from '@/components/FullScreen'; import SqlEditor from '@/components/SqlEditor'; -import type { TaskResultParams, TaskResultItem, DataInstanceItem, TaskResultColumn } from '../data'; -import { excuteSql } from '../service'; -import { getDatabaseByDomainId } from '../../service'; +import type { TaskResultItem, DataInstanceItem, TaskResultColumn } from '../data'; +import { excuteSql } from '@/pages/SemanticModel/service'; +// import { getDatabaseByDomainId } from '../../service'; import DataSourceCreateForm from './DataSourceCreateForm'; +import type { Dispatch } from 'umi'; +import type { StateType } from '../../model'; import styles from '../style.less'; import 'ace-builds/src-min-noconflict/ext-searchbox'; @@ -27,7 +30,8 @@ import 'ace-builds/src-min-noconflict/theme-monokai'; import 'ace-builds/src-min-noconflict/mode-sql'; type IProps = { - oprType: 'add' | 'edit'; + domainManger: StateType; + dispatch: Dispatch; dataSourceItem: DataInstanceItem; domainId: number; onUpdateSql?: (sql: string) => void; @@ -52,6 +56,7 @@ type JdbcSourceItems = { }; const SqlDetail: React.FC = ({ + domainManger, dataSourceItem, onSubmitSuccess, domainId, @@ -59,6 +64,7 @@ const SqlDetail: React.FC = ({ onUpdateSql, onJdbcSourceChange, }) => { + const { dataBaseConfig } = domainManger; const [resultTable, setResultTable] = useState([]); const [resultTableLoading, setResultTableLoading] = useState(false); const [resultCols, setResultCols] = useState([]); @@ -111,20 +117,30 @@ const SqlDetail: React.FC = ({ // return 'ClickHouse'; // }); - const queryDatabaseConfig = async () => { - const { code, data } = await getDatabaseByDomainId(domainId); - if (code === 200) { - setJdbcSourceItems([ - { - label: data?.name, - key: data?.id, - }, - ]); - onJdbcSourceChange?.(data?.id && Number(data?.id)); - return; - } - message.error('数据库配置获取错误'); - }; + useEffect(() => { + setJdbcSourceItems([ + { + label: dataBaseConfig?.name, + key: dataBaseConfig?.id, + }, + ]); + onJdbcSourceChange?.(dataBaseConfig?.id && Number(dataBaseConfig?.id)); + }, [dataBaseConfig]); + + // const queryDatabaseConfig = async () => { + // const { code, data } = await getDatabaseByDomainId(domainId); + // if (code === 200) { + // setJdbcSourceItems([ + // { + // label: data?.name, + // key: data?.id, + // }, + // ]); + // onJdbcSourceChange?.(data?.id && Number(data?.id)); + // return; + // } + // message.error('数据库配置获取错误'); + // }; function creatCalcItem(key: string, data: string) { const line = document.createElement('div'); // 需要每条数据一行,这样避免数据换行的时候获得的宽度不准确 @@ -185,7 +201,7 @@ const SqlDetail: React.FC = ({ } }; - const fetchTaskResult = (params: TaskResultParams) => { + const fetchTaskResult = (params) => { setResultTable( params.resultList.map((item, index) => { return { @@ -367,7 +383,7 @@ const SqlDetail: React.FC = ({ }, [resultTable, isSqlResFullScreen]); useEffect(() => { - queryDatabaseConfig(); + // queryDatabaseConfig(); const windowHeight = window.innerHeight; let size: ScreenSize = 'small'; if (windowHeight > 1100) { @@ -527,4 +543,6 @@ const SqlDetail: React.FC = ({ ); }; -export default SqlDetail; +export default connect(({ domainManger }: { domainManger: StateType }) => ({ + domainManger, +}))(SqlDetail); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlSide.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlSide.tsx index 2b414cfe4..57575e397 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlSide.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/SqlSide.tsx @@ -1,7 +1,6 @@ import React, { useState, useRef, useEffect } from 'react'; import { Tabs } from 'antd'; import SqlDetail from './SqlDetail'; -import type { SqlItem } from '../data'; import styles from '../style.less'; @@ -11,7 +10,6 @@ type Panes = { type: 'add' | 'edit'; scriptId?: number; sql?: string; - sqlInfo?: SqlItem; isSave?: boolean; // 暂存提示保存 }; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/data.d.ts b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/data.d.ts new file mode 100644 index 000000000..307965464 --- /dev/null +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/data.d.ts @@ -0,0 +1,16 @@ +// 数据类型 +export type DataInstanceItem = { + sourceInstanceId: number; // 数据实例id + sourceInstanceName: string; // 数据实例名 + defaultSourceId: number; // 查询表需要的默认datasource id + bindSourceId: number; +}; + +// 任务查询结果列 +export type TaskResultColumn = { + name: string; + type: string; +}; + +// 任务查询结果 +export type TaskResultItem = Record; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/service.ts b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/service.ts index 69ec9f83a..e69de29bb 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/service.ts +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/service.ts @@ -1,12 +0,0 @@ -import request from 'umi-request'; - -type ExcuteSqlParams = { - sql: string; - domainId: number; -}; - -// 执行脚本 -export async function excuteSql(params: ExcuteSqlParams) { - const data = { ...params }; - return request.post(`${process.env.API_BASE_URL}database/executeSql`, { data }); -} diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/ProjectManager.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/ProjectManager.tsx index 3f7467ecb..b15de9dd5 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/ProjectManager.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/ProjectManager.tsx @@ -1,4 +1,4 @@ -import { Tabs } from 'antd'; +import { Tabs, Popover } from 'antd'; import React, { useEffect, useState } from 'react'; import { connect, Helmet } from 'umi'; import ProjectListTree from './components/ProjectList'; @@ -9,11 +9,8 @@ import PermissionSection from './components/Permission/PermissionSection'; import DatabaseSection from './components/Database/DatabaseSection'; import styles from './components/style.less'; import type { StateType } from './model'; -import { RightOutlined, LeftOutlined } from '@ant-design/icons'; +import { DownOutlined } from '@ant-design/icons'; import SemanticFlow from './SemanticFlows'; -// import SemanticGraph from './SemanticGraph'; -import SplitPane from 'react-split-pane'; -import Pane from 'react-split-pane/lib/Pane'; import type { Dispatch } from 'umi'; const { TabPane } = Tabs; @@ -23,20 +20,15 @@ type Props = { dispatch: Dispatch; }; -const DEFAULT_LEFT_SIZE = '300px'; - const DomainManger: React.FC = ({ domainManger, dispatch }) => { window.RUNNING_ENV = 'semantic'; - const [collapsed, setCollapsed] = useState(false); - const [leftSize, setLeftSize] = useState(''); const { selectDomainId, selectDomainName } = domainManger; - useEffect(() => { - const semanticLeftCollapsed = localStorage.getItem('semanticLeftCollapsed'); - const semanticLeftSize = - semanticLeftCollapsed === 'true' ? '0px' : localStorage.getItem('semanticLeftSize'); - setCollapsed(semanticLeftCollapsed === 'true'); - setLeftSize(semanticLeftSize || DEFAULT_LEFT_SIZE); - }, []); + + const [open, setOpen] = useState(false); + + const handleOpenChange = (newOpen: boolean) => { + setOpen(newOpen); + }; useEffect(() => { if (selectDomainId) { @@ -52,23 +44,15 @@ const DomainManger: React.FC = ({ domainManger, dispatch }) => { domainId: selectDomainId, }, }); + dispatch({ + type: 'domainManger/queryDatabaseByDomainId', + payload: { + domainId: selectDomainId, + }, + }); } }, [selectDomainId]); - const onCollapse = () => { - const collapsedValue = !collapsed; - setCollapsed(collapsedValue); - localStorage.setItem('semanticLeftCollapsed', String(collapsedValue)); - const semanticLeftSize = collapsedValue ? '0px' : localStorage.getItem('semanticLeftSize'); - const sizeValue = parseInt(semanticLeftSize || '0'); - if (!collapsedValue && sizeValue <= 10) { - setLeftSize(DEFAULT_LEFT_SIZE); - localStorage.setItem('semanticLeftSize', DEFAULT_LEFT_SIZE); - } else { - setLeftSize(semanticLeftSize || DEFAULT_LEFT_SIZE); - } - }; - useEffect(() => { const width = document.getElementById('tab'); const switchWarpper: any = document.getElementById('switch'); @@ -80,61 +64,73 @@ const DomainManger: React.FC = ({ domainManger, dispatch }) => { return (
- { - localStorage.setItem('semanticLeftSize', size[0]); - setLeftSize(size[0]); - }} - > - -
- -
-
- -
-
- {collapsed ? : } -
-

- {selectDomainName ? `选择的主题域:${selectDomainName}` : '主题域信息'} -

- {selectDomainId ? ( - <> - - {/* + {/* 页面改版取消侧边栏转换为popover形式后,因为popover不触发则组件不加载,需要保留原本页面初始化需要ProjectListTree向model中写入首个主题域数据逻辑,在此引入但并不显示 */} +
+ +
+
+

+ { + setOpen(false); + }} + /> + } + trigger="click" + open={open} + onOpenChange={handleOpenChange} + > +
+ + {selectDomainName ? `选择的主题域:${selectDomainName}` : '主题域信息'} + + + + +
+
+

+ {selectDomainId ? ( + <> + + {/*
*/} - -
- -
-
- - - - - - - - - - - - - - - -
- - ) : ( -

请选择项目

- )} -
- + +
+ +
+
+ + + + + + + + + + + + + + + +
+ + ) : ( +

请选择项目

+ )} +
); }; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx index 0a0487b6d..ab0c6f164 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx @@ -6,6 +6,8 @@ import { NS_DATA_SOURCE_RELATION_MODAL_OPEN_STATE } from '../ConfigModelService' import { connect } from 'umi'; import { DATASOURCE_NODE_RENDER_ID } from '../constant'; import DataSourceRelationFormDrawer from './DataSourceRelationFormDrawer'; +import DataSourceCreateForm from '../../Datasource/components/DataSourceCreateForm'; +import ClassDataSourceTypeModal from '../../components/ClassDataSourceTypeModal'; import { GraphApi } from '../service'; import type { StateType } from '../../model'; import DataSource from '../../Datasource'; @@ -19,6 +21,7 @@ export type CreateFormProps = { const XflowJsonSchemaFormDrawerForm: React.FC = (props) => { const { domainManger } = props; + const { selectDomainId } = domainManger; const [visible, setVisible] = useState(false); const [createModalVisible, setCreateModalVisible] = useState(false); const [dataSourceItem, setDataSourceItem] = useState(); @@ -26,7 +29,8 @@ const XflowJsonSchemaFormDrawerForm: React.FC = (props) => { sourceData: {}, targetData: {}, }); - + const [createDataSourceModalOpen, setCreateDataSourceModalOpen] = useState(false); + const [dataSourceModalVisible, setDataSourceModalVisible] = useState(false); const app = useXFlowApp(); // 借用JsonSchemaForm钩子函数对元素状态进行监听 const { state, commandService, modelService } = useJsonSchemaFormModel({ @@ -53,7 +57,15 @@ const XflowJsonSchemaFormDrawerForm: React.FC = (props) => { const { renderKey, payload } = targetData as any; if (renderKey === DATASOURCE_NODE_RENDER_ID) { setDataSourceItem(payload); - setCreateModalVisible(true); + if (!payload) { + setCreateDataSourceModalOpen(true); + } else { + if (payload?.datasourceDetail?.queryType === 'table_query') { + setDataSourceModalVisible(true); + } else { + setCreateModalVisible(true); + } + } } else { const { sourceNodeData, targetNodeData } = targetData as any; setNodeDataSource({ @@ -85,6 +97,31 @@ const XflowJsonSchemaFormDrawerForm: React.FC = (props) => { }} open={visible} /> + {dataSourceModalVisible && ( + { + setDataSourceModalVisible(false); + }} + onSubmit={(dataSourceInfo: any) => { + setDataSourceModalVisible(false); + const { targetCell, targetData } = state; + targetCell?.setData({ + ...targetData, + label: dataSourceInfo.name, + payload: dataSourceInfo, + id: `dataSource-${dataSourceInfo.id}`, + }); + setDataSourceItem(undefined); + commandService.executeCommand(XFlowGraphCommands.SAVE_GRAPH_DATA.id, { + saveGraphDataService: (meta, graphData) => GraphApi.saveGraphData!(meta, graphData), + }); + }} + createModalVisible={dataSourceModalVisible} + /> + )} = (props) => { }} /> + { + { + if (type === 'fast') { + setDataSourceModalVisible(true); + } else { + setCreateModalVisible(true); + } + setCreateDataSourceModalOpen(false); + }} + /> + } ); }; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/components/ToolTips.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/components/ToolTips.tsx index 64e195327..a14cf746d 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/components/ToolTips.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/components/ToolTips.tsx @@ -17,7 +17,7 @@ const initTooltips = () => { outDiv.style.width = 'fit-content'; outDiv.style.height = 'fit-content'; const model = e.item.getModel(); - console.log(model, e.item, 'model'); + const { name, bizName, createdBy, updatedAt, description } = model; const list = [ { diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx index ba6d01565..b782fd25c 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx @@ -106,7 +106,7 @@ const DomainManger: React.FC = ({ domainManger, domainId }) => { const { id, name } = datasource; const dataSourceId = `dataSource-${id}`; let childrenList = []; - if (type === 'metirc') { + if (type === 'metric') { childrenList = getMetricChildren(metrics, dataSourceId); } if (type === 'dimension') { @@ -247,7 +247,6 @@ const DomainManger: React.FC = ({ domainManger, domainId }) => { }, }, }); - // 我使用TreeGraph进行layout布局,采用{type: 'compactBox',direction: 'LR'}模式,如何使子节点与根节点的连线只连接到上下连接桩上 graphRef.current = new G6.TreeGraph({ container: 'semanticGraph', diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/service.ts b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/service.ts index 69ec9f83a..e69de29bb 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/service.ts +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/service.ts @@ -1,12 +0,0 @@ -import request from 'umi-request'; - -type ExcuteSqlParams = { - sql: string; - domainId: number; -}; - -// 执行脚本 -export async function excuteSql(params: ExcuteSqlParams) { - const data = { ...params }; - return request.post(`${process.env.API_BASE_URL}database/executeSql`, { data }); -} diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDataSourceTable.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDataSourceTable.tsx index 439db372e..23b8974a6 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDataSourceTable.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDataSourceTable.tsx @@ -1,23 +1,31 @@ import type { ActionType, ProColumns } from '@ant-design/pro-table'; import ProTable from '@ant-design/pro-table'; -import { message, Button, Drawer, Space, Popconfirm } from 'antd'; -import React, { useRef, useState } from 'react'; +import { message, Button, Drawer, Space, Popconfirm, Modal, Card, Row, Col } from 'antd'; +import { ConsoleSqlOutlined, CoffeeOutlined } from '@ant-design/icons'; +import React, { useRef, useState, useEffect } from 'react'; import type { Dispatch } from 'umi'; import { connect } from 'umi'; +import DataSourceCreateForm from '../Datasource/components/DataSourceCreateForm'; +import ClassDataSourceTypeModal from './ClassDataSourceTypeModal'; import type { StateType } from '../model'; import { getDatasourceList, deleteDatasource } from '../service'; import DataSource from '../Datasource'; import moment from 'moment'; +const { Meta } = Card; type Props = { dispatch: Dispatch; domainManger: StateType; }; const ClassDataSourceTable: React.FC = ({ dispatch, domainManger }) => { - const { selectDomainId } = domainManger; + const { selectDomainId, dataBaseResultColsMap, dataBaseConfig } = domainManger; const [createModalVisible, setCreateModalVisible] = useState(false); const [dataSourceItem, setDataSourceItem] = useState(); + const [createDataSourceModalOpen, setCreateDataSourceModalOpen] = useState(false); + const [dataSourceModalVisible, setDataSourceModalVisible] = useState(false); + const [fastModeSql, setFastModeSql] = useState(''); + const [fastModeTableName, setFastModeTableName] = useState(''); const actionRef = useRef(); @@ -62,6 +70,10 @@ const ClassDataSourceTable: React.FC = ({ dispatch, domainManger }) => { key="classEditBtn" onClick={() => { setDataSourceItem(record); + if (record.datasourceDetail.queryType === 'table_query') { + setDataSourceModalVisible(true); + return; + } setCreateModalVisible(true); }} > @@ -72,12 +84,12 @@ const ClassDataSourceTable: React.FC = ({ dispatch, domainManger }) => { okText="是" cancelText="否" onConfirm={async () => { - const { code } = await deleteDatasource(record.id); + const { code, msg } = await deleteDatasource(record.id); if (code === 200) { setDataSourceItem(undefined); actionRef.current?.reload(); } else { - message.error('删除失败'); + message.error(msg); } }} > @@ -121,6 +133,20 @@ const ClassDataSourceTable: React.FC = ({ dispatch, domainManger }) => { return resData; }; + const queryDataBaseExcuteSql = (tableName: string) => { + const sql = `select * from ${tableName}`; + setFastModeSql(sql); + setFastModeTableName(tableName); + dispatch({ + type: 'domainManger/queryDataBaseExcuteSql', + payload: { + sql, + domainId: selectDomainId, + tableName, + }, + }); + }; + return ( <> = ({ dispatch, domainManger }) => { type="primary" onClick={() => { setDataSourceItem(undefined); - setCreateModalVisible(true); + setCreateDataSourceModalOpen(true); }} > 创建数据源 , ]} /> + { + { + if (type === 'fast') { + setDataSourceModalVisible(true); + } else { + setCreateModalVisible(true); + } + setCreateDataSourceModalOpen(false); + }} + /> + } + {dataSourceModalVisible && ( + { + setDataSourceModalVisible(false); + }} + onDataBaseTableChange={(tableName: string) => { + queryDataBaseExcuteSql(tableName); + }} + onSubmit={() => { + setDataSourceModalVisible(false); + setDataSourceItem(undefined); + actionRef.current?.reload(); + }} + createModalVisible={dataSourceModalVisible} + /> + )} {createModalVisible && ( void; +}; + +const ClassDataSourceTypeModal: React.FC = ({ open, onTypeChange }) => { + const [createDataSourceModalOpen, setCreateDataSourceModalOpen] = useState(false); + useEffect(() => { + setCreateDataSourceModalOpen(open); + }, [open]); + + return ( + <> + { + setCreateDataSourceModalOpen(false); + }} + footer={null} + centered + closable={false} + > + + + { + onTypeChange('fast'); + setCreateDataSourceModalOpen(false); + }} + cover={ + + } + > + + + + + { + onTypeChange('normal'); + setCreateDataSourceModalOpen(false); + }} + hoverable + style={{ height: 220 }} + cover={ + + } + > + + + + + + + ); +}; +export default ClassDataSourceTypeModal; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx index e87fbba4d..a950560a2 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx @@ -88,6 +88,10 @@ const ClassDimensionTable: React.FC = ({ domainManger, dispatch }) => { dataIndex: 'name', title: '维度名称', }, + { + dataIndex: 'alias', + title: '别名', + }, { dataIndex: 'bizName', title: '字段名称', @@ -146,12 +150,12 @@ const ClassDimensionTable: React.FC = ({ domainManger, dispatch }) => { okText="是" cancelText="否" onConfirm={async () => { - const { code } = await deleteDimension(record.id); + const { code, msg } = await deleteDimension(record.id); if (code === 200) { setDimensionItem(undefined); actionRef.current?.reload(); } else { - message.error('删除失败'); + message.error(msg); } }} > diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassMetricTable.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassMetricTable.tsx index 89bdaa78e..6e3203d1d 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassMetricTable.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassMetricTable.tsx @@ -68,6 +68,10 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { dataIndex: 'name', title: '指标名称', }, + { + dataIndex: 'alias', + title: '别名', + }, { dataIndex: 'bizName', title: '字段名称', @@ -118,12 +122,12 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { okText="是" cancelText="否" onConfirm={async () => { - const { code } = await deleteMetric(record.id); + const { code, msg } = await deleteMetric(record.id); if (code === 200) { setMetricItem(undefined); actionRef.current?.reload(); } else { - message.error('删除失败'); + message.error(msg); } }} > diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseCreateForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseCreateForm.tsx index 4d033cfca..402e53404 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseCreateForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseCreateForm.tsx @@ -7,29 +7,39 @@ import { formLayout } from '@/components/FormHelper/utils'; import styles from '../style.less'; type Props = { domainId: number; + dataBaseConfig: any; onSubmit: (params?: any) => void; }; const FormItem = Form.Item; const TextArea = Input.TextArea; -const DatabaseCreateForm: ForwardRefRenderFunction = ({ domainId }, ref) => { +const DatabaseCreateForm: ForwardRefRenderFunction = ( + { domainId, dataBaseConfig, onSubmit }, + ref, +) => { const [form] = Form.useForm(); const [selectedDbType, setSelectedDbType] = useState('h2'); - const queryDatabaseConfig = async () => { - const { code, data } = await getDatabaseByDomainId(domainId); - if (code === 200) { - form.setFieldsValue({ ...data }); - setSelectedDbType(data?.type); - return; - } - message.error('数据库配置获取错误'); - }; + // const queryDatabaseConfig = async () => { + // const { code, data } = await getDatabaseByDomainId(domainId); + // if (code === 200) { + // form.setFieldsValue({ ...data }); + // setSelectedDbType(data?.type); + // return; + // } + // message.error('数据库配置获取错误'); + // }; useEffect(() => { form.resetFields(); - queryDatabaseConfig(); - }, [domainId]); + form.setFieldsValue({ ...dataBaseConfig }); + setSelectedDbType(dataBaseConfig?.type); + }, [dataBaseConfig]); + + // useEffect(() => { + // form.resetFields(); + // // queryDatabaseConfig(); + // }, [domainId]); const getFormValidateFields = async () => { return await form.validateFields(); @@ -48,6 +58,7 @@ const DatabaseCreateForm: ForwardRefRenderFunction = ({ domainId }, if (code === 200) { message.success('保存成功'); + onSubmit?.(); return; } message.error(msg); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseSection.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseSection.tsx index 1b3ca276e..adf64efe5 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseSection.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Database/DatabaseSection.tsx @@ -11,8 +11,8 @@ type Props = { domainManger: StateType; }; -const DatabaseSection: React.FC = ({ domainManger }) => { - const { selectDomainId } = domainManger; +const DatabaseSection: React.FC = ({ domainManger, dispatch }) => { + const { selectDomainId, dataBaseConfig } = domainManger; const entityCreateRef = useRef({}); @@ -22,8 +22,16 @@ const DatabaseSection: React.FC = ({ domainManger }) => { {}} + onSubmit={() => { + dispatch({ + type: 'domainManger/queryDatabaseByDomainId', + payload: { + domainId: selectDomainId, + }, + }); + }} /> diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DimensionInfoModal.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DimensionInfoModal.tsx index 37148d11a..9a7a4430c 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DimensionInfoModal.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DimensionInfoModal.tsx @@ -85,6 +85,7 @@ const DimensionInfoModal: React.FC = ({ >
+ = ({ ))} + + + = ({ onSubmit, }) => { const [sourceList, setSourceList] = useState([]); - const [visibilityData, setVisibilityData] = useState({}); const [selectedKeyList, setSelectedKeyList] = useState([]); const settingTypeConfig = settingType === 'dimension' ? dimensionConfig : metricConfig; useEffect(() => { @@ -47,27 +48,12 @@ const DimensionMetricVisibleModal: React.FC = ({ setSourceList(list); }, [settingSourceList]); - const queryThemeListData: any = async () => { - const { code, data } = await getDomainExtendDetailConfig({ - domainId, - }); - if (code === 200) { - setVisibilityData(data.visibility); - return; - } - message.error('获取可见信息失败'); - }; - useEffect(() => { - queryThemeListData(); - }, []); - - useEffect(() => { - setSelectedKeyList(visibilityData?.[settingTypeConfig.visibleIdListKey] || []); - }, [visibilityData]); + setSelectedKeyList(themeData.visibility?.[settingTypeConfig.visibleIdListKey] || []); + }, [themeData]); const saveEntity = async () => { - const { id } = themeData; + const { id, entity } = themeData; let saveDomainExtendQuery = addDomainExtend; if (id) { saveDomainExtendQuery = editDomainExtend; @@ -79,6 +65,8 @@ const DimensionMetricVisibleModal: React.FC = ({ } return list; }, []); + const entityParams = exChangeRichEntityListToIds(entity); + themeData.entity = entityParams; const params = { ...themeData, visibility: themeData.visibility || {}, diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntityCreateForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntityCreateForm.tsx index 07f85230b..bfd7d2d29 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntityCreateForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntityCreateForm.tsx @@ -2,15 +2,17 @@ import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'; import type { ForwardRefRenderFunction } from 'react'; import { message, Form, Input, Select, Button } from 'antd'; import { addDomainExtend, editDomainExtend } from '../../service'; +import type { ISemantic, IChatConfig } from '../../data'; import { formLayout } from '@/components/FormHelper/utils'; - +import { exChangeRichEntityListToIds } from './utils'; import styles from '../style.less'; + type Props = { - entityData: any; - metricList: any[]; - dimensionList: any[]; + entityData: IChatConfig.IEntity; + metricList: ISemantic.IMetricList; + dimensionList: ISemantic.IDimensionList; domainId: number; - onSubmit: (params?: any) => void; + onSubmit: () => void; }; const FormItem = Form.Item; @@ -34,33 +36,19 @@ const EntityCreateForm: ForwardRefRenderFunction = ( if (Object.keys(entityData).length === 0) { return; } - const { detailData = {}, names = [] } = entityData; - if (!detailData.dimensionIds) { - entityData = { - ...entityData, - detailData: { - ...detailData, - dimensionIds: [], - }, - }; - } - if (!detailData.metricIds) { - entityData = { - ...entityData, - detailData: { - ...detailData, - metricIds: [], - }, - }; - } - form.setFieldsValue({ ...entityData, name: names.join(',') }); + const names = entityData.names || []; + const formatEntityData = exChangeRichEntityListToIds(entityData); + form.setFieldsValue({ + ...formatEntityData, + name: names.join(','), + }); }, [entityData]); useImperativeHandle(ref, () => ({ getFormValidateFields, })); useEffect(() => { - const metricOption = metricList.map((item: any) => { + const metricOption = metricList.map((item: ISemantic.IMetricItem) => { return { label: item.name, value: item.id, @@ -70,7 +58,7 @@ const EntityCreateForm: ForwardRefRenderFunction = ( }, [metricList]); useEffect(() => { - const dimensionEnum = dimensionList.map((item: any) => { + const dimensionEnum = dimensionList.map((item: ISemantic.IDimensionItem) => { return { label: item.name, value: item.id, @@ -128,6 +116,13 @@ const EntityCreateForm: ForwardRefRenderFunction = ( mode="multiple" allowClear style={{ width: '100%' }} + filterOption={(inputValue: string, item: any) => { + const { label } = item; + if (label.includes(inputValue)) { + return true; + } + return false; + }} placeholder="请选择主体标识" options={dimensionListOptions} /> @@ -137,6 +132,13 @@ const EntityCreateForm: ForwardRefRenderFunction = ( mode="multiple" allowClear style={{ width: '100%' }} + filterOption={(inputValue: string, item: any) => { + const { label } = item; + if (label.includes(inputValue)) { + return true; + } + return false; + }} placeholder="请选择展示维度信息" options={dimensionListOptions} /> @@ -146,6 +148,13 @@ const EntityCreateForm: ForwardRefRenderFunction = ( mode="multiple" allowClear style={{ width: '100%' }} + filterOption={(inputValue: string, item: any) => { + const { label } = item; + if (label.includes(inputValue)) { + return true; + } + return false; + }} placeholder="请选择展示指标信息" options={metricListOptions} /> diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntitySection.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntitySection.tsx index 981d94fb1..1c0054b39 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntitySection.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/EntitySection.tsx @@ -3,10 +3,11 @@ import React, { useState, useEffect, useRef } from 'react'; import type { Dispatch } from 'umi'; import { connect } from 'umi'; import type { StateType } from '../../model'; -import { getDomainExtendConfig } from '../../service'; +import { getDomainExtendConfig, getDomainExtendDetailConfig } from '../../service'; import ProCard from '@ant-design/pro-card'; import EntityCreateForm from './EntityCreateForm'; import MetricSettingForm from './MetricSettingForm'; +import type { IChatConfig } from '../../data'; import DimensionMetricVisibleForm from './DimensionMetricVisibleForm'; type Props = { @@ -17,18 +18,21 @@ type Props = { const EntitySection: React.FC = ({ domainManger, dispatch }) => { const { selectDomainId, dimensionList, metricList } = domainManger; - const [entityData, setEntityData] = useState({}); + const [entityData, setEntityData] = useState({} as IChatConfig.IEntity); const [themeData, setThemeData] = useState({}); const entityCreateRef = useRef({}); const queryThemeListData: any = async () => { - const { code, data } = await getDomainExtendConfig({ + const { code, data } = await getDomainExtendDetailConfig({ domainId: selectDomainId, }); + // getDomainExtendConfig({ + // domainId: selectDomainId, + // }); if (code === 200) { - const target = data?.[0] || {}; + const target = data; if (target) { setThemeData(target); setEntityData({ @@ -75,7 +79,14 @@ const EntitySection: React.FC = ({ domainManger, dispatch }) => { { + const blackMetricIdList = themeData.visibility?.blackMetricIdList; + if (Array.isArray(blackMetricIdList)) { + return !blackMetricIdList.includes(item.id); + } + return false; + })} onSubmit={() => { queryThemeListData(); }} @@ -86,8 +97,22 @@ const EntitySection: React.FC = ({ domainManger, dispatch }) => { ref={entityCreateRef} domainId={Number(selectDomainId)} entityData={entityData} - metricList={metricList} - dimensionList={dimensionList} + // metricList={metricList} + metricList={metricList.filter((item) => { + const blackMetricIdList = themeData.visibility?.blackMetricIdList; + if (Array.isArray(blackMetricIdList)) { + return !blackMetricIdList.includes(item.id); + } + return false; + })} + // dimensionList={dimensionList} + dimensionList={dimensionList.filter((item) => { + const blackDimensionList = themeData.visibility?.blackDimIdList; + if (Array.isArray(blackDimensionList)) { + return !blackDimensionList.includes(item.id); + } + return false; + })} onSubmit={() => { queryThemeListData(); }} diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/MetricSettingForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/MetricSettingForm.tsx index 5e74f2ede..643b0dde9 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/MetricSettingForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/MetricSettingForm.tsx @@ -17,7 +17,7 @@ const FormItem = Form.Item; const Option = Select.Option; const MetricSettingForm: ForwardRefRenderFunction = ( - { metricList, domainId, themeData: uniqueMetricData }, + { metricList, domainId, themeData: uniqueMetricData, onSubmit }, ref, ) => { const [form] = Form.useForm(); @@ -82,6 +82,7 @@ const MetricSettingForm: ForwardRefRenderFunction = ( if (code === 200) { form.setFieldValue('id', data); + onSubmit?.(); message.success('保存成功'); return; } @@ -116,6 +117,13 @@ const MetricSettingForm: ForwardRefRenderFunction = ( allowClear showSearch style={{ width: '100%' }} + filterOption={(inputValue: string, item: any) => { + const { label } = item; + if (label.includes(inputValue)) { + return true; + } + return false; + }} placeholder="请选择展示指标信息" options={metricListOptions} /> diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/utils.ts b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/utils.ts new file mode 100644 index 000000000..386831882 --- /dev/null +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/Entity/utils.ts @@ -0,0 +1,28 @@ +import { IChatConfig, ISemantic } from '../../data'; + +export const exChangeRichEntityListToIds = (entityData: IChatConfig.IEntity) => { + const entityList = entityData.entityIds || []; + const detailData: { + dimensionIds: number[]; + metricIds: number[]; + } = { dimensionIds: [], metricIds: [] }; + const { dimensionList, metricList } = entityData.entityInternalDetailDesc || {}; + if (Array.isArray(dimensionList)) { + detailData.dimensionIds = dimensionList.map((item: ISemantic.IDimensionItem) => { + return item.id; + }); + } + if (Array.isArray(metricList)) { + detailData.metricIds = metricList.map((item: ISemantic.IMetricItem) => { + return item.id; + }); + } + const entityIds = entityList.map((item) => { + return item.id; + }); + return { + ...entityData, + entityIds, + detailData, + }; +}; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/MetricInfoCreateForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/MetricInfoCreateForm.tsx index c223db9b6..0ef2f0b8f 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/MetricInfoCreateForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/MetricInfoCreateForm.tsx @@ -159,6 +159,9 @@ const MetricInfoCreateForm: React.FC = ({ > + + + = ({ domainManger }) => { okText="是" cancelText="否" onConfirm={async () => { - const { code } = await removeGroupAuth({ + const { code, msg } = await removeGroupAuth({ domainId: record.domainId, groupId: record.groupId, }); @@ -223,7 +223,7 @@ const PermissionTable: React.FC = ({ domainManger }) => { setPermissonData({}); queryListData(); } else { - message.error('删除失败'); + message.error(msg); } }} > diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ProjectList.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ProjectList.tsx index 125e6dbbe..d47168e23 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ProjectList.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ProjectList.tsx @@ -1,7 +1,7 @@ import { DownOutlined, PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'; -import { Input, message, Tree, Popconfirm, Space, Tooltip } from 'antd'; +import { Input, message, Tree, Popconfirm, Space, Tooltip, Row, Col } from 'antd'; import type { DataNode } from 'antd/lib/tree'; -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import type { FC, Key } from 'react'; import { connect } from 'umi'; import type { Dispatch } from 'umi'; @@ -21,6 +21,8 @@ type ProjectListProps = { selectDomainName: string; createDomainBtnVisible?: boolean; dispatch: Dispatch; + onCreateDomainBtnClick?: () => void; + onTreeSelected?: () => void; }; const projectTreeFlat = (projectTree: DataNode[], filterValue: string): DataNode[] => { @@ -41,6 +43,8 @@ const projectTreeFlat = (projectTree: DataNode[], filterValue: string): DataNode const ProjectListTree: FC = ({ selectDomainId, createDomainBtnVisible = true, + onCreateDomainBtnClick, + onTreeSelected, dispatch, }) => { const [projectTree, setProjectTree] = useState([]); @@ -89,6 +93,7 @@ const ProjectListTree: FC = ({ const targetNodeData = classList.filter((item: any) => { return item.id === selectedKeys; })[0]; + onTreeSelected?.(); dispatch({ type: 'domainManger/setSelectDomain', selectDomainId: selectedKeys, @@ -196,28 +201,29 @@ const ProjectListTree: FC = ({ return (
-

- 主题域 - - {createDomainBtnVisible && ( - - { - setProjectInfoParams({ type: 'top', modelType: 'add' }); - setProjectInfoModalVisible(true); - }} - className={styles.addBtn} - /> - - )} - -

- + + + + + + + { + setProjectInfoParams({ type: 'top', modelType: 'add' }); + setProjectInfoModalVisible(true); + onCreateDomainBtnClick?.(); + }} + className={styles.addBtn} + /> + + + + ; domainData: any; + dataBaseResultColsMap: any; + dataBaseConfig: any; }; export type ModelType = { @@ -19,11 +21,15 @@ export type ModelType = { effects: { queryDimensionList: Effect; queryMetricList: Effect; + queryDataBaseExcuteSql: Effect; + queryDatabaseByDomainId: Effect; }; reducers: { setSelectDomain: Reducer; setPagination: Reducer; setDimensionList: Reducer; + setDataBaseScriptColumn: Reducer; + setDataBaseConfig: Reducer; setMetricList: Reducer; reset: Reducer; }; @@ -38,6 +44,8 @@ export const defaultState: StateType = { dimensionList: [], metricList: [], domainData: {}, + dataBaseResultColsMap: {}, + dataBaseConfig: {}, }; const Model: ModelType = { @@ -61,6 +69,46 @@ const Model: ModelType = { message.error(msg); } }, + *queryDataBaseExcuteSql({ payload }, { call, put, select }) { + const { tableName } = payload; + if (!tableName) { + return; + } + const isExists = yield select((state: any) => { + return state.domainManger.dataBaseResultColsMap[tableName]; + }); + if (isExists) { + return; + } + const { code, data, msg } = yield call(excuteSql, payload); + if (code === 200) { + const resultList = data.resultList.map((item, index) => { + return { + ...item, + index, + }; + }); + const scriptColumns = data.columns; + yield put({ + type: 'setDataBaseScriptColumn', + payload: { resultList, scriptColumns, tableName }, + }); + } else { + message.error(msg); + } + }, + *queryDatabaseByDomainId({ payload }, { call, put }) { + const domainId = payload.domainId; + const { code, data, msg } = yield call(getDatabaseByDomainId, domainId); + if (code === 200) { + yield put({ + type: 'setDataBaseConfig', + payload: { dataBaseConfig: data }, + }); + } else { + message.error(msg); + } + }, }, reducers: { setSelectDomain(state = defaultState, action) { @@ -89,6 +137,21 @@ const Model: ModelType = { ...action.payload, }; }, + setDataBaseScriptColumn(state = defaultState, action) { + return { + ...state, + dataBaseResultColsMap: { + ...state.dataBaseResultColsMap, + [action.payload.tableName]: { ...action.payload }, + }, + }; + }, + setDataBaseConfig(state = defaultState, action) { + return { + ...state, + ...action.payload, + }; + }, reset() { return defaultState; }, diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/service.ts b/webapp/packages/supersonic-fe/src/pages/SemanticModel/service.ts index 439588415..b8cbd599e 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/service.ts +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/service.ts @@ -237,3 +237,32 @@ export function testDatabaseConnect(data: SaveDatabaseParams): Promise { data, }); } + +type ExcuteSqlParams = { + sql: string; + domainId: number; +}; + +// 执行脚本 +export async function excuteSql(params: ExcuteSqlParams) { + const data = { ...params }; + return request.post(`${process.env.API_BASE_URL}database/executeSql`, { data }); +} + +export function getDbNames(dbId: number): Promise { + return request(`${process.env.API_BASE_URL}database/getDbNames/${dbId}`, { + method: 'GET', + }); +} + +export function getTables(dbId: number, dbName: string): Promise { + return request(`${process.env.API_BASE_URL}database/getTables/${dbId}/${dbName}`, { + method: 'GET', + }); +} + +export function getColumns(dbId: number, dbName: string, tableName: string): Promise { + return request(`${process.env.API_BASE_URL}database/getColumns/${dbId}/${dbName}/${tableName}`, { + method: 'GET', + }); +}