@@ -39,6 +39,7 @@ import (
3939 "github.com/apache/skywalking-banyandb/banyand/internal/sidx"
4040 "github.com/apache/skywalking-banyandb/banyand/protector"
4141 "github.com/apache/skywalking-banyandb/pkg/convert"
42+ "github.com/apache/skywalking-banyandb/pkg/encoding"
4243 "github.com/apache/skywalking-banyandb/pkg/fs"
4344 "github.com/apache/skywalking-banyandb/pkg/index/inverted"
4445 "github.com/apache/skywalking-banyandb/pkg/logger"
@@ -797,6 +798,13 @@ func dumpSidxFullScan(sidxPath, segmentPath string, criteria *modelv1.Criteria,
797798 }
798799 }
799800
801+ // Discover projected tag value types so binary values (for example int64) can be rendered as readable values.
802+ projectionTagTypes , err := discoverProjectionTagTypes (sidxPath , projectionTagNames )
803+ if err != nil {
804+ fmt .Fprintf (os .Stderr , "Warning: failed to discover projection tag types: %v\n " , err )
805+ projectionTagTypes = nil
806+ }
807+
800808 // Create dynamic tag registry if criteria is provided
801809 var tagRegistry * dynamicTagRegistry
802810 if criteria != nil {
@@ -878,9 +886,9 @@ func dumpSidxFullScan(sidxPath, segmentPath string, criteria *modelv1.Criteria,
878886
879887 // Output results
880888 if csvOutput {
881- return outputScanResultsAsCSV (results , seriesMap , projectionTagNames , dataFilter )
889+ return outputScanResultsAsCSV (results , seriesMap , projectionTagNames , projectionTagTypes , dataFilter )
882890 }
883- return outputScanResultsAsText (results , sidxPath , seriesMap , projectionTagNames , dataFilter )
891+ return outputScanResultsAsText (results , sidxPath , seriesMap , projectionTagNames , projectionTagTypes , dataFilter )
884892}
885893
886894// parseProjectionTags parses a comma-separated list of tag names.
@@ -939,7 +947,9 @@ func loadSeriesMap(segmentPath string) (map[common.SeriesID]string, error) {
939947 return seriesMap , nil
940948}
941949
942- func outputScanResultsAsText (results []* sidx.QueryResponse , sidxPath string , seriesMap map [common.SeriesID ]string , projectionTagNames []string , dataFilter string ) error {
950+ func outputScanResultsAsText (results []* sidx.QueryResponse , sidxPath string , seriesMap map [common.SeriesID ]string ,
951+ projectionTagNames []string , projectionTagTypes map [string ]pbv1.ValueType , dataFilter string ,
952+ ) error {
943953 fmt .Printf ("Opening sidx: %s\n " , sidxPath )
944954 fmt .Printf ("================================================================================\n \n " )
945955
@@ -984,9 +994,9 @@ func outputScanResultsAsText(results []*sidx.QueryResponse, sidxPath string, ser
984994 if len (projectionTagNames ) > 0 && resp .Tags != nil {
985995 for _ , tagName := range projectionTagNames {
986996 if tagValues , ok := resp .Tags [tagName ]; ok && i < len (tagValues ) {
987- tagValue := tagValues [i ]
997+ tagValue := decodeProjectedTagValue ( tagValues [i ], projectionTagTypes [ tagName ])
988998 // Calculate size of the tag value
989- tagSize := len (tagValue )
999+ tagSize := len (tagValues [ i ] )
9901000 fmt .Printf (" %s: %s (size: %d bytes)\n " , tagName , tagValue , tagSize )
9911001 }
9921002 }
@@ -1008,7 +1018,9 @@ func outputScanResultsAsText(results []*sidx.QueryResponse, sidxPath string, ser
10081018 return nil
10091019}
10101020
1011- func outputScanResultsAsCSV (results []* sidx.QueryResponse , seriesMap map [common.SeriesID ]string , projectionTagNames []string , dataFilter string ) error {
1021+ func outputScanResultsAsCSV (results []* sidx.QueryResponse , seriesMap map [common.SeriesID ]string ,
1022+ projectionTagNames []string , projectionTagTypes map [string ]pbv1.ValueType , dataFilter string ,
1023+ ) error {
10121024 writer := csv .NewWriter (os .Stdout )
10131025 defer writer .Flush ()
10141026
@@ -1058,9 +1070,9 @@ func outputScanResultsAsCSV(results []*sidx.QueryResponse, seriesMap map[common.
10581070
10591071 if resp .Tags != nil {
10601072 if tagValues , ok := resp .Tags [tagName ]; ok && i < len (tagValues ) {
1061- tagValue = tagValues [i ]
1073+ tagValue = decodeProjectedTagValue ( tagValues [i ], projectionTagTypes [ tagName ])
10621074 // Calculate size of the tag value
1063- tagSize = fmt .Sprintf ("%d" , len (tagValue ))
1075+ tagSize = fmt .Sprintf ("%d" , len (tagValues [ i ] ))
10641076 }
10651077 }
10661078
@@ -1077,3 +1089,81 @@ func outputScanResultsAsCSV(results []*sidx.QueryResponse, seriesMap map[common.
10771089
10781090 return nil
10791091}
1092+
1093+ func discoverProjectionTagTypes (sidxPath string , projectionTagNames []string ) (map [string ]pbv1.ValueType , error ) {
1094+ if len (projectionTagNames ) == 0 {
1095+ return nil , nil
1096+ }
1097+ partEntries , err := os .ReadDir (sidxPath )
1098+ if err != nil {
1099+ return nil , fmt .Errorf ("failed to read sidx path %s: %w" , sidxPath , err )
1100+ }
1101+ partPaths := make ([]string , 0 , len (partEntries ))
1102+ for _ , entry := range partEntries {
1103+ if ! entry .IsDir () {
1104+ continue
1105+ }
1106+ partPaths = append (partPaths , filepath .Join (sidxPath , entry .Name ()))
1107+ }
1108+ sort .Strings (partPaths )
1109+
1110+ result := make (map [string ]pbv1.ValueType , len (projectionTagNames ))
1111+ for _ , tagName := range projectionTagNames {
1112+ for _ , partPath := range partPaths {
1113+ tmPath := filepath .Join (partPath , tagName + ".tm" )
1114+ data , readErr := os .ReadFile (tmPath )
1115+ if readErr != nil {
1116+ continue
1117+ }
1118+ valueType , parseErr := parseSidxTagValueType (data )
1119+ if parseErr != nil {
1120+ fmt .Fprintf (os .Stderr , "Warning: failed to parse %s: %v\n " , tmPath , parseErr )
1121+ break
1122+ }
1123+ result [tagName ] = valueType
1124+ break
1125+ }
1126+ }
1127+ return result , nil
1128+ }
1129+
1130+ func parseSidxTagValueType (data []byte ) (pbv1.ValueType , error ) {
1131+ src , _ , err := encoding .DecodeBytes (data )
1132+ if err != nil {
1133+ return pbv1 .ValueTypeUnknown , fmt .Errorf ("cannot decode tag name: %w" , err )
1134+ }
1135+ if len (src ) < 1 {
1136+ return pbv1 .ValueTypeUnknown , fmt .Errorf ("invalid tag metadata: missing value type" )
1137+ }
1138+ return pbv1 .ValueType (src [0 ]), nil
1139+ }
1140+
1141+ func decodeProjectedTagValue (raw string , valueType pbv1.ValueType ) string {
1142+ if raw == "" {
1143+ return raw
1144+ }
1145+ rawBytes := []byte (raw )
1146+
1147+ switch valueType {
1148+ case pbv1 .ValueTypeInt64 :
1149+ if len (rawBytes ) != 8 {
1150+ return raw
1151+ }
1152+ return strconv .FormatInt (convert .BytesToInt64 (rawBytes ), 10 )
1153+ case pbv1 .ValueTypeFloat64 :
1154+ if len (rawBytes ) != 8 {
1155+ return raw
1156+ }
1157+ return strconv .FormatFloat (convert .BytesToFloat64 (rawBytes ), 'f' , - 1 , 64 )
1158+ case pbv1 .ValueTypeTimestamp :
1159+ if len (rawBytes ) != 8 {
1160+ return raw
1161+ }
1162+ nanos := convert .BytesToInt64 (rawBytes )
1163+ return strconv .FormatInt (nanos , 10 )
1164+ case pbv1 .ValueTypeBinaryData :
1165+ return fmt .Sprintf ("%x" , rawBytes )
1166+ default :
1167+ return raw
1168+ }
1169+ }
0 commit comments