From 5f1a8bc256a7e257515751b9d2e5c9918f424ceb Mon Sep 17 00:00:00 2001 From: Ian Molee Date: Sat, 23 Mar 2024 20:13:30 -0700 Subject: [PATCH] initial commit --- .gitignore | 1 + ProjectDescription.pdf | Bin 0 -> 72048 bytes go.mod | 5 + go.sum | 18 ++ main.go | 373 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 397 insertions(+) create mode 100644 .gitignore create mode 100644 ProjectDescription.pdf create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..397b4a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/ProjectDescription.pdf b/ProjectDescription.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8c549fd8ed2992362afee6ddf0b214814e6fa17b GIT binary patch literal 72048 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%0DVPjU8iPe|u|ZR;x;jOYTANX{=vfd* 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 EFNJlqO#lD@ literal 0 HcmV?d00001 diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..49f2ba2 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/ianfoo/steelray-docgrouper + +go 1.22.1 + +require github.com/adrg/strutil v0.3.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e81f627 --- /dev/null +++ b/go.sum @@ -0,0 +1,18 @@ +github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4= +github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..7fe8cb1 --- /dev/null +++ b/main.go @@ -0,0 +1,373 @@ +// Timesheet +// Previously ~1h +// March 13, 2024: 00:00-02:30 +// March 19, 2024: 15:00-19:00 +// March 23, 2024: 20:00- +package main + +import ( + "bufio" + "flag" + "fmt" + "log/slog" + "os" + "path" + "slices" + "strconv" + "strings" + "sync" + "sync/atomic" +) + +// DataFilePath describes the default location where the file pool can be found. +const DefaultDataFilePath = "files" + +// Command line options +var ( + DataFilePath string + UseDocPrefix bool + Verbose bool +) + +func main() { + if err := run(os.Args); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } +} + +// run is the main entry point for the program. +func run(args []string) error { + flags := flag.NewFlagSet(args[0], flag.ExitOnError) + flags.StringVar(&DataFilePath, "path", DefaultDataFilePath, "path to the file pool") + flags.BoolVar(&UseDocPrefix, "prefix", false, "use '[doc ###]' prefix for output") + flags.BoolVar(&Verbose, "verbose", false, "enable verbose logging") + flags.Parse(args[1:]) + + // SimilarityThreshold is the minimum similarity required for two files + // to be considered related. This value is arbitrary and could be adjusted + // based on the specific requirements of the problem. + const SimilarityThreshold = 0.5 + + fileTimes, times, err := orderFiles() + if err != nil { + return err + } + + var ( + // documents is the master list of documents that will be built up. + documents []*Document + + // fcc handles reading files and caching contents. + fcc = make(fileContentsCache) + ) + + for i, timestamp := range times { + _ = i + // fmt.Printf("\rProcessing timestamp %d/%d", i+1, len(fileTimes)) + // Track the files at this timestamp that have been associated with documents, so + // we can identify unassociated files later and then create new documents for them. + var ( + wg sync.WaitGroup + associatedFiles sync.Map + ) + + wg.Add(len(documents)) + log("processing timestamp", "timestamp", timestamp, "numWorkers", len(documents)) + for _, doc := range documents { + // Start a goroutine for each document, to parallelize the + // comparison with the files in the current timestamp. A more robust + // solution would limit the number of concurrent goroutines to avoid + // exhausting system resources, but for this problem we won't have + // more than a couple thousand documents. Goroutines are + // lightweight enough (2K stack) that we can start them pretty + // capriciously. + go func(doc *Document, files []int) { + defer wg.Done() + for _, candidateFileNumber := range files { + // Check to be certain this file hasn't been associated with another + // document already. If it has been, continue to the next file. + if _, ok := associatedFiles.Load(candidateFileNumber); ok { + continue + } + + latestFileNumber := doc.LatestAssociatedFile() + overlap, err := compareFiles(fcc, latestFileNumber, candidateFileNumber) + if err != nil { + fmt.Fprintf( + os.Stderr, + "error comparing files %d and %d: %v\n", + latestFileNumber, candidateFileNumber, err, + ) + } + if overlap >= SimilarityThreshold { + // Add file to Document associated list + doc.AssociateFile(candidateFileNumber, timestamp) + associatedFiles.Store(candidateFileNumber, struct{}{}) + + // We know this document won't be associated with any other files + // with this timestamp, so we can stop looking at files with this + // timestamp, for this document. + return + } + } + }(doc, fileTimes[timestamp]) + } + + // Wait for all document comparisons to complete for this timestamp. + wg.Wait() + + // If we haven't associated all the files with existing documents, we need + // to create new documents for those that remain. + currentNumDocs := len(documents) + for _, fileNumber := range fileTimes[timestamp] { + if _, ok := associatedFiles.Load(fileNumber); !ok { + doc := NewDocument(fileNumber, timestamp) + documents = append(documents, &doc) + } + } + if len(documents) > currentNumDocs { + log("created new documents", "numAdded", len(documents)-currentNumDocs, "timestamp", timestamp) + } + + // Now we can clear the cache of file contents for files that aren't associated with + // a document, to conserve memory. + var latestDocumentFiles []int + for _, doc := range documents { + latestDocumentFiles = append(latestDocumentFiles, doc.LatestAssociatedFile()) + } + fcc.clearFilesExcept(latestDocumentFiles) + } + + // Output the list of documents, showing their associated files in ascending order. + // Order the documents by their first associated file. + slices.SortFunc(documents, func(a, b *Document) int { + return a.AssociatedFiles[0] - b.AssociatedFiles[0] + }) + for _, doc := range documents { + doc.SortAssociatedFiles() + fmt.Println(doc) + } + + return nil +} + +// DocumentIDSource is a concurrency-safe source from which to identify +// documents. This could easily be something other than an integer, but using +// this allows us to just use the standard library. +var DocumentIDSource atomic.Uint32 + +// Document stores a document ID and a list of associated files. +type Document struct { + AssociatedFiles []int + LatestTimestamp int + ID uint32 +} + +// String formats a document for output in the format described in the +// requirements. +func (d Document) String() string { + var sb strings.Builder + for _, f := range d.AssociatedFiles { + sb.WriteString(fmt.Sprintf("%d ", f)) + } + if UseDocPrefix { + return fmt.Sprintf("[doc %4d] %s", d.ID, sb.String()) + } + return sb.String() +} + +// AssociateFile adds a file number to the list of associated files for a +// document, and also records the latest timestamp now associated with the +// document. +func (d *Document) AssociateFile(fileNumber, timestamp int) { + d.AssociatedFiles = append(d.AssociatedFiles, fileNumber) + d.LatestTimestamp = timestamp +} + +// LatestAssociatedFile returns the most recent file associated with a document. +func (d Document) LatestAssociatedFile() int { + return d.AssociatedFiles[len(d.AssociatedFiles)-1] +} + +// SortAssociatedFiles sorts the list of associated files for a document, +// since the requirements stipulate output in ascending order. +func (d *Document) SortAssociatedFiles() { + slices.Sort(d.AssociatedFiles) +} + +// NewDocument creates a new Document struct and initializes an ID and records +// the first file and timestamp associated with it. +func NewDocument(fileNumber, timestamp int) Document { + return Document{ + ID: DocumentIDSource.Add(1), + LatestTimestamp: timestamp, + AssociatedFiles: []int{fileNumber}, + } +} + +// readFileTime reads the first line of the file, which represents a +// time/version. The integer value will be returned. +func readFileTime(filepath string) (int, error) { + file, err := os.Open(filepath) + if err != nil { + return 0, err + } + defer file.Close() + + s := bufio.NewScanner(file) + var firstLine string + if s.Scan() { + firstLine = s.Text() + } + if err := s.Err(); err != nil { + return 0, err + } + + time, err := strconv.Atoi(firstLine) + if err != nil { + return 0, fmt.Errorf("invalid time %s: %w", firstLine, err) + } + return time, nil +} + +// compareFiles computes how much two files overlap, on a scale +// of 0 to 1 by iterating through the files and identifying lines +// that are duplicated. +func compareFiles(fcc fileContentsCache, f1Number, f2Number int) (float64, error) { + f1, err := fcc.getFileContents(f1Number) + if err != nil { + return 0, fmt.Errorf("file %d: %w", f1Number, err) + } + f2, err := fcc.getFileContents(f2Number) + if err != nil { + return 0, fmt.Errorf("file %d: %w", f2Number, err) + } + + histogram := make(map[string]int) + for _, lines := range [][]string{f1, f2} { + for _, line := range lines { + histogram[line]++ + } + } + + var overlap int + for _, v := range histogram { + if v == 2 { + overlap++ + } + } + return float64(overlap) / float64(len(histogram)), nil +} + +// fileContentsCache is a cache of file contents, keyed by file number, +// to avoid reading the same file from disk multiple times. +type fileContentsCache map[int][]string + +// getFileContents returns the contents of a file, excluding the first timestamp +// line. If the file is already in the cache, the contents are returned from +// there, otherwise the file is read from disk and the contents are cached. +func (fcc fileContentsCache) getFileContents(fileNumber int) ([]string, error) { + if contents, ok := fcc[fileNumber]; ok { + return contents, nil + } + var ( + fileName = makeFilePath(fileNumber) + lines []string + ) + + f, err := os.Open(fileName) + if err != nil { + return nil, err + } + + s := bufio.NewScanner(f) + + // Ignore first line that's just a timestamp. + if !s.Scan() { + fcc[fileNumber] = []string{} + return []string{}, nil + } + + for s.Scan() { + lines = append(lines, s.Text()) + } + if err := s.Err(); err != nil { + return nil, err + } + return lines, nil +} + +// clearFilesExcept removes the contents of the fileContentsCache except for the +// provided file numbers. This helps conserve memory by removing the contents of +// files that are no longer of interest, which we can be sure of since we are +// proceeding in order of time. +func (fcc fileContentsCache) clearFilesExcept(fileNumbers []int) { + for fNum := range fcc { + if !slices.Contains(fileNumbers, fNum) { + delete(fcc, fNum) + } + } +} + +func makeFileName(number int) string { + return fmt.Sprintf("%d.txt", number) +} + +func makeFilePath(number int) string { + return path.Join(DataFilePath, makeFileName(number)) +} + +// orderFiles determines the timestamp version of each file and creates a map of +// time to file numbers. It sorts the times (since maps are not ordered) so that +// the map can be iterated in order of time. This allows stepping through the +// history of the files from the beginning. Using this, we can construct a +// "chain" of evolution for a given document. +func orderFiles() (map[int][]int, []int, error) { + timeMap := make(map[int][]int) + + dirEntries, err := os.ReadDir(DataFilePath) + if err != nil { + return nil, nil, fmt.Errorf("reading directory %s: %w", DataFilePath, err) + } + for _, entry := range dirEntries { + if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".txt") { + continue + } + + // Get the numeric representation of the file number. + var fileNumber int + { + numberStr := strings.TrimSuffix(entry.Name(), ".txt") + var err error + if fileNumber, err = strconv.Atoi(numberStr); err != nil { + return nil, nil, fmt.Errorf("invalid file number in file name %q: %w", entry.Name(), err) + } + } + + filePath := path.Join(DataFilePath, entry.Name()) + modTime, err := readFileTime(filePath) + if err != nil { + return nil, nil, err + } + if timeMap[modTime] == nil { + timeMap[modTime] = make([]int, 0) + } + timeMap[modTime] = append(timeMap[modTime], fileNumber) + } + + // Now make a slice of the times and sort them, so we can iterate through + // them in order. + timeSlice := make([]int, 0, len(timeMap)) + for k := range timeMap { + timeSlice = append(timeSlice, k) + } + slices.Sort(timeSlice) + return timeMap, timeSlice, nil +} + +func log(msg string, args ...any) { + if Verbose { + slog.Info(msg, args...) + } +}