計算機科学のブログ

関数(とその他の数学とコンピュータに関する予備知識) 入門 ミニ検索エンジン ファイルの読み込み、osパッケージ、Open関数、bufioパッケージ、Scanner、文字列処理、stringsパッケージ、Split関数

行列プログラマー (Philip N. Klein(著)、松田 晃一(翻訳)、弓林 司(翻訳)、脇本 佑紀(翻訳)、中田 洋(翻訳)、齋藤 大吾(翻訳)、オライリー・ジャパン)の0章(関数(とその他の数学とコンピュータに関する予備知識))、0.6(ラボ: Pythonと逆インデックス - モジュールと制御構造)、0.6.7(ミニ検索エンジン)の課題0.6.6の解答をPythonではなくGoで求めてみる。

コード

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

type intSet map[int]bool

func (s intSet) add(n int) {
	s[n] = true
}
func (s intSet) String() string {
	ns := []int{}
	for n := range s {
		ns = append(ns, n)
	}
	return fmt.Sprintf("%v", ns)
}
func makeInverseIndex(strSlice []string) map[string]intSet {
	m := map[string]intSet{}
	for i, line := range strSlice {
		for _, word := range strings.Split(line, " ") {
			s, ok := m[word]
			if !ok {
				s = map[int]bool{}
			}
			s[i] = true
			m[word] = s
		}
	}
	return m
}
func orSearch(inverseIndex map[string]intSet, query []string) intSet {
	s := intSet(map[int]bool{})
	for _, q := range query {
		for word, iSet := range inverseIndex {
			if word == q {
				for n := range iSet {
					s[n] = true
				}
			}
		}
	}
	return s
}
func andSearch(inverseIndex map[string]intSet, query []string) intSet {
	s := intSet(map[int]bool{})
	if iSet, ok := inverseIndex[query[0]]; ok {
		for n := range iSet {
			s[n] = true
		}
	} else {
		return s
	}
	for _, q := range query[1:] {
		if iSet, ok := inverseIndex[q]; ok {
			for n := range iSet {
				exist := false
				for m := range s {
					if m == n {
						exist = true
						break
					}
				}
				if !exist {
					delete(s, n)
				}
			}
		} else {
			return intSet(map[int]bool{})
		}
	}
	return s
}
func main() {
	filenames := []string{"stories_small.txt", "stories_big.txt"}
	query := []string{"sky", "water"}
	fmt.Println("query:", query)
	for _, filename := range filenames {
		fmt.Println(filename)
		file, err := os.Open(filename)
		if err != nil {
			fmt.Println(err)
			continue
		}
		strSlice := []string{}
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			strSlice = append(strSlice, scanner.Text())
		}
		if err := scanner.Err(); err != nil {
			fmt.Println(err)
		}
		inverseIndex := makeInverseIndex(strSlice)
		fmt.Println("単語数:", len(inverseIndex))
		orInverseIndex := orSearch(inverseIndex, query)
		fmt.Println("or検索一致数:", len(orInverseIndex))
		fmt.Println("文章番号:", orInverseIndex)
		andInverseIndex := andSearch(inverseIndex, query)
		fmt.Println("and検索一致数:", len(andInverseIndex))
		fmt.Println("文章番号:", andInverseIndex)
	}
}

入出力結果

% go run ./main.go
query: [sky water]
stories_small.txt
単語数: 8681
or検索一致数: 5
文章番号: [49 1 24 18 45]
and検索一致数: 2
文章番号: [24 1]
stories_big.txt
単語数: 44566
or検索一致数: 83
文章番号: [491 755 74 169 1016 134 985 572 45 1063 602 773 754 1074 361 430 601 862 745 286 585 195 146 577 196 693 321 638 758 1025 1089 1087 756 556 677 743 851 292 768 254 590 871 749 453 1098 574 828 1081 580 740 24 492 787 85 377 18 439 615 1020 49 571 211 549 654 753 1 699 135 472 283 815 367 513 1096 1068 396 841 55 880 486 273 710 972]
and検索一致数: 13
文章番号: [1 601 615 756 1068 24 556 638 321 453 492 749 1063]
%