Bleve是Golang实现的一个全文检索库,类似Lucene之于Java。在这里通过阅读其代码,来学习如何使用及定制检索功能。也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式。代码的路径在github上https://github.com/blevesearch/bleve。
1 新建索引下面的代码摘自Bleve的"Hello World"示例。
// open a new index mapping := bleve.NewIndexMapping() index, err := bleve.New("example.bleve", mapping) if err != nil { fmt.Println(err) return }1.1和1.2两节是对上面逻辑的展开介绍,1.3节是在阅读代码中遇到的一些Golang特性的介绍,1.4节是当我们在使用bleve新建索引时可能会怎么做。
1.1 新建一个IndexMapping下面这段代码是Bleve的"Hello World"示例的第一条语句,表示打开一个新索引。
// open a new index mapping := bleve.NewIndexMapping()这个函数的定义位于bleve目录下的mapping.go文件
func NewIndexMapping() *mapping.IndexMappingImpl { return mapping.NewIndexMapping() }可以看出它是一个封装函数,调用了mapping package的NewIndexMapping函数。该函数的定义位于bleve/mapping/index.go文件内,属于github.com/blevesearch/bleve/mapping包。
// NewIndexMapping creates a new IndexMapping that will use all the default indexing rules func NewIndexMapping() *IndexMappingImpl { return &IndexMappingImpl{ TypeMapping: make(map[string]*DocumentMapping), DefaultMapping: NewDocumentMapping(), TypeField: defaultTypeField, DefaultType: defaultType, DefaultAnalyzer: defaultAnalyzer, DefaultDateTimeParser: defaultDateTimeParser, DefaultField: defaultField, IndexDynamic: IndexDynamic, StoreDynamic: StoreDynamic, DocValuesDynamic: DocValuesDynamic, CustomAnalysis: newCustomAnalysis(), cache: registry.NewCache(), } }建立了一个IndexMappingImpl结构并返回其指针,该IndexMappingImpl的所有成员均以默认方式初始化。接下来看一下IndexMappingImpl结构的定义,该结构同样属于github.com/blevesearch/bleve/mapping包,并位于bleve/mapping/index.go文件内。
// An IndexMappingImpl controls how objects are placed // into an index. // First the type of the object is determined. // Once the type is know, the appropriate // DocumentMapping is selected by the type. // If no mapping was determined for that type, // a DefaultMapping will be used. type IndexMappingImpl struct { TypeMapping map[string]*DocumentMapping `json:"types,omitempty"` DefaultMapping *DocumentMapping `json:"default_mapping"` TypeField string `json:"type_field"` DefaultType string `json:"default_type"` DefaultAnalyzer string `json:"default_analyzer"` DefaultDateTimeParser string `json:"default_datetime_parser"` DefaultField string `json:"default_field"` StoreDynamic bool `json:"store_dynamic"` IndexDynamic bool `json:"index_dynamic"` DocValuesDynamic bool `json:"docvalues_dynamic,omitempty"` CustomAnalysis *customAnalysis `json:"analysis,omitempty"` cache *registry.Cache }从注释可以看出,IndexMappingImpl结构是用来控制每一个对象应该被如何放入Index中,其各字段也是围绕这个目标展开的。
TypeMapping :一个map类型,Key是string类型,表示文档的类型。Value是DocumentMapping类型的指针,表示该类型文档对应的DocumentMapping。
DefaultMapping:一个DocumentMapping类型的指针。当文档的类型未知时,使用的默认DocumentMapping。
函数bleve.NewIndexMapping()仅仅返回了一个结构,这个结构用来控制所有文档应该被如何建立索引。
1.2 新建一个索引文件 index, err := bleve.New("example.bleve", mapping)示例的第二条语句,将IndexMappingImpl结构与一个具体路径结合起来,新建一个索引。这个函数定义在bleve/index.go文件内,在bleve包内。
// New index at the specified path, must not exist. // The provided mapping will be used for all // Index/Search operations. func New(path string, mapping mapping.IndexMapping) (Index, error) { return newIndexUsing(path, mapping, Config.DefaultIndexType, Config.DefaultKVStore, nil) }这个函数调用了newIndexUsing函数,前两个参数就是New函数传进来的,第3个和第4个参数通过 Config变量给出。接下来的主要逻辑都在newIndexUsing函数实现,本节剩余部分都在newIndexUsing函数内部讨论。该函数位于index_impl.go文件内,在bleve包里。
首先,总体说一下newIndexUsing函数的功能。校验参数的合法性,根据参数从物理层面打开一个具体类型的index,保存元数据,关联统计模块。
err := mapping.Validate() if err != nil { return nil, err }校验indexMapping的合法性。具体在bleve/mapping.go中实现,主要是检查analyzer和DocumentMapping可以被建立。
if kvconfig == nil { kvconfig = map[string]interface{}{} } if kvstore == "" { return nil, fmt.Errorf("bleve not configured for file based indexing") }必须给出kv存储的具体方式,默认是用boltdb,一个golang实现的kv存储。
rv := indexImpl{ path: path, name: path, m: mapping, meta: newIndexMeta(indexType, kvstore, kvconfig), } rv.stats = &IndexStat{i: &rv}