Bleve代码阅读(二)——Index Mapping
引言
Bleve是Golang实现的一个全文检索库,类似Lucene之于Java。在这里通过阅读其代码,来学习如何使用及定制检索功能。也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式。代码的路径在github上https://github.com/blevesearch/bleve。
Index Mapping是bleve的一个功能特性,用来控制每个类型的文档,文档内的每个字段,具体应该如何被分析、索引、存储,这部分与Lucence的设计思路相同。
1 IndexMapping的结构
Bleve通过IndexMapping及各成员结构,来控制如何对每种类型的Document,Document内的NestDocument,Document内的各Field进行分析、索引和存储。它本身是一个递归的结构,在DocumentMapping这一层可以进行任意深度的嵌套。
我们先整体看一下Index Mapping及其成员的从属关系。下图是我画的结构简图,很多成员并未在图上体现出来。本节的内容就是从左到右依次介绍每个结构类型的及其成员对应的物理意义。

1.1 IndexMapping
从上一篇文章Bleve代码阅读(一)——新建索引我们知道,新建一个索引首先需要初始化一个IndexMapping结构。在示例代码中,这是通过函数bleve.NewIndexMapping()实现的,然后这个结构的指针被作为参数传递给bleve.New(index_path, index_mapping)。我们还知道,这个结构的内容被序列化后,存储在index文件里了。因此,这个结构与索引是一一对应的。
下面我们先看一下IndexMapping的定义代码,这个结构在上一篇文章也给出了。
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这个结构,下面都以IndexMapping这个名称代替。TypeMapping也与图中的同名矩形对应,它是IndexMapping的一个成员。我们这里重点看一下这四个成员:
- TypeMapping:它是一个字符串到DocumentMapping指针的map。它的key是字符串,代表Document的类型。它的value是DocumentMapping的指针,用来定制该类型文档的索引方式。
- DefaultMapping:它是DocumentMapping的指针。当TypeMapping没有配置某类型文档的DocumentMapping时,则该类文档使用该默认的DocumentMapping。
- DefaultAnalyzer:默认的根节点Analyzer。由于每个DocumentMapping、每个DocumentField都可以配置自己的Analyzer,当处理某个Field时,优先使用最个性化的设置。找不到个性化的才使用默认的,一级一级往上找,直到这里。
- DefaultType:当一篇文档未提供分类时,就会使用DefaultType设置的类型名称,默认是“_default”,也可以修改。需要注意的是,一个文档时DefaultType不等于它就要使用DefaultMapping,可以在TypeMapping中为DefaultType设置个性化的索引方式。
1.2 DocumentMapping
从本文开头的图中可以看出,DocumentMapping是最多出现的一个结构,在文档、嵌入文档、字段这几个概念层次上都要用到。任何一个文本结构,都应该对应一个DocumentMapping,文本结构包括整个文档、文档内的嵌入文档、文档或嵌入文档内的字段。DocumentMapping的定义如下:
type DocumentMapping struct {
Enabled bool `json:"enabled"`
Dynamic bool `json:"dynamic"`
Properties map[string]*DocumentMapping `json:"properties,omitempty"`
Fields []*FieldMapping `json:"fields,omitempty"`
DefaultAnalyzer string `json:"default_analyzer,omitempty"`
// StructTagKey overrides "json" when looking for field names in struct tags
StructTagKey string `json:"struct_tag_key,omitempty"`
}
1.2.1 文档
图中第二列最顶端的矩形,是一个对应原始文档的DocumentMapping。我们在这里重点关注以下几个成员:
- Enabled:如果为False,则整个文本结构不被index处理。
- Properties:一个map。key为文档的成员名,value是一个DocumentMapping的指针,该DocumentMapping对定义该成员的文本应该被如何处理。无论该成员是一个嵌入文档或是一个字段,都需要一个DocumentMapping与之对应。
- Fields:一个FieldMapping指针的切片。作为DocumentMapping的成员,如果当前DocumentMapping对应于一个文档或嵌入文档,则该字段为空。只有当前DocumentMapping对应一个字段,该成员才有可能非空。每个FieldMapping用来控制该字段应该被索引怎样分析、存储,一个字段可以有多个分析、存储方式。
- DefaultAnalyzer:当前文本结构的默认Analyzer。
1.2.2 嵌入文档
图中第三列下面的矩形,是一个对应嵌入文档的DocumentMapping。它所有成员的意义与对应文档的DocumentMapping相同。
1.2.3 字段
图中第三列顶端的矩形,是一个对应字段的DocumentMapping。它的成员的意义与对应文档的DocumentMapping略有不同,体现在以下两方面:
- Properties:当它是一个对应字段的DocumentMapping的成员时,为空。
- Fields:当它是一个对应字段的DocumentMapping的成员时,才可以不为空。它是一个FieldMapping指针的切片,定义了该字段应该被怎样处理,可以有多个处理方式。
1.3 FieldMapping
FieldMapping描述了一个具体的字段如何被放入索引。它一定包含于一个对应字段DocumentMapping,而不能直接被对应文档的DocumentMapping包含。FieldMapping的定义如下:
type FieldMapping struct {
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
// Analyzer specifies the name of the analyzer to use for this field. If
// Analyzer is empty, traverse the DocumentMapping tree toward the root and
// pick the first non-empty DefaultAnalyzer found. If there is none, use
// the IndexMapping.DefaultAnalyzer.
Analyzer string `json:"analyzer,omitempty"`
// Store indicates whether to store field values in the index. Stored
// values can be retrieved from search results using SearchRequest.Fields.
Store bool `json:"store,omitempty"`
Index bool `json:"index,omitempty"`
// IncludeTermVectors, if true, makes terms occurrences to be recorded for
// this field. It includes the term position within the terms sequence and
// the term offsets in the source document field. Term vectors are required
// to perform phrase queries or terms highlighting in source documents.
IncludeTermVectors bool `json:"include_term_vectors,omitempty"`
IncludeInAll bool `json:"include_in_all,omitempty"`
DateFormat string `json:"date_format,omitempty"`
// DocValues, if true makes the index uninverting possible for this field
// It is useful for faceting and sorting queries.
DocValues bool `json:"docvalues,omitempty"`
}
FieldMapping不会再包含任何上述结构了,它是整个IndexMapping的叶节点。它的成员大多是bool型,其他string类型的变量也大多是描述作用。
- Type:描述该字段是作为那种类型,文本、数字、布尔、日期、地理坐标等。
- Store:该字段是否被存入索引。
- Index:该字段是否被索引。
- IncludeTermVectors:该字段的occ是否被保存,用于标红、短语query。
- IncludeInAll:该字段是否包含在all字段里,默认所有字段都在all字段,除非明确指定不包含。
- Analyzer:该字段使用哪种Analyzer。
2 实践落地
上一篇文章中建立新索引的代码,只包含了2个函数调用,代码重复如下。
indexMapping := bleve.NewIndexMapping()
index, err := bleve.New("example.bleve", mapping)
为了指定各字段的索引方式,我们需要在初始化indexMapping后对其进行一些编辑修改。
blogMapping := bleve.NewDocumentMapping()
indexMapping.AddDocumentMapping("blog", blogMapping)
上面的代码,在indexMapping新增加了一个文档类型blog,并为其建立了一个DocumentMapping。此时的DocumentMapping是空的,是默认方式。
nameFieldMapping := bleve.NewTextFieldMapping()
nameFieldMapping.Analyzer = "en"
blogMapping.AddFieldMappingsAt("name", nameFieldMapping)
上面的代码为blog类型的文本的name字段,添加了一个FieldMapping,并将其Analyzer指定为“en”。
注意:在1.2.1节中,我们提到了当DocumentMapping对应于文档或嵌入文档时,它不能包含FieldMapping。这里调用方法
blogMapping.AddFieldMappingsAt("name", nameFieldMapping),相当于为blogMapping在Properties成员上添加了一个key为"name"的DocumentMapping,再将nameFieldMapping这个FieldMapping添加到这个中间DocumentMapping的Fields。
author := bleve.NewDocumentMapping()
authorNameFieldMapping := bleve.NewTextFieldMapping()
authorNameFieldMapping.Store = false
author.AddFieldMappingsAt("name", authorFieldNameMapping)
authorEmailFieldMapping := bleve.NewTextFieldMapping()
authorEmailFieldMapping.IncludeInAll = false
author.AddFieldMappingsAt("email", authorEmailFieldMapping)
blog.AddSubDocumentMapping("author", author)
上面的代码演示了如何在blog类型的DocumentMapping上添加一个嵌入文档的DocumentMapping。该嵌入文档在文档的key为author,包含name、email两个成员。并且,name只索引不存储,email不包含在_all字段。
Bleve代码阅读(二)——Index Mapping的更多相关文章
- Bleve代码阅读(一)——新建索引
引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...
- Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- [置顶] Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- Linux内核启动代码分析二之开发板相关驱动程序加载分析
Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c start_ke ...
- 代码阅读分析工具Understand 2.0试用
Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...
- [置顶] Linux协议栈代码阅读笔记(一)
Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...
- Android4.0图库Gallery2代码分析(二) 数据管理和数据加载
Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Androi ...
- Python - 关于代码阅读的一些建议
初始能力 让阅读思路保持清晰连贯,主力关注在流程架构和逻辑实现上,不被语法.技巧和业务流程等频繁地阻碍和打断. 建议基本满足以下条件,再开始进行代码阅读: 具备一定的语言基础:熟悉基础语法,常用的函数 ...
- Tools - 一些代码阅读的方法
1 初始能力 让阅读思路清晰连贯,保持在程序的流程架构和逻辑实现上,不被语法.编程技巧和业务流程等频繁地阻碍和打断. 语言基础:熟悉基础语法,常用的函数.库.编程技巧等: 了解设计模式.构建工具.代码 ...
随机推荐
- MT【52】空间法向量理解直线条数
[从最简单的做起.]--波利亚 评:线面角转化成线与线的角,这道题还有类似的这类题是学生的难点.
- 【 Gym - 101138F 】GukiZ Height (数学)
BUPT2017 wintertraining(15) #4 C Gym - 101138F 题意 初始高度0,目标值h,第i天目标值会下降i,当前高度会改变a[i%n],求高度不小于目标值的最早的时 ...
- 【POI每日题解 #9】SKA-Piggy Banks
题目链接 题意: 有一棵环套树 求最少从多少个节点出发能沿边走过整棵树 环套树 并查集求联通块 有几块就砸几个 太简单不发代码了 不过某大佬的环套树找环dfs让我研究了好久… 贴一下以Orz #inc ...
- 自学Zabbix12.5 Zabbix命令-zabbix_proxy
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix12.5 Zabbix命令-zabbix_proxy 1. zabbix prox ...
- 自学Python6.3-内置模块(1)
自学Python之路-Python基础+模块+面向对象自学Python之路-Python网络编程自学Python之路-Python并发编程+数据库+前端自学Python之路-django 自学Pyth ...
- AutoCompleteTextView和自定义的CursorAdapter
用雅虎天气接口和AutoCompleteTextView开发天气应用(1) 2014/03/20 | 分类: ANDROID, 开发 | 2 条评论 | 标签: 天气, 安卓开发 分享到:5 jQue ...
- intest
/* ============================================================================ Name : http.c Author ...
- 斯坦福大学公开课机器学习:梯度下降运算的特征缩放(gradient descent in practice 1:feature scaling)
以房屋价格为例,假设有两个特征向量:X1:房子大小(1-2000 feets), X2:卧室数量(1-5) 关于这两个特征向量的代价函数如下图所示: 从上图可以看出,代价函数是一个又瘦又高的椭圆形轮廓 ...
- springboot整合freemarker
前后端分离现在越来越多,如何有效的使用springboot来整合我们的页面是一个很重要的问题. springboot整合freemarker有以下几个步骤,也总结下我所犯的错误: 1.加依赖: 2.配 ...
- 线程的状态有哪些,线程中的start与run方法的区别
线程在一定条件下,状态会发生变化.线程一共有以下几种状态: 1.新建状态(New):新创建了一个线程对象. 2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法. ...