diff --git a/api.go b/api.go index 9204411de..70e7774bd 100644 --- a/api.go +++ b/api.go @@ -161,7 +161,13 @@ type ChunkMatch struct { // beginning of a line (Column will always be 1). ContentStart Location + // Score is the overall relevance score of this chunk. Score float64 + + // BestLineMatch is the line number of the highest-scoring line match in this chunk. + // The line number represents the index in the full file, and is 1-based. If FileName: true, + // this number will be 0. + BestLineMatch uint32 } func (cm *ChunkMatch) sizeBytes() (sz uint64) { diff --git a/api_proto.go b/api_proto.go index 457671a90..4ca3e0758 100644 --- a/api_proto.go +++ b/api_proto.go @@ -96,13 +96,14 @@ func ChunkMatchFromProto(p *proto.ChunkMatch) ChunkMatch { } return ChunkMatch{ - Content: p.GetContent(), - ContentStart: LocationFromProto(p.GetContentStart()), - FileName: p.GetFileName(), - Ranges: ranges, - SymbolInfo: symbols, - Score: p.GetScore(), - DebugScore: p.GetDebugScore(), + Content: p.GetContent(), + ContentStart: LocationFromProto(p.GetContentStart()), + FileName: p.GetFileName(), + Ranges: ranges, + SymbolInfo: symbols, + Score: p.GetScore(), + BestLineMatch: p.GetBestLineMatch(), + DebugScore: p.GetDebugScore(), } } @@ -118,13 +119,14 @@ func (cm *ChunkMatch) ToProto() *proto.ChunkMatch { } return &proto.ChunkMatch{ - Content: cm.Content, - ContentStart: cm.ContentStart.ToProto(), - FileName: cm.FileName, - Ranges: ranges, - SymbolInfo: symbolInfo, - Score: cm.Score, - DebugScore: cm.DebugScore, + Content: cm.Content, + ContentStart: cm.ContentStart.ToProto(), + FileName: cm.FileName, + Ranges: ranges, + SymbolInfo: symbolInfo, + Score: cm.Score, + BestLineMatch: cm.BestLineMatch, + DebugScore: cm.DebugScore, } } diff --git a/api_test.go b/api_test.go index b8e0c9d97..d37daf39a 100644 --- a/api_test.go +++ b/api_test.go @@ -149,7 +149,7 @@ func TestMatchSize(t *testing.T) { size: 256, }, { v: ChunkMatch{}, - size: 112, + size: 120, }, { v: candidateMatch{}, size: 80, diff --git a/build/scoring_test.go b/build/scoring_test.go index ac703e242..ea0bfc638 100644 --- a/build/scoring_test.go +++ b/build/scoring_test.go @@ -27,11 +27,12 @@ import ( ) type scoreCase struct { - fileName string - content []byte - query query.Q - language string - wantScore float64 + fileName string + content []byte + query query.Q + language string + wantScore float64 + wantBestLineMatch uint32 } func TestFileNameMatch(t *testing.T) { @@ -79,6 +80,8 @@ func TestBM25(t *testing.T) { language: "Java", // bm25-score: 0.58 <- sum-termFrequencyScore: 14.00, length-ratio: 1.00 wantScore: 0.58, + // line 5: private final int exampleField; + wantBestLineMatch: 5, }, { // Matches only on content fileName: "example.java", @@ -91,6 +94,8 @@ func TestBM25(t *testing.T) { language: "Java", // bm25-score: 1.81 <- sum-termFrequencyScore: 116.00, length-ratio: 1.00 wantScore: 1.81, + // line 3: public class InnerClasses { + wantBestLineMatch: 3, }, { // Matches only on filename @@ -130,6 +135,8 @@ func TestJava(t *testing.T) { language: "Java", // 5500 (partial symbol at boundary) + 1000 (Java class) + 50 (partial word) wantScore: 6550, + // line 37: public class InnerClass implements InnerInterface { + wantBestLineMatch: 37, }, { fileName: "example.java", @@ -138,6 +145,8 @@ func TestJava(t *testing.T) { language: "Java", // 5500 (partial symbol at boundary) + 1000 (Java class) + 500 (word) wantScore: 7000, + // line 32: public static class InnerStaticClass { + wantBestLineMatch: 32, }, { fileName: "example.java", @@ -146,6 +155,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (symbol) + 900 (Java enum) + 500 (word) wantScore: 8400, + // line 16: public enum InnerEnum { + wantBestLineMatch: 16, }, { fileName: "example.java", @@ -154,6 +165,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (symbol) + 800 (Java interface) + 500 (word) wantScore: 8300, + // line 22: public interface InnerInterface { + wantBestLineMatch: 22, }, { fileName: "example.java", @@ -162,6 +175,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (symbol) + 700 (Java method) + 500 (word) wantScore: 8200, + // line 44: public void innerMethod() { + wantBestLineMatch: 44, }, { fileName: "example.java", @@ -170,6 +185,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (symbol) + 600 (Java field) + 500 (word) wantScore: 8100, + // line 38: private final int field; + wantBestLineMatch: 38, }, { fileName: "example.java", @@ -178,6 +195,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (symbol) + 500 (Java enum constant) + 500 (word) wantScore: 8000, + // line 18: B, + wantBestLineMatch: 18, }, // 2 Atoms (1x content and 1x filename) { @@ -187,6 +206,8 @@ func TestJava(t *testing.T) { language: "Java", // 5500 (edge symbol) + 600 (Java field) + 500 (word) + 200 (atom) wantScore: 6800, + // line 5: private final int exampleField; + wantBestLineMatch: 5, }, // 3 Atoms (2x content, 1x filename) { @@ -199,6 +220,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (symbol) + 700 (Java method) + 500 (word) + 266.67 (atom) wantScore: 8466, + // line 54: private static B runInnerInterface(InnerInterface fn, A a) { + wantBestLineMatch: 54, }, // 4 Atoms (4x content) { @@ -213,6 +236,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (symbol) + 900 (Java enum) + 500 (word) + 300 (atom) wantScore: 8700, + // line 16: public enum InnerEnum { + wantBestLineMatch: 16, }, { fileName: "example.java", @@ -221,6 +246,8 @@ func TestJava(t *testing.T) { language: "Java", // 4000 (overlap Symbol) + 700 (Java method) + 50 (partial word) wantScore: 4750, + // line 54: private static B runInnerInterface(InnerInterface fn, A a) { + wantBestLineMatch: 54, }, { fileName: "example.java", @@ -229,6 +256,8 @@ func TestJava(t *testing.T) { language: "Java", // 7000 (Symbol) + 900 (Java enum) + 500 (word) wantScore: 8400, + // line 16: public enum InnerEnum { + wantBestLineMatch: 16, }, { fileName: "example.java", @@ -237,6 +266,8 @@ func TestJava(t *testing.T) { language: "Java", // 5500 (edge Symbol) + 900 (Java enum) + 500 (word) wantScore: 6900, + // line 16: public enum InnerEnum { + wantBestLineMatch: 16, }, { fileName: "example.java", @@ -245,6 +276,8 @@ func TestJava(t *testing.T) { language: "Java", // 4000 (overlap Symbol) + 900 (Java enum) + 500 (word) wantScore: 5400, + // line 16: public enum InnerEnum { + wantBestLineMatch: 16, }, } @@ -640,6 +673,16 @@ func checkScoring(t *testing.T, c scoreCase, useBM25 bool, parserType ctags.CTag t.Fatalf("score: want %f, got %f\ndebug: %s\ndebugscore: %s", c.wantScore, got, srs.Files[0].Debug, srs.Files[0].ChunkMatches[0].DebugScore) } + if c.wantBestLineMatch != 0 { + if len(srs.Files[0].ChunkMatches) == 0 { + t.Fatalf("want BestLineMatch %d, but no chunk matches were returned", c.wantBestLineMatch) + } + chunkMatch := srs.Files[0].ChunkMatches[0] + if chunkMatch.BestLineMatch != c.wantBestLineMatch { + t.Fatalf("want BestLineMatch %d, got %d", c.wantBestLineMatch, chunkMatch.BestLineMatch) + } + } + if got := srs.Files[0].Language; got != c.language { t.Fatalf("want %s, got %s", c.language, got) } diff --git a/contentprovider.go b/contentprovider.go index bbd334d75..34600f303 100644 --- a/contentprovider.go +++ b/contentprovider.go @@ -164,12 +164,12 @@ func (p *contentProvider) fillMatches(ms []*candidateMatch, numContextLines int, } // Otherwise, we return a single line containing the filematch match. - score, debugScore, _ := p.candidateMatchScore(filenameMatches, language, debug) + bestMatch, _ := p.candidateMatchScore(filenameMatches, language, debug) res := LineMatch{ Line: p.id.fileName(p.idx), FileName: true, - Score: score, - DebugScore: debugScore, + Score: bestMatch.score, + DebugScore: bestMatch.debugScore, } for _, m := range ms { @@ -210,7 +210,7 @@ func (p *contentProvider) fillChunkMatches(ms []*candidateMatch, numContextLines } // Otherwise, we return a single chunk representing the filename match. - score, debugScore, _ := p.candidateMatchScore(filenameMatches, language, debug) + bestMatch, _ := p.candidateMatchScore(filenameMatches, language, debug) fileName := p.id.fileName(p.idx) ranges := make([]Range, 0, len(ms)) for _, m := range ms { @@ -233,9 +233,8 @@ func (p *contentProvider) fillChunkMatches(ms []*candidateMatch, numContextLines ContentStart: Location{ByteOffset: 0, LineNumber: 1, Column: 1}, Ranges: ranges, FileName: true, - - Score: score, - DebugScore: debugScore, + Score: bestMatch.score, + DebugScore: bestMatch.debugScore, }} } @@ -297,9 +296,9 @@ func (p *contentProvider) fillContentMatches(ms []*candidateMatch, numContextLin finalMatch.After = p.newlines().getLines(data, num+1, num+1+numContextLines) } - score, debugScore, symbolInfo := p.candidateMatchScore(lineCands, language, debug) - finalMatch.Score = score - finalMatch.DebugScore = debugScore + bestMatch, symbolInfo := p.candidateMatchScore(lineCands, language, debug) + finalMatch.Score = bestMatch.score + finalMatch.DebugScore = bestMatch.debugScore for i, m := range lineCands { fragment := LineFragmentMatch{ @@ -336,7 +335,7 @@ func (p *contentProvider) fillContentChunkMatches(ms []*candidateMatch, numConte chunks := chunkCandidates(ms, newlines, numContextLines) chunkMatches := make([]ChunkMatch, 0, len(chunks)) for _, chunk := range chunks { - score, debugScore, symbolInfo := p.candidateMatchScore(chunk.candidates, language, debug) + bestMatch, symbolInfo := p.candidateMatchScore(chunk.candidates, language, debug) ranges := make([]Range, 0, len(chunk.candidates)) for _, cm := range chunk.candidates { @@ -364,6 +363,14 @@ func (p *contentProvider) fillContentChunkMatches(ms []*candidateMatch, numConte } firstLineStart := newlines.lineStart(firstLineNumber) + bestLineMatch := 0 + if bestMatch.match != nil { + bestLineMatch = newlines.atOffset(bestMatch.match.byteOffset) + if debug { + bestMatch.debugScore = fmt.Sprintf("%s, (line: %d)", bestMatch.debugScore, bestLineMatch) + } + } + chunkMatches = append(chunkMatches, ChunkMatch{ Content: newlines.getLines(data, firstLineNumber, int(chunk.lastLine)+numContextLines+1), ContentStart: Location{ @@ -371,11 +378,12 @@ func (p *contentProvider) fillContentChunkMatches(ms []*candidateMatch, numConte LineNumber: uint32(firstLineNumber), Column: 1, }, - FileName: false, - Ranges: ranges, - SymbolInfo: symbolInfo, - Score: score, - DebugScore: debugScore, + FileName: false, + Ranges: ranges, + SymbolInfo: symbolInfo, + BestLineMatch: uint32(bestLineMatch), + Score: bestMatch.score, + DebugScore: bestMatch.debugScore, }) } return chunkMatches @@ -658,25 +666,30 @@ func (p *contentProvider) calculateTermFrequency(cands []*candidateMatch, df ter return termFreqs } -func (p *contentProvider) candidateMatchScore(ms []*candidateMatch, language string, debug bool) (float64, string, []*Symbol) { - type debugScore struct { - what string - score float64 - } +// scoredMatch holds the score information for a candidate match. +type scoredMatch struct { + score float64 + debugScore string + match *candidateMatch +} - score := &debugScore{} - maxScore := &debugScore{} +// candidateMatchScore scores all candidate matches and returns the best-scoring match plus its score information. +// Invariant: there should be at least one input candidate, len(ms) > 0. +func (p *contentProvider) candidateMatchScore(ms []*candidateMatch, language string, debug bool) (scoredMatch, []*Symbol) { + score := 0.0 + what := "" - addScore := func(what string, s float64) { + addScore := func(w string, s float64) { if s != 0 && debug { - score.what += fmt.Sprintf("%s:%.2f, ", what, s) + what += fmt.Sprintf("%s:%.2f, ", w, s) } - score.score += s + score += s } filename := p.data(true) var symbolInfo []*Symbol + var bestMatch scoredMatch for i, m := range ms { data := p.data(m.fileName) @@ -684,8 +697,8 @@ func (p *contentProvider) candidateMatchScore(ms []*candidateMatch, language str startBoundary := m.byteOffset < uint32(len(data)) && (m.byteOffset == 0 || byteClass(data[m.byteOffset-1]) != byteClass(data[m.byteOffset])) endBoundary := endOffset > 0 && (endOffset == uint32(len(data)) || byteClass(data[endOffset-1]) != byteClass(data[endOffset])) - score.score = 0 - score.what = "" + score = 0 + what = "" if startBoundary && endBoundary { addScore("WordMatch", scoreWordMatch) @@ -737,23 +750,24 @@ func (p *contentProvider) candidateMatchScore(ms []*candidateMatch, language str // scoreWeight != 1 means it affects score if !epsilonEqualsOne(m.scoreWeight) { - score.score = score.score * m.scoreWeight + score = score * m.scoreWeight if debug { - score.what += fmt.Sprintf("boost:%.2f, ", m.scoreWeight) + what += fmt.Sprintf("boost:%.2f, ", m.scoreWeight) } } - if score.score > maxScore.score { - maxScore.score = score.score - maxScore.what = score.what + if score > bestMatch.score { + bestMatch.score = score + bestMatch.debugScore = what + bestMatch.match = m } } if debug { - maxScore.what = fmt.Sprintf("score:%.2f <- %s", maxScore.score, strings.TrimSuffix(maxScore.what, ", ")) + bestMatch.debugScore = fmt.Sprintf("score:%.2f <- %s", bestMatch.score, strings.TrimSuffix(bestMatch.debugScore, ", ")) } - return maxScore.score, maxScore.what, symbolInfo + return bestMatch, symbolInfo } // sectionSlice will return data[sec.Start:sec.End] but will clip Start and diff --git a/grpc/protos/zoekt/webserver/v1/webserver.pb.go b/grpc/protos/zoekt/webserver/v1/webserver.pb.go index 955c1e3c0..fb4511bc6 100644 --- a/grpc/protos/zoekt/webserver/v1/webserver.pb.go +++ b/grpc/protos/zoekt/webserver/v1/webserver.pb.go @@ -2071,9 +2071,10 @@ type ChunkMatch struct { Ranges []*Range `protobuf:"bytes,4,rep,name=ranges,proto3" json:"ranges,omitempty"` // The symbol information associated with Ranges. If it is non-nil, // its length will equal that of Ranges. Any of its elements may be nil. - SymbolInfo []*SymbolInfo `protobuf:"bytes,5,rep,name=symbol_info,json=symbolInfo,proto3" json:"symbol_info,omitempty"` - Score float64 `protobuf:"fixed64,6,opt,name=score,proto3" json:"score,omitempty"` - DebugScore string `protobuf:"bytes,7,opt,name=debug_score,json=debugScore,proto3" json:"debug_score,omitempty"` + SymbolInfo []*SymbolInfo `protobuf:"bytes,5,rep,name=symbol_info,json=symbolInfo,proto3" json:"symbol_info,omitempty"` + Score float64 `protobuf:"fixed64,6,opt,name=score,proto3" json:"score,omitempty"` + DebugScore string `protobuf:"bytes,7,opt,name=debug_score,json=debugScore,proto3" json:"debug_score,omitempty"` + BestLineMatch uint32 `protobuf:"varint,8,opt,name=best_line_match,json=bestLineMatch,proto3" json:"best_line_match,omitempty"` } func (x *ChunkMatch) Reset() { @@ -2157,6 +2158,13 @@ func (x *ChunkMatch) GetDebugScore() string { return "" } +func (x *ChunkMatch) GetBestLineMatch() uint32 { + if x != nil { + return x.BestLineMatch + } + return 0 +} + type Range struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2684,7 +2692,7 @@ var file_zoekt_webserver_v1_webserver_proto_rawDesc = []byte{ 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0xb1, 0x02, 0x0a, + 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0xd9, 0x02, 0x0a, 0x0a, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, @@ -2704,51 +2712,53 @@ var file_zoekt_webserver_v1_webserver_proto_rawDesc = []byte{ 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x22, 0x6b, 0x0a, 0x05, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, - 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2e, 0x0a, - 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x7a, 0x6f, 0x65, - 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x64, 0x0a, - 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x79, 0x74, - 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, - 0x62, 0x79, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x69, - 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0a, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x63, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x2a, 0x8c, 0x01, 0x0a, 0x0b, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x52, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x4c, 0x55, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x46, 0x4c, 0x55, - 0x53, 0x48, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x52, 0x5f, - 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x4c, 0x55, - 0x53, 0x48, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, - 0x46, 0x4c, 0x55, 0x53, 0x48, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x4c, 0x55, 0x53, 0x48, - 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x58, 0x5f, 0x53, 0x49, 0x5a, 0x45, - 0x10, 0x03, 0x32, 0x99, 0x02, 0x0a, 0x10, 0x57, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x12, 0x21, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a, 0x0c, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x27, 0x2e, 0x7a, 0x6f, 0x65, - 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, - 0x01, 0x12, 0x4b, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, - 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x7a, 0x6f, 0x65, - 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3d, - 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2f, 0x67, - 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x7a, 0x6f, 0x65, 0x6b, 0x74, - 0x2f, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x26, 0x0a, 0x0f, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x62, 0x65, 0x73, 0x74, 0x4c, + 0x69, 0x6e, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x6b, 0x0a, 0x05, 0x52, 0x61, 0x6e, 0x67, + 0x65, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2e, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x64, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x2a, 0x8c, 0x01, 0x0a, 0x0b, + 0x46, 0x6c, 0x75, 0x73, 0x68, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x20, 0x46, + 0x4c, 0x55, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x46, 0x4c, 0x55, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, + 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x52, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, + 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x4c, 0x55, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, + 0x4e, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x46, 0x4c, 0x55, 0x53, 0x48, 0x10, 0x02, 0x12, + 0x19, 0x0a, 0x15, 0x46, 0x4c, 0x55, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, + 0x4d, 0x41, 0x58, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x10, 0x03, 0x32, 0x99, 0x02, 0x0a, 0x10, 0x57, + 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x51, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x21, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, + 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x7a, + 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x65, 0x0a, 0x0c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x12, 0x27, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x7a, 0x6f, + 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4b, 0x0a, 0x04, 0x4c, 0x69, 0x73, + 0x74, 0x12, 0x1f, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2f, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x73, 0x2f, 0x7a, 0x6f, 0x65, 0x6b, 0x74, 0x2f, 0x77, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/grpc/protos/zoekt/webserver/v1/webserver.proto b/grpc/protos/zoekt/webserver/v1/webserver.proto index 9cfa15dad..4a1db249f 100644 --- a/grpc/protos/zoekt/webserver/v1/webserver.proto +++ b/grpc/protos/zoekt/webserver/v1/webserver.proto @@ -485,6 +485,7 @@ message ChunkMatch { double score = 6; string debug_score = 7; + uint32 best_line_match = 8; } message Range { diff --git a/index_test.go b/index_test.go index 5aeec11ff..bdb92f5a4 100644 --- a/index_test.go +++ b/index_test.go @@ -38,6 +38,7 @@ func clearScores(r *SearchResult) { } for j := range r.Files[i].ChunkMatches { r.Files[i].ChunkMatches[j].Score = 0.0 + r.Files[i].ChunkMatches[j].BestLineMatch = 0 } r.Files[i].Checksum = nil r.Files[i].Debug = ""