fork of https://github.com/sourcegraph/zoekt
1// Copyright 2016 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package zoekt // import "github.com/sourcegraph/zoekt"
16
17import (
18 "context"
19 "encoding/json"
20 "errors"
21 "fmt"
22 "math"
23 "reflect"
24 "strconv"
25 "time"
26
27 "github.com/sourcegraph/zoekt/query"
28)
29
30const mapHeaderBytes uint64 = 48
31const sliceHeaderBytes uint64 = 24
32const stringHeaderBytes uint64 = 16
33const pointerSize uint64 = 8
34
35// FileMatch contains all the matches within a file.
36type FileMatch struct {
37 // Ranking; the higher, the better.
38 Score float64 // TODO - hide this field?
39
40 // Experimental. Ranks is a vector containing floats in the interval [0, 1]. The
41 // length of the vector depends on the output from the ranking function at index
42 // time.
43 //
44 // This field is only set if the shard contains ranking information and
45 // SearchOptions.UseDocumentRanks is true.
46 Ranks []float64
47
48 // For debugging. Needs DebugScore set, but public so tests in
49 // other packages can print some diagnostics.
50 Debug string
51
52 FileName string
53
54 // Repository is the globally unique name of the repo of the
55 // match
56 Repository string
57 Branches []string
58
59 // One of LineMatches or ChunkMatches will be returned depending on whether
60 // the SearchOptions.ChunkMatches is set.
61 LineMatches []LineMatch
62 ChunkMatches []ChunkMatch
63
64 // RepositoryID is a Sourcegraph extension. This is the ID of Repository in
65 // Sourcegraph.
66 RepositoryID uint32
67
68 // RepositoryPriority is a Sourcegraph extension. It is used by Sourcegraph to
69 // order results from different repositories relative to each other.
70 RepositoryPriority float64
71
72 // Only set if requested
73 Content []byte
74
75 // Checksum of the content.
76 Checksum []byte
77
78 // Detected language of the result.
79 Language string
80
81 // SubRepositoryName is the globally unique name of the repo,
82 // if it came from a subrepository
83 SubRepositoryName string
84
85 // SubRepositoryPath holds the prefix where the subrepository
86 // was mounted.
87 SubRepositoryPath string
88
89 // Commit SHA1 (hex) of the (sub)repo holding the file.
90 Version string
91}
92
93func (m *FileMatch) sizeBytes() (sz uint64) {
94 // Score
95 sz += 8
96
97 // ranks
98 sz += 8 * uint64(len(m.Ranks))
99
100 for _, s := range []string{
101 m.Debug,
102 m.FileName,
103 m.Repository,
104 m.Language,
105 m.SubRepositoryName,
106 m.SubRepositoryPath,
107 m.Version,
108 } {
109 sz += stringHeaderBytes + uint64(len(s))
110 }
111
112 // Branches
113 sz += sliceHeaderBytes
114 for _, s := range m.Branches {
115 sz += stringHeaderBytes + uint64(len(s))
116 }
117
118 // LineMatches
119 sz += sliceHeaderBytes
120 for _, lm := range m.LineMatches {
121 sz += lm.sizeBytes()
122 }
123
124 // ChunkMatches
125 sz += sliceHeaderBytes
126 for _, cm := range m.ChunkMatches {
127 sz += cm.sizeBytes()
128 }
129
130 // RepositoryID
131 sz += 4
132
133 // RepositoryPriority
134 sz += 8
135
136 // Content
137 sz += sliceHeaderBytes + uint64(len(m.Content))
138
139 // Checksum
140 sz += sliceHeaderBytes + uint64(len(m.Checksum))
141
142 return
143}
144
145// ChunkMatch is a set of non-overlapping matches within a contiguous range of
146// lines in the file.
147type ChunkMatch struct {
148 // Content is a contiguous range of complete lines that fully contains Ranges.
149 Content []byte
150 // ContentStart is the location (inclusive) of the beginning of content
151 // relative to the beginning of the file. It will always be at the
152 // beginning of a line (Column will always be 1).
153 ContentStart Location
154
155 // FileName indicates whether this match is a match on the file name, in
156 // which case Content will contain the file name.
157 FileName bool
158
159 // Ranges is a set of matching ranges within this chunk. Each range is relative
160 // to the beginning of the file (not the beginning of Content).
161 Ranges []Range
162
163 // SymbolInfo is the symbol information associated with Ranges. If it is non-nil,
164 // its length will equal that of Ranges. Any of its elements may be nil.
165 SymbolInfo []*Symbol
166
167 Score float64
168 DebugScore string
169}
170
171func (cm *ChunkMatch) sizeBytes() (sz uint64) {
172 // Content
173 sz += sliceHeaderBytes + uint64(len(cm.Content))
174
175 // ContentStart
176 sz += cm.ContentStart.sizeBytes()
177
178 // FileName
179 sz += 1
180
181 // Ranges
182 sz += sliceHeaderBytes
183 if len(cm.Ranges) > 0 {
184 sz += uint64(len(cm.Ranges)) * cm.Ranges[0].sizeBytes()
185 }
186
187 // SymbolInfo
188 sz += sliceHeaderBytes
189 for _, si := range cm.SymbolInfo {
190 sz += pointerSize
191 if si != nil {
192 sz += si.sizeBytes()
193 }
194 }
195
196 // Score
197 sz += 8
198
199 // DebugScore
200 sz += stringHeaderBytes + uint64(len(cm.DebugScore))
201
202 return
203}
204
205type Range struct {
206 // The inclusive beginning of the range.
207 Start Location
208 // The exclusive end of the range.
209 End Location
210}
211
212func (r *Range) sizeBytes() uint64 {
213 return r.Start.sizeBytes() + r.End.sizeBytes()
214}
215
216type Location struct {
217 // 0-based byte offset from the beginning of the file
218 ByteOffset uint32
219 // 1-based line number from the beginning of the file
220 LineNumber uint32
221 // 1-based column number (in runes) from the beginning of line
222 Column uint32
223}
224
225func (l *Location) sizeBytes() uint64 {
226 return 3 * 4
227}
228
229// LineMatch holds the matches within a single line in a file.
230type LineMatch struct {
231 // The line in which a match was found.
232 Line []byte
233 LineStart int
234 LineEnd int
235 LineNumber int
236
237 // Before and After are only set when SearchOptions.NumContextLines is > 0
238 Before []byte
239 After []byte
240
241 // If set, this was a match on the filename.
242 FileName bool
243
244 // The higher the better. Only ranks the quality of the match
245 // within the file, does not take rank of file into account
246 Score float64
247 DebugScore string
248
249 LineFragments []LineFragmentMatch
250}
251
252func (lm *LineMatch) sizeBytes() (sz uint64) {
253 // Line
254 sz += sliceHeaderBytes + uint64(len(lm.Line))
255
256 // LineStart, LineEnd, LineNumber
257 sz += 3 * 8
258
259 // Before
260 sz += sliceHeaderBytes + uint64(len(lm.Before))
261
262 // After
263 sz += sliceHeaderBytes + uint64(len(lm.After))
264
265 // FileName
266 sz += 1
267
268 // Score
269 sz += 8
270
271 // DebugScore
272 sz += stringHeaderBytes + uint64(len(lm.DebugScore))
273
274 // LineFragments
275 sz += sliceHeaderBytes
276 for _, lf := range lm.LineFragments {
277 sz += lf.sizeBytes()
278 }
279
280 return
281}
282
283type Symbol struct {
284 Sym string
285 Kind string
286 Parent string
287 ParentKind string
288}
289
290func (s *Symbol) sizeBytes() uint64 {
291 return 4*stringHeaderBytes + uint64(len(s.Sym)+len(s.Kind)+len(s.Parent)+len(s.ParentKind))
292}
293
294// LineFragmentMatch a segment of matching text within a line.
295type LineFragmentMatch struct {
296 // Offset within the line, in bytes.
297 LineOffset int
298
299 // Offset from file start, in bytes.
300 Offset uint32
301
302 // Number bytes that match.
303 MatchLength int
304
305 SymbolInfo *Symbol
306}
307
308func (lfm *LineFragmentMatch) sizeBytes() (sz uint64) {
309 // LineOffset
310 sz += 8
311
312 // Offset
313 sz += 4
314
315 // MatchLength
316 sz += 8
317
318 // SymbolInfo
319 sz += pointerSize
320 if lfm.SymbolInfo != nil {
321 sz += lfm.SymbolInfo.sizeBytes()
322 }
323
324 return
325}
326
327type FlushReason uint8
328
329const (
330 FlushReasonTimerExpired FlushReason = 1 << iota
331 FlushReasonFinalFlush
332 FlushReasonMaxSize
333)
334
335var FlushReasonStrings = map[FlushReason]string{
336 FlushReasonTimerExpired: "timer_expired",
337 FlushReasonFinalFlush: "final_flush",
338 FlushReasonMaxSize: "max_size_reached",
339}
340
341func (fr FlushReason) String() string {
342 if v, ok := FlushReasonStrings[fr]; ok {
343 return v
344 }
345
346 return "none"
347}
348
349// Stats contains interesting numbers on the search
350type Stats struct {
351 // Amount of I/O for reading contents.
352 ContentBytesLoaded int64
353
354 // Amount of I/O for reading from index.
355 IndexBytesLoaded int64
356
357 // Number of search shards that had a crash.
358 Crashes int
359
360 // Wall clock time for this search
361 Duration time.Duration
362
363 // Number of files containing a match.
364 FileCount int
365
366 // Number of files in shards that we considered.
367 ShardFilesConsidered int
368
369 // Files that we evaluated. Equivalent to files for which all
370 // atom matches (including negations) evaluated to true.
371 FilesConsidered int
372
373 // Files for which we loaded file content to verify substring matches
374 FilesLoaded int
375
376 // Candidate files whose contents weren't examined because we
377 // gathered enough matches.
378 FilesSkipped int
379
380 // Shards that we scanned to find matches.
381 ShardsScanned int
382
383 // Shards that we did not process because a query was canceled.
384 ShardsSkipped int
385
386 // Shards that we did not process because the query was rejected by the
387 // ngram filter indicating it had no matches.
388 ShardsSkippedFilter int
389
390 // Number of non-overlapping matches
391 MatchCount int
392
393 // Number of candidate matches as a result of searching ngrams.
394 NgramMatches int
395
396 // Wall clock time for queued search.
397 Wait time.Duration
398
399 // Number of times regexp was called on files that we evaluated.
400 RegexpsConsidered int
401
402 // FlushReason explains why results were flushed.
403 FlushReason FlushReason
404}
405
406func (s *Stats) sizeBytes() (sz uint64) {
407 sz = 16 * 8 // This assumes we are running on a 64-bit architecture
408 sz += 1 // FlushReason
409
410 return
411}
412
413func (s *Stats) Add(o Stats) {
414 s.ContentBytesLoaded += o.ContentBytesLoaded
415 s.IndexBytesLoaded += o.IndexBytesLoaded
416 s.Crashes += o.Crashes
417 s.FileCount += o.FileCount
418 s.FilesConsidered += o.FilesConsidered
419 s.FilesLoaded += o.FilesLoaded
420 s.FilesSkipped += o.FilesSkipped
421 s.MatchCount += o.MatchCount
422 s.NgramMatches += o.NgramMatches
423 s.ShardFilesConsidered += o.ShardFilesConsidered
424 s.ShardsScanned += o.ShardsScanned
425 s.ShardsSkipped += o.ShardsSkipped
426 s.ShardsSkippedFilter += o.ShardsSkippedFilter
427 s.Wait += o.Wait
428 s.RegexpsConsidered += o.RegexpsConsidered
429
430 // We want the first non-zero FlushReason to be sticky. This is a useful
431 // property when aggregating stats from several Zoekts.
432 if s.FlushReason == 0 {
433 s.FlushReason = o.FlushReason
434 }
435}
436
437// Zero returns true if stats is empty.
438func (s *Stats) Zero() bool {
439 if s == nil {
440 return true
441 }
442
443 return !(s.ContentBytesLoaded > 0 ||
444 s.IndexBytesLoaded > 0 ||
445 s.Crashes > 0 ||
446 s.FileCount > 0 ||
447 s.FilesConsidered > 0 ||
448 s.FilesLoaded > 0 ||
449 s.FilesSkipped > 0 ||
450 s.MatchCount > 0 ||
451 s.NgramMatches > 0 ||
452 s.ShardFilesConsidered > 0 ||
453 s.ShardsScanned > 0 ||
454 s.ShardsSkipped > 0 ||
455 s.ShardsSkippedFilter > 0 ||
456 s.Wait > 0 ||
457 s.RegexpsConsidered > 0)
458}
459
460// Progress contains information about the global progress of the running search query.
461// This is used by the frontend to reorder results and emit them when stable.
462// Sourcegraph specific: this is used when querying multiple zoekt-webserver instances.
463type Progress struct {
464 // Priority of the shard that was searched.
465 Priority float64
466
467 // MaxPendingPriority is the maximum priority of pending result that is being searched in parallel.
468 // This is used to reorder results when the result set is known to be stable-- that is, when a result's
469 // Priority is greater than the max(MaxPendingPriority) from the latest results of each backend, it can be returned to the user.
470 //
471 // MaxPendingPriority decreases monotonically in each SearchResult.
472 MaxPendingPriority float64
473}
474
475func (p *Progress) sizeBytes() uint64 {
476 return 2 * 8
477}
478
479// SearchResult contains search matches and extra data
480type SearchResult struct {
481 Stats
482 Progress
483 Files []FileMatch
484
485 // RepoURLs holds a repo => template string map.
486 RepoURLs map[string]string
487
488 // FragmentNames holds a repo => template string map, for
489 // the line number fragment.
490 LineFragments map[string]string
491}
492
493// SizeBytes is a best-effort estimate of the size of SearchResult in memory.
494// The estimate does not take alignment into account. The result is a lower
495// bound on the actual size in memory.
496func (sr *SearchResult) SizeBytes() (sz uint64) {
497 sz += sr.Stats.sizeBytes()
498 sz += sr.Progress.sizeBytes()
499
500 // Files
501 sz += sliceHeaderBytes
502 for _, f := range sr.Files {
503 sz += f.sizeBytes()
504 }
505
506 // RepoURLs
507 sz += mapHeaderBytes
508 for k, v := range sr.RepoURLs {
509 sz += stringHeaderBytes + uint64(len(k))
510 sz += stringHeaderBytes + uint64(len(v))
511 }
512
513 // LineFragments
514 sz += mapHeaderBytes
515 for k, v := range sr.LineFragments {
516 sz += stringHeaderBytes + uint64(len(k))
517 sz += stringHeaderBytes + uint64(len(v))
518 }
519
520 return
521}
522
523// RepositoryBranch describes an indexed branch, which is a name
524// combined with a version.
525type RepositoryBranch struct {
526 Name string
527 Version string
528}
529
530func (r RepositoryBranch) String() string {
531 return fmt.Sprintf("%s@%s", r.Name, r.Version)
532}
533
534// Repository holds repository metadata.
535type Repository struct {
536 // Sourcergaph's repository ID
537 ID uint32
538
539 // The repository name
540 Name string
541
542 // The repository URL.
543 URL string
544
545 // The physical source where this repo came from, eg. full
546 // path to the zip filename or git repository directory. This
547 // will not be exposed in the UI, but can be used to detect
548 // orphaned index shards.
549 Source string
550
551 // The branches indexed in this repo.
552 Branches []RepositoryBranch
553
554 // Nil if this is not the super project.
555 SubRepoMap map[string]*Repository
556
557 // URL template to link to the commit of a branch
558 CommitURLTemplate string
559
560 // The repository URL for getting to a file. Has access to
561 // {{Branch}}, {{Path}}
562 FileURLTemplate string
563
564 // The URL fragment to add to a file URL for line numbers. has
565 // access to {{LineNumber}}. The fragment should include the
566 // separator, generally '#' or ';'.
567 LineFragmentTemplate string
568
569 // Perf optimization: priority is set when we load the shard. It corresponds to
570 // the value of "priority" stored in RawConfig.
571 priority float64
572
573 // All zoekt.* configuration settings.
574 RawConfig map[string]string
575
576 // Importance of the repository, bigger is more important
577 Rank uint16
578
579 // IndexOptions is a hash of the options used to create the index for the
580 // repo.
581 IndexOptions string
582
583 // HasSymbols is true if this repository has indexed ctags
584 // output. Sourcegraph specific: This field is more appropriate for
585 // IndexMetadata. However, we store it here since the Sourcegraph frontend
586 // can read this structure but not IndexMetadata.
587 HasSymbols bool
588
589 // Tombstone is true if we are not allowed to search this repo.
590 Tombstone bool
591
592 // LatestCommitDate is the date of the latest commit among all indexed Branches.
593 // The date might be time.Time's 0-value if the repository was last indexed
594 // before this field was added.
595 LatestCommitDate time.Time
596
597 // FileTombstones is a set of file paths that should be ignored across all branches
598 // in this shard.
599 FileTombstones map[string]struct{} `json:",omitempty"`
600}
601
602func (r *Repository) UnmarshalJSON(data []byte) error {
603 // We define a new type so that we can use json.Unmarshal
604 // without recursing into this same method.
605 type repository *Repository
606 repo := repository(r)
607
608 err := json.Unmarshal(data, repo)
609 if err != nil {
610 return err
611 }
612
613 if v, ok := repo.RawConfig["repoid"]; ok {
614 id, _ := strconv.ParseUint(v, 10, 32)
615 r.ID = uint32(id)
616 }
617
618 if v, ok := repo.RawConfig["priority"]; ok {
619 r.priority, err = strconv.ParseFloat(v, 64)
620 if err != nil {
621 r.priority = 0
622 }
623
624 // Sourcegraph indexserver doesn't set repo.Rank, so we set it here
625 // based on priority. Setting it on read instead of during indexing
626 // allows us to avoid a complete reindex.
627 if r.Rank == 0 && r.priority > 0 {
628 l := math.Log(float64(r.priority))
629 repo.Rank = uint16((1.0 - 1.0/math.Pow(1+l, 0.6)) * 10000)
630 }
631 }
632 return nil
633}
634
635// MergeMutable will merge x into r. mutated will be true if it made any
636// changes. err is non-nil if we needed to mutate an immutable field.
637//
638// Note: SubRepoMap, IndexOptions and HasSymbol fields are ignored. They are
639// computed while indexing so can't be synthesized from x.
640//
641// Note: We ignore RawConfig fields which are duplicated into Repository:
642// name and id.
643//
644// Note: URL, *Template fields are ignored. They are not used by Sourcegraph.
645func (r *Repository) MergeMutable(x *Repository) (mutated bool, err error) {
646 if r.ID != x.ID {
647 // Sourcegraph: strange behaviour may occur if ID changes but names don't.
648 return mutated, errors.New("ID is immutable")
649 }
650 if r.Name != x.Name {
651 // Name is encoded into the shard name on disk. We need to re-index if it
652 // changes.
653 return mutated, errors.New("Name is immutable")
654 }
655 if !reflect.DeepEqual(r.Branches, x.Branches) {
656 // Need a reindex if content changing.
657 return mutated, errors.New("Branches is immutable")
658 }
659
660 for k, v := range x.RawConfig {
661 // We ignore name and id since they are encoded into the repository.
662 if k == "name" || k == "id" {
663 continue
664 }
665 if r.RawConfig == nil {
666 mutated = true
667 r.RawConfig = make(map[string]string)
668 }
669 if r.RawConfig[k] != v {
670 mutated = true
671 r.RawConfig[k] = v
672 }
673 }
674
675 return mutated, nil
676}
677
678// IndexMetadata holds metadata stored in the index file. It contains
679// data generated by the core indexing library.
680type IndexMetadata struct {
681 IndexFormatVersion int
682 IndexFeatureVersion int
683 IndexMinReaderVersion int
684 IndexTime time.Time
685 PlainASCII bool
686 LanguageMap map[string]uint16
687 ZoektVersion string
688 ID string
689}
690
691// Statistics of a (collection of) repositories.
692type RepoStats struct {
693 // Repos is used for aggregrating the number of repositories.
694 Repos int
695
696 // Shards is the total number of search shards.
697 Shards int
698
699 // Documents holds the number of documents or files.
700 Documents int
701
702 // IndexBytes is the amount of RAM used for index overhead.
703 IndexBytes int64
704
705 // ContentBytes is the amount of RAM used for raw content.
706 ContentBytes int64
707
708 // Sourcegraph specific stats below. These are not as efficient to calculate
709 // as the above statistics. We experimentally measured about a 10% slower
710 // shard load time. However, we find these values very useful to track and
711 // computing them outside of load time introduces a lot of complexity.
712
713 // NewLinesCount is the number of newlines "\n" that appear in the zoekt
714 // indexed documents. This is not exactly the same as line count, since it
715 // will not include lines not terminated by "\n" (eg a file with no "\n", or
716 // a final line without "\n"). Note: Zoekt deduplicates documents across
717 // branches, so if a path has the same contents on multiple branches, there
718 // is only one document for it. As such that document's newlines is only
719 // counted once. See DefaultBranchNewLinesCount and AllBranchesNewLinesCount
720 // for counts which do not deduplicate.
721 NewLinesCount uint64
722
723 // DefaultBranchNewLinesCount is the number of newlines "\n" in the default
724 // branch.
725 DefaultBranchNewLinesCount uint64
726
727 // OtherBranchesNewLinesCount is the number of newlines "\n" in all branches
728 // except the default branch.
729 OtherBranchesNewLinesCount uint64
730}
731
732func (s *RepoStats) Add(o *RepoStats) {
733 // can't update Repos, since one repo may have multiple
734 // shards.
735 s.Shards += o.Shards
736 s.IndexBytes += o.IndexBytes
737 s.Documents += o.Documents
738 s.ContentBytes += o.ContentBytes
739
740 // Sourcegraph specific
741 s.NewLinesCount += o.NewLinesCount
742 s.DefaultBranchNewLinesCount += o.DefaultBranchNewLinesCount
743 s.OtherBranchesNewLinesCount += o.OtherBranchesNewLinesCount
744}
745
746type RepoListEntry struct {
747 Repository Repository
748 IndexMetadata IndexMetadata
749 Stats RepoStats
750}
751
752type MinimalRepoListEntry struct {
753 HasSymbols bool
754 Branches []RepositoryBranch
755}
756
757// RepoList holds a set of Repository metadata.
758type RepoList struct {
759 // Full response to a List request. Returned when ListOptions.Minimal is false.
760 Repos []*RepoListEntry
761
762 Crashes int
763
764 // Minimal response to a List request. Returned when ListOptions.Minimal is true.
765 Minimal map[uint32]*MinimalRepoListEntry
766
767 // Stats response to a List request.
768 // This is the aggregate RepoStats of all repos matching the input query.
769 Stats RepoStats
770}
771
772type Searcher interface {
773 Search(ctx context.Context, q query.Q, opts *SearchOptions) (*SearchResult, error)
774
775 // List lists repositories. The query `q` can only contain
776 // query.Repo atoms.
777 List(ctx context.Context, q query.Q, opts *ListOptions) (*RepoList, error)
778 Close()
779
780 // Describe the searcher for debug messages.
781 String() string
782}
783
784type ListOptions struct {
785 // Return only Minimal data per repo that Sourcegraph frontend needs.
786 Minimal bool
787}
788
789func (o *ListOptions) String() string {
790 return fmt.Sprintf("%#v", o)
791}
792
793type SearchOptions struct {
794 // Return an upper-bound estimate of eligible documents in
795 // stats.ShardFilesConsidered.
796 EstimateDocCount bool
797
798 // Return the whole file.
799 Whole bool
800
801 // Maximum number of matches: skip all processing an index
802 // shard after we found this many non-overlapping matches.
803 ShardMaxMatchCount int
804
805 // Maximum number of matches: stop looking for more matches
806 // once we have this many matches across shards.
807 TotalMaxMatchCount int
808
809 // Maximum number of matches: skip processing documents for a repository in
810 // a shard once we have found ShardRepoMaxMatchCount.
811 //
812 // A compound shard may contain multiple repositories. This will most often
813 // be set to 1 to find all repositories containing a result.
814 ShardRepoMaxMatchCount int
815
816 // Deprecated: this field is not read anymore.
817 ShardMaxImportantMatch int
818
819 // Deprecated: this field is not read anymore.
820 TotalMaxImportantMatch int
821
822 // Abort the search after this much time has passed.
823 MaxWallTime time.Duration
824
825 // FlushWallTime if non-zero will stop streaming behaviour at first and
826 // instead will collate and sort results. At FlushWallTime the results will
827 // be sent and then the behaviour will revert to the normal streaming.
828 FlushWallTime time.Duration
829
830 // Trim the number of results after collating and sorting the
831 // results
832 MaxDocDisplayCount int
833
834 // If set to a number greater than zero then up to this many number
835 // of context lines will be added before and after each matched line.
836 // Note that the included context lines might contain matches and
837 // it's up to the consumer of the result to remove those lines.
838 NumContextLines int
839
840 // If true, ChunkMatches will be returned in each FileMatch rather than LineMatches
841 // EXPERIMENTAL: the behavior of this flag may be changed in future versions.
842 ChunkMatches bool
843
844 // EXPERIMENTAL. If true, document ranks are used as additional input for
845 // sorting matches.
846 UseDocumentRanks bool
847
848 // RanksDampingFactor determines the contribution of documents ranks to the
849 // final ranking based on RRF. A value in (0,1] reduces the contribution,
850 // while a value in (-inf,0) increases it.
851 RanksDampingFactor float64
852
853 // Trace turns on opentracing for this request if true and if the Jaeger address was provided as
854 // a command-line flag
855 Trace bool
856
857 // If set, the search results will contain debug information for scoring.
858 DebugScore bool
859
860 // SpanContext is the opentracing span context, if it exists, from the zoekt client
861 SpanContext map[string]string
862}
863
864func (s *SearchOptions) String() string {
865 return fmt.Sprintf("%#v", s)
866}
867
868// Sender is the interface that wraps the basic Send method.
869type Sender interface {
870 Send(*SearchResult)
871}
872
873// Streamer adds the method StreamSearch to the Searcher interface.
874type Streamer interface {
875 Searcher
876 StreamSearch(ctx context.Context, q query.Q, opts *SearchOptions, sender Sender) (err error)
877}