Skip to content

ikawaha/bleveplugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bleve plugin

GoDoc

Japanese language analysis plugins for the bleve v2 indexing/search library.

Usage example

blog: 全文検索エンジン Bleve で日本語形態素解析をおこなう

see. example/analyzer/main.go

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"

	"github.com/blevesearch/bleve/v2"
	"github.com/blevesearch/bleve/v2/analysis/analyzer/custom"
	"github.com/blevesearch/bleve/v2/analysis/analyzer/keyword"
	"github.com/blevesearch/bleve/v2/analysis/token/lowercase"
	"github.com/ikawaha/bleveplugin/analysis/lang/ja"
)

func main() {
	if err := run(os.Args); err != nil {
		log.Println(err)
		os.Exit(1)
	}
	os.Exit(0)
}

func run(_ []string) error {
	// document mapping
	keywordFieldMapping := bleve.NewTextFieldMapping()
	keywordFieldMapping.Analyzer = keyword.Name
	jaTextFieldMapping := bleve.NewTextFieldMapping()
	jaTextFieldMapping.Analyzer = "ja"
	dm := bleve.NewDocumentMapping()
	dm.AddFieldMappingsAt("type", keywordFieldMapping)
	dm.AddFieldMappingsAt("id", jaTextFieldMapping)
	dm.AddFieldMappingsAt("author", jaTextFieldMapping)
	dm.AddFieldMappingsAt("text", jaTextFieldMapping)

	// index mapping
	im := bleve.NewIndexMapping()
	im.TypeField = "type"
	im.AddDocumentMapping("book", dm)
	if err := im.AddCustomTokenizer("ja_tokenizer", map[string]any{
		"type":      ja.Name,
		"dict":      ja.DictIPA,
		"base_form": true,
		"stop_tags": true,
	}); err != nil {
		return fmt.Errorf("failed to create ja tokenizer: %w", err)
	}
	if err := im.AddCustomAnalyzer("ja", map[string]any{
		"type":      custom.Name,
		"tokenizer": "ja_tokenizer",
		"token_filters": []string{
			ja.StopWordsName,
			lowercase.Name,
		},
	}); err != nil {
		return fmt.Errorf("failed to create ja analyzer: %w", err)
	}

	// index
	index, err := bleve.NewMemOnly(im)
	defer index.Close()

	// documents
	docs := []string{
		`{"type": "book", "id": "1:赤い蝋燭と人魚", "author": "小川未明", "text": "人魚は南の方の海にばかり棲んでいるのではありません"}`,
		`{"type": "book", "id": "2:吾輩は猫である", "author": "夏目漱石", "text":   "吾輩は猫である。名前はまだない"}`,
		`{"type": "book", "id": "3:狐と踊れ", "author": "神林長平", "text": "踊っているのでなければ踊らされているのだろうさ"}`,
		`{"type": "book", "id": "4:ダンスダンスダンス", "author": "村上春樹", "text": "音楽の鳴っている間はとにかく踊り続けるんだ。おいらの言っていることはわかるかい?"}`,
	}
	// indexing
	for _, doc := range docs {
		var data map[string]any
		if err := json.Unmarshal([]byte(doc), &data); err != nil {
			log.Printf("SKIP: failed to unmarshal doc: %v, %s", err, doc)
			continue
		}
		if err := index.Index(data["id"].(string), data); err != nil {
			return fmt.Errorf("error indexing document: %w", err)
		}
		// printing ...
		fmt.Printf("indexed document with id:%s, %s\n", data["id"], doc)
	}
	dc, err := index.DocCount()
	if err != nil {
		return fmt.Errorf("failed to count documents: %w", err)
	}
	fmt.Printf("doc count: %d\n --------\n", dc)

	// query
	q := "踊る人形"
	query := bleve.NewMatchQuery(q)
	query.SetField("text")
	req := bleve.NewSearchRequest(query)
	fmt.Printf("query: search field %q, value %q\n", query.Field(), q)

	// search
	result, err := index.Search(req)
	if err != nil {
		log.Fatalf("error executing search: %v", err)
	}
	// search result
	for _, v := range result.Hits {
		fmt.Println(v.ID)
	}
	return nil
}

OUTPUT:

indexed document with id:1:赤い蝋燭と人魚, {"type": "book", "id": "1:赤い蝋燭と人魚", "author": "小川未明", "text": "人魚は南の方の海にばかり棲んでいるのではありません"}
indexed document with id:2:吾輩は猫である, {"type": "book", "id": "2:吾輩は猫である", "author": "夏目漱石", "text":   "吾輩は猫である。名前はまだない"}
indexed document with id:3:狐と踊れ, {"type": "book", "id": "3:狐と踊れ", "author": "神林長平", "text": "踊っているのでなければ踊らされているのだろうさ"}
indexed document with id:4:ダンスダンスダンス, {"type": "book", "id": "4:ダンスダンスダンス", "author": "村上春樹", "text": "音楽の鳴っている間はとにかく踊り続けるんだ。おいらの言っていることはわかるかい?"}
doc count: 4
 --------
query: search field "text", value "踊る人形"
3:狐と踊れ
4:ダンスダンスダンス