(improvement)(headless) transfer term nature modelId to viewId before providing it to chat and put the modelId of metadata into the dict word instead of viewId (#739)

Co-authored-by: jolunoluo
This commit is contained in:
LXW
2024-02-23 10:29:21 +08:00
committed by GitHub
parent 16643e8d75
commit e95a528219
52 changed files with 456 additions and 245 deletions

View File

@@ -45,7 +45,8 @@ public class GroupByCorrector extends BaseSemanticCorrector {
ViewResp viewResp = viewService.getView(viewId); ViewResp viewResp = viewService.getView(viewId);
List<Long> modelIds = viewResp.getViewDetail().getViewModelConfigs().stream().map(config -> config.getId()) List<Long> modelIds = viewResp.getViewDetail().getViewModelConfigs().stream().map(config -> config.getId())
.collect(Collectors.toList()); .collect(Collectors.toList());
MetaFilter metaFilter = new MetaFilter(modelIds); MetaFilter metaFilter = new MetaFilter();
metaFilter.setIds(modelIds);
List<ModelResp> modelRespList = modelService.getModelList(metaFilter); List<ModelResp> modelRespList = modelService.getModelList(metaFilter);
for (ModelResp modelResp : modelRespList) { for (ModelResp modelResp : modelRespList) {
List<Dim> dimList = modelResp.getModelDetail().getDimensions(); List<Dim> dimList = modelResp.getModelDetail().getDimensions();

View File

@@ -10,9 +10,10 @@ import com.tencent.supersonic.headless.api.pojo.response.S2Term;
import com.tencent.supersonic.headless.core.knowledge.EmbeddingResult; import com.tencent.supersonic.headless.core.knowledge.EmbeddingResult;
import com.tencent.supersonic.headless.core.knowledge.builder.BaseWordBuilder; import com.tencent.supersonic.headless.core.knowledge.builder.BaseWordBuilder;
import com.tencent.supersonic.headless.core.knowledge.helper.HanlpHelper; import com.tencent.supersonic.headless.core.knowledge.helper.HanlpHelper;
import com.tencent.supersonic.headless.server.service.KnowledgeService;
import lombok.extern.slf4j.Slf4j;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
/*** /***
* A mapper that recognizes schema elements with vector embedding. * A mapper that recognizes schema elements with vector embedding.
@@ -24,7 +25,8 @@ public class EmbeddingMapper extends BaseMapper {
public void doMap(QueryContext queryContext) { public void doMap(QueryContext queryContext) {
//1. query from embedding by queryText //1. query from embedding by queryText
String queryText = queryContext.getQueryText(); String queryText = queryContext.getQueryText();
List<S2Term> terms = HanlpHelper.getTerms(queryText); KnowledgeService knowledgeService = ContextUtils.getBean(KnowledgeService.class);
List<S2Term> terms = knowledgeService.getTerms(queryText);
EmbeddingMatchStrategy matchStrategy = ContextUtils.getBean(EmbeddingMatchStrategy.class); EmbeddingMatchStrategy matchStrategy = ContextUtils.getBean(EmbeddingMatchStrategy.class);
List<EmbeddingResult> matchResults = matchStrategy.getMatches(queryContext, terms); List<EmbeddingResult> matchResults = matchStrategy.getMatches(queryContext, terms);

View File

@@ -1,36 +1,27 @@
package com.tencent.supersonic.chat.core.parser.sql.llm; package com.tencent.supersonic.chat.core.parser.sql.llm;
import com.tencent.supersonic.chat.api.pojo.request.ChatConfigFilter; import com.tencent.supersonic.chat.api.pojo.ViewSchema;
import com.tencent.supersonic.chat.api.pojo.response.ChatConfigRichResp;
import com.tencent.supersonic.chat.api.pojo.response.ChatDefaultRichConfigResp;
import com.tencent.supersonic.chat.core.pojo.QueryContext; import com.tencent.supersonic.chat.core.pojo.QueryContext;
import com.tencent.supersonic.common.util.DatePeriodEnum; import com.tencent.supersonic.common.util.DatePeriodEnum;
import com.tencent.supersonic.common.util.DateUtils; import com.tencent.supersonic.common.util.DateUtils;
import com.tencent.supersonic.headless.api.pojo.TimeDefaultConfig;
import java.util.Objects; import java.util.Objects;
public class S2SqlDateHelper { public class S2SqlDateHelper {
public static String getReferenceDate(QueryContext queryContext, Long modelId) { public static String getReferenceDate(QueryContext queryContext, Long viewId) {
String defaultDate = DateUtils.getBeforeDate(0); String defaultDate = DateUtils.getBeforeDate(0);
if (Objects.isNull(modelId)) { if (Objects.isNull(viewId)) {
return defaultDate; return defaultDate;
} }
ChatConfigFilter filter = new ChatConfigFilter(); ViewSchema viewSchema = queryContext.getSemanticSchema().getViewSchemaMap().get(viewId);
filter.setModelId(modelId); if (viewSchema == null || viewSchema.getTagTypeTimeDefaultConfig() == null) {
ChatConfigRichResp chatConfigRichResp = queryContext.getModelIdToChatRichConfig().get(modelId);
if (Objects.isNull(chatConfigRichResp)) {
return defaultDate; return defaultDate;
} }
if (Objects.isNull(chatConfigRichResp.getChatDetailRichConfig()) || Objects.isNull( TimeDefaultConfig tagTypeTimeDefaultConfig = viewSchema.getTagTypeTimeDefaultConfig();
chatConfigRichResp.getChatDetailRichConfig().getChatDefaultConfig())) { Integer unit = tagTypeTimeDefaultConfig.getUnit();
return defaultDate; String period = tagTypeTimeDefaultConfig.getPeriod();
}
ChatDefaultRichConfigResp chatDefaultConfig = chatConfigRichResp.getChatDetailRichConfig()
.getChatDefaultConfig();
Integer unit = chatDefaultConfig.getUnit();
String period = chatDefaultConfig.getPeriod();
if (Objects.nonNull(unit)) { if (Objects.nonNull(unit)) {
// If the unit is set to less than 0, then do not add relative date. // If the unit is set to less than 0, then do not add relative date.
if (unit < 0) { if (unit < 0) {

View File

@@ -44,6 +44,7 @@ public class ViewSchemaBuilder {
SchemaElement metricToAdd = SchemaElement.builder() SchemaElement metricToAdd = SchemaElement.builder()
.view(resp.getId()) .view(resp.getId())
.model(metric.getModelId())
.id(metric.getId()) .id(metric.getId())
.name(metric.getName()) .name(metric.getName())
.bizName(metric.getBizName()) .bizName(metric.getBizName())
@@ -84,6 +85,7 @@ public class ViewSchemaBuilder {
} }
SchemaElement dimToAdd = SchemaElement.builder() SchemaElement dimToAdd = SchemaElement.builder()
.view(resp.getId()) .view(resp.getId())
.model(dim.getModelId())
.id(dim.getId()) .id(dim.getId())
.name(dim.getName()) .name(dim.getName())
.bizName(dim.getBizName()) .bizName(dim.getBizName())
@@ -96,6 +98,7 @@ public class ViewSchemaBuilder {
SchemaElement dimValueToAdd = SchemaElement.builder() SchemaElement dimValueToAdd = SchemaElement.builder()
.view(resp.getId()) .view(resp.getId())
.model(dim.getModelId())
.id(dim.getId()) .id(dim.getId())
.name(dim.getName()) .name(dim.getName())
.bizName(dim.getBizName()) .bizName(dim.getBizName())
@@ -107,6 +110,7 @@ public class ViewSchemaBuilder {
if (dim.getIsTag() == 1) { if (dim.getIsTag() == 1) {
SchemaElement tagToAdd = SchemaElement.builder() SchemaElement tagToAdd = SchemaElement.builder()
.view(resp.getId()) .view(resp.getId())
.model(dim.getModelId())
.id(dim.getId()) .id(dim.getId())
.name(dim.getName()) .name(dim.getName())
.bizName(dim.getBizName()) .bizName(dim.getBizName())
@@ -126,6 +130,7 @@ public class ViewSchemaBuilder {
if (dim != null) { if (dim != null) {
SchemaElement entity = SchemaElement.builder() SchemaElement entity = SchemaElement.builder()
.view(resp.getId()) .view(resp.getId())
.model(dim.getModelId())
.id(dim.getId()) .id(dim.getId())
.name(dim.getName()) .name(dim.getName())
.bizName(dim.getBizName()) .bizName(dim.getBizName())

View File

@@ -38,11 +38,11 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor {
queryResult.setRecommendedDimensions(dimensionRecommended); queryResult.setRecommendedDimensions(dimensionRecommended);
} }
private List<SchemaElement> getDimensions(Long metricId, Long modelId) { private List<SchemaElement> getDimensions(Long metricId, Long viewId) {
SemanticService semanticService = ContextUtils.getBean(SemanticService.class); SemanticService semanticService = ContextUtils.getBean(SemanticService.class);
ViewSchema modelSchema = semanticService.getModelSchema(modelId); ViewSchema viewSchema = semanticService.getViewSchema(viewId);
List<Long> drillDownDimensions = Lists.newArrayList(); List<Long> drillDownDimensions = Lists.newArrayList();
Set<SchemaElement> metricElements = modelSchema.getMetrics(); Set<SchemaElement> metricElements = viewSchema.getMetrics();
if (!CollectionUtils.isEmpty(metricElements)) { if (!CollectionUtils.isEmpty(metricElements)) {
Optional<SchemaElement> metric = metricElements.stream().filter(schemaElement -> Optional<SchemaElement> metric = metricElements.stream().filter(schemaElement ->
metricId.equals(schemaElement.getId()) metricId.equals(schemaElement.getId())
@@ -54,7 +54,7 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor {
} }
} }
final List<Long> drillDownDimensionsFinal = drillDownDimensions; final List<Long> drillDownDimensionsFinal = drillDownDimensions;
return modelSchema.getDimensions().stream() return viewSchema.getDimensions().stream()
.filter(dim -> filterDimension(drillDownDimensionsFinal, dim)) .filter(dim -> filterDimension(drillDownDimensionsFinal, dim))
.sorted(Comparator.comparing(SchemaElement::getUseCnt).reversed()) .sorted(Comparator.comparing(SchemaElement::getUseCnt).reversed())
.limit(recommend_dimension_size) .limit(recommend_dimension_size)

View File

@@ -50,7 +50,7 @@ public class SemanticService {
return schemaService.getSemanticSchema(); return schemaService.getSemanticSchema();
} }
public ViewSchema getModelSchema(Long id) { public ViewSchema getViewSchema(Long id) {
return schemaService.getViewSchema(id); return schemaService.getViewSchema(id);
} }

View File

@@ -219,7 +219,7 @@ public class ConfigServiceImpl implements ConfigService {
} }
BeanUtils.copyProperties(chatConfigResp, chatConfigRich); BeanUtils.copyProperties(chatConfigResp, chatConfigRich);
ViewSchema viewSchema = semanticService.getModelSchema(modelId); ViewSchema viewSchema = semanticService.getViewSchema(modelId);
if (viewSchema == null) { if (viewSchema == null) {
return chatConfigRich; return chatConfigRich;
} }

View File

@@ -48,7 +48,7 @@ public class RecommendServiceImpl implements RecommendService {
if (Objects.isNull(modelId)) { if (Objects.isNull(modelId)) {
return new RecommendResp(); return new RecommendResp();
} }
ViewSchema modelSchema = semanticService.getModelSchema(modelId); ViewSchema modelSchema = semanticService.getViewSchema(modelId);
if (Objects.isNull(modelSchema)) { if (Objects.isNull(modelSchema)) {
return new RecommendResp(); return new RecommendResp();
} }

View File

@@ -1,17 +1,19 @@
package com.tencent.supersonic.chat.server.service.impl; package com.tencent.supersonic.chat.server.service.impl;
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
import com.tencent.supersonic.chat.api.pojo.SemanticSchema; import com.tencent.supersonic.chat.api.pojo.SemanticSchema;
import com.tencent.supersonic.headless.core.knowledge.DictWord;
import com.tencent.supersonic.headless.core.knowledge.builder.WordBuilderFactory;
import com.tencent.supersonic.chat.core.query.semantic.SemanticInterpreter; import com.tencent.supersonic.chat.core.query.semantic.SemanticInterpreter;
import com.tencent.supersonic.chat.core.utils.ComponentFactory; import com.tencent.supersonic.chat.core.utils.ComponentFactory;
import com.tencent.supersonic.common.pojo.enums.DictWordType; import com.tencent.supersonic.common.pojo.enums.DictWordType;
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
import com.tencent.supersonic.headless.core.knowledge.DictWord;
import com.tencent.supersonic.headless.core.knowledge.builder.WordBuilderFactory;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service @Service
@@ -28,7 +30,6 @@ public class WordService {
addWordsByType(DictWordType.DIMENSION, semanticSchema.getDimensions(), words); addWordsByType(DictWordType.DIMENSION, semanticSchema.getDimensions(), words);
addWordsByType(DictWordType.METRIC, semanticSchema.getMetrics(), words); addWordsByType(DictWordType.METRIC, semanticSchema.getMetrics(), words);
addWordsByType(DictWordType.VIEW, semanticSchema.getViews(), words);
addWordsByType(DictWordType.ENTITY, semanticSchema.getEntities(), words); addWordsByType(DictWordType.ENTITY, semanticSchema.getEntities(), words);
addWordsByType(DictWordType.VALUE, semanticSchema.getDimensionValues(), words); addWordsByType(DictWordType.VALUE, semanticSchema.getDimensionValues(), words);
@@ -36,6 +37,7 @@ public class WordService {
} }
private void addWordsByType(DictWordType value, List<SchemaElement> metas, List<DictWord> natures) { private void addWordsByType(DictWordType value, List<SchemaElement> metas, List<DictWord> natures) {
metas = distinct(metas);
List<DictWord> natureList = WordBuilderFactory.get(value).getDictWords(metas); List<DictWord> natureList = WordBuilderFactory.get(value).getDictWords(metas);
log.debug("nature type:{} , nature size:{}", value.name(), natureList.size()); log.debug("nature type:{} , nature size:{}", value.name(), natureList.size());
natures.addAll(natureList); natures.addAll(natureList);
@@ -48,4 +50,13 @@ public class WordService {
public void setPreDictWords(List<DictWord> preDictWords) { public void setPreDictWords(List<DictWord> preDictWords) {
this.preDictWords = preDictWords; this.preDictWords = preDictWords;
} }
private List<SchemaElement> distinct(List<SchemaElement> metas) {
return metas.stream()
.collect(Collectors.toMap(SchemaElement::getId, Function.identity(), (e1, e2) -> e1))
.values()
.stream()
.collect(Collectors.toList());
}
} }

View File

@@ -19,13 +19,13 @@ public class ModelDetail {
private String tableQuery; private String tableQuery;
private List<Identify> identifiers; private List<Identify> identifiers = Lists.newArrayList();
private List<Dim> dimensions; private List<Dim> dimensions = Lists.newArrayList();
private List<Measure> measures; private List<Measure> measures = Lists.newArrayList();
private List<Field> fields; private List<Field> fields = Lists.newArrayList();
public String getSqlQuery() { public String getSqlQuery() {
if (StringUtils.isNotBlank(sqlQuery) && sqlQuery.endsWith(";")) { if (StringUtils.isNotBlank(sqlQuery) && sqlQuery.endsWith(";")) {

View File

@@ -3,6 +3,7 @@ package com.tencent.supersonic.headless.api.pojo;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data @Data
public class Param { public class Param {
@@ -10,7 +11,7 @@ public class Param {
@NotBlank(message = "Invald parameter name") @NotBlank(message = "Invald parameter name")
private String name; private String name;
@NotBlank(message = "Invalid parameter value") @NotNull(message = "Invalid parameter value")
private String value; private String value;
public Param() { public Param() {
@@ -21,14 +22,4 @@ public class Param {
this.value = value; this.value = value;
} }
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"name\":\"")
.append(name).append('\"');
sb.append(",\"value\":\"")
.append(value).append('\"');
sb.append('}');
return sb.toString();
}
} }

View File

@@ -1,7 +1,6 @@
package com.tencent.supersonic.headless.api.pojo; package com.tencent.supersonic.headless.api.pojo;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@@ -19,6 +18,7 @@ import java.util.List;
public class SchemaElement implements Serializable { public class SchemaElement implements Serializable {
private Long view; private Long view;
private Long model;
private Long id; private Long id;
private String name; private String name;
private String bizName; private String bizName;
@@ -52,7 +52,4 @@ public class SchemaElement implements Serializable {
return Objects.hashCode(view, id, name, bizName, type); return Objects.hashCode(view, id, name, bizName, type);
} }
public List<String> getModelNames() {
return Lists.newArrayList(name);
}
} }

View File

@@ -30,6 +30,8 @@ public class MetricResp extends SchemaItem {
private Long domainId; private Long domainId;
private String modelBizName;
private String modelName; private String modelName;
//ATOMIC DERIVED //ATOMIC DERIVED

View File

@@ -6,8 +6,15 @@ import com.hankcs.hanlp.corpus.tag.Nature;
import com.hankcs.hanlp.dictionary.CoreDictionary; import com.hankcs.hanlp.dictionary.CoreDictionary;
import com.hankcs.hanlp.seg.common.Term; import com.hankcs.hanlp.seg.common.Term;
import com.tencent.supersonic.common.pojo.enums.DictWordType; import com.tencent.supersonic.common.pojo.enums.DictWordType;
import com.tencent.supersonic.headless.api.pojo.request.DimensionValueReq;
import com.tencent.supersonic.headless.core.knowledge.helper.NatureHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@@ -17,11 +24,6 @@ import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.tencent.supersonic.headless.api.pojo.request.DimensionValueReq;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
@Slf4j @Slf4j
public class SearchService { public class SearchService {
@@ -39,14 +41,14 @@ public class SearchService {
* @param key * @param key
* @return * @return
*/ */
public static List<HanlpMapResult> prefixSearch(String key, int limit, Set<Long> detectModelIds) { public static List<HanlpMapResult> prefixSearch(String key, int limit, Map<Long, List<Long>> modelIdToViewIds) {
return prefixSearch(key, limit, trie, detectModelIds); return prefixSearch(key, limit, trie, modelIdToViewIds);
} }
public static List<HanlpMapResult> prefixSearch(String key, int limit, BinTrie<List<String>> binTrie, public static List<HanlpMapResult> prefixSearch(String key, int limit, BinTrie<List<String>> binTrie,
Set<Long> detectModelIds) { Map<Long, List<Long>> modelIdToViewIds) {
Set<Map.Entry<String, List<String>>> result = prefixSearchLimit(key, limit, binTrie, detectModelIds); Set<Map.Entry<String, List<String>>> result = prefixSearchLimit(key, limit, binTrie, modelIdToViewIds.keySet());
return result.stream().map( List<HanlpMapResult> hanlpMapResults = result.stream().map(
entry -> { entry -> {
String name = entry.getKey().replace("#", " "); String name = entry.getKey().replace("#", " ");
return new HanlpMapResult(name, entry.getValue(), key); return new HanlpMapResult(name, entry.getValue(), key);
@@ -54,6 +56,13 @@ public class SearchService {
).sorted((a, b) -> -(b.getName().length() - a.getName().length())) ).sorted((a, b) -> -(b.getName().length() - a.getName().length()))
.limit(SEARCH_SIZE) .limit(SEARCH_SIZE)
.collect(Collectors.toList()); .collect(Collectors.toList());
for (HanlpMapResult hanlpMapResult : hanlpMapResults) {
List<String> natures = hanlpMapResult.getNatures().stream()
.map(nature -> NatureHelper.changeModel2View(nature, modelIdToViewIds))
.flatMap(Collection::stream).collect(Collectors.toList());
hanlpMapResult.setNatures(natures);
}
return hanlpMapResults;
} }
/*** /***

View File

@@ -38,11 +38,11 @@ public class DimensionWordBuilder extends BaseWordBuilder {
private DictWord getOnwWordNature(String word, SchemaElement schemaElement, boolean isSuffix) { private DictWord getOnwWordNature(String word, SchemaElement schemaElement, boolean isSuffix) {
DictWord dictWord = new DictWord(); DictWord dictWord = new DictWord();
dictWord.setWord(word); dictWord.setWord(word);
Long viewId = schemaElement.getView(); Long modelId = schemaElement.getModel();
String nature = DictWordType.NATURE_SPILT + viewId + DictWordType.NATURE_SPILT + schemaElement.getId() String nature = DictWordType.NATURE_SPILT + modelId + DictWordType.NATURE_SPILT + schemaElement.getId()
+ DictWordType.DIMENSION.getType(); + DictWordType.DIMENSION.getType();
if (isSuffix) { if (isSuffix) {
nature = DictWordType.NATURE_SPILT + viewId + DictWordType.NATURE_SPILT + schemaElement.getId() nature = DictWordType.NATURE_SPILT + modelId + DictWordType.NATURE_SPILT + schemaElement.getId()
+ DictWordType.SUFFIX.getType() + DictWordType.DIMENSION.getType(); + DictWordType.SUFFIX.getType() + DictWordType.DIMENSION.getType();
} }
dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature)); dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature));

View File

@@ -27,8 +27,8 @@ public class EntityWordBuilder extends BaseWordBuilder {
return result; return result;
} }
Long view = schemaElement.getView(); Long modelId = schemaElement.getModel();
String nature = DictWordType.NATURE_SPILT + view + DictWordType.NATURE_SPILT + schemaElement.getId() String nature = DictWordType.NATURE_SPILT + modelId + DictWordType.NATURE_SPILT + schemaElement.getId()
+ DictWordType.ENTITY.getType(); + DictWordType.ENTITY.getType();
if (!CollectionUtils.isEmpty(schemaElement.getAlias())) { if (!CollectionUtils.isEmpty(schemaElement.getAlias())) {

View File

@@ -38,11 +38,11 @@ public class MetricWordBuilder extends BaseWordBuilder {
private DictWord getOnwWordNature(String word, SchemaElement schemaElement, boolean isSuffix) { private DictWord getOnwWordNature(String word, SchemaElement schemaElement, boolean isSuffix) {
DictWord dictWord = new DictWord(); DictWord dictWord = new DictWord();
dictWord.setWord(word); dictWord.setWord(word);
Long viewId = schemaElement.getView(); Long modelId = schemaElement.getModel();
String nature = DictWordType.NATURE_SPILT + viewId + DictWordType.NATURE_SPILT + schemaElement.getId() String nature = DictWordType.NATURE_SPILT + modelId + DictWordType.NATURE_SPILT + schemaElement.getId()
+ DictWordType.METRIC.getType(); + DictWordType.METRIC.getType();
if (isSuffix) { if (isSuffix) {
nature = DictWordType.NATURE_SPILT + viewId + DictWordType.NATURE_SPILT + schemaElement.getId() nature = DictWordType.NATURE_SPILT + modelId + DictWordType.NATURE_SPILT + schemaElement.getId()
+ DictWordType.SUFFIX.getType() + DictWordType.METRIC.getType(); + DictWordType.SUFFIX.getType() + DictWordType.METRIC.getType();
} }
dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature)); dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature));

View File

@@ -27,8 +27,8 @@ public class ValueWordBuilder extends BaseWordBuilder {
schemaElement.getAlias().stream().forEach(value -> { schemaElement.getAlias().stream().forEach(value -> {
DictWord dictWord = new DictWord(); DictWord dictWord = new DictWord();
Long viewId = schemaElement.getView(); Long modelId = schemaElement.getModel();
String nature = DictWordType.NATURE_SPILT + viewId + DictWordType.NATURE_SPILT + schemaElement.getId(); String nature = DictWordType.NATURE_SPILT + modelId + DictWordType.NATURE_SPILT + schemaElement.getId();
dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature)); dictWord.setNatureWithFrequency(String.format("%s " + DEFAULT_FREQUENCY, nature));
dictWord.setWord(value); dictWord.setWord(value);
result.add(dictWord); result.add(dictWord);

View File

@@ -1,34 +1,36 @@
package com.tencent.supersonic.headless.core.knowledge.helper; package com.tencent.supersonic.headless.core.knowledge.helper;
import static com.hankcs.hanlp.HanLP.Config.CustomDictionaryPath; import com.google.common.collect.Lists;
import com.hankcs.hanlp.HanLP; import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.corpus.tag.Nature; import com.hankcs.hanlp.corpus.tag.Nature;
import com.hankcs.hanlp.dictionary.CoreDictionary; import com.hankcs.hanlp.dictionary.CoreDictionary;
import com.hankcs.hanlp.dictionary.DynamicCustomDictionary; import com.hankcs.hanlp.dictionary.DynamicCustomDictionary;
import com.hankcs.hanlp.seg.Segment; import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import com.tencent.supersonic.common.pojo.enums.DictWordType;
import com.tencent.supersonic.headless.api.pojo.response.S2Term; import com.tencent.supersonic.headless.api.pojo.response.S2Term;
import com.tencent.supersonic.headless.core.knowledge.DictWord; import com.tencent.supersonic.headless.core.knowledge.DictWord;
import com.tencent.supersonic.headless.core.knowledge.HadoopFileIOAdapter; import com.tencent.supersonic.headless.core.knowledge.HadoopFileIOAdapter;
import com.tencent.supersonic.headless.core.knowledge.MapResult; import com.tencent.supersonic.headless.core.knowledge.MapResult;
import com.tencent.supersonic.headless.core.knowledge.MultiCustomDictionary; import com.tencent.supersonic.headless.core.knowledge.MultiCustomDictionary;
import com.tencent.supersonic.headless.core.knowledge.SearchService; import com.tencent.supersonic.headless.core.knowledge.SearchService;
import com.tencent.supersonic.common.pojo.enums.DictWordType; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.hankcs.hanlp.seg.common.Term; import static com.hankcs.hanlp.HanLP.Config.CustomDictionaryPath;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
/** /**
* HanLP helper * HanLP helper
@@ -212,18 +214,25 @@ public class HanlpHelper {
} }
} }
public static List<com.tencent.supersonic.headless.api.pojo.response.S2Term> getTerms(String text) { public static List<S2Term> getTerms(String text, Map<Long, List<Long>> modelIdToViewIds) {
return getSegment().seg(text.toLowerCase()).stream() return getSegment().seg(text.toLowerCase()).stream()
.filter(term -> term.getNature().startsWith(DictWordType.NATURE_SPILT)) .filter(term -> term.getNature().startsWith(DictWordType.NATURE_SPILT))
.map(term -> transform2ApiTerm(term)) .map(term -> transform2ApiTerm(term, modelIdToViewIds))
.flatMap(Collection::stream)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public static S2Term transform2ApiTerm(Term term) { public static List<S2Term> transform2ApiTerm(Term term, Map<Long, List<Long>> modelIdToViewIds) {
S2Term knowledgeTerm = new S2Term(); List<S2Term> s2Terms = Lists.newArrayList();
BeanUtils.copyProperties(term, knowledgeTerm); List<String> natures = NatureHelper.changeModel2View(String.valueOf(term.getNature()), modelIdToViewIds);
knowledgeTerm.setFrequency(term.getFrequency()); for (String nature : natures) {
return knowledgeTerm; S2Term s2Term = new S2Term();
BeanUtils.copyProperties(term, s2Term);
s2Term.setNature(Nature.create(nature));
s2Term.setFrequency(term.getFrequency());
s2Terms.add(s2Term);
}
return s2Terms;
} }
} }

View File

@@ -1,12 +1,14 @@
package com.tencent.supersonic.headless.core.knowledge.helper; package com.tencent.supersonic.headless.core.knowledge.helper;
import com.google.common.collect.Lists;
import com.hankcs.hanlp.corpus.tag.Nature; import com.hankcs.hanlp.corpus.tag.Nature;
import com.tencent.supersonic.common.pojo.enums.DictWordType;
import com.tencent.supersonic.headless.api.pojo.SchemaElementType; import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
import com.tencent.supersonic.headless.api.pojo.response.S2Term; import com.tencent.supersonic.headless.api.pojo.response.S2Term;
import com.tencent.supersonic.headless.core.knowledge.ViewInfoStat; import com.tencent.supersonic.headless.core.knowledge.ViewInfoStat;
import com.tencent.supersonic.common.pojo.enums.DictWordType;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
@@ -81,6 +83,43 @@ public class NatureHelper {
return null; return null;
} }
private static Long getModelId(String nature) {
try {
String[] split = nature.split(DictWordType.NATURE_SPILT);
if (split.length <= 1) {
return null;
}
return Long.valueOf(split[1]);
} catch (NumberFormatException e) {
log.error("", e);
}
return null;
}
private static Nature changeModel2View(String nature, Long viewId) {
try {
String[] split = nature.split(DictWordType.NATURE_SPILT);
if (split.length <= 1) {
return null;
}
split[1] = String.valueOf(viewId);
return Nature.create(StringUtils.join(split, DictWordType.NATURE_SPILT));
} catch (NumberFormatException e) {
log.error("", e);
}
return null;
}
public static List<String> changeModel2View(String nature, Map<Long, List<Long>> modelIdToViewIds) {
Long modelId = getModelId(nature);
List<Long> viewIds = modelIdToViewIds.get(modelId);
if (CollectionUtils.isEmpty(viewIds)) {
return Lists.newArrayList();
}
return viewIds.stream().map(viewId -> String.valueOf(changeModel2View(nature, viewId)))
.collect(Collectors.toList());
}
public static boolean isDimensionValueViewId(String nature) { public static boolean isDimensionValueViewId(String nature) {
if (StringUtils.isEmpty(nature)) { if (StringUtils.isEmpty(nature)) {
return false; return false;

View File

@@ -11,11 +11,13 @@ import com.tencent.supersonic.headless.api.pojo.response.MetricResp;
import com.tencent.supersonic.headless.api.pojo.response.MetricSchemaResp; import com.tencent.supersonic.headless.api.pojo.response.MetricSchemaResp;
import com.tencent.supersonic.headless.api.pojo.response.SemanticSchemaResp; import com.tencent.supersonic.headless.api.pojo.response.SemanticSchemaResp;
import com.tencent.supersonic.headless.core.pojo.QueryStatement; import com.tencent.supersonic.headless.core.pojo.QueryStatement;
import com.tencent.supersonic.headless.server.service.MetricService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.Collection; import java.util.Collection;
@@ -28,6 +30,9 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class MetricDrillDownChecker { public class MetricDrillDownChecker {
@Autowired
private MetricService metricService;
@Around("execution(* com.tencent.supersonic.headless.core.parser.QueryParser.parse(..))") @Around("execution(* com.tencent.supersonic.headless.core.parser.QueryParser.parse(..))")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] objects = joinPoint.getArgs(); Object[] objects = joinPoint.getArgs();
@@ -52,7 +57,7 @@ public class MetricDrillDownChecker {
List<DimensionResp> necessaryDimensions = getNecessaryDimensions(metric, semanticSchemaResp); List<DimensionResp> necessaryDimensions = getNecessaryDimensions(metric, semanticSchemaResp);
List<DimensionResp> dimensionsMissing = getNecessaryDimensionMissing(necessaryDimensions, dimensionFields); List<DimensionResp> dimensionsMissing = getNecessaryDimensionMissing(necessaryDimensions, dimensionFields);
if (!CollectionUtils.isEmpty(dimensionsMissing)) { if (!CollectionUtils.isEmpty(dimensionsMissing)) {
String errMsg = String.format("指标:%s 缺失必要维度:%s", metric.getName(), String errMsg = String.format("指标:%s 缺失必要下钻维度:%s", metric.getName(),
dimensionsMissing.stream().map(DimensionResp::getName).collect(Collectors.toList())); dimensionsMissing.stream().map(DimensionResp::getName).collect(Collectors.toList()));
throw new InvalidArgumentException(errMsg); throw new InvalidArgumentException(errMsg);
} }
@@ -92,8 +97,9 @@ public class MetricDrillDownChecker {
return true; return true;
} }
List<String> relateDimensions = metricResps.stream() List<String> relateDimensions = metricResps.stream()
.filter(metric -> !CollectionUtils.isEmpty(metric.getDrillDownDimensions())) .map(this::getDrillDownDimensions)
.map(metric -> metric.getDrillDownDimensions().stream() .filter(drillDownDimensions -> !CollectionUtils.isEmpty(drillDownDimensions))
.map(drillDownDimensions -> drillDownDimensions.stream()
.map(DrillDownDimension::getDimensionId).collect(Collectors.toList())) .map(DrillDownDimension::getDimensionId).collect(Collectors.toList()))
.flatMap(Collection::stream) .flatMap(Collection::stream)
.map(id -> convertDimensionIdToBizName(id, semanticSchemaResp)) .map(id -> convertDimensionIdToBizName(id, semanticSchemaResp))
@@ -111,7 +117,7 @@ public class MetricDrillDownChecker {
if (metric == null) { if (metric == null) {
return Lists.newArrayList(); return Lists.newArrayList();
} }
List<DrillDownDimension> drillDownDimensions = metric.getDrillDownDimensions(); List<DrillDownDimension> drillDownDimensions = getDrillDownDimensions(metric);
if (CollectionUtils.isEmpty(drillDownDimensions)) { if (CollectionUtils.isEmpty(drillDownDimensions)) {
return Lists.newArrayList(); return Lists.newArrayList();
} }
@@ -147,4 +153,8 @@ public class MetricDrillDownChecker {
return dimension.getBizName(); return dimension.getBizName();
} }
private List<DrillDownDimension> getDrillDownDimensions(MetricResp metricResp) {
return metricService.getDrillDownDimension(metricResp.getId());
}
} }

View File

@@ -30,7 +30,7 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class ModelYamlManager { public class ModelYamlManager {
public static DataModelYamlTpl convert2YamlObj(ModelResp modelResp, DatabaseResp databaseResp) { public static synchronized DataModelYamlTpl convert2YamlObj(ModelResp modelResp, DatabaseResp databaseResp) {
ModelDetail modelDetail = modelResp.getModelDetail(); ModelDetail modelDetail = modelResp.getModelDetail();
DbAdaptor engineAdaptor = DbAdaptorFactory.getEngineAdaptor(databaseResp.getType()); DbAdaptor engineAdaptor = DbAdaptorFactory.getEngineAdaptor(databaseResp.getType());
SysTimeDimensionBuilder.addSysTimeDimension(modelDetail.getDimensions(), engineAdaptor); SysTimeDimensionBuilder.addSysTimeDimension(modelDetail.getDimensions(), engineAdaptor);

View File

@@ -109,8 +109,9 @@ public class DownloadServiceImpl implements DownloadService {
metaFilter.setIds(metricIds); metaFilter.setIds(metricIds);
List<MetricResp> metricResps = metricService.getMetrics(metaFilter); List<MetricResp> metricResps = metricService.getMetrics(metaFilter);
Map<String, List<MetricResp>> metricMap = getMetricMap(metricResps); Map<String, List<MetricResp>> metricMap = getMetricMap(metricResps);
List<Long> dimensionIds = metricResps.stream().map(MetricResp::getRelateDimension) List<Long> dimensionIds = metricResps.stream()
.map(RelateDimension::getDrillDownDimensions).flatMap(Collection::stream) .map(metricResp -> metricService.getDrillDownDimension(metricResp.getId()))
.flatMap(Collection::stream)
.map(DrillDownDimension::getDimensionId).collect(Collectors.toList()); .map(DrillDownDimension::getDimensionId).collect(Collectors.toList());
metaFilter.setIds(dimensionIds); metaFilter.setIds(dimensionIds);
Map<Long, DimensionResp> dimensionRespMap = dimensionService.getDimensions(metaFilter) Map<Long, DimensionResp> dimensionRespMap = dimensionService.getDimensions(metaFilter)

View File

@@ -8,13 +8,14 @@ import com.tencent.supersonic.headless.core.knowledge.SearchService;
import com.tencent.supersonic.headless.core.knowledge.helper.HanlpHelper; import com.tencent.supersonic.headless.core.knowledge.helper.HanlpHelper;
import com.tencent.supersonic.headless.server.service.KnowledgeService; import com.tencent.supersonic.headless.server.service.KnowledgeService;
import com.tencent.supersonic.headless.server.service.ViewService; import com.tencent.supersonic.headless.server.service.ViewService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service @Service
@Slf4j @Slf4j
@@ -68,17 +69,19 @@ public class KnowledgeServiceImpl implements KnowledgeService {
@Override @Override
public List<S2Term> getTerms(String text) { public List<S2Term> getTerms(String text) {
return HanlpHelper.getTerms(text); Map<Long, List<Long>> modelIdToViewIds = viewService.getModelIdToViewIds(new ArrayList<>());
return HanlpHelper.getTerms(text, modelIdToViewIds);
} }
@Override @Override
public List<HanlpMapResult> prefixSearch(String key, int limit, Set<Long> viewIds) { public List<HanlpMapResult> prefixSearch(String key, int limit, Set<Long> viewIds) {
Map<Long, List<Long>> modelIdToViewIds = viewService.getModelIdToViewIds(new ArrayList<>(viewIds)); Map<Long, List<Long>> modelIdToViewIds = viewService.getModelIdToViewIds(new ArrayList<>(viewIds));
return prefixSearchByModel(key, limit, modelIdToViewIds.keySet()); return prefixSearchByModel(key, limit, modelIdToViewIds);
} }
public List<HanlpMapResult> prefixSearchByModel(String key, int limit, Set<Long> models) { public List<HanlpMapResult> prefixSearchByModel(String key, int limit,
return SearchService.prefixSearch(key, limit, models); Map<Long, List<Long>> modelIdToViewIds) {
return SearchService.prefixSearch(key, limit, modelIdToViewIds);
} }
@Override @Override

View File

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.TypeReference;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.pojo.User;
import com.tencent.supersonic.common.pojo.Constants; import com.tencent.supersonic.common.pojo.Constants;
import com.tencent.supersonic.common.pojo.DataEvent; import com.tencent.supersonic.common.pojo.DataEvent;
@@ -16,6 +17,7 @@ import com.tencent.supersonic.common.pojo.enums.TypeEnums;
import com.tencent.supersonic.common.util.BeanMapper; import com.tencent.supersonic.common.util.BeanMapper;
import com.tencent.supersonic.common.util.ChatGptHelper; import com.tencent.supersonic.common.util.ChatGptHelper;
import com.tencent.supersonic.headless.api.pojo.DrillDownDimension; import com.tencent.supersonic.headless.api.pojo.DrillDownDimension;
import com.tencent.supersonic.headless.api.pojo.MeasureParam;
import com.tencent.supersonic.headless.api.pojo.MetricParam; import com.tencent.supersonic.headless.api.pojo.MetricParam;
import com.tencent.supersonic.headless.api.pojo.MetricQueryDefaultConfig; import com.tencent.supersonic.headless.api.pojo.MetricQueryDefaultConfig;
import com.tencent.supersonic.headless.api.pojo.enums.MetricDefineType; import com.tencent.supersonic.headless.api.pojo.enums.MetricDefineType;
@@ -40,6 +42,12 @@ import com.tencent.supersonic.headless.server.service.ModelService;
import com.tencent.supersonic.headless.server.service.ViewService; import com.tencent.supersonic.headless.server.service.ViewService;
import com.tencent.supersonic.headless.server.utils.MetricCheckUtils; import com.tencent.supersonic.headless.server.utils.MetricCheckUtils;
import com.tencent.supersonic.headless.server.utils.MetricConverter; import com.tencent.supersonic.headless.server.utils.MetricConverter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@@ -48,11 +56,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@Service @Service
@Slf4j @Slf4j
@@ -228,28 +231,44 @@ public class MetricServiceImpl implements MetricService {
} }
private List<MetricResp> filterByField(List<MetricResp> metricResps, List<String> fields) { private List<MetricResp> filterByField(List<MetricResp> metricResps, List<String> fields) {
List<MetricResp> metricRespFiltered = Lists.newArrayList(); Set<MetricResp> metricRespFiltered = Sets.newHashSet();
for (MetricResp metricResp : metricResps) { for (MetricResp metricResp : metricResps) {
for (String field : fields) { filterByField(metricResps, metricResp, fields, metricRespFiltered);
if (MetricDefineType.METRIC.equals(metricResp.getMetricDefineType())) { }
List<Long> ids = metricResp.getMetricDefineByMetricParams().getMetrics() return new ArrayList<>(metricRespFiltered);
.stream().map(MetricParam::getId).collect(Collectors.toList()); }
List<MetricResp> metricById = metricResps.stream()
.filter(metric -> ids.contains(metric.getId())) private boolean filterByField(List<MetricResp> metricResps, MetricResp metricResp,
.collect(Collectors.toList()); List<String> fields, Set<MetricResp> metricRespFiltered) {
for (MetricResp metric : metricById) { if (MetricDefineType.METRIC.equals(metricResp.getMetricDefineType())) {
if (metric.getExpr().contains(field)) { List<Long> ids = metricResp.getMetricDefineByMetricParams().getMetrics()
metricRespFiltered.add(metricResp); .stream().map(MetricParam::getId).collect(Collectors.toList());
} List<MetricResp> metricById = metricResps.stream()
} .filter(metric -> ids.contains(metric.getId()))
} else { .collect(Collectors.toList());
if (metricResp.getExpr().contains(field)) { for (MetricResp metric : metricById) {
metricRespFiltered.add(metricResp); if (filterByField(metricResps, metric, fields, metricRespFiltered)) {
} metricRespFiltered.add(metricResp);
return true;
} }
} }
} else if (MetricDefineType.FIELD.equals(metricResp.getMetricDefineType())) {
if (fields.stream().anyMatch(field -> metricResp.getExpr().contains(field))) {
metricRespFiltered.add(metricResp);
return true;
}
} else if (MetricDefineType.MEASURE.equals(metricResp.getMetricDefineType())) {
List<MeasureParam> measures = metricResp.getMetricDefineByMeasureParams().getMeasures();
List<String> fieldNameDepended = measures.stream().map(MeasureParam::getBizName)
//measure bizName = model bizName_fieldName
.map(name -> name.replaceFirst(metricResp.getModelBizName() + "_", ""))
.collect(Collectors.toList());
if (fields.stream().anyMatch(fieldNameDepended::contains)) {
metricRespFiltered.add(metricResp);
return true;
}
} }
return metricRespFiltered; return false;
} }
@Override @Override

View File

@@ -64,6 +64,13 @@ public class SchemaServiceImpl implements SchemaService {
protected final Cache<String, List<ItemUseResp>> itemUseCache = protected final Cache<String, List<ItemUseResp>> itemUseCache =
CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.DAYS).build(); CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.DAYS).build();
protected final Cache<ViewFilterReq, List<ViewSchemaResp>> viewSchemaCache =
CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build();
protected final Cache<SchemaFilterReq, SemanticSchemaResp> semanticSchemaCache =
CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build();
private final StatUtils statUtils; private final StatUtils statUtils;
private final ModelService modelService; private final ModelService modelService;
private final DimensionService dimensionService; private final DimensionService dimensionService;
@@ -91,6 +98,22 @@ public class SchemaServiceImpl implements SchemaService {
@SneakyThrows @SneakyThrows
@Override @Override
public List<ViewSchemaResp> fetchViewSchema(ViewFilterReq filter) { public List<ViewSchemaResp> fetchViewSchema(ViewFilterReq filter) {
List<ViewSchemaResp> viewList = viewSchemaCache.getIfPresent(filter);
if (CollectionUtils.isEmpty(viewList)) {
viewList = buildViewSchema(filter);
viewSchemaCache.put(filter, viewList);
}
return viewList;
}
public ViewSchemaResp fetchViewSchema(Long viewId) {
if (viewId == null) {
return null;
}
return fetchViewSchema(new ViewFilterReq(viewId)).stream().findFirst().orElse(null);
}
public List<ViewSchemaResp> buildViewSchema(ViewFilterReq filter) {
List<ViewSchemaResp> viewSchemaResps = new ArrayList<>(); List<ViewSchemaResp> viewSchemaResps = new ArrayList<>();
List<Long> viewIds = filter.getViewIds(); List<Long> viewIds = filter.getViewIds();
MetaFilter metaFilter = new MetaFilter(); MetaFilter metaFilter = new MetaFilter();
@@ -127,13 +150,6 @@ public class SchemaServiceImpl implements SchemaService {
return viewSchemaResps; return viewSchemaResps;
} }
public ViewSchemaResp fetchViewSchema(Long viewId) {
if (viewId == null) {
return null;
}
return fetchViewSchema(new ViewFilterReq(viewId)).stream().findFirst().orElse(null);
}
public List<ModelSchemaResp> fetchModelSchemaResps(List<Long> modelIds) { public List<ModelSchemaResp> fetchModelSchemaResps(List<Long> modelIds) {
List<ModelSchemaResp> modelSchemaResps = Lists.newArrayList(); List<ModelSchemaResp> modelSchemaResps = Lists.newArrayList();
if (CollectionUtils.isEmpty(modelIds)) { if (CollectionUtils.isEmpty(modelIds)) {
@@ -258,8 +274,7 @@ public class SchemaServiceImpl implements SchemaService {
return viewService.getViewList(metaFilter); return viewService.getViewList(metaFilter);
} }
@Override public SemanticSchemaResp buildSemanticSchema(SchemaFilterReq schemaFilterReq) {
public SemanticSchemaResp fetchSemanticSchema(SchemaFilterReq schemaFilterReq) {
SemanticSchemaResp semanticSchemaResp = new SemanticSchemaResp(); SemanticSchemaResp semanticSchemaResp = new SemanticSchemaResp();
semanticSchemaResp.setViewId(schemaFilterReq.getViewId()); semanticSchemaResp.setViewId(schemaFilterReq.getViewId());
semanticSchemaResp.setModelIds(schemaFilterReq.getModelIds()); semanticSchemaResp.setModelIds(schemaFilterReq.getModelIds());
@@ -294,6 +309,16 @@ public class SchemaServiceImpl implements SchemaService {
return semanticSchemaResp; return semanticSchemaResp;
} }
@Override
public SemanticSchemaResp fetchSemanticSchema(SchemaFilterReq schemaFilterReq) {
SemanticSchemaResp semanticSchemaResp = semanticSchemaCache.getIfPresent(schemaFilterReq);
if (semanticSchemaResp == null) {
semanticSchemaResp = buildSemanticSchema(schemaFilterReq);
semanticSchemaCache.put(schemaFilterReq, semanticSchemaResp);
}
return semanticSchemaResp;
}
@SneakyThrows @SneakyThrows
@Override @Override
public List<ItemUseResp> getStatInfo(ItemUseReq itemUseReq) { public List<ItemUseResp> getStatInfo(ItemUseReq itemUseReq) {

View File

@@ -10,17 +10,29 @@ import com.tencent.supersonic.auth.api.authentication.pojo.User;
import com.tencent.supersonic.common.pojo.enums.AuthType; import com.tencent.supersonic.common.pojo.enums.AuthType;
import com.tencent.supersonic.common.pojo.enums.StatusEnum; import com.tencent.supersonic.common.pojo.enums.StatusEnum;
import com.tencent.supersonic.common.pojo.enums.TypeEnums; import com.tencent.supersonic.common.pojo.enums.TypeEnums;
import com.tencent.supersonic.common.pojo.exception.InvalidArgumentException;
import com.tencent.supersonic.common.util.BeanMapper; import com.tencent.supersonic.common.util.BeanMapper;
import com.tencent.supersonic.headless.api.pojo.QueryConfig; import com.tencent.supersonic.headless.api.pojo.QueryConfig;
import com.tencent.supersonic.headless.api.pojo.ViewDetail; import com.tencent.supersonic.headless.api.pojo.ViewDetail;
import com.tencent.supersonic.headless.api.pojo.request.ViewReq; import com.tencent.supersonic.headless.api.pojo.request.ViewReq;
import com.tencent.supersonic.headless.api.pojo.response.DimensionResp;
import com.tencent.supersonic.headless.api.pojo.response.DomainResp; import com.tencent.supersonic.headless.api.pojo.response.DomainResp;
import com.tencent.supersonic.headless.api.pojo.response.MetricResp;
import com.tencent.supersonic.headless.api.pojo.response.ViewResp; import com.tencent.supersonic.headless.api.pojo.response.ViewResp;
import com.tencent.supersonic.headless.server.persistence.dataobject.ViewDO; import com.tencent.supersonic.headless.server.persistence.dataobject.ViewDO;
import com.tencent.supersonic.headless.server.persistence.mapper.ViewDOMapper; import com.tencent.supersonic.headless.server.persistence.mapper.ViewDOMapper;
import com.tencent.supersonic.headless.server.pojo.MetaFilter; import com.tencent.supersonic.headless.server.pojo.MetaFilter;
import com.tencent.supersonic.headless.server.service.DimensionService;
import com.tencent.supersonic.headless.server.service.DomainService; import com.tencent.supersonic.headless.server.service.DomainService;
import com.tencent.supersonic.headless.server.service.MetricService;
import com.tencent.supersonic.headless.server.service.ViewService; import com.tencent.supersonic.headless.server.service.ViewService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
@@ -29,12 +41,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@Service @Service
public class ViewServiceImpl public class ViewServiceImpl
@@ -46,21 +54,33 @@ public class ViewServiceImpl
@Autowired @Autowired
private DomainService domainService; private DomainService domainService;
@Lazy
@Autowired
private DimensionService dimensionService;
@Lazy
@Autowired
private MetricService metricService;
@Override @Override
public ViewResp save(ViewReq viewReq, User user) { public ViewResp save(ViewReq viewReq, User user) {
viewReq.createdBy(user.getName()); viewReq.createdBy(user.getName());
ViewDO viewDO = convert(viewReq); ViewDO viewDO = convert(viewReq);
viewDO.setStatus(StatusEnum.ONLINE.getCode()); viewDO.setStatus(StatusEnum.ONLINE.getCode());
ViewResp viewResp = convert(viewDO);
conflictCheck(viewResp);
save(viewDO); save(viewDO);
return convert(viewDO); return viewResp;
} }
@Override @Override
public ViewResp update(ViewReq viewReq, User user) { public ViewResp update(ViewReq viewReq, User user) {
viewReq.updatedBy(user.getName()); viewReq.updatedBy(user.getName());
ViewDO viewDO = convert(viewReq); ViewDO viewDO = convert(viewReq);
ViewResp viewResp = convert(viewDO);
conflictCheck(viewResp);
updateById(viewDO); updateById(viewDO);
return convert(viewDO); return viewResp;
} }
@Override @Override
@@ -78,6 +98,9 @@ public class ViewServiceImpl
if (!CollectionUtils.isEmpty(metaFilter.getIds())) { if (!CollectionUtils.isEmpty(metaFilter.getIds())) {
wrapper.lambda().in(ViewDO::getId, metaFilter.getIds()); wrapper.lambda().in(ViewDO::getId, metaFilter.getIds());
} }
if (metaFilter.getStatus() != null) {
wrapper.lambda().eq(ViewDO::getStatus, metaFilter.getStatus());
}
wrapper.lambda().ne(ViewDO::getStatus, StatusEnum.DELETED.getCode()); wrapper.lambda().ne(ViewDO::getStatus, StatusEnum.DELETED.getCode());
return list(wrapper).stream().map(this::convert).collect(Collectors.toList()); return list(wrapper).stream().map(this::convert).collect(Collectors.toList());
} }
@@ -175,4 +198,43 @@ public class ViewServiceImpl
viewResp -> viewResp.getAllModels().stream().map(modelId -> Pair.of(modelId, viewResp.getId()))) viewResp -> viewResp.getAllModels().stream().map(modelId -> Pair.of(modelId, viewResp.getId())))
.collect(Collectors.groupingBy(Pair::getLeft, Collectors.mapping(Pair::getRight, Collectors.toList()))); .collect(Collectors.groupingBy(Pair::getLeft, Collectors.mapping(Pair::getRight, Collectors.toList())));
} }
private void conflictCheck(ViewResp viewResp) {
List<Long> allDimensionIds = viewResp.getAllDimensions();
List<Long> allMetricIds = viewResp.getAllMetrics();
MetaFilter metaFilter = new MetaFilter();
metaFilter.setIds(allDimensionIds);
List<DimensionResp> dimensionResps = dimensionService.getDimensions(metaFilter);
metaFilter.setIds(allMetricIds);
List<MetricResp> metricResps = metricService.getMetrics(metaFilter);
List<String> duplicateDimensionNames = findDuplicates(dimensionResps, DimensionResp::getName);
List<String> duplicateDimensionBizNames = findDuplicates(dimensionResps, DimensionResp::getBizName);
List<String> duplicateMetricNames = findDuplicates(metricResps, MetricResp::getName);
List<String> duplicateMetricBizNames = findDuplicates(metricResps, MetricResp::getBizName);
if (!duplicateDimensionNames.isEmpty()) {
throw new InvalidArgumentException("存在相同的维度名: " + duplicateDimensionNames);
}
if (!duplicateDimensionBizNames.isEmpty()) {
throw new InvalidArgumentException("存在相同的维度英文名: " + duplicateDimensionBizNames);
}
if (!duplicateMetricNames.isEmpty()) {
throw new InvalidArgumentException("存在相同的指标名: " + duplicateMetricNames);
}
if (!duplicateMetricBizNames.isEmpty()) {
throw new InvalidArgumentException("存在相同的指标英文名: " + duplicateMetricBizNames);
}
}
private <T, R> List<String> findDuplicates(List<T> list, Function<T, R> keyExtractor) {
return list.stream()
.collect(Collectors.groupingBy(keyExtractor, Collectors.counting()))
.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.map(Map.Entry::getKey)
.map(Object::toString)
.collect(Collectors.toList());
}
} }

View File

@@ -72,6 +72,7 @@ public class MetricConverter {
ModelResp modelResp = modelMap.get(metricDO.getModelId()); ModelResp modelResp = modelMap.get(metricDO.getModelId());
if (modelResp != null) { if (modelResp != null) {
metricResp.setModelName(modelResp.getName()); metricResp.setModelName(modelResp.getName());
metricResp.setModelBizName(modelResp.getBizName());
metricResp.setDomainId(modelResp.getDomainId()); metricResp.setDomainId(modelResp.getDomainId());
} }
metricResp.setIsCollect(collect != null && collect.contains(metricDO.getId())); metricResp.setIsCollect(collect != null && collect.contains(metricDO.getId()));

View File

@@ -224,7 +224,7 @@ public class BenchMarkDemoDataLoader {
new ViewModelConfig(5L, Lists.newArrayList(8L), Lists.newArrayList()), new ViewModelConfig(5L, Lists.newArrayList(8L), Lists.newArrayList()),
new ViewModelConfig(6L, Lists.newArrayList(9L, 10L), Lists.newArrayList()), new ViewModelConfig(6L, Lists.newArrayList(9L, 10L), Lists.newArrayList()),
new ViewModelConfig(7L, Lists.newArrayList(11L, 12L), Lists.newArrayList()), new ViewModelConfig(7L, Lists.newArrayList(11L, 12L), Lists.newArrayList()),
new ViewModelConfig(8L, Lists.newArrayList(13L, 14L, 15L), Lists.newArrayList(8L, 9L)) new ViewModelConfig(8L, Lists.newArrayList(13L, 14L), Lists.newArrayList(8L, 9L))
); );
ViewDetail viewDetail = new ViewDetail(); ViewDetail viewDetail = new ViewDetail();
viewDetail.setViewModelConfigs(viewModelConfigs); viewDetail.setViewModelConfigs(viewModelConfigs);

View File

@@ -5,14 +5,14 @@ dean _1_2 36
john _1_2 50 john _1_2 50
jack _1_2 38 jack _1_2 38
admin _1_2 70 admin _1_2 70
周杰伦 _2_7 100 周杰伦 _4_7 100
陈奕迅 _2_7 100 陈奕迅 _4_7 100
林俊杰 _2_7 100 林俊杰 _4_7 100
张碧晨 _2_7 100 张碧晨 _4_7 100
程响 _2_7 100 程响 _4_7 100
Taylor#Swift _2_7 100 Taylor#Swift _4_7 100
内地 _2_4 100 内地 _4_4 100
欧美 _2_4 100 欧美 _4_4 100
港台 _2_4 100 港台 _4_4 100
流行 _2_6 100 流行 _4_6 100
国风 _2_6 100 国风 _4_6 100

View File

@@ -1,6 +1,6 @@
p1 _2_3 52 p1 _3_3 52
p2 _2_3 47 p2 _3_3 47
p3 _2_3 31 p3 _3_3 31
p4 _2_3 36 p4 _3_3 36
p5 _2_3 50 p5 _3_3 50
p6 _2_3 38 p6 _3_3 38

View File

@@ -1,9 +1,9 @@
周杰伦 _2_7 9000 周杰伦 _4_7 9000
周深 _2_7 8000 周深 _4_7 8000
周传雄 _2_7 7000 周传雄 _4_7 7000
周华建 _2_7 6000 周华建 _4_7 6000
陈奕迅 _2_7 8000 陈奕迅 _4_7 8000
林俊杰 _2_7 7000 林俊杰 _4_7 7000
张碧晨 _2_7 7000 张碧晨 _4_7 7000
程响 _2_7 7000 程响 _4_7 7000
Taylor#Swift _2_7 7000 Taylor#Swift _4_7 7000

View File

@@ -1,4 +1,4 @@
美国 _3_8 1 美国 _5_8 1
加拿大 _3_8 1 加拿大 _5_8 1
锡尔赫特、吉大港、库斯蒂亚 _3_8 1 锡尔赫特、吉大港、库斯蒂亚 _5_8 1
孟加拉国 _3_8 3 孟加拉国 _5_8 3

View File

@@ -1,6 +1,6 @@
现代 _3_9 1 现代 _5_9 1
tagore _3_9 1 tagore _5_9 1
蓝调 _3_9 1 蓝调 _5_9 1
流行 _3_9 1 流行 _5_9 1
民间 _3_9 1 民间 _5_9 1
nazrul _3_9 1 nazrul _5_9 1

View File

@@ -1,4 +1,4 @@
美国 _3_11 1 美国 _6_11 1
印度 _3_11 2 印度 _6_11 2
英国 _3_11 1 英国 _6_11 1
孟加拉国 _3_11 2 孟加拉国 _6_11 2

View File

@@ -1,2 +1,2 @@
男性 _3_12 3 男性 _6_12 3
女性 _3_12 3 女性 _6_12 3

View File

@@ -1,2 +1,2 @@
mp4 _3_14 4 mp4 _7_14 4
mp3 _3_14 2 mp3 _7_14 2

View File

@@ -1,4 +1,4 @@
美国 _3_17 1 美国 _8_17 1
印度 _3_17 2 印度 _8_17 2
英国 _3_17 1 英国 _8_17 1
孟加拉国 _3_17 2 孟加拉国 _8_17 2

View File

@@ -1,2 +1,2 @@
英文 _3_18 2 英文 _8_18 2
孟加拉语 _3_18 4 孟加拉语 _8_18 4

View File

@@ -1,6 +1,6 @@
阿米·奥帕尔·霍伊 _3_16 1 阿米·奥帕尔·霍伊 _8_16 1
我的爱 _3_16 1 我的爱 _8_16 1
打败它 _3_16 1 打败它 _8_16 1
阿杰伊阿卡什 _3_16 1 阿杰伊阿卡什 _8_16 1
Tumi#长袍#尼罗布 _3_16 1 Tumi#长袍#尼罗布 _8_16 1
舒克诺#帕塔尔#努普尔#帕埃 _3_16 1 舒克诺#帕塔尔#努普尔#帕埃 _8_16 1

View File

@@ -0,0 +1,33 @@
package com.tencent.supersonic.headless;
import com.google.common.collect.Lists;
import com.tencent.supersonic.headless.api.pojo.request.FieldRemovedReq;
import com.tencent.supersonic.headless.api.pojo.response.MetricResp;
import com.tencent.supersonic.headless.api.pojo.response.UnAvailableItemResp;
import com.tencent.supersonic.headless.server.service.ModelService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class ModelSchemaTest extends BaseTest {
@Autowired
private ModelService modelService;
@Test
void testGetUnAvailableItem() {
FieldRemovedReq fieldRemovedReq = new FieldRemovedReq();
fieldRemovedReq.setModelId(2L);
fieldRemovedReq.setFields(Lists.newArrayList("pv"));
UnAvailableItemResp unAvailableItemResp = modelService.getUnAvailableItem(fieldRemovedReq);
List<Long> expectedUnAvailableMetricId = Lists.newArrayList(1L, 3L);
List<Long> actualUnAvailableMetricId = unAvailableItemResp.getMetricResps()
.stream().map(MetricResp::getId).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
Assertions.assertEquals(expectedUnAvailableMetricId, actualUnAvailableMetricId);
}
}

View File

@@ -5,14 +5,14 @@ dean _1_2 36
john _1_2 50 john _1_2 50
jack _1_2 38 jack _1_2 38
admin _1_2 70 admin _1_2 70
周杰伦 _2_7 100 周杰伦 _4_7 100
陈奕迅 _2_7 100 陈奕迅 _4_7 100
林俊杰 _2_7 100 林俊杰 _4_7 100
张碧晨 _2_7 100 张碧晨 _4_7 100
程响 _2_7 100 程响 _4_7 100
Taylor#Swift _2_7 100 Taylor#Swift _4_7 100
内地 _2_4 100 内地 _4_4 100
欧美 _2_4 100 欧美 _4_4 100
港台 _2_4 100 港台 _4_4 100
流行 _2_6 100 流行 _4_6 100
国风 _2_6 100 国风 _4_6 100

View File

@@ -1,6 +1,6 @@
p1 _2_3 52 p1 _3_3 52
p2 _2_3 47 p2 _3_3 47
p3 _2_3 31 p3 _3_3 31
p4 _2_3 36 p4 _3_3 36
p5 _2_3 50 p5 _3_3 50
p6 _2_3 38 p6 _3_3 38

View File

@@ -1,9 +1,9 @@
周杰伦 _2_7 9000 周杰伦 _4_7 9000
周深 _2_7 8000 周深 _4_7 8000
周传雄 _2_7 7000 周传雄 _4_7 7000
周华建 _2_7 6000 周华建 _4_7 6000
陈奕迅 _2_7 8000 陈奕迅 _4_7 8000
林俊杰 _2_7 7000 林俊杰 _4_7 7000
张碧晨 _2_7 7000 张碧晨 _4_7 7000
程响 _2_7 7000 程响 _4_7 7000
Taylor#Swift _2_7 7000 Taylor#Swift _4_7 7000

View File

@@ -1,4 +1,4 @@
美国 _5_8 1 美国 _5_8 1
加拿大 _5_8 1 加拿大 _5_8 1
锡尔赫特、吉大港、库斯蒂亚 _5_8 1 锡尔赫特、吉大港、库斯蒂亚 _5_8 1
孟加拉国 _5_8 3 孟加拉国 _5_8 3

View File

@@ -3,4 +3,4 @@ tagore _5_9 1
蓝调 _5_9 1 蓝调 _5_9 1
流行 _5_9 1 流行 _5_9 1
民间 _5_9 1 民间 _5_9 1
nazrul _5_9 1 nazrul _5_9 1

View File

@@ -1,4 +1,4 @@
美国 _6_10 1 美国 _6_11 1
印度 _6_10 2 印度 _6_11 2
英国 _6_10 1 英国 _6_11 1
孟加拉国 _6_10 2 孟加拉国 _6_11 2

View File

@@ -1,2 +1,2 @@
男性 _6_11 3 男性 _6_12 3
女性 _6_11 3 女性 _6_12 3

View File

@@ -1,2 +1,2 @@
mp4 _7_14 4 mp4 _7_14 4
mp3 _7_14 2 mp3 _7_14 2

View File

@@ -1,4 +1,4 @@
美国 _8_16 1 美国 _8_17 1
印度 _8_16 2 印度 _8_17 2
英国 _8_16 1 英国 _8_17 1
孟加拉国 _8_16 2 孟加拉国 _8_17 2

View File

@@ -1,2 +1,2 @@
英文 _8_17 2 英文 _8_18 2
孟加拉语 _8_17 4 孟加拉语 _8_18 4

View File

@@ -1,6 +1,6 @@
阿米·奥帕尔·霍伊 _8_19 1 阿米·奥帕尔·霍伊 _8_16 1
我的爱 _8_19 1 我的爱 _8_16 1
打败它 _8_19 1 打败它 _8_16 1
阿杰伊阿卡什 _8_19 1 阿杰伊阿卡什 _8_16 1
Tumi#长袍#尼罗布 _8_19 1 Tumi#长袍#尼罗布 _8_16 1
舒克诺#帕塔尔#努普尔#帕埃 _8_19 1 舒克诺#帕塔尔#努普尔#帕埃 _8_16 1