bleve搜索引擎源码分析之索引——mapping真复杂啊

简介:

接下来看看下面index部分的源码实现:

复制代码
    data := struct {
        Name string
        Des  string
    }{
        Name: "hello world this is bone",
        Des:  "this is a good time",
    }

    // index some data
    index.Index("id", data)
复制代码

其中,

index.Index("id", data)

实现代码:

复制代码
// Index adds the specified index operation to the
// batch.  NOTE: the bleve Index is not updated
// until the batch is executed.
func (b *Batch) Index(id string, data interface{}) error {
    if id == "" {
        return ErrorEmptyID
    }
    doc := document.NewDocument(id)
    err := b.index.Mapping().MapDocument(doc, data)
    if err != nil {
        return err
    }
    b.internal.Update(doc)
    return nil
}
复制代码

根据mapping来映射文档,

 b.index.Mapping().MapDocument(doc, data)

该代码的实现:

复制代码
func (im *IndexMappingImpl) MapDocument(doc *document.Document, data interface{}) error {
    docType := im.determineType(data)
    docMapping := im.mappingForType(docType)
    walkContext := im.newWalkContext(doc, docMapping)
    if docMapping.Enabled {
        docMapping.walkDocument(data, []string{}, []uint64{}, walkContext)

        // see if the _all field was disabled
        allMapping := docMapping.documentMappingForPath("_all")
        if allMapping == nil || (allMapping.Enabled != false) {
            field := document.NewCompositeFieldWithIndexingOptions("_all", true, []string{}, walkContext.excludedFromAll, document.IndexField|document.IncludeTermVectors)
            doc.AddField(field)
        }
    }
    
    return nil
} 
复制代码
复制代码
func (dm *DocumentMapping) walkDocument(data interface{}, path []string, indexes []uint64, context *walkContext) {
    // allow default "json" tag to be overriden
    structTagKey := dm.StructTagKey
    if structTagKey == "" {
        structTagKey = "json"
    }

    val := reflect.ValueOf(data)
    typ := val.Type()
    switch typ.Kind() {
    case reflect.Map:
        // FIXME can add support for other map keys in the future
        if typ.Key().Kind() == reflect.String {
            for _, key := range val.MapKeys() {
                fieldName := key.String()
                fieldVal := val.MapIndex(key).Interface()
                dm.processProperty(fieldVal, append(path, fieldName), indexes, context)
            }
        }
    case reflect.Struct:
        for i := 0; i < val.NumField(); i++ {
            field := typ.Field(i)
            fieldName := field.Name
            // anonymous fields of type struct can elide the type name
            if field.Anonymous && field.Type.Kind() == reflect.Struct {
                fieldName = ""
            }

            // if the field has a name under the specified tag, prefer that
            tag := field.Tag.Get(structTagKey)
            tagFieldName := parseTagName(tag)
            if tagFieldName == "-" {
                continue
            }
            // allow tag to set field name to empty, only if anonymous
            if field.Tag != "" && (tagFieldName != "" || field.Anonymous) {
                fieldName = tagFieldName
            }

            if val.Field(i).CanInterface() {
                fieldVal := val.Field(i).Interface()
                newpath := path
                if fieldName != "" {
                    newpath = append(path, fieldName)
                }
                dm.processProperty(fieldVal, newpath, indexes, context)
            }
        }
    case reflect.Slice, reflect.Array:
        for i := 0; i < val.Len(); i++ {
            if val.Index(i).CanInterface() {
                fieldVal := val.Index(i).Interface()
                dm.processProperty(fieldVal, path, append(indexes, uint64(i)), context)
            }
        }
    case reflect.Ptr:
        ptrElem := val.Elem()
        if ptrElem.IsValid() && ptrElem.CanInterface() {
            dm.processProperty(ptrElem.Interface(), path, indexes, context)
        }
    case reflect.String:
        dm.processProperty(val.String(), path, indexes, context)
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        dm.processProperty(float64(val.Int()), path, indexes, context)
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
        dm.processProperty(float64(val.Uint()), path, indexes, context)
    case reflect.Float32, reflect.Float64:
        dm.processProperty(float64(val.Float()), path, indexes, context)
    case reflect.Bool:
        dm.processProperty(val.Bool(), path, indexes, context)
    }

}
复制代码

 

 

