mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-14 22:25:19 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
package com.tencent.supersonic.chat.application;
|
||||
|
||||
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;
|
||||
import com.tencent.supersonic.chat.domain.dataobject.QueryDO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq;
|
||||
import com.tencent.supersonic.chat.domain.repository.ChatContextRepository;
|
||||
import com.tencent.supersonic.chat.domain.repository.ChatQueryRepository;
|
||||
import com.tencent.supersonic.chat.domain.repository.ChatRepository;
|
||||
import com.tencent.supersonic.chat.domain.service.ChatService;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service("ChatService")
|
||||
@Primary
|
||||
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) {
|
||||
this.chatContextRepository = chatContextRepository;
|
||||
this.chatRepository = chatRepository;
|
||||
this.chatQueryRepository = chatQueryRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getContextDomain(Integer chatId) {
|
||||
if (Objects.isNull(chatId)) {
|
||||
return null;
|
||||
}
|
||||
ChatContext chatContext = getOrCreateContext(chatId);
|
||||
if (Objects.isNull(chatContext)) {
|
||||
return null;
|
||||
}
|
||||
SemanticParseInfo originalSemanticParse = chatContext.getParseInfo();
|
||||
if (Objects.nonNull(originalSemanticParse) && Objects.nonNull(originalSemanticParse.getDomainId())) {
|
||||
return originalSemanticParse.getDomainId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ChatContext getOrCreateContext(int chatId) {
|
||||
return chatContextRepository.getOrCreateContext(chatId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContext(ChatContext chatCtx) {
|
||||
logger.debug("save ChatContext {}", chatCtx);
|
||||
chatContextRepository.updateContext(chatCtx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void switchContext(ChatContext chatCtx) {
|
||||
logger.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.setIsDelete(0);
|
||||
intelligentConversionDO.setLastTime(datetime);
|
||||
intelligentConversionDO.setLastQuestion("Hello, welcome to using supersonic");
|
||||
intelligentConversionDO.setIsTop(0);
|
||||
return chatRepository.createChat(intelligentConversionDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChatDO> getAll(String userName) {
|
||||
return chatRepository.getAll(userName);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateFeedback(Integer id, Integer score, String feedback) {
|
||||
QueryDO intelligentQueryDO = new QueryDO();
|
||||
intelligentQueryDO.setId(id);
|
||||
intelligentQueryDO.setScore(score);
|
||||
intelligentQueryDO.setFeedback(feedback);
|
||||
return chatRepository.updateFeedback(intelligentQueryDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateChatIsTop(Long chatId, int isTop) {
|
||||
return chatRepository.updateConversionIsTop(chatId, isTop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteChat(Long chatId, String userName) {
|
||||
return chatRepository.deleteChat(chatId, userName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageInfo<ChatQueryVO> queryInfo(PageQueryInfoReq pageQueryInfoCommend, long chatId) {
|
||||
return chatQueryRepository.getChatQuery(pageQueryInfoCommend, chatId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx) {
|
||||
chatQueryRepository.createChatQuery(queryResponse, queryContext, chatCtx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
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.domain.pojo.config.ChatConfig;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigBase;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigEditReq;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilter;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigInfo;
|
||||
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.repository.ChatConfigRepository;
|
||||
import com.tencent.supersonic.chat.domain.service.ConfigService;
|
||||
import com.tencent.supersonic.chat.domain.utils.ChatConfigUtils;
|
||||
import com.tencent.supersonic.common.util.json.JsonUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ConfigServiceImpl implements ConfigService {
|
||||
|
||||
private final ChatConfigRepository chaConfigRepository;
|
||||
private final SemanticLayer semanticLayer;
|
||||
private final ChatConfigUtils chatConfigUtils;
|
||||
|
||||
public ConfigServiceImpl(ChatConfigRepository chaConfigRepository,
|
||||
@Lazy SemanticLayer semanticLayer,
|
||||
ChatConfigUtils chatConfigUtils) {
|
||||
this.chaConfigRepository = chaConfigRepository;
|
||||
this.semanticLayer = semanticLayer;
|
||||
this.chatConfigUtils = chatConfigUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long addConfig(ChatConfigBase configBaseCmd, User user) {
|
||||
log.info("[create domain extend] object:{}", JsonUtil.toString(configBaseCmd, true));
|
||||
duplicateCheck(configBaseCmd.getDomainId());
|
||||
permissionCheckLogic(configBaseCmd.getDomainId(), user.getName());
|
||||
ChatConfig chaConfig = chatConfigUtils.newChatConfig(configBaseCmd, user);
|
||||
chaConfigRepository.createConfig(chaConfig);
|
||||
return chaConfig.getDomainId();
|
||||
}
|
||||
|
||||
private void duplicateCheck(Long domainId) {
|
||||
ChatConfigFilter filter = new ChatConfigFilter();
|
||||
filter.setDomainId(domainId);
|
||||
List<ChatConfigInfo> chaConfigDescList = chaConfigRepository.getChatConfig(filter);
|
||||
if (!CollectionUtils.isEmpty(chaConfigDescList)) {
|
||||
throw new RuntimeException("chat config existed, no need to add repeatedly");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Long editConfig(ChatConfigEditReq configEditCmd, User user) {
|
||||
log.info("[edit domain extend] object:{}", JsonUtil.toString(configEditCmd, true));
|
||||
if (Objects.isNull(configEditCmd) || Objects.isNull(configEditCmd.getId()) && Objects.isNull(
|
||||
configEditCmd.getDomainId())) {
|
||||
throw new RuntimeException("editConfig, id and domainId are not allowed to be empty at the same time");
|
||||
}
|
||||
permissionCheckLogic(configEditCmd.getDomainId(), user.getName());
|
||||
ChatConfig chaConfig = chatConfigUtils.editChaConfig(configEditCmd, user);
|
||||
chaConfigRepository.updateConfig(chaConfig);
|
||||
return configEditCmd.getDomainId();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* domain administrators have the right to modify related configuration information.
|
||||
*/
|
||||
private Boolean permissionCheckLogic(Long domainId, String staffName) {
|
||||
// todo
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChatConfigInfo> search(ChatConfigFilter filter, User user) {
|
||||
log.info("[search domain extend] object:{}", JsonUtil.toString(filter, true));
|
||||
List<ChatConfigInfo> chaConfigDescList = chaConfigRepository.getChatConfig(filter);
|
||||
return chaConfigDescList;
|
||||
}
|
||||
|
||||
|
||||
public ChatConfigInfo fetchConfigByDomainId(Long domainId) {
|
||||
return chaConfigRepository.getConfigByDomainId(domainId);
|
||||
}
|
||||
|
||||
public EntityRichInfo fetchEntityDescByDomainId(Long domainId) {
|
||||
|
||||
ChatConfigInfo chaConfigDesc = chaConfigRepository.getConfigByDomainId(domainId);
|
||||
return fetchEntityDescByConfig(chaConfigDesc);
|
||||
}
|
||||
|
||||
public EntityRichInfo fetchEntityDescByConfig(ChatConfigInfo chatConfigDesc) {
|
||||
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());
|
||||
entityDesc.setDomainName(domain.getName());
|
||||
entityDesc.setNames(chatConfigDesc.getEntity().getNames());
|
||||
|
||||
entityDesc.setEntityIds(chatConfigUtils.generateDimDesc(chatConfigDesc.getEntity().getEntityIds(), domain));
|
||||
entityDesc.setEntityInternalDetailDesc(
|
||||
chatConfigUtils.generateEntityDetailData(chatConfigDesc.getEntity().getDetailData(), domain));
|
||||
return entityDesc;
|
||||
}
|
||||
|
||||
|
||||
public List<DefaultMetric> fetchDefaultMetricDescByDomainId(Long domainId) {
|
||||
ChatConfigInfo chatConfigDesc = chaConfigRepository.getConfigByDomainId(domainId);
|
||||
return fetchDefaultMetricDescByConfig(chatConfigDesc);
|
||||
}
|
||||
|
||||
public List<DefaultMetric> fetchDefaultMetricDescByConfig(ChatConfigInfo chatConfigDesc) {
|
||||
Long domainId = chatConfigDesc.getDomainId();
|
||||
DomainSchemaResp domain = semanticLayer.getDomainSchemaInfo(domainId);
|
||||
List<DefaultMetric> defaultMetricDescList = new ArrayList<>();
|
||||
if (Objects.isNull(chatConfigDesc) || CollectionUtils.isEmpty(chatConfigDesc.getDefaultMetrics())) {
|
||||
log.info("domainId:{}, defaultMetricDescList info is null", domainId);
|
||||
return defaultMetricDescList;
|
||||
}
|
||||
List<Long> metricIds = chatConfigDesc.getDefaultMetrics().stream()
|
||||
.map(defaultMetricInfo -> defaultMetricInfo.getMetricId()).collect(Collectors.toList());
|
||||
Map<Long, MetricSchemaResp> metricIdAndDescPair = chatConfigUtils.generateMetricIdAndDescPair(metricIds,
|
||||
domain);
|
||||
chatConfigDesc.getDefaultMetrics().stream().forEach(defaultMetricInfo -> {
|
||||
DefaultMetric defaultMetricDesc = new DefaultMetric();
|
||||
BeanUtils.copyProperties(defaultMetricInfo, defaultMetricDesc);
|
||||
if (metricIdAndDescPair.containsKey(defaultMetricInfo.getMetricId())) {
|
||||
MetricSchemaResp metricDesc = metricIdAndDescPair.get(defaultMetricInfo.getMetricId());
|
||||
defaultMetricDesc.setBizName(metricDesc.getBizName());
|
||||
defaultMetricDesc.setName(metricDesc.getName());
|
||||
}
|
||||
defaultMetricDescList.add(defaultMetricDesc);
|
||||
});
|
||||
return defaultMetricDescList;
|
||||
}
|
||||
|
||||
public ItemVisibilityInfo fetchVisibilityDescByDomainId(Long domainId) {
|
||||
ChatConfigInfo chatConfigDesc = chaConfigRepository.getConfigByDomainId(domainId);
|
||||
return fetchVisibilityDescByConfig(chatConfigDesc);
|
||||
}
|
||||
|
||||
private ItemVisibilityInfo fetchVisibilityDescByConfig(ChatConfigInfo chatConfigDesc) {
|
||||
ItemVisibilityInfo itemVisibilityDesc = new ItemVisibilityInfo();
|
||||
Long domainId = chatConfigDesc.getDomainId();
|
||||
DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domainId);
|
||||
List<Long> dimIdAllList = chatConfigUtils.generateAllDimIdList(domainSchemaDesc);
|
||||
List<Long> metricIdAllList = chatConfigUtils.generateAllMetricIdList(domainSchemaDesc);
|
||||
|
||||
List<Long> blackDimIdList = new ArrayList<>();
|
||||
List<Long> blackMetricIdList = new ArrayList<>();
|
||||
if (Objects.nonNull(chatConfigDesc.getVisibility())) {
|
||||
if (!CollectionUtils.isEmpty(chatConfigDesc.getVisibility().getBlackDimIdList())) {
|
||||
blackDimIdList.addAll(chatConfigDesc.getVisibility().getBlackDimIdList());
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(chatConfigDesc.getVisibility().getBlackMetricIdList())) {
|
||||
blackMetricIdList.addAll(chatConfigDesc.getVisibility().getBlackMetricIdList());
|
||||
}
|
||||
}
|
||||
List<Long> whiteMetricIdList = metricIdAllList.stream().filter(id -> !blackMetricIdList.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
List<Long> whiteDimIdList = dimIdAllList.stream().filter(id -> !blackDimIdList.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
itemVisibilityDesc.setBlackDimIdList(blackDimIdList);
|
||||
itemVisibilityDesc.setBlackMetricIdList(blackMetricIdList);
|
||||
itemVisibilityDesc.setWhiteDimIdList(whiteDimIdList);
|
||||
itemVisibilityDesc.setWhiteMetricIdList(whiteMetricIdList);
|
||||
|
||||
return itemVisibilityDesc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatConfigRichInfo getConfigRichInfo(Long domainId) {
|
||||
ChatConfigRichInfo chaConfigRichDesc = new ChatConfigRichInfo();
|
||||
ChatConfigInfo chatConfigDesc = chaConfigRepository.getConfigByDomainId(domainId);
|
||||
BeanUtils.copyProperties(chatConfigDesc, chaConfigRichDesc);
|
||||
|
||||
DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(domainId);
|
||||
chaConfigRichDesc.setBizName(domainSchemaDesc.getBizName());
|
||||
chaConfigRichDesc.setName(domainSchemaDesc.getName());
|
||||
|
||||
chaConfigRichDesc.setDefaultMetrics(fetchDefaultMetricDescByConfig(chatConfigDesc));
|
||||
chaConfigRichDesc.setVisibility(fetchVisibilityDescByConfig(chatConfigDesc));
|
||||
chaConfigRichDesc.setEntity(fetchEntityDescByConfig(chatConfigDesc));
|
||||
|
||||
return chaConfigRichDesc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
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.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.DefaultSemanticInternalUtils;
|
||||
import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter;
|
||||
import com.tencent.supersonic.common.pojo.DateConf;
|
||||
import com.tencent.supersonic.common.pojo.SchemaItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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
|
||||
public class DomainEntityService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DomainEntityService.class);
|
||||
@Autowired
|
||||
private SemanticLayer semanticLayer;
|
||||
|
||||
@Autowired
|
||||
private DefaultSemanticInternalUtils defaultSemanticUtils;
|
||||
|
||||
public EntityInfo getEntityInfo(QueryContextReq queryCtx, ChatContext chatCtx, User user) {
|
||||
SemanticParseInfo parseInfo = queryCtx.getParseInfo();
|
||||
|
||||
if (parseInfo != null && parseInfo.getDomainId() > 0) {
|
||||
EntityInfo entityInfo = getEntityInfo(parseInfo.getDomainId());
|
||||
if (parseInfo.getDimensionFilters().size() <= 0) {
|
||||
entityInfo.setMetrics(null);
|
||||
entityInfo.setDimensions(null);
|
||||
return entityInfo;
|
||||
}
|
||||
if (entityInfo.getDomainInfo() != null && entityInfo.getDomainInfo().getPrimaryEntityBizName() != null) {
|
||||
String domainInfoPrimaryName = entityInfo.getDomainInfo().getPrimaryEntityBizName();
|
||||
String domainInfoId = "";
|
||||
for (Filter chatFilter : parseInfo.getDimensionFilters()) {
|
||||
if (chatFilter.getBizName().equals(domainInfoPrimaryName)) {
|
||||
if (chatFilter.getOperator().equals(FilterOperatorEnum.EQUALS)) {
|
||||
domainInfoId = chatFilter.getValue().toString();
|
||||
}
|
||||
if (chatFilter.getOperator().equals(FilterOperatorEnum.IN)) {
|
||||
domainInfoId = ((List<String>) chatFilter.getValue()).get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!"".equals(domainInfoId)) {
|
||||
try {
|
||||
setMainDomain(entityInfo, parseInfo.getDomainId(),
|
||||
domainInfoId, user);
|
||||
|
||||
return entityInfo;
|
||||
} catch (Exception e) {
|
||||
logger.error("setMaintDomain error {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public EntityInfo getEntityInfo(Long domain) {
|
||||
ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(domain);
|
||||
return getEntityInfo(chaConfigRichDesc.getEntity());
|
||||
}
|
||||
|
||||
private EntityInfo getEntityInfo(EntityRichInfo entityDesc) {
|
||||
EntityInfo entityInfo = new EntityInfo();
|
||||
|
||||
if (entityDesc != null) {
|
||||
DomainInfo domainInfo = new DomainInfo();
|
||||
domainInfo.setItemId(Integer.valueOf(entityDesc.getDomainId().intValue()));
|
||||
domainInfo.setName(entityDesc.getDomainName());
|
||||
domainInfo.setWords(entityDesc.getNames());
|
||||
domainInfo.setBizName(entityDesc.getDomainBizName());
|
||||
if (entityDesc.getEntityIds().size() > 0) {
|
||||
domainInfo.setPrimaryEntityBizName(entityDesc.getEntityIds().get(0).getBizName());
|
||||
}
|
||||
entityInfo.setDomainInfo(domainInfo);
|
||||
List<DataInfo> dimensions = new ArrayList<>();
|
||||
List<DataInfo> metrics = new ArrayList<>();
|
||||
if (entityDesc.getEntityInternalDetailDesc() != null) {
|
||||
for (DimSchemaResp dimensionDesc : entityDesc.getEntityInternalDetailDesc().getDimensionList()) {
|
||||
DataInfo mainEntityDimension = new DataInfo();
|
||||
mainEntityDimension.setItemId(dimensionDesc.getId().intValue());
|
||||
mainEntityDimension.setName(dimensionDesc.getName());
|
||||
mainEntityDimension.setBizName(dimensionDesc.getBizName());
|
||||
dimensions.add(mainEntityDimension);
|
||||
}
|
||||
entityInfo.setDimensions(dimensions);
|
||||
for (MetricSchemaResp metricDesc : entityDesc.getEntityInternalDetailDesc().getMetricList()) {
|
||||
DataInfo dataInfo = new DataInfo();
|
||||
dataInfo.setName(metricDesc.getName());
|
||||
dataInfo.setBizName(metricDesc.getBizName());
|
||||
dataInfo.setItemId(metricDesc.getId().intValue());
|
||||
metrics.add(dataInfo);
|
||||
}
|
||||
entityInfo.setMetrics(metrics);
|
||||
}
|
||||
}
|
||||
return entityInfo;
|
||||
}
|
||||
|
||||
public void setMainDomain(EntityInfo domainInfo, Long domain, String entity, User user) {
|
||||
domainInfo.setEntityId(entity);
|
||||
SemanticParseInfo semanticParseInfo = new SemanticParseInfo();
|
||||
semanticParseInfo.setDomainId(Long.valueOf(domain));
|
||||
semanticParseInfo.setNativeQuery(true);
|
||||
semanticParseInfo.setMetrics(getMetrics(domainInfo));
|
||||
semanticParseInfo.setDimensions(getDimensions(domainInfo));
|
||||
DateConf dateInfo = new DateConf();
|
||||
dateInfo.setUnit(1);
|
||||
dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS);
|
||||
semanticParseInfo.setDateInfo(dateInfo);
|
||||
|
||||
// add filter
|
||||
Filter chatFilter = new Filter();
|
||||
chatFilter.setValue(String.valueOf(entity));
|
||||
chatFilter.setOperator(FilterOperatorEnum.EQUALS);
|
||||
chatFilter.setBizName(getEntityPrimaryName(domainInfo));
|
||||
List<Filter> chatFilters = new ArrayList<>();
|
||||
chatFilters.add(chatFilter);
|
||||
semanticParseInfo.setDimensionFilters(chatFilters);
|
||||
|
||||
QueryResultWithSchemaResp queryResultWithColumns = null;
|
||||
try {
|
||||
queryResultWithColumns = semanticLayer.queryByStruct(SchemaInfoConverter.convertTo(semanticParseInfo),
|
||||
user);
|
||||
} catch (Exception e) {
|
||||
logger.warn("setMainDomain queryByStruct error, e:", e);
|
||||
}
|
||||
|
||||
if (queryResultWithColumns != null) {
|
||||
if (!CollectionUtils.isEmpty(queryResultWithColumns.getResultList())
|
||||
&& queryResultWithColumns.getResultList().size() > 0) {
|
||||
Map<String, Object> result = queryResultWithColumns.getResultList().get(0);
|
||||
for (Map.Entry<String, Object> entry : result.entrySet()) {
|
||||
String entryKey = getEntryKey(entry);
|
||||
if (entry.getValue() == null || entryKey == null) {
|
||||
continue;
|
||||
}
|
||||
domainInfo.getDimensions().stream().filter(i -> entryKey.equals(i.getBizName()))
|
||||
.forEach(i -> i.setValue(entry.getValue().toString()));
|
||||
domainInfo.getMetrics().stream().filter(i -> entryKey.equals(i.getBizName()))
|
||||
.forEach(i -> i.setValue(entry.getValue().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<SchemaItem> getDimensions(EntityInfo domainInfo) {
|
||||
List<SchemaItem> dimensions = new ArrayList<>();
|
||||
for (DataInfo mainEntityDimension : domainInfo.getDimensions()) {
|
||||
SchemaItem dimension = new SchemaItem();
|
||||
dimension.setBizName(mainEntityDimension.getBizName());
|
||||
dimensions.add(dimension);
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
private String getEntryKey(Map.Entry<String, Object> entry) {
|
||||
// metric parser special handle, TODO delete
|
||||
String entryKey = entry.getKey();
|
||||
if (entryKey.contains("__")) {
|
||||
entryKey = entryKey.split("__")[1];
|
||||
}
|
||||
return entryKey;
|
||||
}
|
||||
|
||||
private List<SchemaItem> getMetrics(EntityInfo domainInfo) {
|
||||
List<SchemaItem> metrics = new ArrayList<>();
|
||||
for (DataInfo metricValue : domainInfo.getMetrics()) {
|
||||
SchemaItem metric = new SchemaItem();
|
||||
metric.setBizName(metricValue.getBizName());
|
||||
metrics.add(metric);
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
private String getEntityPrimaryName(EntityInfo domainInfo) {
|
||||
return domainInfo.getDomainInfo().getPrimaryEntityBizName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
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.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.domain.pojo.chat.QueryData;
|
||||
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.common.util.json.JsonUtil;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class QueryServiceImpl implements QueryService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QueryServiceImpl.class);
|
||||
private List<SchemaMapper> schemaMappers;
|
||||
private List<SemanticParser> 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());
|
||||
}
|
||||
|
||||
public QueryResultResp executeQuery(QueryContextReq queryCtx) throws Exception {
|
||||
schemaMappers.stream().forEach(s -> s.map(queryCtx));
|
||||
|
||||
// in order to support multi-turn conversation, we need to consider chat context
|
||||
ChatContext chatCtx = chatService.getOrCreateContext(queryCtx.getChatId());
|
||||
|
||||
for (SemanticParser semanticParser : semanticParsers) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SemanticParseInfo queryContext(QueryContextReq queryCtx) {
|
||||
ChatContext context = chatService.getOrCreateContext(queryCtx.getChatId());
|
||||
return context.getParseInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResultResp queryData(QueryData queryData, User user) throws Exception {
|
||||
SemanticParseInfo semanticParseInfo = new SemanticParseInfo();
|
||||
QueryResultResp queryResponse = new QueryResultResp();
|
||||
BeanUtils.copyProperties(queryData, semanticParseInfo);
|
||||
QueryResultWithSchemaResp resultWithColumns = semanticLayer.queryByStruct(
|
||||
SchemaInfoConverter.convertTo(semanticParseInfo), user);
|
||||
queryResponse.setQueryColumns(resultWithColumns.getColumns());
|
||||
queryResponse.setQueryResults(resultWithColumns.getResultList());
|
||||
return queryResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
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.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;
|
||||
|
||||
/***
|
||||
* Recommend Service impl
|
||||
*/
|
||||
@Service
|
||||
public class RecommendServiceImpl implements RecommendService {
|
||||
|
||||
@Autowired
|
||||
private SemanticLayer semanticLayer;
|
||||
|
||||
@Override
|
||||
public RecommendResponse recommend(QueryContextReq queryCtx) {
|
||||
Integer domainId = queryCtx.getDomainId();
|
||||
if (Objects.isNull(domainId)) {
|
||||
return new RecommendResponse();
|
||||
}
|
||||
|
||||
DomainSchemaResp domainSchemaDesc = semanticLayer.getDomainSchemaInfo(
|
||||
Long.valueOf(domainId));
|
||||
|
||||
List<RecommendResponse.Item> dimensions = domainSchemaDesc.getDimensions().stream().map(dimSchemaDesc -> {
|
||||
RecommendResponse.Item item = new RecommendResponse.Item();
|
||||
item.setDomain(domainId);
|
||||
item.setName(dimSchemaDesc.getName());
|
||||
item.setBizName(dimSchemaDesc.getBizName());
|
||||
return item;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
List<RecommendResponse.Item> metrics = domainSchemaDesc.getMetrics().stream().map(metricSchemaDesc -> {
|
||||
RecommendResponse.Item item = new RecommendResponse.Item();
|
||||
item.setDomain(domainId);
|
||||
item.setName(metricSchemaDesc.getName());
|
||||
item.setBizName(metricSchemaDesc.getBizName());
|
||||
return item;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
RecommendResponse response = new RecommendResponse();
|
||||
response.setDimensions(dimensions);
|
||||
response.setMetrics(metrics);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package com.tencent.supersonic.chat.application;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.hankcs.hanlp.seg.common.Term;
|
||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementType;
|
||||
import com.tencent.supersonic.chat.api.request.QueryContextReq;
|
||||
import com.tencent.supersonic.chat.api.service.SemanticLayer;
|
||||
import com.tencent.supersonic.chat.application.knowledge.NatureHelper;
|
||||
import com.tencent.supersonic.chat.application.mapper.SearchMatchStrategy;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.DomainInfoStat;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.DomainWithSemanticType;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.MatchText;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.SearchResult;
|
||||
import com.tencent.supersonic.chat.domain.pojo.semantic.DomainInfos;
|
||||
import com.tencent.supersonic.chat.domain.service.ChatService;
|
||||
import com.tencent.supersonic.chat.domain.service.SearchService;
|
||||
import com.tencent.supersonic.chat.domain.utils.NatureConverter;
|
||||
import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter;
|
||||
import com.tencent.supersonic.common.nlp.ItemDO;
|
||||
import com.tencent.supersonic.common.nlp.MapResult;
|
||||
import com.tencent.supersonic.common.nlp.NatureType;
|
||||
import com.tencent.supersonic.common.nlp.WordNature;
|
||||
import com.tencent.supersonic.knowledge.application.online.BaseWordNature;
|
||||
import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* search service impl
|
||||
*/
|
||||
@Service
|
||||
public class SearchServiceImpl implements SearchService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SearchServiceImpl.class);
|
||||
@Autowired
|
||||
private SemanticLayer semanticLayer;
|
||||
@Autowired
|
||||
private ChatService chatService;
|
||||
|
||||
@Autowired
|
||||
private SearchMatchStrategy searchMatchStrategy;
|
||||
|
||||
private static final int RESULT_SIZE = 10;
|
||||
|
||||
|
||||
@Override
|
||||
public List<SearchResult> search(QueryContextReq queryCtx) {
|
||||
String queryText = queryCtx.getQueryText();
|
||||
// 1.get meta info
|
||||
DomainInfos domainInfosDb = SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>()));
|
||||
List<ItemDO> metricsDb = domainInfosDb.getMetrics();
|
||||
final Map<Integer, String> domainToName = domainInfosDb.getDomainToName();
|
||||
// 2.detect by segment
|
||||
List<Term> originals = HanlpHelper.getSegment().seg(queryText).stream().collect(Collectors.toList());
|
||||
Map<MatchText, List<MapResult>> regTextMap = searchMatchStrategy.matchWithMatchText(queryText, originals);
|
||||
|
||||
// 3.get the most matching data
|
||||
Optional<Entry<MatchText, List<MapResult>>> mostSimilarSearchResult = regTextMap.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> CollectionUtils.isNotEmpty(entry.getValue()))
|
||||
.reduce((entry1, entry2) ->
|
||||
entry1.getKey().getDetectSegment().length() >= entry2.getKey().getDetectSegment().length()
|
||||
? entry1 : entry2);
|
||||
logger.debug("mostSimilarSearchResult:{}", mostSimilarSearchResult);
|
||||
// 4.optimize the results after the query
|
||||
if (!mostSimilarSearchResult.isPresent()) {
|
||||
logger.info("unable to find any information through search , queryCtx:{}", queryCtx);
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
Map.Entry<MatchText, List<MapResult>> searchTextEntry = mostSimilarSearchResult.get();
|
||||
logger.info("searchTextEntry:{},queryCtx:{}", searchTextEntry, queryCtx);
|
||||
|
||||
Set<SearchResult> searchResults = new LinkedHashSet();
|
||||
DomainInfoStat domainStat = NatureHelper.getDomainStat(originals);
|
||||
|
||||
List<Integer> possibleDomains = getPossibleDomains(queryCtx, originals, domainStat);
|
||||
|
||||
// 4.1 priority dimension metric
|
||||
boolean existMetricAndDimension = searchMetricAndDimension(new HashSet<>(possibleDomains), domainToName,
|
||||
searchTextEntry,
|
||||
searchResults);
|
||||
|
||||
// 4.2 process based on dimension values
|
||||
MatchText matchText = searchTextEntry.getKey();
|
||||
Map<String, String> natureToNameMap = getNatureToNameMap(searchTextEntry);
|
||||
|
||||
for (Map.Entry<String, String> natureToNameEntry : natureToNameMap.entrySet()) {
|
||||
searchDimensionValue(metricsDb, domainToName, domainStat.getMetricDomainCount(), searchResults,
|
||||
existMetricAndDimension, matchText, natureToNameMap, natureToNameEntry);
|
||||
}
|
||||
return searchResults.stream().limit(RESULT_SIZE).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Integer> getPossibleDomains(QueryContextReq queryCtx, List<Term> originals,
|
||||
DomainInfoStat domainStat) {
|
||||
List<Integer> possibleDomains = NatureHelper.selectPossibleDomains(originals);
|
||||
|
||||
Long contextDomain = chatService.getContextDomain(queryCtx.getChatId());
|
||||
|
||||
logger.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)) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
result.add(Math.toIntExact(contextDomain));
|
||||
return result;
|
||||
}
|
||||
return possibleDomains;
|
||||
}
|
||||
|
||||
private boolean nothingOrOnlyMetric(DomainInfoStat domainStat) {
|
||||
return domainStat.getMetricDomainCount() >= 0 && domainStat.getDimensionDomainCount() <= 0
|
||||
&& domainStat.getDimensionValueDomainCount() <= 0 && domainStat.getDomainCount() <= 0;
|
||||
}
|
||||
|
||||
private boolean effectiveDomain(Long contextDomain) {
|
||||
return Objects.nonNull(contextDomain) && contextDomain > 0;
|
||||
}
|
||||
|
||||
private void searchDimensionValue(List<ItemDO> metricsDb,
|
||||
Map<Integer, String> domainToName,
|
||||
long metricDomainCount,
|
||||
Set<SearchResult> searchResults,
|
||||
boolean existMetricAndDimension,
|
||||
MatchText matchText,
|
||||
Map<String, String> natureToNameMap,
|
||||
Map.Entry<String, String> natureToNameEntry) {
|
||||
String nature = natureToNameEntry.getKey();
|
||||
String wordName = natureToNameEntry.getValue();
|
||||
|
||||
Integer domain = BaseWordNature.getDomain(nature);
|
||||
SchemaElementType schemaElementType = NatureConverter.convertTo(nature);
|
||||
|
||||
if (SchemaElementType.ENTITY.equals(schemaElementType)) {
|
||||
return;
|
||||
}
|
||||
// If there are no metric/dimension, complete the metric information
|
||||
if (metricDomainCount <= 0 && !existMetricAndDimension) {
|
||||
searchResults.add(
|
||||
new SearchResult(matchText.getRegText() + wordName, wordName, domainToName.get(domain), domain,
|
||||
schemaElementType));
|
||||
int metricSize = RESULT_SIZE / (natureToNameMap.entrySet().size());
|
||||
if (metricSize <= 1) {
|
||||
metricSize = 1;
|
||||
}
|
||||
List<String> metrics = filerMetricsByDomain(metricsDb, domain).stream().limit(metricSize).collect(
|
||||
Collectors.toList());
|
||||
;
|
||||
for (String metric : metrics) {
|
||||
String subRecommend = matchText.getRegText() + wordName + NatureType.SPACE + metric;
|
||||
searchResults.add(
|
||||
new SearchResult(subRecommend, wordName + NatureType.SPACE + metric, domainToName.get(domain),
|
||||
domain, false));
|
||||
}
|
||||
} else {
|
||||
searchResults.add(
|
||||
new SearchResult(matchText.getRegText() + wordName, wordName, domainToName.get(domain), domain,
|
||||
schemaElementType));
|
||||
}
|
||||
}
|
||||
|
||||
protected List<String> filerMetricsByDomain(List<ItemDO> metricsDb, Integer domain) {
|
||||
if (CollectionUtils.isEmpty(metricsDb)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return metricsDb.stream()
|
||||
.filter(mapDO -> Objects.nonNull(mapDO) && domain.equals(mapDO.getDomain()))
|
||||
.sorted(Comparator.comparing(ItemDO::getUseCnt).reversed())
|
||||
.flatMap(entry -> {
|
||||
List<String> result = new ArrayList<>();
|
||||
result.add(entry.getName());
|
||||
return result.stream();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/***
|
||||
* convert nature to name
|
||||
* @param recommendTextListEntry
|
||||
* @return
|
||||
*/
|
||||
private Map<String, String> getNatureToNameMap(Map.Entry<MatchText, List<MapResult>> recommendTextListEntry) {
|
||||
List<MapResult> recommendValues = recommendTextListEntry.getValue();
|
||||
return recommendValues.stream()
|
||||
.flatMap(entry -> entry.getNatures().stream().map(nature -> {
|
||||
WordNature posDO = new WordNature();
|
||||
posDO.setWord(entry.getName());
|
||||
posDO.setNature(nature);
|
||||
return posDO;
|
||||
}
|
||||
)).sorted(Comparator.comparingInt(a -> a.getWord().length()))
|
||||
.collect(Collectors.toMap(WordNature::getNature, WordNature::getWord, (value1, value2) -> value1,
|
||||
LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private boolean searchMetricAndDimension(Set<Integer> possibleDomains, Map<Integer, String> domainToName,
|
||||
Map.Entry<MatchText, List<MapResult>> searchTextEntry, Set<SearchResult> searchResults) {
|
||||
boolean existMetric = false;
|
||||
|
||||
MatchText matchText = searchTextEntry.getKey();
|
||||
List<MapResult> mapResults = searchTextEntry.getValue();
|
||||
|
||||
for (MapResult mapResult : mapResults) {
|
||||
|
||||
List<DomainWithSemanticType> dimensionMetricClassIds = mapResult.getNatures().stream()
|
||||
.map(nature -> new DomainWithSemanticType(BaseWordNature.getDomain(nature),
|
||||
NatureConverter.convertTo(nature)))
|
||||
.filter(entry -> matchCondition(entry, possibleDomains)).collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isNotEmpty(dimensionMetricClassIds)) {
|
||||
for (DomainWithSemanticType domainWithSemanticType : dimensionMetricClassIds) {
|
||||
existMetric = true;
|
||||
Integer domain = domainWithSemanticType.getDomain();
|
||||
SchemaElementType semanticType = domainWithSemanticType.getSemanticType();
|
||||
searchResults.add(
|
||||
new SearchResult(matchText.getRegText() + mapResult.getName(), mapResult.getName(),
|
||||
domainToName.get(domain), domain, semanticType));
|
||||
}
|
||||
}
|
||||
logger.info("parseResult:{},dimensionMetricClassIds:{},possibleDomains:{}", mapResult,
|
||||
dimensionMetricClassIds, possibleDomains);
|
||||
}
|
||||
return existMetric;
|
||||
}
|
||||
|
||||
private boolean matchCondition(DomainWithSemanticType entry, Set<Integer> possibleDomains) {
|
||||
if (!(SchemaElementType.METRIC.equals(entry.getSemanticType()) || SchemaElementType.DIMENSION.equals(
|
||||
entry.getSemanticType()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(possibleDomains)) {
|
||||
return true;
|
||||
}
|
||||
return possibleDomains.contains(entry.getDomain());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.tencent.supersonic.chat.application.knowledge;
|
||||
|
||||
import com.tencent.supersonic.common.nlp.WordNature;
|
||||
import com.tencent.supersonic.knowledge.domain.service.OnlineKnowledgeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ApplicationStartedInit implements ApplicationListener<ApplicationStartedEvent> {
|
||||
|
||||
@Autowired
|
||||
private OnlineKnowledgeService onlineKnowledgeService;
|
||||
|
||||
@Autowired
|
||||
private WordNatureService wordNatureService;
|
||||
|
||||
private List<WordNature> preWordNatures = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationStartedEvent event) {
|
||||
try {
|
||||
log.info("ApplicationStartedInit start");
|
||||
|
||||
List<WordNature> wordNatures = wordNatureService.getAllWordNature();
|
||||
|
||||
this.preWordNatures = wordNatures;
|
||||
|
||||
onlineKnowledgeService.reloadAllData(wordNatures);
|
||||
|
||||
log.info("ApplicationStartedInit end");
|
||||
} catch (Exception e) {
|
||||
log.error("ApplicationStartedInit error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* reload knowledge task
|
||||
*/
|
||||
@Scheduled(cron = "${reload.knowledge.corn:0 0/1 * * * ?}")
|
||||
public void reloadKnowledge() {
|
||||
log.debug("reloadKnowledge start");
|
||||
|
||||
try {
|
||||
List<WordNature> wordNatures = wordNatureService.getAllWordNature();
|
||||
|
||||
if (CollectionUtils.isEqualCollection(wordNatures, preWordNatures)) {
|
||||
log.debug("wordNatures is not change, reloadKnowledge end");
|
||||
return;
|
||||
}
|
||||
this.preWordNatures = wordNatures;
|
||||
|
||||
onlineKnowledgeService.updateOnlineKnowledge(wordNatureService.getAllWordNature());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("reloadKnowledge error", e);
|
||||
}
|
||||
|
||||
log.debug("reloadKnowledge end");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.tencent.supersonic.chat.application.knowledge;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||
import com.tencent.supersonic.chat.domain.dataobject.DimValueDO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.Dim4Dict;
|
||||
import com.tencent.supersonic.chat.domain.utils.DictMetaUtils;
|
||||
import com.tencent.supersonic.chat.domain.utils.DictQueryUtils;
|
||||
import com.tencent.supersonic.common.constant.Constants;
|
||||
import com.tencent.supersonic.common.enums.TaskStatusEnum;
|
||||
import com.tencent.supersonic.knowledge.domain.FileHandler;
|
||||
import com.tencent.supersonic.knowledge.domain.converter.DictTaskConverter;
|
||||
import com.tencent.supersonic.knowledge.domain.dataobject.DimValueDictTaskPO;
|
||||
import com.tencent.supersonic.knowledge.domain.pojo.DictConfig;
|
||||
import com.tencent.supersonic.knowledge.domain.pojo.DictTaskFilter;
|
||||
import com.tencent.supersonic.knowledge.domain.pojo.DictUpdateMode;
|
||||
import com.tencent.supersonic.knowledge.domain.pojo.DimValue2DictCommand;
|
||||
import com.tencent.supersonic.knowledge.domain.pojo.DimValueDictInfo;
|
||||
import com.tencent.supersonic.knowledge.domain.repository.DictRepository;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DictApplicationService {
|
||||
|
||||
@Value("${dict.flush.enable:true}")
|
||||
private Boolean dictFlushEnable;
|
||||
|
||||
@Value("${dict.file.type:txt}")
|
||||
private String dictFileType;
|
||||
private String dimValue = "DimValue_%d_%d";
|
||||
private String dateTimeFormatter = "yyyyMMddHHmmss";
|
||||
|
||||
|
||||
private final DictMetaUtils metaUtils;
|
||||
private final DictQueryUtils dictQueryUtils;
|
||||
private final FileHandler fileHandler;
|
||||
private final DictRepository dictRepository;
|
||||
|
||||
public DictApplicationService(DictMetaUtils metaUtils,
|
||||
DictQueryUtils dictQueryUtils,
|
||||
FileHandler fileHandler,
|
||||
DictRepository dictRepository) {
|
||||
this.metaUtils = metaUtils;
|
||||
this.dictQueryUtils = dictQueryUtils;
|
||||
this.fileHandler = fileHandler;
|
||||
this.dictRepository = dictRepository;
|
||||
}
|
||||
|
||||
public Long addDictTask(DimValue2DictCommand dimValue2DictCommend, User user) {
|
||||
if (!dictFlushEnable) {
|
||||
return 0L;
|
||||
}
|
||||
DimValueDictTaskPO dimValueDictTaskPO = DictTaskConverter.generateDimValueDictTaskPO(dimValue2DictCommend,
|
||||
user);
|
||||
log.info("[addDictTask] dimValueDictTaskPO:{}", dimValueDictTaskPO);
|
||||
dictRepository.createDimValueDictTask(dimValueDictTaskPO);
|
||||
TaskStatusEnum finalStatus = TaskStatusEnum.SUCCESS;
|
||||
try {
|
||||
//1. construct internal dictionary requirements
|
||||
List<DimValueDO> dimValueDOList = metaUtils.generateDimValueInfo(dimValue2DictCommend);
|
||||
log.info("dimValueDOList:{}", dimValueDOList);
|
||||
//2. query dimension value information
|
||||
for (DimValueDO dimValueDO : dimValueDOList) {
|
||||
Long domainId = dimValueDO.getDomainId();
|
||||
DefaultMetric defaultMetricDesc = dimValueDO.getDefaultMetricDescList().get(0);
|
||||
for (Dim4Dict dim4Dict : dimValueDO.getDimensions()) {
|
||||
List<String> data = dictQueryUtils.fetchDimValueSingle(domainId, defaultMetricDesc, dim4Dict, user);
|
||||
//3. local file changes
|
||||
String fileName = String.format(dimValue + Constants.DOT + dictFileType, domainId,
|
||||
dim4Dict.getDimId());
|
||||
fileHandler.writeFile(data, fileName, false);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("addDictInfo exception:", e);
|
||||
finalStatus = TaskStatusEnum.ERROR;
|
||||
}
|
||||
dictRepository.updateDictTaskStatus(finalStatus.getCode(), dimValueDictTaskPO);
|
||||
return 1L;
|
||||
}
|
||||
|
||||
|
||||
public Long deleteDictTask(DimValue2DictCommand dimValue2DictCommend, User user) {
|
||||
if (!dictFlushEnable) {
|
||||
return 0L;
|
||||
}
|
||||
if (Objects.isNull(dimValue2DictCommend) || DictUpdateMode.REALTIME_DELETE.equals(
|
||||
dimValue2DictCommend.getUpdateMode())) {
|
||||
throw new RuntimeException("illegal parameter");
|
||||
}
|
||||
Map<Long, List<Long>> domainAndDimPair = dimValue2DictCommend.getDomainAndDimPair();
|
||||
if (CollectionUtils.isEmpty(domainAndDimPair)) {
|
||||
return 0L;
|
||||
}
|
||||
for (Long domainId : domainAndDimPair.keySet()) {
|
||||
if (CollectionUtils.isEmpty(domainAndDimPair.get(domainId))) {
|
||||
continue;
|
||||
}
|
||||
for (Long dimId : domainAndDimPair.get(domainId)) {
|
||||
String fileName = String.format(dimValue + Constants.DOT + dictFileType, domainId, dimId);
|
||||
fileHandler.deleteDictFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
return 1L;
|
||||
}
|
||||
|
||||
public String getDictRootPath() {
|
||||
return fileHandler.getDictRootPath();
|
||||
}
|
||||
|
||||
|
||||
public List<DimValueDictInfo> searchDictTaskList(DictTaskFilter filter, User user) {
|
||||
return dictRepository.searchDictTaskList(filter);
|
||||
}
|
||||
|
||||
public DictConfig getDictInfoByDomainId(Long domainId) {
|
||||
return dictRepository.getDictInfoByDomainId(domainId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.tencent.supersonic.chat.application.knowledge;
|
||||
|
||||
import com.hankcs.hanlp.corpus.tag.Nature;
|
||||
import com.hankcs.hanlp.seg.common.Term;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.DomainInfoStat;
|
||||
import com.tencent.supersonic.common.nlp.NatureType;
|
||||
import com.tencent.supersonic.knowledge.application.online.BaseWordNature;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* nature parse helper
|
||||
*/
|
||||
public class NatureHelper {
|
||||
|
||||
|
||||
private static boolean isDomainOrEntity(Term term, Integer domain) {
|
||||
return (NatureType.NATURE_SPILT + domain).equals(term.nature.toString()) || term.nature.toString()
|
||||
.endsWith(NatureType.ENTITY.getType());
|
||||
}
|
||||
|
||||
public static Integer getDomainByNature(Nature nature) {
|
||||
if (nature.startsWith(NatureType.NATURE_SPILT)) {
|
||||
String[] dimensionValues = nature.toString().split(NatureType.NATURE_SPILT);
|
||||
if (StringUtils.isNumeric(dimensionValues[1])) {
|
||||
return Integer.valueOf(dimensionValues[1]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static Integer getDomain(String nature) {
|
||||
String[] split = nature.split(NatureType.NATURE_SPILT);
|
||||
return Integer.valueOf(split[1]);
|
||||
}
|
||||
|
||||
public static boolean isDimensionValueClassId(String nature) {
|
||||
if (StringUtils.isEmpty(nature)) {
|
||||
return false;
|
||||
}
|
||||
if (!nature.startsWith(NatureType.NATURE_SPILT)) {
|
||||
return false;
|
||||
}
|
||||
String[] split = nature.split(NatureType.NATURE_SPILT);
|
||||
if (split.length <= 1) {
|
||||
return false;
|
||||
}
|
||||
return !nature.endsWith(NatureType.METRIC.getType()) && !nature.endsWith(NatureType.DIMENSION.getType())
|
||||
&& StringUtils.isNumeric(split[1]);
|
||||
}
|
||||
|
||||
public static DomainInfoStat getDomainStat(List<Term> terms) {
|
||||
DomainInfoStat stat = new DomainInfoStat();
|
||||
stat.setDimensionDomainCount(getDimensionCount(terms));
|
||||
stat.setMetricDomainCount(getMetricCount(terms));
|
||||
stat.setDomainCount(getDomainCount(terms));
|
||||
stat.setDimensionValueDomainCount(getDimensionValueCount(terms));
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
private static long getDomainCount(List<Term> terms) {
|
||||
return terms.stream().filter(term -> isDomainOrEntity(term, getDomainByNature(term.nature))).count();
|
||||
}
|
||||
|
||||
private static long getDimensionValueCount(List<Term> terms) {
|
||||
return terms.stream().filter(term -> isDimensionValueClassId(term.nature.toString())).count();
|
||||
}
|
||||
|
||||
private static long getDimensionCount(List<Term> terms) {
|
||||
return terms.stream().filter(term -> term.nature.startsWith(NatureType.NATURE_SPILT) && term.nature.toString()
|
||||
.endsWith(NatureType.DIMENSION.getType())).count();
|
||||
}
|
||||
|
||||
private static long getMetricCount(List<Term> terms) {
|
||||
return terms.stream().filter(term -> term.nature.startsWith(NatureType.NATURE_SPILT) && term.nature.toString()
|
||||
.endsWith(NatureType.METRIC.getType())).count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of types of class parts of speech
|
||||
* classId -> (nature , natureCount)
|
||||
*
|
||||
* @param terms
|
||||
* @return
|
||||
*/
|
||||
public static Map<Integer, Map<NatureType, Integer>> getDomainToNatureStat(List<Term> terms) {
|
||||
Map<Integer, Map<NatureType, Integer>> domainToNature = new HashMap<>();
|
||||
terms.stream().filter(
|
||||
term -> term.nature.startsWith(NatureType.NATURE_SPILT)
|
||||
).forEach(term -> {
|
||||
NatureType natureType = NatureType.getNatureType(String.valueOf(term.nature));
|
||||
Integer domain = BaseWordNature.getDomain(String.valueOf(term.nature));
|
||||
|
||||
Map<NatureType, Integer> natureTypeMap = new HashMap<>();
|
||||
natureTypeMap.put(natureType, 1);
|
||||
|
||||
Map<NatureType, Integer> original = domainToNature.get(domain);
|
||||
if (Objects.isNull(original)) {
|
||||
domainToNature.put(domain, natureTypeMap);
|
||||
} else {
|
||||
Integer count = original.get(natureType);
|
||||
if (Objects.isNull(count)) {
|
||||
count = 1;
|
||||
} else {
|
||||
count = count + 1;
|
||||
}
|
||||
original.put(natureType, count);
|
||||
}
|
||||
});
|
||||
return domainToNature;
|
||||
}
|
||||
|
||||
public static List<Integer> selectPossibleDomains(List<Term> terms) {
|
||||
Map<Integer, Map<NatureType, Integer>> domainToNatureStat = getDomainToNatureStat(terms);
|
||||
Integer maxDomainTypeSize = domainToNatureStat.entrySet().stream()
|
||||
.max(Comparator.comparingInt(o -> o.getValue().size())).map(entry -> entry.getValue().size())
|
||||
.orElse(null);
|
||||
if (Objects.isNull(maxDomainTypeSize) || maxDomainTypeSize == 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return domainToNatureStat.entrySet().stream().filter(entry -> entry.getValue().size() == maxDomainTypeSize)
|
||||
.map(entry -> entry.getKey()).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.tencent.supersonic.chat.application.knowledge;
|
||||
|
||||
import com.tencent.supersonic.chat.api.service.SemanticLayer;
|
||||
import com.tencent.supersonic.chat.domain.pojo.semantic.DomainInfos;
|
||||
import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter;
|
||||
import com.tencent.supersonic.common.nlp.ItemDO;
|
||||
import com.tencent.supersonic.common.nlp.NatureType;
|
||||
import com.tencent.supersonic.common.nlp.WordNature;
|
||||
import com.tencent.supersonic.knowledge.application.online.WordNatureStrategyFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
/**
|
||||
* word nature service
|
||||
**/
|
||||
@Service
|
||||
public class WordNatureService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(WordNatureService.class);
|
||||
|
||||
@Autowired
|
||||
private SemanticLayer semanticLayer;
|
||||
|
||||
public List<WordNature> getAllWordNature() {
|
||||
|
||||
DomainInfos domainInfos = SchemaInfoConverter.convert(semanticLayer.getDomainSchemaInfo(new ArrayList<>()));
|
||||
|
||||
List<WordNature> natures = new ArrayList<>();
|
||||
|
||||
addNatureToResult(NatureType.DIMENSION, domainInfos.getDimensions(), natures);
|
||||
|
||||
addNatureToResult(NatureType.METRIC, domainInfos.getMetrics(), natures);
|
||||
|
||||
addNatureToResult(NatureType.DOMAIN, domainInfos.getDomains(), natures);
|
||||
|
||||
addNatureToResult(NatureType.ENTITY, domainInfos.getEntities(), natures);
|
||||
|
||||
return natures;
|
||||
}
|
||||
|
||||
private void addNatureToResult(NatureType value, List<ItemDO> metas, List<WordNature> natures) {
|
||||
List<WordNature> natureList = WordNatureStrategyFactory.get(value).getWordNatureList(metas);
|
||||
logger.debug("nature type:{} , nature size:{}", value.name(), natureList.size());
|
||||
natures.addAll(natureList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.tencent.supersonic.chat.application.mapper;
|
||||
|
||||
import com.hankcs.hanlp.seg.common.Term;
|
||||
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.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.WordNatureStrategyFactory;
|
||||
import com.tencent.supersonic.knowledge.infrastructure.nlp.HanlpHelper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class HanlpSchemaMapper implements SchemaMapper {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HanlpSchemaMapper.class);
|
||||
|
||||
@Override
|
||||
public void map(QueryContextReq searchCtx) {
|
||||
|
||||
List<Term> terms = HanlpHelper.getSegment().seg(searchCtx.getQueryText()).stream().collect(Collectors.toList());
|
||||
terms.forEach(
|
||||
item -> LOGGER.info("word:{},nature:{},frequency:{}", item.word, item.nature.toString(), item.frequency)
|
||||
);
|
||||
QueryMatchStrategy matchStrategy = ContextUtils.getBean(QueryMatchStrategy.class);
|
||||
|
||||
List<MapResult> matches = matchStrategy.match(searchCtx.getQueryText(), terms, 0);
|
||||
|
||||
convertTermsToSchemaMapInfo(matches, searchCtx.getMapInfo());
|
||||
}
|
||||
|
||||
private void convertTermsToSchemaMapInfo(List<MapResult> mapResults, SchemaMapInfo schemaMap) {
|
||||
if (CollectionUtils.isEmpty(mapResults)) {
|
||||
return;
|
||||
}
|
||||
for (MapResult mapResult : mapResults) {
|
||||
for (String nature : mapResult.getNatures()) {
|
||||
Integer domain = NatureHelper.getDomain(nature);
|
||||
if (Objects.isNull(domain)) {
|
||||
continue;
|
||||
}
|
||||
SchemaElementType elementType = NatureConverter.convertTo(nature);
|
||||
if (Objects.isNull(elementType)) {
|
||||
continue;
|
||||
}
|
||||
SchemaElementMatch schemaElementMatch = new SchemaElementMatch();
|
||||
|
||||
schemaElementMatch.setElementType(elementType);
|
||||
Integer elementID = WordNatureStrategyFactory.get(NatureType.getNatureType(nature))
|
||||
.getElementID(nature);
|
||||
schemaElementMatch.setElementID(elementID);
|
||||
schemaElementMatch.setWord(mapResult.getName());
|
||||
schemaElementMatch.setSimilarity(mapResult.getSimilarity());
|
||||
|
||||
Map<Integer, List<SchemaElementMatch>> domainElementMatches = schemaMap.getDomainElementMatches();
|
||||
List<SchemaElementMatch> schemaElementMatches = domainElementMatches.putIfAbsent(domain,
|
||||
new ArrayList<>());
|
||||
if (schemaElementMatches == null) {
|
||||
schemaElementMatches = domainElementMatches.get(domain);
|
||||
}
|
||||
schemaElementMatches.add(schemaElementMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
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;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* match strategy
|
||||
*/
|
||||
public interface MatchStrategy {
|
||||
|
||||
/***
|
||||
* match
|
||||
* @param terms
|
||||
* @return
|
||||
*/
|
||||
List<MapResult> match(String text, List<Term> terms, int retryCount);
|
||||
|
||||
|
||||
List<MapResult> match(String text, List<Term> terms, int retryCount, Integer detectDomainId);
|
||||
|
||||
|
||||
Map<MatchText, List<MapResult>> matchWithMatchText(String text, List<Term> originals);
|
||||
|
||||
/***
|
||||
* exist dimension values
|
||||
* @param natures
|
||||
* @return
|
||||
*/
|
||||
default boolean existDimensionValues(List<String> 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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.tencent.supersonic.chat.application.mapper;
|
||||
|
||||
import com.hankcs.hanlp.seg.common.Term;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.MatchText;
|
||||
import com.tencent.supersonic.common.nlp.MapResult;
|
||||
import com.tencent.supersonic.common.nlp.NatureType;
|
||||
import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester;
|
||||
import 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.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* match strategy implement
|
||||
*/
|
||||
@Service
|
||||
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;
|
||||
|
||||
@Override
|
||||
public List<MapResult> match(String text, List<Term> terms, int retryCount) {
|
||||
return match(text, terms, retryCount, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapResult> match(String text, List<Term> terms, int retryCount, Integer detectDomainId) {
|
||||
if (CollectionUtils.isEmpty(terms) || StringUtils.isEmpty(text)) {
|
||||
return null;
|
||||
}
|
||||
Map<Integer, Integer> regOffsetToLength = terms.stream().sorted(Comparator.comparing(Term::length))
|
||||
.collect(Collectors.toMap(Term::getOffset, term -> term.word.length(), (value1, value2) -> value2));
|
||||
List<Integer> offsetList = terms.stream().sorted(Comparator.comparing(Term::getOffset))
|
||||
.map(term -> term.getOffset()).collect(Collectors.toList());
|
||||
|
||||
LOGGER.debug("retryCount:{},terms:{},regOffsetToLength:{},offsetList:{},detectDomainId:{}", retryCount, terms,
|
||||
regOffsetToLength, offsetList,
|
||||
detectDomainId);
|
||||
|
||||
return detect(text, regOffsetToLength, offsetList, detectDomainId, retryCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MatchText, List<MapResult>> matchWithMatchText(String text, List<Term> originals) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<MapResult> detect(String text, Map<Integer, Integer> regOffsetToLength, List<Integer> offsetList,
|
||||
Integer detectDomainId, int retryCount) {
|
||||
List<MapResult> results = Lists.newArrayList();
|
||||
|
||||
for (Integer index = 0; index <= text.length() - 1; ) {
|
||||
|
||||
Set<MapResult> mapResultRowSet = new LinkedHashSet();
|
||||
|
||||
for (Integer i = index; i <= text.length(); ) {
|
||||
int offset = getStepOffset(offsetList, index);
|
||||
i = getStepIndex(regOffsetToLength, i);
|
||||
if (i <= text.length()) {
|
||||
List<MapResult> mapResults = detectByStep(text, detectDomainId, index, i, offset, retryCount);
|
||||
mapResultRowSet.addAll(mapResults);
|
||||
}
|
||||
}
|
||||
|
||||
index = getStepIndex(regOffsetToLength, index);
|
||||
results.addAll(mapResultRowSet);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<MapResult> detectByStep(String text, Integer detectClassId, Integer index, Integer i, int offset,
|
||||
int retryCount) {
|
||||
String detectSegment = text.substring(index, i);
|
||||
// step1. pre search
|
||||
LinkedHashSet<MapResult> mapResults = Suggester.prefixSearch(detectSegment, oneDetectionMaxSize)
|
||||
.stream().collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
// step2. suffix search
|
||||
LinkedHashSet<MapResult> suffixMapResults = Suggester.suffixSearch(detectSegment, oneDetectionMaxSize)
|
||||
.stream().collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
|
||||
mapResults.addAll(suffixMapResults);
|
||||
|
||||
if (CollectionUtils.isEmpty(mapResults)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// step3. merge pre/suffix result
|
||||
mapResults = mapResults.stream().sorted((a, b) -> -(b.getName().length() - a.getName().length()))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
// step4. filter by classId
|
||||
if (Objects.nonNull(detectClassId) && detectClassId > 0) {
|
||||
LOGGER.debug("detectDomainId:{}, before parseResults:{}", mapResults);
|
||||
mapResults = mapResults.stream().map(entry -> {
|
||||
List<String> natures = entry.getNatures().stream().filter(
|
||||
nature -> nature.startsWith(NatureType.NATURE_SPILT + detectClassId) || (nature.startsWith(
|
||||
NatureType.NATURE_SPILT))
|
||||
).collect(Collectors.toList());
|
||||
entry.setNatures(natures);
|
||||
return entry;
|
||||
}).collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
LOGGER.info("after domainId parseResults:{}", mapResults);
|
||||
}
|
||||
// step5. filter by similarity
|
||||
mapResults = mapResults.stream()
|
||||
.filter(term -> getSimilarity(detectSegment, term.getName()) >= getThresholdMatch(term.getNatures(),
|
||||
retryCount))
|
||||
.filter(term -> CollectionUtils.isNotEmpty(term.getNatures()))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
|
||||
LOGGER.debug("metricDimensionThreshold:{},dimensionValueThreshold:{},after isSimilarity parseResults:{}",
|
||||
mapResults);
|
||||
|
||||
mapResults = mapResults.stream().map(parseResult -> {
|
||||
parseResult.setOffset(offset);
|
||||
parseResult.setSimilarity(getSimilarity(detectSegment, parseResult.getName()));
|
||||
return parseResult;
|
||||
}).collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
|
||||
// step6. take only one dimension or 10 metric/dimension value per rond.
|
||||
List<MapResult> dimensionMetrics = mapResults.stream().filter(entry -> existDimensionValues(entry.getNatures()))
|
||||
.collect(Collectors.toList())
|
||||
.stream()
|
||||
.limit(1)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isNotEmpty(dimensionMetrics)) {
|
||||
return dimensionMetrics;
|
||||
} else {
|
||||
return mapResults.stream().limit(oneDetectionSize).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private Integer getStepIndex(Map<Integer, Integer> regOffsetToLength, Integer index) {
|
||||
Integer subRegLength = regOffsetToLength.get(index);
|
||||
if (Objects.nonNull(subRegLength)) {
|
||||
index = index + subRegLength;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private Integer getStepOffset(List<Integer> 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<String> natures, int retryCount) {
|
||||
if (existDimensionValues(natures)) {
|
||||
return dimensionValueThresholdConfig;
|
||||
}
|
||||
return metricDimensionThresholdConfig - STEP * retryCount;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.tencent.supersonic.chat.application.mapper;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.hankcs.hanlp.seg.common.Term;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.MatchText;
|
||||
import com.tencent.supersonic.common.nlp.MapResult;
|
||||
import com.tencent.supersonic.common.nlp.NatureType;
|
||||
import com.tencent.supersonic.knowledge.infrastructure.nlp.Suggester;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* match strategy implement
|
||||
*/
|
||||
@Service
|
||||
public class SearchMatchStrategy implements MatchStrategy {
|
||||
|
||||
private static final int SEARCH_SIZE = 3;
|
||||
|
||||
@Override
|
||||
public List<MapResult> match(String text, List<Term> terms, int retryCount) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapResult> match(String text, List<Term> terms, int retryCount, Integer detectDomainId) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MatchText, List<MapResult>> matchWithMatchText(String text, List<Term> originals) {
|
||||
|
||||
Map<Integer, Integer> regOffsetToLength = originals.stream()
|
||||
.filter(entry -> !entry.nature.toString().startsWith(NatureType.NATURE_SPILT))
|
||||
.collect(Collectors.toMap(Term::getOffset, value -> value.word.length(),
|
||||
(value1, value2) -> value2));
|
||||
|
||||
List<Integer> detectIndexList = Lists.newArrayList();
|
||||
|
||||
for (Integer index = 0; index < text.length(); ) {
|
||||
|
||||
if (index < text.length()) {
|
||||
detectIndexList.add(index);
|
||||
}
|
||||
Integer regLength = regOffsetToLength.get(index);
|
||||
if (Objects.nonNull(regLength)) {
|
||||
index = index + regLength;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
Map<MatchText, List<MapResult>> regTextMap = new ConcurrentHashMap<>();
|
||||
detectIndexList.stream().parallel().forEach(detectIndex -> {
|
||||
String regText = text.substring(0, detectIndex);
|
||||
String detectSegment = text.substring(detectIndex);
|
||||
|
||||
if (StringUtils.isNotEmpty(detectSegment)) {
|
||||
List<MapResult> mapResults = Suggester.prefixSearch(detectSegment);
|
||||
List<MapResult> suffixMapResults = Suggester.suffixSearch(detectSegment, SEARCH_SIZE);
|
||||
mapResults.addAll(suffixMapResults);
|
||||
// remove entity name where search
|
||||
mapResults = mapResults.stream().filter(entry -> {
|
||||
List<String> natures = entry.getNatures().stream()
|
||||
.filter(nature -> !nature.endsWith(NatureType.ENTITY.getType()))
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(natures)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).collect(Collectors.toList());
|
||||
regTextMap.put(new MatchText(regText, detectSegment), mapResults);
|
||||
}
|
||||
}
|
||||
);
|
||||
return regTextMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.tencent.supersonic.chat.application.parser;
|
||||
|
||||
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.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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AggregateSemanticParser implements SemanticParser {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AggregateSemanticParser.class);
|
||||
public static final Integer TOPN_LIMIT = 10;
|
||||
|
||||
private AggregateTypeResolver aggregateTypeResolver;
|
||||
|
||||
@Override
|
||||
public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) {
|
||||
aggregateTypeResolver = ContextUtils.getBean(AggregateTypeResolver.class);
|
||||
|
||||
AggregateTypeEnum aggregateType = aggregateTypeResolver.resolve(queryContext.getQueryText());
|
||||
|
||||
SemanticParseInfo semanticParse = queryContext.getParseInfo();
|
||||
|
||||
List<SchemaItem> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* query mode reset by the AggregateType
|
||||
*
|
||||
* @param searchCtx
|
||||
* @param aggregateType
|
||||
*/
|
||||
private void resetQueryModeByAggregateType(QueryContextReq searchCtx, AggregateTypeEnum aggregateType) {
|
||||
|
||||
SemanticParseInfo parseInfo = searchCtx.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)
|
||||
|| AggregateTypeEnum.TOPN.equals(aggregateType)) {
|
||||
parseInfo.setQueryMode(MetricOrderBy.QUERY_MODE);
|
||||
} else {
|
||||
parseInfo.setQueryMode(MetricGroupBy.QUERY_MODE);
|
||||
}
|
||||
}
|
||||
if (MetricFilter.QUERY_MODE.equals(queryMode) || MetricCompare.QUERY_MODE.equals(queryMode)) {
|
||||
if (aggregateTypeResolver.hasCompareIntentionalWords(searchCtx.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 searchCtx) {
|
||||
if (AggregateTypeEnum.TOPN.equals(aggregateType)) {
|
||||
return true;
|
||||
}
|
||||
return searchCtx.getParseInfo().getNativeQuery();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package com.tencent.supersonic.chat.application.parser;
|
||||
|
||||
import static java.time.LocalDate.now;
|
||||
|
||||
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.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.parser.resolver.DomainResolver;
|
||||
import com.tencent.supersonic.chat.application.query.EntityDetail;
|
||||
import com.tencent.supersonic.chat.application.query.EntityListFilter;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import 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 {
|
||||
|
||||
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();
|
||||
if (StringUtils.isNotEmpty(queryMode)) {
|
||||
// QueryMode Selected
|
||||
if (!EntityListFilter.QUERY_MODE.equals(queryMode)) {
|
||||
Integer domainId = queryContext.getDomainId().intValue();
|
||||
|
||||
List<SchemaElementMatch> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
fillDateDomain(chatCtx, 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);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> addPrimaryDimension(EntityRichInfo entity, List<SchemaItem> dimensions) {
|
||||
Set<String> 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);
|
||||
dimensions.add(dimension);
|
||||
primaryDimensions.add(dimSchemaDesc.getBizName());
|
||||
});
|
||||
return primaryDimensions;
|
||||
}
|
||||
|
||||
protected void addEntityDetailDimensionMetric(QueryContextReq searchCtx, ChatContext chatCtx) {
|
||||
if (searchCtx.getParseInfo().getDomainId() > 0) {
|
||||
ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(
|
||||
searchCtx.getParseInfo().getDomainId());
|
||||
if (chaConfigRichDesc != null) {
|
||||
SemanticParseInfo semanticParseInfo = searchCtx.getParseInfo();
|
||||
if (Objects.nonNull(semanticParseInfo) && CollectionUtils.isEmpty(semanticParseInfo.getDimensions())) {
|
||||
List<SchemaItem> dimensions = new ArrayList<>();
|
||||
List<SchemaItem> metrics = new ArrayList<>();
|
||||
if (chaConfigRichDesc.getEntity() != null
|
||||
&& chaConfigRichDesc.getEntity().getEntityInternalDetailDesc() != null) {
|
||||
chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getMetricList().stream()
|
||||
.forEach(m -> metrics.add(getMetric(m)));
|
||||
chaConfigRichDesc.getEntity().getEntityInternalDetailDesc().getDimensionList().stream()
|
||||
.forEach(m -> dimensions.add(getDimension(m)));
|
||||
}
|
||||
semanticParseInfo.setDimensions(dimensions);
|
||||
semanticParseInfo.setMetrics(metrics);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void defaultQueryMode(QueryContextReq searchCtx, ChatContext chatCtx) {
|
||||
SchemaMapInfo schemaMap = searchCtx.getMapInfo();
|
||||
SemanticParseInfo parseInfo = searchCtx.getParseInfo();
|
||||
if (StringUtils.isEmpty(parseInfo.getQueryMode())) {
|
||||
if (chatCtx.getParseInfo() != null && chatCtx.getParseInfo().getDomainId() > 0) {
|
||||
//
|
||||
Long domain = chatCtx.getParseInfo().getDomainId();
|
||||
String queryMode = chatCtx.getParseInfo().getQueryMode();
|
||||
if (!CollectionUtils.isEmpty(schemaMap.getMatchedDomains()) && schemaMap.getMatchedDomains()
|
||||
.contains(domain.intValue())) {
|
||||
List<SchemaElementMatch> elementMatches = schemaMap.getMatchedElements(domain.intValue());
|
||||
Long filterNUm = elementMatches.stream()
|
||||
.filter(e -> e.getElementType().equals(SchemaElementType.VALUE) || e.getElementType()
|
||||
.equals(SchemaElementType.ID)).count();
|
||||
Long dimensionNUm = elementMatches.stream()
|
||||
.filter(e -> e.getElementType().equals(SchemaElementType.DIMENSION)).count();
|
||||
Long metricrNUm = elementMatches.stream()
|
||||
.filter(e -> e.getElementType().equals(SchemaElementType.METRIC)).count();
|
||||
if (filterNUm > 0 && dimensionNUm > 0 && metricrNUm > 0) {
|
||||
// default as entity detail queryMode
|
||||
logger.info("defaultQueryMode [{}]", EntityDetail.QUERY_MODE);
|
||||
parseInfo.setQueryMode(EntityDetail.QUERY_MODE);
|
||||
parseInfo.setDomainId(domain);
|
||||
return;
|
||||
}
|
||||
Long entityNUm = elementMatches.stream()
|
||||
.filter(e -> e.getElementType().equals(SchemaElementType.ENTITY)).count();
|
||||
if (filterNUm <= 0 && dimensionNUm <= 0 && entityNUm <= 0) {
|
||||
// default as metric domain
|
||||
if (metricrNUm > 0 || MetricDomain.QUERY_MODE.equals(queryMode)) {
|
||||
// default as entity detail queryMode
|
||||
logger.info("defaultQueryMode [{}]", MetricDomain.QUERY_MODE);
|
||||
parseInfo.setQueryMode(MetricDomain.QUERY_MODE);
|
||||
parseInfo.setDomainId(domain);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isEmpty(schemaMap.getMatchedDomains()) && parseInfo != null
|
||||
&& parseInfo.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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void fillDateDomain(ChatContext chatCtx, QueryContextReq searchCtx) {
|
||||
SemanticParseInfo parseInfo = searchCtx.getParseInfo();
|
||||
|
||||
if (parseInfo == null || parseInfo.getDateInfo() == null) {
|
||||
boolean isUpdateTime = false;
|
||||
if (selectStrategy.isDomainSwitch(chatCtx, searchCtx)) {
|
||||
isUpdateTime = true;
|
||||
}
|
||||
if (chatCtx.getParseInfo() == null
|
||||
|| chatCtx.getParseInfo().getDateInfo() == null) {
|
||||
isUpdateTime = true;
|
||||
}
|
||||
if (isUpdateTime && parseInfo != null && parseInfo.getDomainId() > 0) {
|
||||
logger.info("fillThemeDefaultTime");
|
||||
fillThemeDefaultTime(parseInfo.getDomainId(), parseInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillThemeDefaultMetricLogic(SemanticParseInfo semanticParseInfo) {
|
||||
ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(
|
||||
semanticParseInfo.getDomainId());
|
||||
|
||||
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())) {
|
||||
List<SchemaItem> metrics = new ArrayList<>();
|
||||
chaConfigRichDesc.getDefaultMetrics().stream().forEach(metric -> {
|
||||
SchemaItem metricTmp = new SchemaItem();
|
||||
metricTmp.setId(metric.getMetricId());
|
||||
metricTmp.setBizName(metric.getBizName());
|
||||
metrics.add(metricTmp);
|
||||
});
|
||||
semanticParseInfo.setMetrics(metrics);
|
||||
}
|
||||
|
||||
if (Objects.isNull(semanticParseInfo.getDateInfo()) || Objects.isNull(
|
||||
semanticParseInfo.getDateInfo().getDateMode())) {
|
||||
DefaultMetric defaultMetricInfo = chaConfigRichDesc.getDefaultMetrics().get(0);
|
||||
DateConf dateInfo = new DateConf();
|
||||
dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS);
|
||||
dateInfo.setUnit(defaultMetricInfo.getUnit());
|
||||
dateInfo.setPeriod(defaultMetricInfo.getPeriod());
|
||||
semanticParseInfo.setDateInfo(dateInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void fillThemeDefaultTime(Long domain, SemanticParseInfo semanticParseInfo) {
|
||||
ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(
|
||||
semanticParseInfo.getDomainId());
|
||||
if (!Objects.isNull(chaConfigRichDesc) && !CollectionUtils.isEmpty(chaConfigRichDesc.getDefaultMetrics())) {
|
||||
DefaultMetric defaultMetricInfo = chaConfigRichDesc.getDefaultMetrics().get(0);
|
||||
DateConf dateInfo = new DateConf();
|
||||
dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS);
|
||||
dateInfo.setUnit(defaultMetricInfo.getUnit());
|
||||
dateInfo.setStartDate(now().minusDays(defaultMetricInfo.getUnit()).toString());
|
||||
dateInfo.setEndDate(now().minusDays(1).toString());
|
||||
dateInfo.setPeriod(defaultMetricInfo.getPeriod());
|
||||
semanticParseInfo.setDateInfo(dateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
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.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.domain.pojo.semantic.DomainInfos;
|
||||
import com.tencent.supersonic.chat.domain.utils.ContextHelper;
|
||||
import com.tencent.supersonic.chat.domain.utils.SchemaInfoConverter;
|
||||
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.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Component
|
||||
public class DomainSemanticParser implements SemanticParser {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DomainSemanticParser.class);
|
||||
private DomainResolver domainResolver;
|
||||
|
||||
private SemanticQueryResolver semanticQueryResolver;
|
||||
|
||||
@Override
|
||||
public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) {
|
||||
DomainInfos domainInfosDb = SchemaInfoConverter.convert(
|
||||
ContextUtils.getBean(SemanticLayer.class).getDomainSchemaInfo(new ArrayList<>()));
|
||||
Map<Integer, String> domainToName = domainInfosDb.getDomainToName();
|
||||
|
||||
SchemaMapInfo mapInfo = queryContext.getMapInfo();
|
||||
SemanticParseInfo parseInfo = queryContext.getParseInfo();
|
||||
|
||||
domainResolver = ContextUtils.getBean(DomainResolver.class);
|
||||
semanticQueryResolver = ContextUtils.getBean(SemanticQueryResolver.class);
|
||||
|
||||
Map<Integer, SemanticQuery> domainSemanticQuery = new HashMap<>();
|
||||
// Round 1: find all domains that can be resolved to any query mode
|
||||
|
||||
for (Integer domain : mapInfo.getMatchedDomains()) {
|
||||
List<SchemaElementMatch> elementMatches = mapInfo.getMatchedElements(domain);
|
||||
|
||||
SemanticQuery query = semanticQueryResolver.resolve(elementMatches, queryContext);
|
||||
|
||||
if (Objects.nonNull(query)) {
|
||||
domainSemanticQuery.put(domain, query);
|
||||
}
|
||||
}
|
||||
// only one domain is found, no need to rank
|
||||
if (domainSemanticQuery.size() == 1) {
|
||||
Optional<Map.Entry<Integer, SemanticQuery>> 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
|
||||
Integer domainId = domainResolver.resolve(domainSemanticQuery, queryContext, chatCtx, mapInfo);
|
||||
if (domainId > 0) {
|
||||
Map.Entry<Integer, SemanticQuery> match = domainSemanticQuery.entrySet().stream()
|
||||
.filter(entry -> entry.getKey().equals(domainId)).findFirst().orElse(null);
|
||||
logger.info("select by selectStrategy [{}:{}]", domainId, match.getValue());
|
||||
parseInfo.setDomainId(Long.valueOf(match.getKey()));
|
||||
parseInfo.setDomainName(domainToName.get(Integer.valueOf(match.getKey())));
|
||||
parseInfo.setQueryMode(match.getValue().getQueryMode());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 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<SchemaElementMatch> 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* try to add ChatContext to SchemaElementMatch and look if match QueryMode
|
||||
*
|
||||
* @param elementMatches
|
||||
* @param chatCtx
|
||||
* @return
|
||||
*/
|
||||
private SemanticQuery tryParseByContext(List<SchemaElementMatch> elementMatches, ChatContext chatCtx,
|
||||
QueryContextReq searchCt) {
|
||||
if (chatCtx.getParseInfo() != null && chatCtx.getParseInfo().getEntity() > 0) {
|
||||
Long entityCount = elementMatches.stream().filter(i -> SchemaElementType.ENTITY.equals(i.getElementType()))
|
||||
.count();
|
||||
Long metricCount = elementMatches.stream().filter(i -> SchemaElementType.METRIC.equals(i.getElementType()))
|
||||
.count();
|
||||
if (entityCount <= 0 && metricCount <= 0 && ContextHelper.hasEntityId(chatCtx)) {
|
||||
// try entity parse
|
||||
SchemaElementMatch entityElementMatch = new SchemaElementMatch();
|
||||
entityElementMatch.setElementType(SchemaElementType.ENTITY);
|
||||
List<SchemaElementMatch> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return doParseByContext(elementMatches, chatCtx, searchCt);
|
||||
}
|
||||
|
||||
private SemanticQuery doParseByContext(List<SchemaElementMatch> elementMatches, ChatContext chatCtx,
|
||||
QueryContextReq searchCt) {
|
||||
SemanticParseInfo contextSemanticParseInfo = chatCtx.getParseInfo();
|
||||
if (contextSemanticParseInfo != null) {
|
||||
List<SchemaElementMatch> newSchemaElementMatch = new ArrayList<>();
|
||||
List<List<SchemaElementType>> trySchemaElementTypes = new LinkedList<>();
|
||||
// try DIMENSION+METRIC+VALUE
|
||||
// try DIMENSION+METRIC METRIC+VALUE DIMENSION+VALUE
|
||||
// try DIMENSION METRIC VALUE single
|
||||
trySchemaElementTypes.add(new ArrayList<>(
|
||||
Arrays.asList(SchemaElementType.DIMENSION, SchemaElementType.METRIC, SchemaElementType.VALUE)));
|
||||
trySchemaElementTypes.add(
|
||||
new ArrayList<>(Arrays.asList(SchemaElementType.METRIC, SchemaElementType.VALUE)));
|
||||
trySchemaElementTypes.add(
|
||||
new ArrayList<>(Arrays.asList(SchemaElementType.DIMENSION, SchemaElementType.METRIC)));
|
||||
trySchemaElementTypes.add(
|
||||
new ArrayList<>(Arrays.asList(SchemaElementType.DIMENSION, SchemaElementType.VALUE)));
|
||||
trySchemaElementTypes.add(new ArrayList<>(Arrays.asList(SchemaElementType.METRIC)));
|
||||
trySchemaElementTypes.add(new ArrayList<>(Arrays.asList(SchemaElementType.VALUE)));
|
||||
trySchemaElementTypes.add(new ArrayList<>(Arrays.asList(SchemaElementType.DIMENSION)));
|
||||
|
||||
for (List<SchemaElementType> schemaElementTypes : trySchemaElementTypes) {
|
||||
newSchemaElementMatch.clear();
|
||||
if (!CollectionUtils.isEmpty(elementMatches)) {
|
||||
newSchemaElementMatch.addAll(elementMatches);
|
||||
}
|
||||
ContextHelper.mergeContextSchemaElementMatch(newSchemaElementMatch, elementMatches, schemaElementTypes,
|
||||
contextSemanticParseInfo);
|
||||
SemanticQuery semanticQuery = semanticQueryResolver.resolve(newSchemaElementMatch, searchCt);
|
||||
if (semanticQuery != null) {
|
||||
return semanticQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
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.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 false;
|
||||
|
||||
}
|
||||
|
||||
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 searchCtx, ChatContext chatCtx) {
|
||||
if (searchCtx.getParseInfo().getDomainId() > 0L) {
|
||||
ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(
|
||||
searchCtx.getParseInfo().getDomainId());
|
||||
if (chaConfigRichDesc != null) {
|
||||
SemanticParseInfo semanticParseInfo = searchCtx.getParseInfo();
|
||||
List<SchemaItem> dimensions = new ArrayList();
|
||||
Set<String> primaryDimensions = this.addPrimaryDimension(chaConfigRichDesc.getEntity(), dimensions);
|
||||
List<SchemaItem> metrics = new ArrayList();
|
||||
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);
|
||||
List<Order> orders = new ArrayList();
|
||||
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<String> addPrimaryDimension(EntityRichInfo entity, List<SchemaItem> dimensions) {
|
||||
Set<String> 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 searchCtx, boolean isNativeQuery) {
|
||||
if (Objects.nonNull(searchCtx) && Objects.nonNull(searchCtx.getParseInfo())) {
|
||||
searchCtx.getParseInfo().setNativeQuery(isNativeQuery);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.tencent.supersonic.chat.application.parser;
|
||||
|
||||
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.common.constant.Constants;
|
||||
import com.tencent.supersonic.common.pojo.DateConf;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TimeSemanticParser implements SemanticParser {
|
||||
|
||||
public TimeSemanticParser() {
|
||||
}
|
||||
|
||||
private int zhNumParse(String zhNumStr) {
|
||||
Stack<Integer> stack = new Stack<>();
|
||||
String numStr = "一二三四五六七八九";
|
||||
String unitStr = "十百千万亿";
|
||||
|
||||
String[] ssArr = zhNumStr.split("");
|
||||
for (String e : ssArr) {
|
||||
int numIndex = numStr.indexOf(e);
|
||||
int unitIndex = unitStr.indexOf(e);
|
||||
if (numIndex != -1) {
|
||||
stack.push(numIndex + 1);
|
||||
} else if (unitIndex != -1) {
|
||||
int unitNum = (int) Math.pow(10, unitIndex + 1);
|
||||
if (stack.isEmpty()) {
|
||||
stack.push(unitNum);
|
||||
} else {
|
||||
stack.push(stack.pop() * unitNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stack.stream().mapToInt(s -> s).sum();
|
||||
}
|
||||
|
||||
private static final Pattern recentPeriodPattern = Pattern.compile(
|
||||
".*(?<periodStr>(近|过去)((?<enNum>\\d+)|(?<zhNum>[一二三四五六七八九十百千万亿]+))个?(?<zhPeriod>[天周月年])).*");
|
||||
|
||||
@Override
|
||||
public boolean parse(QueryContextReq queryContext, ChatContext chatCtx) {
|
||||
Matcher m = recentPeriodPattern.matcher(queryContext.getQueryText());
|
||||
if (m.matches()) {
|
||||
int num = 0;
|
||||
String enNum = m.group("enNum");
|
||||
String zhNum = m.group("zhNum");
|
||||
if (enNum != null) {
|
||||
num = Integer.parseInt(enNum);
|
||||
} else if (zhNum != null) {
|
||||
num = zhNumParse(zhNum);
|
||||
}
|
||||
if (num > 0) {
|
||||
DateConf info = new DateConf();
|
||||
String zhPeriod = m.group("zhPeriod");
|
||||
int days;
|
||||
switch (zhPeriod) {
|
||||
case "周":
|
||||
days = 7;
|
||||
info.setPeriod(Constants.WEEK);
|
||||
break;
|
||||
case "月":
|
||||
days = 30;
|
||||
info.setPeriod(Constants.MONTH);
|
||||
break;
|
||||
case "年":
|
||||
days = 365;
|
||||
info.setPeriod(Constants.YEAR);
|
||||
break;
|
||||
default:
|
||||
days = 1;
|
||||
info.setPeriod(Constants.DAY);
|
||||
}
|
||||
days = days * num;
|
||||
info.setDateMode(DateConf.DateMode.RECENT_UNITS);
|
||||
String text = "近" + num + zhPeriod;
|
||||
if (Strings.isNotEmpty(m.group("periodStr"))) {
|
||||
text = m.group("periodStr");
|
||||
}
|
||||
info.setText(text);
|
||||
info.setStartDate(LocalDate.now().minusDays(days).toString());
|
||||
info.setUnit(days);
|
||||
queryContext.getParseInfo().setDateInfo(info);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.tencent.supersonic.chat.application.parser.resolver;
|
||||
|
||||
|
||||
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.chat.api.service.SemanticQuery;
|
||||
import java.util.Map;
|
||||
|
||||
public interface DomainResolver {
|
||||
|
||||
Integer resolve(Map<Integer, SemanticQuery> domainQueryModes, QueryContextReq queryCtx, ChatContext chatCtx,
|
||||
SchemaMapInfo schemaMap);
|
||||
|
||||
boolean isDomainSwitch(ChatContext chatCtx, QueryContextReq queryCtx);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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<SchemaElementMatch> elementMatches, QueryContextReq queryCtx) {
|
||||
Map<SemanticQuery, SchemaElementCount> 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<SemanticQuery, SchemaElementCount> 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
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 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("heuristicDomainResolver")
|
||||
@Primary
|
||||
public class HeuristicDomainResolver implements DomainResolver {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HeuristicDomainResolver.class);
|
||||
|
||||
@Override
|
||||
public Integer resolve(Map<Integer, SemanticQuery> domainQueryModes, QueryContextReq searchCtx,
|
||||
ChatContext chatCtx, SchemaMapInfo schemaMap) {
|
||||
// if QueryContext has domainId and in domainQueryModes
|
||||
if (domainQueryModes.containsKey(searchCtx.getDomainId())) {
|
||||
LOGGER.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)) {
|
||||
LOGGER.info("selectDomain from ChatContext [{}]", domainId);
|
||||
return domainId;
|
||||
}
|
||||
}
|
||||
// get the max SchemaElementType number
|
||||
Map<Integer, SchemaElementCount> domainTypeMap = getDomainTypeMap(schemaMap);
|
||||
if (domainTypeMap.size() == 1) {
|
||||
Integer domainSelect = domainTypeMap.entrySet().stream().collect(Collectors.toList()).get(0).getKey();
|
||||
if (domainQueryModes.containsKey(domainSelect)) {
|
||||
LOGGER.info("selectDomain from domainTypeMap not order [{}]", domainSelect);
|
||||
return domainSelect;
|
||||
}
|
||||
} else {
|
||||
Map.Entry<Integer, SchemaElementCount> maxDomain = domainTypeMap.entrySet().stream()
|
||||
.filter(entry -> domainQueryModes.containsKey(entry.getKey()))
|
||||
.sorted(ContextHelper.DomainStatComparator).findFirst().orElse(null);
|
||||
if (maxDomain != null) {
|
||||
LOGGER.info("selectDomain from domainTypeMap need order [{}]", maxDomain.getKey());
|
||||
return maxDomain.getKey();
|
||||
}
|
||||
}
|
||||
// bad case , here will not reach , default 0
|
||||
LOGGER.error("selectDomain not found ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@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);
|
||||
LOGGER.info("ChatContext isDomainSwitch [{}]", !noSwitch);
|
||||
return !noSwitch;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* to check can switch domain if context exit domain
|
||||
*
|
||||
* @return false will use context domain, true will use other domain , maybe include context domain
|
||||
*/
|
||||
private static boolean isAllowSwitch(Map<Integer, SemanticQuery> 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<Integer, SchemaElementCount> domainTypeMap = getDomainTypeMap(schemaMap);
|
||||
LOGGER.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())) {
|
||||
LOGGER.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) {
|
||||
LOGGER.info("domainId not in schemaMap ");
|
||||
return true;
|
||||
}
|
||||
// other will not switch
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Map<Integer, SchemaElementCount> getDomainTypeMap(SchemaMapInfo schemaMap) {
|
||||
Map<Integer, SchemaElementCount> domainCount = new HashMap<>();
|
||||
for (Map.Entry<Integer, List<SchemaElementMatch>> entry : schemaMap.getDomainElementMatches().entrySet()) {
|
||||
List<SchemaElementMatch> 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<SchemaElementType> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
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<AggregateTypeEnum, Pattern> 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<AggregateTypeEnum, Integer> aggregateCount = new HashMap<>(aggregateRegexMap.size());
|
||||
for (Entry<AggregateTypeEnum, Pattern> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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<SchemaElementMatch> elementMatches, QueryContextReq queryCtx);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
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<Map<String, Object>> resultList = queryResult == null ? new ArrayList<>()
|
||||
: queryResult.getResultList();
|
||||
List<QueryColumn> 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<SchemaElementMatch> 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<SchemaElementMatch> elementMatches, QueryContextReq queryCtx) {
|
||||
return queryModeOption.match(elementMatches, queryCtx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class EntityDetail extends BaseSemanticQuery {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
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());
|
||||
return semanticParseInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class EntityListFilter extends BaseSemanticQuery {
|
||||
|
||||
public static String QUERY_MODE = "ENTITY_LIST_FILTER";
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
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());
|
||||
return semanticParseInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class EntityListTopN extends BaseSemanticQuery {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
return QUERY_MODE;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class EntityMetricFilter extends BaseSemanticQuery {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
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());
|
||||
return semanticParseInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class MetricCompare extends BaseSemanticQuery {
|
||||
|
||||
public static String QUERY_MODE = "METRIC_COMPARE";
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
return QUERY_MODE;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@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.appendList(chatCtx.getParseInfo().getDimensionFilters(), semanticParseInfo.getDimensionFilters());
|
||||
return semanticParseInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class MetricDomain extends BaseSemanticQuery {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
return QUERY_MODE;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class MetricFilter extends BaseSemanticQuery {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
return QUERY_MODE;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class MetricGroupBy extends BaseSemanticQuery {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
return QUERY_MODE;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
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;
|
||||
|
||||
@Service
|
||||
public class MetricOrderBy extends BaseSemanticQuery {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryMode() {
|
||||
return QUERY_MODE;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
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<AggregateTypeEnum> 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<SchemaElementMatch> schemaElementMatches,
|
||||
DomainSchemaResp domainSchemaDesc, ChatConfigRichInfo chaConfigRichDesc,
|
||||
SemanticParseInfo semanticParseInfo) {
|
||||
Map<Long, DimSchemaResp> dimensionDescMap = domainSchemaDesc.getDimensions().stream()
|
||||
.collect(Collectors.toMap(DimSchemaResp::getId, Function.identity()));
|
||||
Map<Long, MetricSchemaResp> metricDescMap = domainSchemaDesc.getMetrics().stream()
|
||||
.collect(Collectors.toMap(MetricSchemaResp::getId, Function.identity()));
|
||||
|
||||
Map<Long, List<SchemaElementMatch>> values = getLinkSchemaElementMatch(schemaElementMatches, dimensionDescMap,
|
||||
semanticParseInfo, metricDescMap);
|
||||
if (!values.isEmpty()) {
|
||||
for (Map.Entry<Long, List<SchemaElementMatch>> 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<String> 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<Long, List<SchemaElementMatch>> getLinkSchemaElementMatch(List<SchemaElementMatch> schemaElementMatches,
|
||||
Map<Long, DimSchemaResp> dimensionDescMap, SemanticParseInfo semanticParseInfo,
|
||||
Map<Long, MetricSchemaResp> metricDescMap) {
|
||||
Map<Long, List<SchemaElementMatch>> 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<SchemaElementMatch> 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<SchemaElementType, Integer> 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<SchemaElementType> 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<SchemaElementType, Integer> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
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<String, SemanticQuery> strategyFactory = new ConcurrentHashMap<>();
|
||||
|
||||
private static List<SemanticQuery> 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<SemanticQuery> getSemanticQueries() {
|
||||
if (CollectionUtils.isEmpty(semanticQueries)) {
|
||||
semanticQueries = SpringFactoriesLoader.loadFactories(SemanticQuery.class,
|
||||
Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
return semanticQueries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.tencent.supersonic.chat.domain.dataobject;
|
||||
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class ChatConfigDO {
|
||||
|
||||
/**
|
||||
* database auto-increment primary key
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
private Long domainId;
|
||||
/**
|
||||
* default metrics information about the domain
|
||||
*/
|
||||
private String defaultMetrics;
|
||||
|
||||
/**
|
||||
* invisible dimensions/metrics
|
||||
*/
|
||||
private String visibility;
|
||||
|
||||
/**
|
||||
* the entity info about the domain
|
||||
*/
|
||||
private String entity;
|
||||
|
||||
/**
|
||||
* information about dictionary about the domain
|
||||
*/
|
||||
private String knowledgeInfo;
|
||||
|
||||
/**
|
||||
* available status
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* record info
|
||||
*/
|
||||
private String createdBy;
|
||||
private String updatedBy;
|
||||
private Date createdAt;
|
||||
private Date updatedAt;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.tencent.supersonic.chat.domain.dataobject;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChatContextDO implements Serializable {
|
||||
|
||||
private Integer chatId;
|
||||
private Instant modifiedAt;
|
||||
private String user;
|
||||
private String queryText;
|
||||
private String semanticParse;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.tencent.supersonic.chat.domain.dataobject;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChatDO {
|
||||
|
||||
private long chatId;
|
||||
private String chatName;
|
||||
private String createTime;
|
||||
private String lastTime;
|
||||
private String creator;
|
||||
private String lastQuestion;
|
||||
private int isDelete;
|
||||
private int isTop;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package com.tencent.supersonic.chat.domain.dataobject;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class ChatQueryDO {
|
||||
|
||||
/**
|
||||
* questionId
|
||||
*/
|
||||
private Long questionId;
|
||||
|
||||
/**
|
||||
* createTime
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* userName
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* queryState
|
||||
*/
|
||||
private Integer queryState;
|
||||
|
||||
/**
|
||||
* chatId
|
||||
*/
|
||||
private Long chatId;
|
||||
|
||||
/**
|
||||
* score
|
||||
*/
|
||||
private Integer score;
|
||||
|
||||
/**
|
||||
* feedback
|
||||
*/
|
||||
private String feedback;
|
||||
|
||||
/**
|
||||
* queryText
|
||||
*/
|
||||
private String queryText;
|
||||
|
||||
/**
|
||||
* queryResponse
|
||||
*/
|
||||
private String queryResponse;
|
||||
|
||||
/**
|
||||
* return question_id
|
||||
*/
|
||||
public Long getQuestionId() {
|
||||
return questionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* questionId
|
||||
*/
|
||||
public void setQuestionId(Long questionId) {
|
||||
this.questionId = questionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* return create_time
|
||||
*/
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* createTime
|
||||
*/
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* return user_name
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* userName
|
||||
*/
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName == null ? null : userName.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* return query_state
|
||||
*/
|
||||
public Integer getQueryState() {
|
||||
return queryState;
|
||||
}
|
||||
|
||||
/**
|
||||
* queryState
|
||||
*/
|
||||
public void setQueryState(Integer queryState) {
|
||||
this.queryState = queryState;
|
||||
}
|
||||
|
||||
/**
|
||||
* return chat_id
|
||||
*/
|
||||
public Long getChatId() {
|
||||
return chatId;
|
||||
}
|
||||
|
||||
/**
|
||||
* chatId
|
||||
*/
|
||||
public void setChatId(Long chatId) {
|
||||
this.chatId = chatId;
|
||||
}
|
||||
|
||||
/**
|
||||
* return score
|
||||
*/
|
||||
public Integer getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
/**
|
||||
* score
|
||||
*/
|
||||
public void setScore(Integer score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
/**
|
||||
* return feedback
|
||||
*/
|
||||
public String getFeedback() {
|
||||
return feedback;
|
||||
}
|
||||
|
||||
/**
|
||||
* feedback
|
||||
*/
|
||||
public void setFeedback(String feedback) {
|
||||
this.feedback = feedback == null ? null : feedback.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* return query_text
|
||||
*/
|
||||
public String getQueryText() {
|
||||
return queryText;
|
||||
}
|
||||
|
||||
/**
|
||||
* queryText
|
||||
*/
|
||||
public void setQueryText(String queryText) {
|
||||
this.queryText = queryText == null ? null : queryText.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* return query_response
|
||||
*/
|
||||
public String getQueryResponse() {
|
||||
return queryResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* queryResponse
|
||||
*/
|
||||
public void setQueryResponse(String queryResponse) {
|
||||
this.queryResponse = queryResponse == null ? null : queryResponse.trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,660 @@
|
||||
package com.tencent.supersonic.chat.domain.dataobject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatQueryDOExample {
|
||||
protected String orderByClause;
|
||||
protected boolean distinct;
|
||||
protected List<Criteria> oredCriteria;
|
||||
protected Integer limitStart;
|
||||
protected Integer limitEnd;
|
||||
|
||||
public ChatQueryDOExample() {
|
||||
oredCriteria = new ArrayList<Criteria>();
|
||||
}
|
||||
|
||||
public void setOrderByClause(String orderByClause) {
|
||||
this.orderByClause = orderByClause;
|
||||
}
|
||||
|
||||
|
||||
public String getOrderByClause() {
|
||||
return orderByClause;
|
||||
}
|
||||
|
||||
public void setDistinct(boolean distinct) {
|
||||
this.distinct = distinct;
|
||||
}
|
||||
|
||||
public boolean isDistinct() {
|
||||
return distinct;
|
||||
}
|
||||
|
||||
public List<Criteria> getOredCriteria() {
|
||||
return oredCriteria;
|
||||
}
|
||||
|
||||
public void or(Criteria criteria) {
|
||||
oredCriteria.add(criteria);
|
||||
}
|
||||
|
||||
public Criteria or() {
|
||||
Criteria criteria = createCriteriaInternal();
|
||||
oredCriteria.add(criteria);
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public Criteria createCriteria() {
|
||||
Criteria criteria = createCriteriaInternal();
|
||||
if (oredCriteria.size() == 0) {
|
||||
oredCriteria.add(criteria);
|
||||
}
|
||||
return criteria;
|
||||
}
|
||||
|
||||
protected Criteria createCriteriaInternal() {
|
||||
Criteria criteria = new Criteria();
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
oredCriteria.clear();
|
||||
orderByClause = null;
|
||||
distinct = false;
|
||||
}
|
||||
|
||||
public void setLimitStart(Integer limitStart) {
|
||||
this.limitStart = limitStart;
|
||||
}
|
||||
|
||||
public Integer getLimitStart() {
|
||||
return limitStart;
|
||||
}
|
||||
|
||||
public void setLimitEnd(Integer limitEnd) {
|
||||
this.limitEnd = limitEnd;
|
||||
}
|
||||
|
||||
public Integer getLimitEnd() {
|
||||
return limitEnd;
|
||||
}
|
||||
|
||||
protected abstract static class GeneratedCriteria {
|
||||
|
||||
protected List<Criterion> criteria;
|
||||
|
||||
protected GeneratedCriteria() {
|
||||
super();
|
||||
criteria = new ArrayList<Criterion>();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return criteria.size() > 0;
|
||||
}
|
||||
|
||||
public List<Criterion> getAllCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public List<Criterion> getCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition) {
|
||||
if (condition == null) {
|
||||
throw new RuntimeException("Value for condition cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition));
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition, Object value, String property) {
|
||||
if (value == null) {
|
||||
throw new RuntimeException("Value for " + property + " cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition, value));
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition, Object value1, Object value2, String property) {
|
||||
if (value1 == null || value2 == null) {
|
||||
throw new RuntimeException("Between values for " + property + " cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition, value1, value2));
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdIsNull() {
|
||||
addCriterion("question_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdIsNotNull() {
|
||||
addCriterion("question_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdEqualTo(Long value) {
|
||||
addCriterion("question_id =", value, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdNotEqualTo(Long value) {
|
||||
addCriterion("question_id <>", value, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdGreaterThan(Long value) {
|
||||
addCriterion("question_id >", value, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdGreaterThanOrEqualTo(Long value) {
|
||||
addCriterion("question_id >=", value, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdLessThan(Long value) {
|
||||
addCriterion("question_id <", value, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdLessThanOrEqualTo(Long value) {
|
||||
addCriterion("question_id <=", value, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdIn(List<Long> values) {
|
||||
addCriterion("question_id in", values, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdNotIn(List<Long> values) {
|
||||
addCriterion("question_id not in", values, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdBetween(Long value1, Long value2) {
|
||||
addCriterion("question_id between", value1, value2, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQuestionIdNotBetween(Long value1, Long value2) {
|
||||
addCriterion("question_id not between", value1, value2, "questionId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeIsNull() {
|
||||
addCriterion("create_time is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeIsNotNull() {
|
||||
addCriterion("create_time is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeEqualTo(Date value) {
|
||||
addCriterion("create_time =", value, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeNotEqualTo(Date value) {
|
||||
addCriterion("create_time <>", value, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeGreaterThan(Date value) {
|
||||
addCriterion("create_time >", value, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeGreaterThanOrEqualTo(Date value) {
|
||||
addCriterion("create_time >=", value, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeLessThan(Date value) {
|
||||
addCriterion("create_time <", value, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeLessThanOrEqualTo(Date value) {
|
||||
addCriterion("create_time <=", value, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeIn(List<Date> values) {
|
||||
addCriterion("create_time in", values, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeNotIn(List<Date> values) {
|
||||
addCriterion("create_time not in", values, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeBetween(Date value1, Date value2) {
|
||||
addCriterion("create_time between", value1, value2, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andCreateTimeNotBetween(Date value1, Date value2) {
|
||||
addCriterion("create_time not between", value1, value2, "createTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameIsNull() {
|
||||
addCriterion("user_name is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameIsNotNull() {
|
||||
addCriterion("user_name is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameEqualTo(String value) {
|
||||
addCriterion("user_name =", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameNotEqualTo(String value) {
|
||||
addCriterion("user_name <>", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameGreaterThan(String value) {
|
||||
addCriterion("user_name >", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("user_name >=", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameLessThan(String value) {
|
||||
addCriterion("user_name <", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameLessThanOrEqualTo(String value) {
|
||||
addCriterion("user_name <=", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameLike(String value) {
|
||||
addCriterion("user_name like", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameNotLike(String value) {
|
||||
addCriterion("user_name not like", value, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameIn(List<String> values) {
|
||||
addCriterion("user_name in", values, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameNotIn(List<String> values) {
|
||||
addCriterion("user_name not in", values, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameBetween(String value1, String value2) {
|
||||
addCriterion("user_name between", value1, value2, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andUserNameNotBetween(String value1, String value2) {
|
||||
addCriterion("user_name not between", value1, value2, "userName");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateIsNull() {
|
||||
addCriterion("query_state is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateIsNotNull() {
|
||||
addCriterion("query_state is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateEqualTo(Integer value) {
|
||||
addCriterion("query_state =", value, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateNotEqualTo(Integer value) {
|
||||
addCriterion("query_state <>", value, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateGreaterThan(Integer value) {
|
||||
addCriterion("query_state >", value, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateGreaterThanOrEqualTo(Integer value) {
|
||||
addCriterion("query_state >=", value, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateLessThan(Integer value) {
|
||||
addCriterion("query_state <", value, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateLessThanOrEqualTo(Integer value) {
|
||||
addCriterion("query_state <=", value, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateIn(List<Integer> values) {
|
||||
addCriterion("query_state in", values, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateNotIn(List<Integer> values) {
|
||||
addCriterion("query_state not in", values, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateBetween(Integer value1, Integer value2) {
|
||||
addCriterion("query_state between", value1, value2, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andQueryStateNotBetween(Integer value1, Integer value2) {
|
||||
addCriterion("query_state not between", value1, value2, "queryState");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdIsNull() {
|
||||
addCriterion("chat_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdIsNotNull() {
|
||||
addCriterion("chat_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdEqualTo(Long value) {
|
||||
addCriterion("chat_id =", value, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdNotEqualTo(Long value) {
|
||||
addCriterion("chat_id <>", value, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdGreaterThan(Long value) {
|
||||
addCriterion("chat_id >", value, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdGreaterThanOrEqualTo(Long value) {
|
||||
addCriterion("chat_id >=", value, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdLessThan(Long value) {
|
||||
addCriterion("chat_id <", value, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdLessThanOrEqualTo(Long value) {
|
||||
addCriterion("chat_id <=", value, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdIn(List<Long> values) {
|
||||
addCriterion("chat_id in", values, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdNotIn(List<Long> values) {
|
||||
addCriterion("chat_id not in", values, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdBetween(Long value1, Long value2) {
|
||||
addCriterion("chat_id between", value1, value2, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andChatIdNotBetween(Long value1, Long value2) {
|
||||
addCriterion("chat_id not between", value1, value2, "chatId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreIsNull() {
|
||||
addCriterion("score is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreIsNotNull() {
|
||||
addCriterion("score is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreEqualTo(Integer value) {
|
||||
addCriterion("score =", value, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreNotEqualTo(Integer value) {
|
||||
addCriterion("score <>", value, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreGreaterThan(Integer value) {
|
||||
addCriterion("score >", value, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreGreaterThanOrEqualTo(Integer value) {
|
||||
addCriterion("score >=", value, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreLessThan(Integer value) {
|
||||
addCriterion("score <", value, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreLessThanOrEqualTo(Integer value) {
|
||||
addCriterion("score <=", value, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreIn(List<Integer> values) {
|
||||
addCriterion("score in", values, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreNotIn(List<Integer> values) {
|
||||
addCriterion("score not in", values, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreBetween(Integer value1, Integer value2) {
|
||||
addCriterion("score between", value1, value2, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScoreNotBetween(Integer value1, Integer value2) {
|
||||
addCriterion("score not between", value1, value2, "score");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackIsNull() {
|
||||
addCriterion("feedback is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackIsNotNull() {
|
||||
addCriterion("feedback is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackEqualTo(String value) {
|
||||
addCriterion("feedback =", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackNotEqualTo(String value) {
|
||||
addCriterion("feedback <>", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackGreaterThan(String value) {
|
||||
addCriterion("feedback >", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("feedback >=", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackLessThan(String value) {
|
||||
addCriterion("feedback <", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackLessThanOrEqualTo(String value) {
|
||||
addCriterion("feedback <=", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackLike(String value) {
|
||||
addCriterion("feedback like", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackNotLike(String value) {
|
||||
addCriterion("feedback not like", value, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackIn(List<String> values) {
|
||||
addCriterion("feedback in", values, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackNotIn(List<String> values) {
|
||||
addCriterion("feedback not in", values, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackBetween(String value1, String value2) {
|
||||
addCriterion("feedback between", value1, value2, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andFeedbackNotBetween(String value1, String value2) {
|
||||
addCriterion("feedback not between", value1, value2, "feedback");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
||||
protected Criteria() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criterion {
|
||||
|
||||
private String condition;
|
||||
|
||||
private Object value;
|
||||
|
||||
private Object secondValue;
|
||||
|
||||
private boolean noValue;
|
||||
|
||||
private boolean singleValue;
|
||||
|
||||
private boolean betweenValue;
|
||||
|
||||
private boolean listValue;
|
||||
|
||||
private String typeHandler;
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object getSecondValue() {
|
||||
return secondValue;
|
||||
}
|
||||
|
||||
public boolean isNoValue() {
|
||||
return noValue;
|
||||
}
|
||||
|
||||
public boolean isSingleValue() {
|
||||
return singleValue;
|
||||
}
|
||||
|
||||
public boolean isBetweenValue() {
|
||||
return betweenValue;
|
||||
}
|
||||
|
||||
public boolean isListValue() {
|
||||
return listValue;
|
||||
}
|
||||
|
||||
public String getTypeHandler() {
|
||||
return typeHandler;
|
||||
}
|
||||
|
||||
protected Criterion(String condition) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.typeHandler = null;
|
||||
this.noValue = true;
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, String typeHandler) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.value = value;
|
||||
this.typeHandler = typeHandler;
|
||||
if (value instanceof List<?>) {
|
||||
this.listValue = true;
|
||||
} else {
|
||||
this.singleValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value) {
|
||||
this(condition, value, null);
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.value = value;
|
||||
this.secondValue = secondValue;
|
||||
this.typeHandler = typeHandler;
|
||||
this.betweenValue = true;
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, Object secondValue) {
|
||||
this(condition, value, secondValue, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.tencent.supersonic.chat.domain.dataobject;
|
||||
|
||||
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.Dim4Dict;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class DimValueDO {
|
||||
|
||||
private Long domainId;
|
||||
|
||||
private List<DefaultMetric> defaultMetricDescList = new ArrayList<>();
|
||||
|
||||
private List<Dim4Dict> dimensions = new ArrayList<>();
|
||||
|
||||
public DimValueDO setDomainId(Long domainId) {
|
||||
this.domainId = domainId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DimValueDO setDefaultMetricIds(List<DefaultMetric> defaultMetricDescList) {
|
||||
this.defaultMetricDescList = defaultMetricDescList;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DimValueDO setDimensions(List<Dim4Dict> dimensions) {
|
||||
this.dimensions = dimensions;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.tencent.supersonic.chat.domain.dataobject;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class QueryDO {
|
||||
|
||||
private long id;
|
||||
private long questionId;
|
||||
private String createTime;
|
||||
private String time;
|
||||
private String userName;
|
||||
private String question;
|
||||
private Object queryResults;
|
||||
private int state;
|
||||
private String dataContent;
|
||||
private String name;
|
||||
private int queryType;
|
||||
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;
|
||||
private int score;
|
||||
private String feedback;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.chat;
|
||||
|
||||
import com.tencent.supersonic.chat.api.response.QueryResultResp;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChatQueryVO {
|
||||
|
||||
private Long questionId;
|
||||
private Date createTime;
|
||||
private Long chatId;
|
||||
private Integer score;
|
||||
private String feedback;
|
||||
private String queryText;
|
||||
private QueryResultResp queryResponse;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.chat;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PageQueryInfoReq {
|
||||
|
||||
private int current;
|
||||
|
||||
private int pageSize;
|
||||
|
||||
private String userName;
|
||||
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public int getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setCurrent(int current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public void setPageSize(int pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.chat;
|
||||
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.Filter;
|
||||
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.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class QueryData {
|
||||
|
||||
Long domainId = 0L;
|
||||
List<SchemaItem> metrics = new ArrayList<>();
|
||||
List<SchemaItem> dimensions = new ArrayList<>();
|
||||
List<Filter> filters = new ArrayList<>();
|
||||
private List<Order> orders = new ArrayList<>();
|
||||
private DateConf dateInfo;
|
||||
private Long limit;
|
||||
private Boolean nativeQuery = false;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.chat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
@Setter
|
||||
@Getter
|
||||
public class RecommendResponse {
|
||||
|
||||
private List<Item> dimensions;
|
||||
private List<Item> metrics;
|
||||
|
||||
|
||||
public static class Item implements Serializable {
|
||||
|
||||
private Integer domain;
|
||||
private String name;
|
||||
private String bizName;
|
||||
|
||||
public Integer getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(Integer domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getBizName() {
|
||||
return bizName;
|
||||
}
|
||||
|
||||
public void setBizName(String bizName) {
|
||||
this.bizName = bizName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.chat;
|
||||
|
||||
public enum SchemaElementOption {
|
||||
REQUIRED,
|
||||
OPTIONAL,
|
||||
UNUSED
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import com.tencent.supersonic.common.enums.StatusEnum;
|
||||
import com.tencent.supersonic.common.util.RecordInfo;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class ChatConfig {
|
||||
|
||||
/**
|
||||
* database auto-increment primary key
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
private Long domainId;
|
||||
/**
|
||||
* default metrics information about the domain
|
||||
*/
|
||||
private List<DefaultMetricInfo> defaultMetrics;
|
||||
|
||||
/**
|
||||
* invisible dimensions/metrics
|
||||
*/
|
||||
private ItemVisibility visibility;
|
||||
|
||||
/**
|
||||
* the entity info about the domain
|
||||
*/
|
||||
private Entity entity;
|
||||
|
||||
/**
|
||||
* information about dictionary about the domain
|
||||
*/
|
||||
private List<KnowledgeInfo> knowledgeInfos;
|
||||
|
||||
/**
|
||||
* available status
|
||||
*/
|
||||
private StatusEnum status;
|
||||
|
||||
/**
|
||||
* about createdBy, createdAt, updatedBy, updatedAt
|
||||
*/
|
||||
private RecordInfo recordInfo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import com.tencent.supersonic.common.enums.StatusEnum;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* extended information command about domain
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
public class ChatConfigBase {
|
||||
|
||||
private Long domainId;
|
||||
/**
|
||||
* default metrics information about the domain
|
||||
*/
|
||||
private List<DefaultMetricInfo> defaultMetrics;
|
||||
|
||||
/**
|
||||
* invisible dimensions/metrics
|
||||
*/
|
||||
private ItemVisibility visibility;
|
||||
|
||||
/**
|
||||
* the entity info about the domain
|
||||
*/
|
||||
private Entity entity;
|
||||
|
||||
/**
|
||||
* information about dictionary about the domain
|
||||
*/
|
||||
private List<KnowledgeInfo> dictionaryInfos;
|
||||
|
||||
/**
|
||||
* available status
|
||||
*/
|
||||
private StatusEnum status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class ChatConfigEditReq extends ChatConfigBase {
|
||||
|
||||
private Long id;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import com.tencent.supersonic.common.enums.StatusEnum;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class ChatConfigFilter {
|
||||
|
||||
private Long id;
|
||||
private Long domainId;
|
||||
private StatusEnum status = StatusEnum.ONLINE;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChatConfigFilterInternal {
|
||||
|
||||
private Long id;
|
||||
private Long domainId;
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import com.tencent.supersonic.common.enums.StatusEnum;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChatConfigInfo {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long domainId;
|
||||
|
||||
/**
|
||||
* default metrics information about the domain
|
||||
*/
|
||||
private List<DefaultMetricInfo> defaultMetrics;
|
||||
|
||||
/**
|
||||
* invisible dimensions/metrics
|
||||
*/
|
||||
private ItemVisibility visibility;
|
||||
|
||||
/**
|
||||
* the entity info about the domain
|
||||
*/
|
||||
private Entity entity;
|
||||
|
||||
/**
|
||||
* information about dictionary about the domain
|
||||
*/
|
||||
private List<KnowledgeInfo> dictionaryInfos;
|
||||
|
||||
/**
|
||||
* available status
|
||||
*/
|
||||
private StatusEnum statusEnum;
|
||||
|
||||
private String createdBy;
|
||||
private String updatedBy;
|
||||
private Date createdAt;
|
||||
private Date updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import com.tencent.supersonic.common.enums.StatusEnum;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChatConfigRichInfo {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long domainId;
|
||||
|
||||
private String name;
|
||||
private String bizName;
|
||||
|
||||
/**
|
||||
* default metrics information about the domain
|
||||
*/
|
||||
private List<DefaultMetric> defaultMetrics;
|
||||
|
||||
/**
|
||||
* invisible dimensions/metrics
|
||||
*/
|
||||
private ItemVisibilityInfo visibility;
|
||||
|
||||
/**
|
||||
* the entity info about the domain
|
||||
*/
|
||||
private EntityRichInfo entity;
|
||||
|
||||
/**
|
||||
* information about dictionary about the domain
|
||||
*/
|
||||
private List<KnowledgeInfo> dictionaryInfos;
|
||||
|
||||
/**
|
||||
* available status
|
||||
*/
|
||||
private StatusEnum statusEnum;
|
||||
|
||||
private String createdBy;
|
||||
private String updatedBy;
|
||||
private Date createdAt;
|
||||
private Date updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class DefaultMetric {
|
||||
|
||||
/**
|
||||
* default metrics
|
||||
*/
|
||||
private Long metricId;
|
||||
|
||||
/**
|
||||
* default time span unit
|
||||
*/
|
||||
private Integer unit;
|
||||
|
||||
/**
|
||||
* default time type: DAY
|
||||
* DAY, WEEK, MONTH, YEAR
|
||||
*/
|
||||
private String period;
|
||||
|
||||
private String bizName;
|
||||
private String name;
|
||||
|
||||
public DefaultMetric(Long metricId, Integer unit, String period) {
|
||||
this.metricId = metricId;
|
||||
this.unit = unit;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public DefaultMetric(String bizName, Integer unit, String period) {
|
||||
this.bizName = bizName;
|
||||
this.unit = unit;
|
||||
this.period = period;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import com.tencent.supersonic.common.constant.Constants;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
|
||||
/**
|
||||
* default metrics about the domain
|
||||
*/
|
||||
|
||||
@ToString
|
||||
@Data
|
||||
public class DefaultMetricInfo {
|
||||
|
||||
/**
|
||||
* default metrics
|
||||
*/
|
||||
private Long metricId;
|
||||
|
||||
/**
|
||||
* default time span unit
|
||||
*/
|
||||
private Integer unit = 1;
|
||||
|
||||
/**
|
||||
* default time type: day
|
||||
* DAY, WEEK, MONTH, YEAR
|
||||
*/
|
||||
private String period = Constants.DAY;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class Dim4Dict {
|
||||
|
||||
private Long dimId;
|
||||
private String bizName;
|
||||
private List<String> blackList;
|
||||
private List<String> whiteList;
|
||||
private List<String> ruleList;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* the entity info about the domain
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
public class Entity {
|
||||
|
||||
/**
|
||||
* uniquely identifies an entity
|
||||
*/
|
||||
private List<Long> entityIds;
|
||||
|
||||
/**
|
||||
* entity name list
|
||||
*/
|
||||
private List<String> names;
|
||||
|
||||
/**
|
||||
* query entity default information
|
||||
*/
|
||||
private EntityDetailData detailData;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* when query an entity, return related dimension/metric info
|
||||
*/
|
||||
@Data
|
||||
public class EntityDetailData {
|
||||
|
||||
private List<Long> dimensionIds;
|
||||
private List<Long> metricIds;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
|
||||
import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class EntityInternalDetail {
|
||||
|
||||
List<DimSchemaResp> dimensionList;
|
||||
List<MetricSchemaResp> metricList;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class EntityRichInfo {
|
||||
|
||||
private Long domainId;
|
||||
private String domainName;
|
||||
private String domainBizName;
|
||||
|
||||
private List<String> names;
|
||||
|
||||
private List<DimSchemaResp> entityIds;
|
||||
|
||||
private EntityInternalDetail entityInternalDetailDesc;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class ItemVisibility {
|
||||
|
||||
/**
|
||||
* invisible dimensions
|
||||
*/
|
||||
private List<Long> blackDimIdList;
|
||||
|
||||
/**
|
||||
* invisible metrics
|
||||
*/
|
||||
private List<Long> blackMetricIdList;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.config;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class ItemVisibilityInfo {
|
||||
|
||||
private List<Long> blackDimIdList;
|
||||
private List<Long> blackMetricIdList;
|
||||
private List<Long> whiteDimIdList;
|
||||
private List<Long> whiteMetricIdList;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* information about dictionary about the domain
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class KnowledgeInfo {
|
||||
|
||||
/**
|
||||
* metricId、DimensionId、domainId
|
||||
*/
|
||||
private Long itemId;
|
||||
|
||||
/**
|
||||
* type: IntentionTypeEnum
|
||||
* temporarily only supports dimension-related information
|
||||
*/
|
||||
@NotNull
|
||||
private TypeEnums type = TypeEnums.DIMENSION;
|
||||
|
||||
private List<String> blackList;
|
||||
private List<String> whiteList;
|
||||
private List<String> ruleList;
|
||||
private Boolean isDictInfo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.search;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class DomainInfoStat implements Serializable {
|
||||
|
||||
private long domainCount;
|
||||
private long metricDomainCount;
|
||||
private long dimensionDomainCount;
|
||||
private long dimensionValueDomainCount;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.search;
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementType;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class DomainWithSemanticType implements Serializable {
|
||||
|
||||
private Integer domain;
|
||||
private SchemaElementType semanticType;
|
||||
|
||||
public DomainWithSemanticType(Integer domain, SchemaElementType semanticType) {
|
||||
this.domain = domain;
|
||||
this.semanticType = semanticType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.search;
|
||||
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@Setter
|
||||
@Getter
|
||||
@ToString
|
||||
public class MatchText {
|
||||
|
||||
private String regText;
|
||||
|
||||
private String detectSegment;
|
||||
|
||||
public MatchText() {
|
||||
}
|
||||
|
||||
|
||||
public MatchText(String regText, String detectSegment) {
|
||||
this.regText = regText;
|
||||
this.detectSegment = detectSegment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MatchText that = (MatchText) o;
|
||||
return Objects.equals(regText, that.regText) && Objects.equals(detectSegment, that.detectSegment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(regText, detectSegment);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.search;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class NameNature implements Serializable {
|
||||
|
||||
private String name;
|
||||
private List<String> natures;
|
||||
|
||||
public NameNature() {
|
||||
}
|
||||
|
||||
public NameNature(String name, List<String> natures) {
|
||||
this.name = name;
|
||||
this.natures = natures;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.search;
|
||||
|
||||
public enum QueryState {
|
||||
NORMAL(0),
|
||||
SEARCH_EXCEPTION(1),
|
||||
EMPTY(2),
|
||||
INVALID(3);
|
||||
|
||||
private int state;
|
||||
|
||||
QueryState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.search;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
@Setter
|
||||
@Getter
|
||||
public class SearchResponse {
|
||||
|
||||
private List<SearchResult> searchResults;
|
||||
|
||||
public SearchResponse(List<SearchResult> searchResults) {
|
||||
this.searchResults = searchResults;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.search;
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementType;
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
@Setter
|
||||
@Getter
|
||||
public class SearchResult {
|
||||
|
||||
private String recommend;
|
||||
|
||||
private String subRecommend;
|
||||
|
||||
private String domainName;
|
||||
|
||||
private Integer domainId;
|
||||
|
||||
private SchemaElementType schemaElementType;
|
||||
|
||||
private boolean isComplete = true;
|
||||
|
||||
public SearchResult(String recommend, String subRecommend, String className, Integer domainId,
|
||||
SchemaElementType schemaElementType) {
|
||||
this.recommend = recommend;
|
||||
this.subRecommend = subRecommend;
|
||||
this.domainName = className;
|
||||
this.domainId = domainId;
|
||||
this.schemaElementType = schemaElementType;
|
||||
}
|
||||
|
||||
public SearchResult(String recommend, String subRecommend, String className, Integer domainId, boolean isComplete) {
|
||||
this.recommend = recommend;
|
||||
this.subRecommend = subRecommend;
|
||||
this.domainName = className;
|
||||
this.domainId = domainId;
|
||||
this.isComplete = isComplete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SearchResult searchResult1 = (SearchResult) o;
|
||||
return Objects.equals(recommend, searchResult1.recommend) && Objects.equals(domainName,
|
||||
searchResult1.domainName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(recommend, domainName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AggregatorInfo implements Serializable {
|
||||
|
||||
private String aggregator;
|
||||
private String targetWord;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
public enum DateTypeEnum {
|
||||
|
||||
|
||||
DAY("DAY", "天", "sys_imp_date"),
|
||||
WEEK("WEEK", "周", "sys_imp_week"),
|
||||
MONTH("MONTH", "月", "sys_imp_month"),
|
||||
YEAR("YEAR", "年", "sys_imp_year");
|
||||
private String code;
|
||||
|
||||
private String name;
|
||||
|
||||
private String field;
|
||||
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
DateTypeEnum(String code, String name, String field) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public static DateTypeEnum fromCode(String code) {
|
||||
for (DateTypeEnum dateTypeEnum : DateTypeEnum.values()) {
|
||||
if (dateTypeEnum.getCode().equals(code)) {
|
||||
return dateTypeEnum;
|
||||
}
|
||||
}
|
||||
return DateTypeEnum.DAY;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
import com.tencent.supersonic.common.nlp.ItemDO;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
/**
|
||||
* DomainInfos
|
||||
*/
|
||||
@Data
|
||||
public class DomainInfos implements Serializable {
|
||||
|
||||
private List<ItemDO> domains = new ArrayList<>();
|
||||
private List<ItemDO> dimensions = new ArrayList<>();
|
||||
private List<ItemDO> metrics = new ArrayList<>();
|
||||
private List<ItemDO> entities = new ArrayList<>();
|
||||
|
||||
public Map<Integer, String> getDomainToName() {
|
||||
if (CollectionUtils.isEmpty(domains)) {
|
||||
return new HashMap();
|
||||
}
|
||||
return domains.stream().collect(
|
||||
Collectors.toMap(ItemDO::getDomain, ItemDO::getName, (value1, value2) -> value2)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
public enum ModeEnum {
|
||||
query,
|
||||
interpret
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ParserSvrResponse<T> {
|
||||
|
||||
private String code;
|
||||
private String msg;
|
||||
private T data;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
public class SemanticDO {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class SemanticText implements Serializable {
|
||||
|
||||
private LinkedHashSet<String> metricList;
|
||||
|
||||
private LinkedHashSet<String> dimensionValues = new LinkedHashSet<>();
|
||||
private Map<String, List<String>> filterDimensionValues = new HashMap<>();
|
||||
private AggregatorInfo aggregatorInfo;
|
||||
private String startTime;
|
||||
private String endTime;
|
||||
private String timeWord;
|
||||
private Integer classId;
|
||||
private String className;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TimeParseDetail {
|
||||
|
||||
private String type;
|
||||
private List<String> time;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tencent.supersonic.chat.domain.pojo.semantic;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TimeParseResult {
|
||||
|
||||
private String text;
|
||||
private List<Integer> offset;
|
||||
private TimeParseDetail detail;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.tencent.supersonic.chat.domain.repository;
|
||||
|
||||
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfig;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilter;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigInfo;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface ChatConfigRepository {
|
||||
|
||||
Long createConfig(ChatConfig chaConfig);
|
||||
|
||||
Long updateConfig(ChatConfig chaConfig);
|
||||
|
||||
List<ChatConfigInfo> getChatConfig(ChatConfigFilter filter);
|
||||
|
||||
ChatConfigInfo getConfigByDomainId(Long domainId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tencent.supersonic.chat.domain.repository;
|
||||
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.ChatContext;
|
||||
|
||||
public interface ChatContextRepository {
|
||||
|
||||
ChatContext getOrCreateContext(int chatId);
|
||||
|
||||
void updateContext(ChatContext chatCtx);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.tencent.supersonic.chat.domain.repository;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.tencent.supersonic.chat.api.pojo.ChatContext;
|
||||
import com.tencent.supersonic.chat.api.request.QueryContextReq;
|
||||
import com.tencent.supersonic.chat.api.response.QueryResultResp;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq;
|
||||
|
||||
public interface ChatQueryRepository {
|
||||
|
||||
PageInfo<ChatQueryVO> getChatQuery(PageQueryInfoReq pageQueryInfoCommend, long chatId);
|
||||
|
||||
void createChatQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.tencent.supersonic.chat.domain.repository;
|
||||
|
||||
import com.tencent.supersonic.chat.domain.dataobject.ChatDO;
|
||||
import com.tencent.supersonic.chat.domain.dataobject.QueryDO;
|
||||
import java.util.List;
|
||||
|
||||
public interface ChatRepository {
|
||||
|
||||
boolean createChat(ChatDO chatDO);
|
||||
|
||||
List<ChatDO> getAll(String creator);
|
||||
|
||||
Boolean updateChatName(Long chatId, String chatName, String lastTime, String creator);
|
||||
|
||||
Boolean updateConversionIsTop(Long chatId, int isTop);
|
||||
|
||||
boolean updateFeedback(QueryDO queryDO);
|
||||
|
||||
Boolean deleteChat(Long chatId, String userName);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
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.request.QueryContextReq;
|
||||
import com.tencent.supersonic.chat.api.response.QueryResultResp;
|
||||
import com.tencent.supersonic.chat.domain.dataobject.ChatDO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.ChatQueryVO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.PageQueryInfoReq;
|
||||
import java.util.List;
|
||||
|
||||
public interface ChatService {
|
||||
|
||||
/***
|
||||
* get the domain from context
|
||||
* @param chatId
|
||||
* @return
|
||||
*/
|
||||
public Long getContextDomain(Integer chatId);
|
||||
|
||||
public ChatContext getOrCreateContext(int chatId);
|
||||
|
||||
public void updateContext(ChatContext chatCtx);
|
||||
|
||||
public void switchContext(ChatContext chatCtx);
|
||||
|
||||
public Boolean addChat(User user, String chatName);
|
||||
|
||||
public List<ChatDO> getAll(String userName);
|
||||
|
||||
public boolean updateChatName(Long chatId, String chatName, String userName);
|
||||
|
||||
public boolean updateFeedback(Integer id, Integer score, String feedback);
|
||||
|
||||
public boolean updateChatIsTop(Long chatId, int isTop);
|
||||
|
||||
Boolean deleteChat(Long chatId, String userName);
|
||||
|
||||
PageInfo<ChatQueryVO> queryInfo(PageQueryInfoReq pageQueryInfoCommend, long chatId);
|
||||
|
||||
public void addQuery(QueryResultResp queryResponse, QueryContextReq queryContext, ChatContext chatCtx);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.tencent.supersonic.chat.domain.service;
|
||||
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigBase;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigEditReq;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilter;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigInfo;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo;
|
||||
import java.util.List;
|
||||
|
||||
public interface ConfigService {
|
||||
|
||||
Long addConfig(ChatConfigBase extendBaseCmd, User user);
|
||||
|
||||
Long editConfig(ChatConfigEditReq extendEditCmd, User user);
|
||||
|
||||
List<ChatConfigInfo> search(ChatConfigFilter filter, User user);
|
||||
|
||||
ChatConfigRichInfo getConfigRichInfo(Long domainId);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.tencent.supersonic.chat.domain.service;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
||||
import com.tencent.supersonic.chat.api.request.QueryContextReq;
|
||||
import com.tencent.supersonic.chat.api.response.QueryResultResp;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.QueryData;
|
||||
|
||||
/***
|
||||
* QueryService for query and search
|
||||
*/
|
||||
public interface QueryService {
|
||||
|
||||
public QueryResultResp executeQuery(QueryContextReq queryCtx) throws Exception;
|
||||
|
||||
public SemanticParseInfo queryContext(QueryContextReq queryCtx);
|
||||
|
||||
QueryResultResp queryData(QueryData queryData, User user) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.tencent.supersonic.chat.domain.service;
|
||||
|
||||
|
||||
import com.tencent.supersonic.chat.api.request.QueryContextReq;
|
||||
import com.tencent.supersonic.chat.domain.pojo.chat.RecommendResponse;
|
||||
|
||||
/***
|
||||
* Recommend Service
|
||||
*/
|
||||
public interface RecommendService {
|
||||
|
||||
RecommendResponse recommend(QueryContextReq queryCtx);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.tencent.supersonic.chat.domain.service;
|
||||
|
||||
import com.tencent.supersonic.chat.api.request.QueryContextReq;
|
||||
import com.tencent.supersonic.chat.domain.pojo.search.SearchResult;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* search service
|
||||
*/
|
||||
public interface SearchService {
|
||||
|
||||
List<SearchResult> search(QueryContextReq queryCtx);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.tencent.supersonic.chat.domain.utils;
|
||||
|
||||
import static com.tencent.supersonic.common.constant.Constants.ADMIN_LOWER;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||
import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp;
|
||||
import com.tencent.supersonic.chat.domain.dataobject.ChatConfigDO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfig;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigBase;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigEditReq;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigInfo;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetricInfo;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.Entity;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.EntityDetailData;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.EntityInternalDetail;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ItemVisibility;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.KnowledgeInfo;
|
||||
import com.tencent.supersonic.common.enums.StatusEnum;
|
||||
import com.tencent.supersonic.common.util.RecordInfo;
|
||||
import com.tencent.supersonic.common.util.json.JsonUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ChatConfigUtils {
|
||||
|
||||
public ChatConfig newChatConfig(ChatConfigBase extendBaseCmd, User user) {
|
||||
ChatConfig chaConfig = new ChatConfig();
|
||||
|
||||
BeanUtils.copyProperties(extendBaseCmd, chaConfig);
|
||||
|
||||
RecordInfo recordInfo = new RecordInfo();
|
||||
String creator = (Objects.isNull(user) || Strings.isEmpty(user.getName())) ? ADMIN_LOWER : user.getName();
|
||||
recordInfo.createdBy(creator);
|
||||
chaConfig.setRecordInfo(recordInfo);
|
||||
chaConfig.setStatus(StatusEnum.ONLINE);
|
||||
return chaConfig;
|
||||
}
|
||||
|
||||
|
||||
public ChatConfig editChaConfig(ChatConfigEditReq extendEditCmd, User facadeUser) {
|
||||
ChatConfig chaConfig = new ChatConfig();
|
||||
|
||||
BeanUtils.copyProperties(extendEditCmd, chaConfig);
|
||||
|
||||
RecordInfo recordInfo = new RecordInfo();
|
||||
String user = (Objects.isNull(facadeUser) || Strings.isEmpty(facadeUser.getName()))
|
||||
? ADMIN_LOWER : facadeUser.getName();
|
||||
recordInfo.updatedBy(user);
|
||||
chaConfig.setRecordInfo(recordInfo);
|
||||
return chaConfig;
|
||||
}
|
||||
|
||||
|
||||
public List<DimSchemaResp> generateDimDesc(List<Long> dimIds, DomainSchemaResp domainSchemaDesc) {
|
||||
List<DimSchemaResp> dimSchemaDescList = new ArrayList<>();
|
||||
if (Objects.nonNull(domainSchemaDesc) && !CollectionUtils.isEmpty(domainSchemaDesc.getDimensions())) {
|
||||
dimSchemaDescList = domainSchemaDesc.getDimensions().stream()
|
||||
.filter(dimSchemaDesc -> dimIds.contains(dimSchemaDesc.getId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return dimSchemaDescList;
|
||||
}
|
||||
|
||||
public List<MetricSchemaResp> generateMetricDesc(List<Long> metricIds, DomainSchemaResp domainSchemaDesc) {
|
||||
List<MetricSchemaResp> metricSchemaDescList = new ArrayList<>();
|
||||
if (Objects.nonNull(domainSchemaDesc) && !CollectionUtils.isEmpty(domainSchemaDesc.getMetrics())) {
|
||||
metricSchemaDescList = domainSchemaDesc.getMetrics().stream()
|
||||
.filter(metricSchemaDesc -> metricIds.contains(metricSchemaDesc.getId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return metricSchemaDescList;
|
||||
}
|
||||
|
||||
public EntityInternalDetail generateEntityDetailData(EntityDetailData detailData,
|
||||
DomainSchemaResp domainSchemaDesc) {
|
||||
EntityInternalDetail entityInternalDetailDesc = new EntityInternalDetail();
|
||||
if (Objects.isNull(detailData)) {
|
||||
return entityInternalDetailDesc;
|
||||
}
|
||||
entityInternalDetailDesc.setDimensionList(generateDimDesc(detailData.getDimensionIds(), domainSchemaDesc));
|
||||
entityInternalDetailDesc.setMetricList(generateMetricDesc(detailData.getMetricIds(), domainSchemaDesc));
|
||||
|
||||
return entityInternalDetailDesc;
|
||||
}
|
||||
|
||||
public Map<Long, MetricSchemaResp> generateMetricIdAndDescPair(List<Long> metricIds,
|
||||
DomainSchemaResp domainSchemaDesc) {
|
||||
Map<Long, MetricSchemaResp> metricIdAndDescPair = new HashMap<>();
|
||||
List<MetricSchemaResp> metricDescList = generateMetricDesc(metricIds, domainSchemaDesc);
|
||||
|
||||
metricDescList.stream().forEach(metricDesc -> metricIdAndDescPair.put(metricDesc.getId(), metricDesc));
|
||||
return metricIdAndDescPair;
|
||||
}
|
||||
|
||||
public List<Long> generateAllDimIdList(DomainSchemaResp domainSchemaDesc) {
|
||||
if (Objects.isNull(domainSchemaDesc) || CollectionUtils.isEmpty(domainSchemaDesc.getDimensions())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Map<Long, List<DimSchemaResp>> dimIdAndDescPair = domainSchemaDesc.getDimensions()
|
||||
.stream().collect(Collectors.groupingBy(DimSchemaResp::getId));
|
||||
return new ArrayList<>(dimIdAndDescPair.keySet());
|
||||
}
|
||||
|
||||
public List<Long> generateAllMetricIdList(DomainSchemaResp domainSchemaDesc) {
|
||||
Map<Long, List<MetricSchemaResp>> metricIdAndDescPair = domainSchemaDesc.getMetrics()
|
||||
.stream().collect(Collectors.groupingBy(MetricSchemaResp::getId));
|
||||
return new ArrayList<>(metricIdAndDescPair.keySet());
|
||||
}
|
||||
|
||||
public ChatConfigDO chatConfig2DO(ChatConfig chaConfig) {
|
||||
ChatConfigDO chaConfigDO = new ChatConfigDO();
|
||||
BeanUtils.copyProperties(chaConfig, chaConfigDO);
|
||||
|
||||
chaConfigDO.setDefaultMetrics(JsonUtil.toString(chaConfig.getDefaultMetrics()));
|
||||
chaConfigDO.setVisibility(JsonUtil.toString(chaConfig.getVisibility()));
|
||||
chaConfigDO.setEntity(JsonUtil.toString(chaConfig.getEntity()));
|
||||
chaConfigDO.setKnowledgeInfo(JsonUtil.toString(chaConfig.getKnowledgeInfos()));
|
||||
|
||||
if (Objects.isNull(chaConfig.getStatus())) {
|
||||
chaConfigDO.setStatus(null);
|
||||
} else {
|
||||
chaConfigDO.setStatus(chaConfig.getStatus().getCode());
|
||||
}
|
||||
|
||||
chaConfigDO.setCreatedBy(chaConfig.getRecordInfo().getCreatedBy());
|
||||
chaConfigDO.setCreatedAt(chaConfig.getRecordInfo().getCreatedAt());
|
||||
chaConfigDO.setUpdatedBy(chaConfig.getRecordInfo().getUpdatedBy());
|
||||
chaConfigDO.setUpdatedAt(chaConfig.getRecordInfo().getUpdatedAt());
|
||||
|
||||
return chaConfigDO;
|
||||
}
|
||||
|
||||
public ChatConfigInfo chatConfigDO2Descriptor(ChatConfigDO chaConfigDO) {
|
||||
ChatConfigInfo chaConfigDescriptor = new ChatConfigInfo();
|
||||
BeanUtils.copyProperties(chaConfigDO, chaConfigDescriptor);
|
||||
|
||||
chaConfigDescriptor.setDefaultMetrics(
|
||||
JsonUtil.toList(chaConfigDO.getDefaultMetrics(), DefaultMetricInfo.class));
|
||||
chaConfigDescriptor.setVisibility(JsonUtil.toObject(chaConfigDO.getVisibility(), ItemVisibility.class));
|
||||
chaConfigDescriptor.setEntity(JsonUtil.toObject(chaConfigDO.getEntity(), Entity.class));
|
||||
chaConfigDescriptor.setDictionaryInfos(JsonUtil.toList(chaConfigDO.getKnowledgeInfo(), KnowledgeInfo.class));
|
||||
chaConfigDescriptor.setStatusEnum(StatusEnum.of(chaConfigDO.getStatus()));
|
||||
|
||||
chaConfigDescriptor.setCreatedBy(chaConfigDO.getCreatedBy());
|
||||
chaConfigDescriptor.setCreatedAt(chaConfigDO.getCreatedAt());
|
||||
chaConfigDescriptor.setUpdatedBy(chaConfigDO.getUpdatedBy());
|
||||
chaConfigDescriptor.setUpdatedAt(chaConfigDO.getUpdatedAt());
|
||||
|
||||
return chaConfigDescriptor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
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.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.semantic.api.core.response.DimSchemaResp;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo;
|
||||
import com.tencent.supersonic.common.pojo.SchemaItem;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ContextHelper {
|
||||
|
||||
public static void updateDomain(SemanticParseInfo from, SemanticParseInfo to) {
|
||||
if (from != null && from.getDomainId() != null) {
|
||||
to.setDomainId(from.getDomainId());
|
||||
}
|
||||
if (from != null && from.getDomainName() != null) {
|
||||
to.setDomainName(from.getDomainName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateEntity(SemanticParseInfo from, SemanticParseInfo to) {
|
||||
if (from != null && from.getEntity() != null && from.getEntity() > 0) {
|
||||
to.setEntity(from.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateSemanticQuery(SemanticParseInfo from, SemanticParseInfo to) {
|
||||
to.setQueryMode(from.getQueryMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* update time if from is not null
|
||||
*
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
public static void updateTime(SemanticParseInfo from, SemanticParseInfo to) {
|
||||
if (from != null && from.getDateInfo() != null) {
|
||||
to.setDateInfo(from.getDateInfo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update time if time is null and from is not null
|
||||
*
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
public static void updateTimeIfEmpty(SemanticParseInfo from, SemanticParseInfo to) {
|
||||
if (from != null && from.getDateInfo() != null && to.getDateInfo() == null) {
|
||||
to.setDateInfo(from.getDateInfo());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* add from to list if list is empty and from is not empty
|
||||
*
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
public static void addIfEmpty(List from, List to) {
|
||||
if (to.isEmpty() && !from.isEmpty()) {
|
||||
to.addAll(from);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* append from to list if from is not empty
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
public static void appendList(List from, List to) {
|
||||
if (!from.isEmpty()) {
|
||||
to.addAll(from);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update list if from is not empty
|
||||
*
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
public static void updateList(List from, List to) {
|
||||
if (!from.isEmpty()) {
|
||||
to.clear();
|
||||
to.addAll(from);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* count desc > similarity desc
|
||||
*/
|
||||
public static int domainSchemaElementCountComparator(SchemaElementCount o1, SchemaElementCount o2) {
|
||||
int difference = o1.getCount() - o2.getCount();
|
||||
if (difference == 0) {
|
||||
return (int) ((o1.getMaxSimilarity() - o2.getMaxSimilarity()) * 100);
|
||||
}
|
||||
return difference;
|
||||
}
|
||||
|
||||
public static Comparator<Map.Entry<Integer, SchemaElementCount>> DomainStatComparator
|
||||
= (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue());
|
||||
|
||||
public static Comparator<Map.Entry<SemanticQuery, SchemaElementCount>> SemanticQueryStatComparator
|
||||
= (o1, o2) -> domainSchemaElementCountComparator(o1.getValue(), o2.getValue());
|
||||
/**
|
||||
* similarity desc
|
||||
*/
|
||||
public static Comparator<SchemaElementMatch> schemaElementMatchComparatorBySimilarity
|
||||
= new Comparator<SchemaElementMatch>() {
|
||||
@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) {
|
||||
Optional<DimSchemaResp> dimensionDesc = chaConfigRichDesc.getEntity().getEntityIds().stream()
|
||||
.filter(i -> i.getId().equals(dimensionId)).findFirst();
|
||||
if (dimensionDesc.isPresent() && StringUtils.isNumeric(value)) {
|
||||
semanticParseInfo.setEntity(Long.valueOf(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasEntityId(ChatContext chatCtx) {
|
||||
if (chatCtx != null && chatCtx.getParseInfo() != null) {
|
||||
return chatCtx.getParseInfo().getEntity() > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***
|
||||
* merge Context SchemaElementMatch
|
||||
* @param toSchemaElementMatch
|
||||
* @param elementMatches
|
||||
* @param schemaElementTypes
|
||||
* @param contextSemanticParseInfo
|
||||
*/
|
||||
public static void mergeContextSchemaElementMatch(List<SchemaElementMatch> toSchemaElementMatch,
|
||||
List<SchemaElementMatch> elementMatches, List<SchemaElementType> schemaElementTypes,
|
||||
SemanticParseInfo contextSemanticParseInfo) {
|
||||
for (SchemaElementType schemaElementType : schemaElementTypes) {
|
||||
switch (schemaElementType) {
|
||||
case DIMENSION:
|
||||
if (contextSemanticParseInfo.getDimensions() != null
|
||||
&& contextSemanticParseInfo.getDimensions().size() > 0) {
|
||||
for (SchemaItem dimension : contextSemanticParseInfo.getDimensions()) {
|
||||
addSchemaElementMatch(toSchemaElementMatch, elementMatches, SchemaElementType.DIMENSION,
|
||||
dimension);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case METRIC:
|
||||
if (contextSemanticParseInfo.getMetrics() != null
|
||||
&& contextSemanticParseInfo.getMetrics().size() > 0) {
|
||||
for (SchemaItem metric : contextSemanticParseInfo.getMetrics()) {
|
||||
addSchemaElementMatch(toSchemaElementMatch, elementMatches, SchemaElementType.METRIC,
|
||||
metric);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VALUE:
|
||||
if (contextSemanticParseInfo.getDimensionFilters() != null
|
||||
&& contextSemanticParseInfo.getDimensionFilters().size() > 0) {
|
||||
for (Filter chatFilter : contextSemanticParseInfo.getDimensionFilters()) {
|
||||
if (!isInSchemaElementMatchList(elementMatches, SchemaElementType.VALUE,
|
||||
chatFilter.getValue().toString())) {
|
||||
toSchemaElementMatch.add(
|
||||
getSchemaElementMatchByContext(chatFilter.getElementID().intValue(),
|
||||
chatFilter.getValue().toString(), SchemaElementType.VALUE));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* is that SchemaElementType and word in SchemaElementMatch list
|
||||
*
|
||||
* @param elementMatches
|
||||
* @param schemaElementType
|
||||
* @param word
|
||||
* @return
|
||||
*/
|
||||
private static boolean isInSchemaElementMatchList(List<SchemaElementMatch> elementMatches,
|
||||
SchemaElementType schemaElementType, String word) {
|
||||
if (CollectionUtils.isEmpty(elementMatches)) {
|
||||
return false;
|
||||
}
|
||||
Long num = elementMatches.stream()
|
||||
.filter(element -> element != null && element.getWord() != null && element.getWord()
|
||||
.equalsIgnoreCase(word) && element.getElementType().equals(schemaElementType)).count();
|
||||
return num > 0;
|
||||
}
|
||||
|
||||
private static void addSchemaElementMatch(List<SchemaElementMatch> toAddSchemaElementMatch,
|
||||
List<SchemaElementMatch> elementMatches, SchemaElementType schemaElementType, SchemaItem schemaItem) {
|
||||
if (Objects.isNull(schemaItem) || Objects.isNull(schemaItem.getId()) || Objects.isNull(schemaItem.getName())) {
|
||||
return;
|
||||
}
|
||||
if (!isInSchemaElementMatchList(elementMatches, schemaElementType, schemaItem.getName())) {
|
||||
toAddSchemaElementMatch.add(
|
||||
getSchemaElementMatchByContext(schemaItem.getId().intValue(), schemaItem.getName(),
|
||||
schemaElementType));
|
||||
}
|
||||
}
|
||||
|
||||
private static SchemaElementMatch getSchemaElementMatchByContext(int id, String word,
|
||||
SchemaElementType schemaElementType) {
|
||||
SchemaElementMatch schemaElementMatch = new SchemaElementMatch();
|
||||
schemaElementMatch.setElementID(id);
|
||||
schemaElementMatch.setElementType(schemaElementType);
|
||||
schemaElementMatch.setWord(word);
|
||||
// todo default similarity
|
||||
schemaElementMatch.setSimilarity(0.5);
|
||||
return schemaElementMatch;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.tencent.supersonic.chat.domain.utils;
|
||||
|
||||
import static com.tencent.supersonic.common.constant.Constants.LIST_LOWER;
|
||||
import static com.tencent.supersonic.common.constant.Constants.PAGESIZE_LOWER;
|
||||
import static com.tencent.supersonic.common.constant.Constants.TOTAL_LOWER;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||
import com.tencent.supersonic.semantic.api.core.request.PageDimensionReq;
|
||||
import com.tencent.supersonic.semantic.api.core.request.PageMetricReq;
|
||||
import com.tencent.supersonic.semantic.api.core.response.DimensionResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.DomainResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.MetricResp;
|
||||
import com.tencent.supersonic.chat.application.ConfigServiceImpl;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo;
|
||||
import com.tencent.supersonic.common.result.ResultData;
|
||||
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;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
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.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DefaultSemanticInternalUtils {
|
||||
|
||||
@Value("${semantic.url.prefix:http://localhost:8081}")
|
||||
private String semanticUrl;
|
||||
|
||||
@Value("${fetchDomainList.path:/api/semantic/schema/dimension/page}")
|
||||
private String fetchDimensionPagePath;
|
||||
|
||||
@Value("${fetchDomainList.path:/api/semantic/schema/metric/page}")
|
||||
private String fetchMetricPagePath;
|
||||
|
||||
@Value("${fetchDomainList.path:/api/semantic/schema/domain/list}")
|
||||
private String fetchDomainListPath;
|
||||
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private ConfigServiceImpl chaConfigService;
|
||||
|
||||
@Autowired
|
||||
private S2ThreadContext s2ThreadContext;
|
||||
|
||||
@Autowired
|
||||
private AuthenticationConfig authenticationConfig;
|
||||
|
||||
|
||||
public ChatConfigRichInfo getChatConfigRichInfo(Long domain) {
|
||||
return chaConfigService.getConfigRichInfo(domain);
|
||||
}
|
||||
|
||||
|
||||
public PageInfo<MetricResp> queryMetricPage(PageMetricReq pageMetricCmd, User user) {
|
||||
String body = JsonUtil.toString(pageMetricCmd);
|
||||
Object dimensionListObject = fetchHttpResult(semanticUrl + fetchMetricPagePath, body, HttpMethod.POST);
|
||||
LinkedHashMap map = (LinkedHashMap) dimensionListObject;
|
||||
PageInfo<Object> metricDescObjectPageInfo = generatePageInfo(map);
|
||||
PageInfo<MetricResp> metricDescPageInfo = new PageInfo<>();
|
||||
BeanUtils.copyProperties(metricDescObjectPageInfo, metricDescPageInfo);
|
||||
metricDescPageInfo.setList(metricDescPageInfo.getList());
|
||||
return metricDescPageInfo;
|
||||
}
|
||||
|
||||
public PageInfo<DimensionResp> queryDimensionPage(PageDimensionReq pageDimensionCmd, User user) {
|
||||
String body = JsonUtil.toString(pageDimensionCmd);
|
||||
Object dimensionListObject = fetchHttpResult(semanticUrl + fetchDimensionPagePath, body, HttpMethod.POST);
|
||||
LinkedHashMap map = (LinkedHashMap) dimensionListObject;
|
||||
PageInfo<Object> dimensionDescObjectPageInfo = generatePageInfo(map);
|
||||
PageInfo<DimensionResp> dimensionDescPageInfo = new PageInfo<>();
|
||||
BeanUtils.copyProperties(dimensionDescObjectPageInfo, dimensionDescPageInfo);
|
||||
dimensionDescPageInfo.setList(dimensionDescPageInfo.getList());
|
||||
return dimensionDescPageInfo;
|
||||
}
|
||||
|
||||
private PageInfo<Object> generatePageInfo(LinkedHashMap map) {
|
||||
PageInfo<Object> pageInfo = new PageInfo<>();
|
||||
pageInfo.setList((List<Object>) map.get(LIST_LOWER));
|
||||
Integer total = (Integer) map.get(TOTAL_LOWER);
|
||||
pageInfo.setTotal(total);
|
||||
Integer pageSize = (Integer) map.get(PAGESIZE_LOWER);
|
||||
pageInfo.setPageSize(pageSize);
|
||||
pageInfo.setPages((int) Math.ceil((double) total / pageSize));
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
|
||||
public Object fetchHttpResult(String url, String bodyJson, HttpMethod httpMethod) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
fillToken(headers);
|
||||
URI requestUrl = UriComponentsBuilder.fromHttpUrl(url).build().encode().toUri();
|
||||
ParameterizedTypeReference<ResultData<Object>> responseTypeRef =
|
||||
new ParameterizedTypeReference<ResultData<Object>>() {
|
||||
};
|
||||
HttpEntity<String> entity = new HttpEntity<>(JsonUtil.toString(bodyJson), headers);
|
||||
try {
|
||||
ResponseEntity<ResultData<Object>> responseEntity = restTemplate.exchange(requestUrl,
|
||||
httpMethod, entity, responseTypeRef);
|
||||
ResultData<Object> responseBody = responseEntity.getBody();
|
||||
log.debug("ApiResponse<fetchDomainSchema> responseBody:{}", responseBody);
|
||||
if (ReturnCode.SUCCESS.getCode() == responseBody.getCode()) {
|
||||
Object data = responseBody.getData();
|
||||
return data;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("fetchDomainSchema interface error", e);
|
||||
}
|
||||
throw new RuntimeException("fetchDomainSchema interface error");
|
||||
}
|
||||
|
||||
public void fillToken(HttpHeaders headers) {
|
||||
ThreadContext threadContext = s2ThreadContext.get();
|
||||
if (Objects.nonNull(threadContext) && Strings.isNotEmpty(threadContext.getToken())) {
|
||||
if (Objects.nonNull(authenticationConfig) && Strings.isNotEmpty(
|
||||
authenticationConfig.getTokenHttpHeaderKey())) {
|
||||
headers.set(authenticationConfig.getTokenHttpHeaderKey(), threadContext.getToken());
|
||||
}
|
||||
} else {
|
||||
log.info("threadContext is null:{}", Objects.isNull(threadContext));
|
||||
}
|
||||
}
|
||||
|
||||
public List<DomainResp> getDomainListForUser(User user) {
|
||||
Object domainDescListObject = fetchHttpResult(semanticUrl + fetchDomainListPath, null, HttpMethod.GET);
|
||||
List<DomainResp> domainDescList = (List<DomainResp>) domainDescListObject;
|
||||
return domainDescList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
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.semantic.api.core.response.DimSchemaResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp;
|
||||
import com.tencent.supersonic.chat.domain.dataobject.DimValueDO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigRichInfo;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.Dim4Dict;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ItemVisibilityInfo;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.KnowledgeInfo;
|
||||
import com.tencent.supersonic.knowledge.domain.pojo.DictUpdateMode;
|
||||
import com.tencent.supersonic.knowledge.domain.pojo.DimValue2DictCommand;
|
||||
import java.util.ArrayList;
|
||||
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 org.apache.logging.log4j.util.Strings;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Component
|
||||
public class DictMetaUtils {
|
||||
|
||||
@Value("${model.internal.metric.suffix:internal_cnt}")
|
||||
private String internalMetricNameSuffix;
|
||||
|
||||
private final SemanticLayer semanticLayer;
|
||||
private final DefaultSemanticInternalUtils defaultSemanticUtils;
|
||||
|
||||
public DictMetaUtils(SemanticLayer semanticLayer,
|
||||
DefaultSemanticInternalUtils defaultSemanticUtils) {
|
||||
this.semanticLayer = semanticLayer;
|
||||
this.defaultSemanticUtils = defaultSemanticUtils;
|
||||
}
|
||||
|
||||
|
||||
public List<DimValueDO> generateDimValueInfo(DimValue2DictCommand dimValue2DictCommend) {
|
||||
List<DimValueDO> dimValueDOList = new ArrayList<>();
|
||||
DictUpdateMode updateMode = dimValue2DictCommend.getUpdateMode();
|
||||
Set<Long> domainIds = new HashSet<>();
|
||||
switch (updateMode) {
|
||||
case OFFLINE_DOMAIN:
|
||||
domainIds.addAll(dimValue2DictCommend.getDomainIds());
|
||||
dimValueDOList = generateDimValueInfoByDomain(domainIds);
|
||||
break;
|
||||
case OFFLINE_FULL:
|
||||
List<DomainSchemaResp> domainSchemaDescList = semanticLayer.getDomainSchemaInfo(new ArrayList<>());
|
||||
if (CollectionUtils.isEmpty(domainSchemaDescList)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Map<Long, DomainSchemaResp> domainIdAndDescPair = domainSchemaDescList.stream()
|
||||
.collect(Collectors.toMap(DomainSchemaResp::getId, domainSchemaDesc -> domainSchemaDesc));
|
||||
if (!CollectionUtils.isEmpty(domainIdAndDescPair)) {
|
||||
domainIds.addAll(domainIdAndDescPair.keySet());
|
||||
dimValueDOList = generateDimValueInfoByDomain(domainIds);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case REALTIME_ADD:
|
||||
dimValueDOList = generateDimValueInfoByDomainAndDim(dimValue2DictCommend.getDomainAndDimPair());
|
||||
break;
|
||||
case NOT_SUPPORT:
|
||||
throw new RuntimeException("illegal parameter for updateMode");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return dimValueDOList;
|
||||
}
|
||||
|
||||
private List<DimValueDO> generateDimValueInfoByDomainAndDim(Map<Long, List<Long>> domainAndDimMap) {
|
||||
List<DimValueDO> dimValueDOList = new ArrayList<>();
|
||||
if (CollectionUtils.isEmpty(domainAndDimMap)) {
|
||||
return dimValueDOList;
|
||||
}
|
||||
|
||||
List<DomainSchemaResp> domainSchemaDescList = semanticLayer.getDomainSchemaInfo(new ArrayList<>());
|
||||
if (CollectionUtils.isEmpty(domainSchemaDescList)) {
|
||||
return dimValueDOList;
|
||||
}
|
||||
Map<Long, DomainSchemaResp> domainIdAndDescPair = domainSchemaDescList.stream()
|
||||
.collect(Collectors.toMap(DomainSchemaResp::getId, domainSchemaDesc -> domainSchemaDesc));
|
||||
|
||||
for (Long domainId : domainAndDimMap.keySet()) {
|
||||
if (!domainIdAndDescPair.containsKey(domainId)) {
|
||||
continue;
|
||||
}
|
||||
Map<Long, DimSchemaResp> dimIdAndDescPairAll;
|
||||
dimIdAndDescPairAll = domainIdAndDescPair.get(domainId).getDimensions().stream()
|
||||
.collect(Collectors.toMap(DimSchemaResp::getId, dimSchemaDesc -> dimSchemaDesc));
|
||||
List<Long> dimIdReq = domainAndDimMap.get(domainId);
|
||||
Map<Long, DimSchemaResp> dimIdAndDescPairReq = new HashMap<>();
|
||||
for (Long dimId : dimIdReq) {
|
||||
if (dimIdAndDescPairAll.containsKey(dimId)) {
|
||||
dimIdAndDescPairReq.put(dimId, dimIdAndDescPairAll.get(dimId));
|
||||
}
|
||||
}
|
||||
fillDimValueDOList(dimValueDOList, domainId, dimIdAndDescPairReq);
|
||||
}
|
||||
|
||||
return dimValueDOList;
|
||||
}
|
||||
|
||||
private List<DimValueDO> generateDimValueInfoByDomain(Set<Long> domainIds) {
|
||||
List<DimValueDO> dimValueDOList = new ArrayList<>();
|
||||
List<DomainSchemaResp> domainSchemaDescList = semanticLayer.getDomainSchemaInfo(new ArrayList<>(domainIds));
|
||||
if (CollectionUtils.isEmpty(domainSchemaDescList)) {
|
||||
return dimValueDOList;
|
||||
}
|
||||
|
||||
domainSchemaDescList.forEach(domainSchemaDesc -> {
|
||||
Map<Long, DimSchemaResp> dimIdAndDescPair = domainSchemaDesc.getDimensions().stream()
|
||||
.collect(Collectors.toMap(DimSchemaResp::getId, dimSchemaDesc -> dimSchemaDesc));
|
||||
fillDimValueDOList(dimValueDOList, domainSchemaDesc.getId(), dimIdAndDescPair);
|
||||
|
||||
});
|
||||
|
||||
return dimValueDOList;
|
||||
}
|
||||
|
||||
private void fillDimValueDOList(List<DimValueDO> dimValueDOList, Long domainId,
|
||||
Map<Long, DimSchemaResp> dimIdAndDescPair) {
|
||||
ChatConfigRichInfo chaConfigRichDesc = defaultSemanticUtils.getChatConfigRichInfo(domainId);
|
||||
if (Objects.nonNull(chaConfigRichDesc)) {
|
||||
|
||||
List<DefaultMetric> defaultMetricDescList = chaConfigRichDesc.getDefaultMetrics();
|
||||
|
||||
List<KnowledgeInfo> dictionaryInfos = chaConfigRichDesc.getDictionaryInfos();
|
||||
if (!CollectionUtils.isEmpty(dictionaryInfos)) {
|
||||
List<Dim4Dict> dimensions = new ArrayList<>();
|
||||
dictionaryInfos.stream()
|
||||
.filter(dictionaryInfo -> dictionaryInfo.getIsDictInfo()
|
||||
&& isVisibleDim(dictionaryInfo, chaConfigRichDesc.getVisibility()))
|
||||
.forEach(dictionaryInfo -> {
|
||||
if (dimIdAndDescPair.containsKey(dictionaryInfo.getItemId())) {
|
||||
DimSchemaResp dimensionDesc = dimIdAndDescPair.get(dictionaryInfo.getItemId());
|
||||
|
||||
//default cnt
|
||||
if (CollectionUtils.isEmpty(defaultMetricDescList)) {
|
||||
String datasourceBizName = dimensionDesc.getDatasourceBizName();
|
||||
if (Strings.isNotEmpty(datasourceBizName)) {
|
||||
String internalMetricName =
|
||||
datasourceBizName + UNDERLINE + internalMetricNameSuffix;
|
||||
defaultMetricDescList.add(new DefaultMetric(internalMetricName, 2, DAY));
|
||||
}
|
||||
}
|
||||
|
||||
String bizName = dimensionDesc.getBizName();
|
||||
dimensions.add(new Dim4Dict(dictionaryInfo.getItemId(), bizName,
|
||||
dictionaryInfo.getBlackList(), dictionaryInfo.getWhiteList(),
|
||||
dictionaryInfo.getRuleList()));
|
||||
}
|
||||
|
||||
});
|
||||
if (!CollectionUtils.isEmpty(dimensions)) {
|
||||
DimValueDO dimValueDO = new DimValueDO()
|
||||
.setDomainId(domainId)
|
||||
.setDefaultMetricIds(defaultMetricDescList)
|
||||
.setDimensions(dimensions);
|
||||
dimValueDOList.add(dimValueDO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isVisibleDim(KnowledgeInfo dictionaryInfo, ItemVisibilityInfo itemVisibilityDesc) {
|
||||
if (Objects.isNull(itemVisibilityDesc) || CollectionUtils.isEmpty(itemVisibilityDesc.getBlackDimIdList())) {
|
||||
return true;
|
||||
}
|
||||
return !itemVisibilityDesc.getBlackDimIdList().contains(dictionaryInfo.getItemId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.tencent.supersonic.chat.domain.utils;
|
||||
|
||||
import static com.tencent.supersonic.common.constant.Constants.AND_UPPER;
|
||||
import static com.tencent.supersonic.common.constant.Constants.APOSTROPHE;
|
||||
import static com.tencent.supersonic.common.constant.Constants.COMMA;
|
||||
import static com.tencent.supersonic.common.constant.Constants.UNDERLINE_DOUBLE;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||
import com.tencent.supersonic.chat.api.service.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;
|
||||
import com.tencent.supersonic.semantic.api.query.pojo.Filter;
|
||||
import com.tencent.supersonic.semantic.api.query.request.QueryStructReq;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.DefaultMetric;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.Dim4Dict;
|
||||
import com.tencent.supersonic.common.constant.Constants;
|
||||
import com.tencent.supersonic.common.enums.AggOperatorEnum;
|
||||
import com.tencent.supersonic.common.pojo.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;
|
||||
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;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DictQueryUtils {
|
||||
|
||||
private final SemanticLayer semanticLayer;
|
||||
Long frequencyMax = 99999999L;
|
||||
|
||||
@Value("${dimension.multi.value.split:#}")
|
||||
private String dimMultiValueSplit;
|
||||
|
||||
@Value("${dimension.value.show:50}")
|
||||
private Integer printDataShow;
|
||||
|
||||
@Value("${dimension.max.limit:3000000}")
|
||||
private Long dimMaxLimit;
|
||||
|
||||
public DictQueryUtils(SemanticLayer semanticLayer) {
|
||||
this.semanticLayer = semanticLayer;
|
||||
}
|
||||
|
||||
|
||||
public List<String> fetchDimValueSingle(Long domainId, DefaultMetric defaultMetricDesc, Dim4Dict dim4Dict,
|
||||
User user) {
|
||||
List<String> data = new ArrayList<>();
|
||||
QueryStructReq queryStructCmd = generateQueryStructCmd(domainId, defaultMetricDesc, dim4Dict);
|
||||
try {
|
||||
QueryResultWithSchemaResp queryResultWithColumns = semanticLayer.queryByStruct(queryStructCmd, user);
|
||||
String nature = String.format("_%d_%d", domainId, dim4Dict.getDimId());
|
||||
String dimNameRewrite = rewriteDimName(queryResultWithColumns.getColumns(), dim4Dict.getBizName());
|
||||
data = generateFileData(queryResultWithColumns.getResultList(), nature, dimNameRewrite,
|
||||
defaultMetricDesc.getBizName());
|
||||
if (!CollectionUtils.isEmpty(data)) {
|
||||
int size = (data.size() > printDataShow) ? printDataShow : data.size();
|
||||
log.info("data:{}", data.subList(0, size - 1));
|
||||
} else {
|
||||
log.warn("data is empty. nature:{}", nature);
|
||||
if (Objects.nonNull(queryResultWithColumns)) {
|
||||
log.warn("sql:{}", queryResultWithColumns.getSql());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("fetchDimValueSingle,e:", e);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private String rewriteDimName(List<QueryColumn> columns, String bizName) {
|
||||
// metric parser join dimension style
|
||||
String dimNameRewrite = bizName;
|
||||
|
||||
if (!CollectionUtils.isEmpty(columns)) {
|
||||
for (QueryColumn column : columns) {
|
||||
if (Strings.isNotEmpty(column.getNameEn())) {
|
||||
String nameEn = column.getNameEn();
|
||||
if (nameEn.endsWith(UNDERLINE_DOUBLE + bizName)) {
|
||||
dimNameRewrite = nameEn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dimNameRewrite;
|
||||
}
|
||||
|
||||
private List<String> generateFileData(List<Map<String, Object>> resultList, String nature, String dimName,
|
||||
String metricName) {
|
||||
List<String> data = new ArrayList<>();
|
||||
if (CollectionUtils.isEmpty(resultList)) {
|
||||
return data;
|
||||
}
|
||||
Map<String, Long> valueAndFrequencyPair = new HashMap<>(2000);
|
||||
for (Map<String, Object> line : resultList) {
|
||||
|
||||
if (CollectionUtils.isEmpty(line) || !line.containsKey(dimName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String dimValue = line.get(dimName).toString();
|
||||
Object metricObject = line.get(metricName);
|
||||
if (Strings.isNotEmpty(dimValue) && Objects.nonNull(metricObject)) {
|
||||
Long metric = Math.round(Double.parseDouble(metricObject.toString()));
|
||||
mergeMultivaluedValue(valueAndFrequencyPair, dimValue, metric);
|
||||
}
|
||||
|
||||
}
|
||||
constructDataLines(valueAndFrequencyPair, nature, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private void constructDataLines(Map<String, Long> valueAndFrequencyPair, String nature, List<String> data) {
|
||||
valueAndFrequencyPair.forEach((dimValue, metric) -> {
|
||||
if (metric > frequencyMax) {
|
||||
metric = frequencyMax;
|
||||
}
|
||||
data.add(String.format("%s %s %s", dimValue, nature, metric));
|
||||
});
|
||||
}
|
||||
|
||||
private void mergeMultivaluedValue(Map<String, Long> valueAndFrequencyPair, String dimValue, Long metric) {
|
||||
if (Strings.isEmpty(dimValue)) {
|
||||
return;
|
||||
}
|
||||
Map<String, Long> tmp = new HashMap<>();
|
||||
if (dimValue.contains(dimMultiValueSplit)) {
|
||||
Arrays.stream(dimValue.split(dimMultiValueSplit))
|
||||
.forEach(dimValueSingle -> tmp.put(dimValueSingle, metric));
|
||||
} else {
|
||||
tmp.put(dimValue, metric);
|
||||
}
|
||||
|
||||
for (String value : tmp.keySet()) {
|
||||
long metricOld = valueAndFrequencyPair.containsKey(value) ? valueAndFrequencyPair.get(value) : 0L;
|
||||
valueAndFrequencyPair.put(value, metric + metricOld);
|
||||
}
|
||||
}
|
||||
|
||||
private QueryStructReq generateQueryStructCmd(Long domainId, DefaultMetric defaultMetricDesc, Dim4Dict dim4Dict) {
|
||||
QueryStructReq queryStructCmd = new QueryStructReq();
|
||||
|
||||
queryStructCmd.setDomainId(domainId);
|
||||
queryStructCmd.setGroups(Arrays.asList(dim4Dict.getBizName()));
|
||||
|
||||
List<Filter> filters = generateFilters(dim4Dict, queryStructCmd);
|
||||
queryStructCmd.setDimensionFilters(filters);
|
||||
|
||||
List<Aggregator> aggregators = new ArrayList<>();
|
||||
aggregators.add(new Aggregator(defaultMetricDesc.getBizName(), AggOperatorEnum.SUM));
|
||||
queryStructCmd.setAggregators(aggregators);
|
||||
|
||||
List<Order> orders = new ArrayList<>();
|
||||
orders.add(new Order(defaultMetricDesc.getBizName(), Constants.DESC_UPPER));
|
||||
queryStructCmd.setOrders(orders);
|
||||
|
||||
DateConf dateInfo = new DateConf();
|
||||
dateInfo.setDateMode(DateConf.DateMode.RECENT_UNITS);
|
||||
dateInfo.setUnit(defaultMetricDesc.getUnit());
|
||||
queryStructCmd.setDateInfo(dateInfo);
|
||||
|
||||
queryStructCmd.setLimit(dimMaxLimit);
|
||||
return queryStructCmd;
|
||||
|
||||
}
|
||||
|
||||
private List<Filter> generateFilters(Dim4Dict dim4Dict, QueryStructReq queryStructCmd) {
|
||||
String whereStr = generateFilter(dim4Dict);
|
||||
if (Strings.isEmpty(whereStr)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Filter filter = new Filter("", FilterOperatorEnum.SQL_PART, whereStr);
|
||||
List<Filter> filters = Objects.isNull(queryStructCmd.getOriginalFilter()) ? new ArrayList<>()
|
||||
: queryStructCmd.getOriginalFilter();
|
||||
filters.add(filter);
|
||||
return filters;
|
||||
}
|
||||
|
||||
private String generateFilter(Dim4Dict dim4Dict) {
|
||||
if (Objects.isNull(dim4Dict)) {
|
||||
return "";
|
||||
}
|
||||
StringJoiner joiner = new StringJoiner(AND_UPPER);
|
||||
|
||||
String dimName = dim4Dict.getBizName();
|
||||
if (!CollectionUtils.isEmpty(dim4Dict.getBlackList())) {
|
||||
StringJoiner joinerBlack = new StringJoiner(COMMA);
|
||||
dim4Dict.getBlackList().stream().forEach(black -> joinerBlack.add(APOSTROPHE + black + APOSTROPHE));
|
||||
joiner.add(String.format("(%s not in (%s))", dimName, joinerBlack.toString()));
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(dim4Dict.getRuleList())) {
|
||||
dim4Dict.getRuleList().stream().forEach(rule -> joiner.add(rule));
|
||||
}
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.tencent.supersonic.chat.domain.utils;
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementType;
|
||||
import com.tencent.supersonic.common.nlp.NatureType;
|
||||
|
||||
/***
|
||||
* nature type to schemaType converter
|
||||
*/
|
||||
public class NatureConverter {
|
||||
|
||||
public static SchemaElementType convertTo(String nature) {
|
||||
NatureType natureType = NatureType.getNatureType(nature);
|
||||
SchemaElementType result = null;
|
||||
switch (natureType) {
|
||||
case METRIC:
|
||||
result = SchemaElementType.METRIC;
|
||||
break;
|
||||
case DIMENSION:
|
||||
result = SchemaElementType.DIMENSION;
|
||||
break;
|
||||
case ENTITY:
|
||||
result = SchemaElementType.ENTITY;
|
||||
break;
|
||||
case DOMAIN:
|
||||
result = SchemaElementType.DOMAIN;
|
||||
break;
|
||||
case VALUE:
|
||||
result = SchemaElementType.VALUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.tencent.supersonic.chat.domain.utils;
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
||||
import com.tencent.supersonic.chat.application.query.MetricCompare;
|
||||
import com.tencent.supersonic.chat.application.query.MetricDomain;
|
||||
import com.tencent.supersonic.chat.application.query.MetricFilter;
|
||||
import com.tencent.supersonic.chat.application.query.MetricGroupBy;
|
||||
import com.tencent.supersonic.chat.application.query.MetricOrderBy;
|
||||
import com.tencent.supersonic.chat.domain.pojo.semantic.DomainInfos;
|
||||
import com.tencent.supersonic.common.constant.Constants;
|
||||
import com.tencent.supersonic.common.enums.AggOperatorEnum;
|
||||
import com.tencent.supersonic.common.enums.AggregateTypeEnum;
|
||||
import com.tencent.supersonic.common.nlp.ItemDO;
|
||||
import com.tencent.supersonic.common.pojo.Aggregator;
|
||||
import com.tencent.supersonic.common.pojo.DateConf;
|
||||
import com.tencent.supersonic.common.pojo.Order;
|
||||
import com.tencent.supersonic.common.pojo.SchemaItem;
|
||||
import com.tencent.supersonic.semantic.api.core.enums.TimeDimensionEnum;
|
||||
import com.tencent.supersonic.semantic.api.core.response.DimSchemaResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.DomainSchemaResp;
|
||||
import com.tencent.supersonic.semantic.api.core.response.MetricSchemaResp;
|
||||
import com.tencent.supersonic.semantic.api.query.pojo.Filter;
|
||||
import com.tencent.supersonic.semantic.api.query.request.QueryStructReq;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
public class SchemaInfoConverter {
|
||||
|
||||
/***
|
||||
* convert to queryStructReq
|
||||
* @param parseInfo
|
||||
* @return
|
||||
*/
|
||||
public static QueryStructReq convertTo(SemanticParseInfo parseInfo) {
|
||||
QueryStructReq queryStructCmd = new QueryStructReq();
|
||||
queryStructCmd.setDomainId(parseInfo.getDomainId());
|
||||
queryStructCmd.setNativeQuery(parseInfo.getNativeQuery());
|
||||
queryStructCmd.setDateInfo(parseInfo.getDateInfo());
|
||||
|
||||
List<Filter> dimensionFilters = parseInfo.getDimensionFilters().stream()
|
||||
.map(chatFilter -> new Filter(chatFilter.getBizName(), chatFilter.getOperator(), chatFilter.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
queryStructCmd.setDimensionFilters(dimensionFilters);
|
||||
|
||||
List<Filter> metricFilters = parseInfo.getMetricFilters().stream()
|
||||
.map(chatFilter -> new Filter(chatFilter.getBizName(), chatFilter.getOperator(), chatFilter.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
queryStructCmd.setMetricFilters(metricFilters);
|
||||
|
||||
addDateDimension(parseInfo);
|
||||
List<String> dimensions = parseInfo.getDimensions().stream().map(entry -> entry.getBizName())
|
||||
.collect(Collectors.toList());
|
||||
queryStructCmd.setGroups(dimensions);
|
||||
queryStructCmd.setLimit(parseInfo.getLimit());
|
||||
queryStructCmd.setOrders(getOrder(parseInfo.getOrders(), parseInfo.getAggType(), parseInfo.getMetrics()));
|
||||
queryStructCmd.setAggregators(getAggregatorByMetric(parseInfo.getMetrics(), parseInfo.getAggType()));
|
||||
return queryStructCmd;
|
||||
}
|
||||
|
||||
private static List<Aggregator> getAggregatorByMetric(List<SchemaItem> metrics, AggregateTypeEnum aggregateType) {
|
||||
List<Aggregator> aggregators = new ArrayList<>();
|
||||
String agg = (aggregateType == null || aggregateType.equals(AggregateTypeEnum.NONE)) ? ""
|
||||
: aggregateType.name();
|
||||
for (SchemaItem metric : metrics) {
|
||||
aggregators.add(new Aggregator(metric.getBizName(), AggOperatorEnum.of(agg)));
|
||||
}
|
||||
return aggregators;
|
||||
}
|
||||
|
||||
private static void addDateDimension(SemanticParseInfo parseInfo) {
|
||||
if (parseInfo != null) {
|
||||
String queryMode = parseInfo.getQueryMode();
|
||||
if (parseInfo.getDateInfo() == null) {
|
||||
return;
|
||||
}
|
||||
if (MetricCompare.QUERY_MODE.equals(queryMode)) {
|
||||
if (parseInfo.getAggType() != null && !parseInfo.getAggType().equals(AggregateTypeEnum.NONE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (parseInfo.getAggType() != null && (parseInfo.getAggType().equals(AggregateTypeEnum.MAX)
|
||||
|| parseInfo.getAggType().equals(AggregateTypeEnum.MIN)) && !CollectionUtils.isEmpty(
|
||||
parseInfo.getDimensions())) {
|
||||
return;
|
||||
}
|
||||
DateConf dateInfo = parseInfo.getDateInfo();
|
||||
String dateField = TimeDimensionEnum.DAY.getName();
|
||||
if (Constants.MONTH.equals(dateInfo.getPeriod())) {
|
||||
dateField = TimeDimensionEnum.MONTH.getName();
|
||||
}
|
||||
if (Constants.WEEK.equals(dateInfo.getPeriod())) {
|
||||
dateField = TimeDimensionEnum.WEEK.getName();
|
||||
}
|
||||
for (SchemaItem dimension : parseInfo.getDimensions()) {
|
||||
if (dimension.getBizName().equalsIgnoreCase(dateField)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SchemaItem dimension = new SchemaItem();
|
||||
dimension.setBizName(dateField);
|
||||
|
||||
if (MetricDomain.QUERY_MODE.equals(queryMode)
|
||||
|| MetricGroupBy.QUERY_MODE.equals(queryMode)
|
||||
|| MetricFilter.QUERY_MODE.equals(queryMode)
|
||||
|| MetricCompare.QUERY_MODE.equals(queryMode)
|
||||
|| MetricOrderBy.QUERY_MODE.equals(queryMode)) {
|
||||
parseInfo.getDimensions().add(dimension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static DomainInfos convert(List<DomainSchemaResp> domainSchemaInfos) {
|
||||
DomainInfos result = new DomainInfos();
|
||||
if (CollectionUtils.isEmpty(domainSchemaInfos)) {
|
||||
return result;
|
||||
}
|
||||
for (DomainSchemaResp domainSchemaDesc : domainSchemaInfos) {
|
||||
int domain = Math.toIntExact(domainSchemaDesc.getId());
|
||||
// domain
|
||||
ItemDO domainDO = new ItemDO();
|
||||
domainDO.setDomain(domain);
|
||||
domainDO.setName(domainSchemaDesc.getName());
|
||||
domainDO.setItemId(domain);
|
||||
result.getDomains().add(domainDO);
|
||||
// entity
|
||||
List<String> entityNames = domainSchemaDesc.getEntityNames();
|
||||
if (!CollectionUtils.isEmpty(entityNames)) {
|
||||
for (String entityName : entityNames) {
|
||||
ItemDO entity = new ItemDO();
|
||||
entity.setDomain(domain);
|
||||
entity.setName(entityName);
|
||||
entity.setItemId(domain);
|
||||
result.getEntities().add(entity);
|
||||
}
|
||||
}
|
||||
// metric
|
||||
for (MetricSchemaResp metric : domainSchemaDesc.getMetrics()) {
|
||||
ItemDO metricDO = new ItemDO();
|
||||
metricDO.setDomain(domain);
|
||||
metricDO.setName(metric.getName());
|
||||
metricDO.setItemId(Math.toIntExact(metric.getId()));
|
||||
metricDO.setUseCnt(metric.getUseCnt());
|
||||
result.getMetrics().add(metricDO);
|
||||
}
|
||||
// dimension
|
||||
for (DimSchemaResp dimension : domainSchemaDesc.getDimensions()) {
|
||||
ItemDO dimensionDO = new ItemDO();
|
||||
dimensionDO.setDomain(domain);
|
||||
dimensionDO.setName(dimension.getName());
|
||||
dimensionDO.setItemId(Math.toIntExact(dimension.getId()));
|
||||
dimensionDO.setUseCnt(dimension.getUseCnt());
|
||||
result.getDimensions().add(dimensionDO);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Order> getOrder(List<Order> parseOrder, AggregateTypeEnum aggregator, List<SchemaItem> metrics) {
|
||||
if (!CollectionUtils.isEmpty(parseOrder)) {
|
||||
return parseOrder;
|
||||
}
|
||||
List<Order> orders = new ArrayList<>();
|
||||
if (CollectionUtils.isEmpty(metrics)) {
|
||||
return orders;
|
||||
}
|
||||
if ((AggregateTypeEnum.TOPN.equals(aggregator) || AggregateTypeEnum.MAX.equals(aggregator)
|
||||
|| AggregateTypeEnum.MIN.equals(
|
||||
aggregator))) {
|
||||
for (SchemaItem metric : metrics) {
|
||||
Order order = new Order();
|
||||
order.setColumn(metric.getBizName());
|
||||
order.setDirection("desc");
|
||||
orders.add(order);
|
||||
}
|
||||
}
|
||||
return orders;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.tencent.supersonic.chat.infrastructure.mapper;
|
||||
|
||||
import com.tencent.supersonic.chat.domain.dataobject.ChatConfigDO;
|
||||
import com.tencent.supersonic.chat.domain.pojo.config.ChatConfigFilterInternal;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface ChatConfigMapper {
|
||||
|
||||
Long addConfig(ChatConfigDO chaConfigPO);
|
||||
|
||||
Long editConfig(ChatConfigDO chaConfigPO);
|
||||
|
||||
List<ChatConfigDO> search(ChatConfigFilterInternal filterInternal);
|
||||
|
||||
ChatConfigDO fetchConfigByDomainId(Long domainId);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user