复制代码
func (dm *DocumentMapping) processProperty(property interface{}, path []string, indexes []uint64, context *walkContext) {
    pathString := encodePath(path)
    // look to see if there is a mapping for this field
    subDocMapping := dm.documentMappingForPath(pathString)
    closestDocMapping := dm.closestDocMapping(pathString)

    // check to see if we even need to do further processing
    if subDocMapping != nil && !subDocMapping.Enabled {
        return
    }

    propertyValue := reflect.ValueOf(property)
    if !propertyValue.IsValid() {
        // cannot do anything with the zero value
        return
    }
    propertyType := propertyValue.Type()
    switch propertyType.Kind() {
    case reflect.String:
        propertyValueString := propertyValue.String()
        if subDocMapping != nil {
            // index by explicit mapping
            for _, fieldMapping := range subDocMapping.Fields {
                fieldMapping.processString(propertyValueString, pathString, path, indexes, context)
            }
        } else if closestDocMapping.Dynamic {
            // automatic indexing behavior

            // first see if it can be parsed by the default date parser
            dateTimeParser := context.im.DateTimeParserNamed(context.im.DefaultDateTimeParser)
            if dateTimeParser != nil {
                parsedDateTime, err := dateTimeParser.ParseDateTime(propertyValueString)
                if err != nil {
                    // index as text
                    fieldMapping := newTextFieldMappingDynamic(context.im)
                    fieldMapping.processString(propertyValueString, pathString, path, indexes, context)
                } else {
                    // index as datetime
                    fieldMapping := newDateTimeFieldMappingDynamic(context.im)
                    fieldMapping.processTime(parsedDateTime, pathString, path, indexes, context)
                }
            }
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        dm.processProperty(float64(propertyValue.Int()), path, indexes, context)
        return
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
        dm.processProperty(float64(propertyValue.Uint()), path, indexes, context)
        return
    case reflect.Float64, reflect.Float32:
        propertyValFloat := propertyValue.Float()
        if subDocMapping != nil {
            // index by explicit mapping
            for _, fieldMapping := range subDocMapping.Fields {
                fieldMapping.processFloat64(propertyValFloat, pathString, path, indexes, context)
            }
        } else if closestDocMapping.Dynamic {
            // automatic indexing behavior
            fieldMapping := newNumericFieldMappingDynamic(context.im)
            fieldMapping.processFloat64(propertyValFloat, pathString, path, indexes, context)
        }
    case reflect.Bool:
        propertyValBool := propertyValue.Bool()
        if subDocMapping != nil {
            // index by explicit mapping
            for _, fieldMapping := range subDocMapping.Fields {
                fieldMapping.processBoolean(propertyValBool, pathString, path, indexes, context)
            }
        } else if closestDocMapping.Dynamic {
            // automatic indexing behavior
            fieldMapping := newBooleanFieldMappingDynamic(context.im)
            fieldMapping.processBoolean(propertyValBool, pathString, path, indexes, context)
        }
    case reflect.Struct:
        switch property := property.(type) {
        case time.Time:
            // don't descend into the time struct
            if subDocMapping != nil {
                // index by explicit mapping
                for _, fieldMapping := range subDocMapping.Fields {
                    fieldMapping.processTime(property, pathString, path, indexes, context)
                }
            } else if closestDocMapping.Dynamic {
                fieldMapping := newDateTimeFieldMappingDynamic(context.im)
                fieldMapping.processTime(property, pathString, path, indexes, context)
            }
        default:
            dm.walkDocument(property, path, indexes, context)
        }
    default:
        dm.walkDocument(property, path, indexes, context)
    }
}
复制代码

 分词的部分终于来了!

复制代码
func (fm *FieldMapping) processString(propertyValueString string, pathString string, path []string, indexes []uint64, context *walkContext) {
    fieldName := getFieldName(pathString, path, fm)
    options := fm.Options()
    if fm.Type == "text" {     
        analyzer := fm.analyzerForField(path, context)
        field := document.NewTextFieldCustom(fieldName, indexes, []byte(propertyValueString), options, analyzer)
        context.doc.AddField(field)     
  
        if !fm.IncludeInAll {  
            context.excludedFromAll = append(context.excludedFromAll, fieldName)
        }
    } else if fm.Type == "datetime" { 
        dateTimeFormat := context.im.DefaultDateTimeParser
        if fm.DateFormat != "" {        
            dateTimeFormat = fm.DateFormat  
        }
        dateTimeParser := context.im.DateTimeParserNamed(dateTimeFormat)
        if dateTimeParser != nil {      
            parsedDateTime, err := dateTimeParser.ParseDateTime(propertyValueString)
            if err == nil {
                fm.processTime(parsedDateTime, pathString, path, indexes, context)
            }                  
        }
    }
}

func (fm *FieldMapping) processFloat64(propertyValFloat float64, pathString string, path []string, indexes []uint64, context *walkContext) {
    fieldName := getFieldName(pathString, path, fm)
    if fm.Type == "number" {
        options := fm.Options()
        field := document.NewNumericFieldWithIndexingOptions(fieldName, indexes, propertyValFloat, options)
        context.doc.AddField(field)

        if !fm.IncludeInAll {
            context.excludedFromAll = append(context.excludedFromAll, fieldName)
        }
    }
}
复制代码

 








本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/bonelee/p/6675628.html,如需转载请自行联系原作者




相关文章
|
7月前
|
JSON 自然语言处理 Java
es索引、类型(mapping)、文档、ik分词器
es索引、类型(mapping)、文档、ik分词器
139 1
|
6月前
|
算法 索引
一篇文章讲明白Lucene学习总结之九:Lucene的查询对象(2)
一篇文章讲明白Lucene学习总结之九:Lucene的查询对象(2)
24 0
|
Java Spring
spring data solr实现关键字搜索+高亮显示+分组查询
spring data solr实现关键字搜索+高亮显示+分组查询
280 0
spring data solr实现关键字搜索+高亮显示+分组查询
|
SQL 机器学习/深度学习 自然语言处理
全面解剖 Solr query 到lucene query
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。围绕从顶之下,从粗到西的关系认识solr 查询流程和实现细节。最低下定位到queryparse的实现。整个过程围绕信息检索这一思路展开,而不是工程实现来看这个问题。目的从整体结构上认识查询这一块的抽象。这样有具体需求的时候,可以知晓参照按个query、从哪个点注入系统中比较省事,而无需侵入solr、lucene底层。
276 0
全面解剖 Solr query 到lucene query
|
存储 自然语言处理 分布式计算
看Lucene源码必须知道的基本规则和算法
 下面介绍一些Lucene使用基本规则和算法。这些规则和算法的选择,都和Lucene和支持TB级的倒排索引有关。
|
存储 JSON 数据格式
Elasticsearch 通关教程(二): 索引映射Mapping问题
数据库建表的时候,我们的DDL语句一般都会指定每个字段的存储类型,例如:varchar,int,datetime等等,目的很明确,就是更精确的存储数据,防止数据类型格式混乱。 CREATE TABLE `shop_` ( `id_` varchar(36) NOT NULL COMMENT '...
3237 0
|
存储 自然语言处理 数据库
Lucene 查询原理
# 前言 Lucene 是一个基于 Java 的全文信息检索工具包,目前主流的搜索系统Elasticsearch和solr都是基于lucene的索引和搜索能力进行。想要理解搜索系统的实现原理,就需要深入lucene这一层,看看lucene是如何存储需要检索的数据,以及如何完成高效的数据检索。
8648 1
|
索引
艾伟_转载:Lucene.net多字段多索引目录搜索
Lucene.net是目前在.net环境中被普遍使用的全文索引的开源项目,这次在项目的开发中也使用它进行全文索引。在开发过程中碰到一些小问题就是对多字段和多索引目录进行搜索。 1、多字段搜索就是同时要一个以上的字段中的内容进行比较搜索,类似概念在SQL中就是select * from Table where a like '%query%' or b like '%query%'。
877 0
|
搜索推荐 Java Maven
学习笔记CB011:lucene搜索引擎库、IKAnalyzer中文切词工具、检索服务、查询索引、导流、word2vec
影视剧字幕聊天语料库特点,把影视剧说话内容一句一句以回车换行罗列三千多万条中国话,相邻第二句很可能是第一句最好回答。一个问句有很多种回答,可以根据相关程度以及历史聊天记录所有回答排序,找到最优,是一个搜索排序过程。
1634 0