欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

elasticsearch索引index之Mapping實現(xiàn)關(guān)系結(jié)構(gòu)示例

 更新時間:2022年04月22日 10:31:42   作者:zziawan  
這篇文章主要介紹了elasticsearch索引index之Mapping實現(xiàn)關(guān)系結(jié)構(gòu)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Mapping的實現(xiàn)關(guān)系結(jié)構(gòu)

Lucene索引的一個特點就filed,索引以field組合。這一特點為索引和搜索提供了很大的靈活性。elasticsearch則在Lucene的基礎(chǔ)上更近一步,它可以是 no scheme。實現(xiàn)這一功能的秘密就Mapping。Mapping是對索引各個字段的一種預(yù)設(shè),包括索引與分詞方式,是否存儲等,數(shù)據(jù)根據(jù)字段名在Mapping中找到對應(yīng)的配置,建立索引。這里將對Mapping的實現(xiàn)結(jié)構(gòu)簡單分析,Mapping的放置、更新、應(yīng)用會在后面的索引fenx中進(jìn)行說明。

這只是Mapping中的一部分內(nèi)容。Mapping擴(kuò)展了lucene的filed,定義了更多的field類型既有Lucene所擁有的string,number等字段又有date,IP,byte及geo的相關(guān)字段,這也是es的強(qiáng)大之處。如上圖所示,可以分為兩類,mapper與documentmapper,前者是所有mapper的父接口。而DocumentMapper則是Mapper的集合,它代表了一個索引的mapper定義。

Mapper的三類

第一類就是核心field結(jié)構(gòu)FileMapper—>AbstractFieldMapper—>StringField這種核心數(shù)據(jù)類型,它代表了一類數(shù)據(jù)類型,如字符串類型,int類型這種;

第二類是Mapper—>ObjectMapper—>RootObjectMapper,object類型的Mapper,這也是elasticsearch對lucene的一大改進(jìn),不想lucene之支持基本數(shù)據(jù)類型;

最后一類是Mapper—>RootMapper—>IndexFieldMapper這種類型,只存在于根Mapper中的一種Mapper,如IdFieldMapper及圖上的IndexFieldMapper,它們類似于index的元數(shù)據(jù),只可能存在于某個index內(nèi)部。

parse方法

Mapper中一個比較重要的方法就是parse(ParseContext context),Mapper的子類對這個方法都有各自的實現(xiàn)。它的主要功能是通過解析ParseContext獲取到對應(yīng)的field,這個方法主要用于建立索引時。索引數(shù)據(jù)被繼續(xù)成parsecontext,每個field解析parseContext構(gòu)建對應(yīng)的lucene Field。它在AbstractFieldMapper中的實現(xiàn)如下所示:

public void parse(ParseContext context) throws IOException {
        final List<Field> fields = new ArrayList<>(2);
        try {
            parseCreateField(context, fields);//實際Filed解析方法
            for (Field field : fields) {
                if (!customBoost()) {//設(shè)置boost
                    field.setBoost(boost);
                }
                if (context.listener().beforeFieldAdded(this, field, context)) {
                    context.doc().add(field);//將解析完成的Field加入到context中
                }
            }
        } catch (Exception e) {
            throw new MapperParsingException("failed to parse [" + names.fullName() + "]", e);
        }
        multiFields.parse(this, context);//進(jìn)行mutiFields解析,MultiFields作用是對同一個field做不同的定義,如可以進(jìn)行不同分詞方式的索引這樣便于通過各種方式查詢
        if (copyTo != null) {
            copyTo.parse(context);
        }
    }

這里的parseCreateField是一個抽象方法,每種數(shù)據(jù)類型都有自己的實現(xiàn),如string的實現(xiàn)方式如下所示:

protected void parseCreateField(ParseContext context, List<Field> fields) throws IOException {
        ValueAndBoost valueAndBoost = parseCreateFieldForString(context, nullValue, boost);//解析成值和boost
        if (valueAndBoost.value() == null) {
            return;
        }
        if (ignoreAbove > 0 && valueAndBoost.value().length() > ignoreAbove) {
            return;
        }
        if (context.includeInAll(includeInAll, this)) {
            context.allEntries().addText(names.fullName(), valueAndBoost.value(), valueAndBoost.boost());
        }
        if (fieldType.indexed() || fieldType.stored()) {//構(gòu)建LuceneField
            Field field = new Field(names.indexName(), valueAndBoost.value(), fieldType);
            field.setBoost(valueAndBoost.boost());
            fields.add(field);
        }
        if (hasDocValues()) {
            fields.add(new SortedSetDocValuesField(names.indexName(), new BytesRef(valueAndBoost.value())));
        }
        if (fields.isEmpty()) {
            context.ignoredValue(names.indexName(), valueAndBoost.value());
        }
    }
//解析出字段的值和boost
    public static ValueAndBoost parseCreateFieldForString(ParseContext context, String nullValue, float defaultBoost) throws IOException {
        if (context.externalValueSet()) {
            return new ValueAndBoost((String) context.externalValue(), defaultBoost);
        }
        XContentParser parser = context.parser();
        if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
            return new ValueAndBoost(nullValue, defaultBoost);
        }
        if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
            XContentParser.Token token;
            String currentFieldName = null;
            String value = nullValue;
            float boost = defaultBoost;
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
                if (token == XContentParser.Token.FIELD_NAME) {
                    currentFieldName = parser.currentName();
                } else {
                    if ("value".equals(currentFieldName) || "_value".equals(currentFieldName)) {
                        value = parser.textOrNull();
                    } else if ("boost".equals(currentFieldName) || "_boost".equals(currentFieldName)) {
                        boost = parser.floatValue();
                    } else {
                        throw new ElasticsearchIllegalArgumentException("unknown property [" + currentFieldName + "]");
                    }
                }
            }
            return new ValueAndBoost(value, boost);
        }
        return new ValueAndBoost(parser.textOrNull(), defaultBoost);
    }

以上就是Mapper如何將一個值解析成對應(yīng)的Field的過程,這里只是簡單介紹,后面會有詳細(xì)分析。

部分Field

DocumentMapper是一個索引所有Mapper的集合,它表述了一個索引所有field的定義,可以說是lucene的Document的定義,同時它還包含以下index的默認(rèn)值,如index和search時默認(rèn)分詞器。它的部分Field如下所示:

private final DocumentMapperParser docMapperParser;
    private volatile ImmutableMap<String, Object> meta;
    private volatile CompressedString mappingSource;
    private final RootObjectMapper rootObjectMapper;
    private final ImmutableMap<Class<? extends RootMapper>, RootMapper> rootMappers;
    private final RootMapper[] rootMappersOrdered;
    private final RootMapper[] rootMappersNotIncludedInObject;
    private final NamedAnalyzer indexAnalyzer;
    private final NamedAnalyzer searchAnalyzer;
    private final NamedAnalyzer searchQuoteAnalyzer;

DocumentMapper的功能也體現(xiàn)在parse方法上,它的作用是解析整條數(shù)據(jù)。之前在Mapper中看到了Field是如何解析出來的,那其實是在DocumentMapper解析之后。index請求發(fā)過來的整條數(shù)據(jù)在這里被解析出Field,查找Mapping中對應(yīng)的Field設(shè)置,交給它去解析。如果沒有且運(yùn)行動態(tài)添加,es則會根據(jù)值自動創(chuàng)建一個Field同時更新Mapping。方法代碼如下所示:

public ParsedDocument parse(SourceToParse source, @Nullable ParseListener listener) throws MapperParsingException {
        ParseContext.InternalParseContext context = cache.get();
        if (source.type() != null && !source.type().equals(this.type)) {
            throw new MapperParsingException("Type mismatch, provide type [" + source.type() + "] but mapper is of type [" + this.type + "]");
        }
        source.type(this.type);
        XContentParser parser = source.parser();
        try {
            if (parser == null) {
                parser = XContentHelper.createParser(source.source());
            }
            if (sourceTransforms != null) {
                parser = transform(parser);
            }
            context.reset(parser, new ParseContext.Document(), source, listener);
            // will result in START_OBJECT
            int countDownTokens = 0;
            XContentParser.Token token = parser.nextToken();
            if (token != XContentParser.Token.START_OBJECT) {
                throw new MapperParsingException("Malformed content, must start with an object");
            }
            boolean emptyDoc = false;
            token = parser.nextToken();
            if (token == XContentParser.Token.END_OBJECT) {
                // empty doc, we can handle it...
                emptyDoc = true;
            } else if (token != XContentParser.Token.FIELD_NAME) {
                throw new MapperParsingException("Malformed content, after first object, either the type field or the actual properties should exist");
            }
            // first field is the same as the type, this might be because the
            // type is provided, and the object exists within it or because
            // there is a valid field that by chance is named as the type.
            // Because of this, by default wrapping a document in a type is
            // disabled, but can be enabled by setting
            // index.mapping.allow_type_wrapper to true
            if (type.equals(parser.currentName()) && indexSettings.getAsBoolean(ALLOW_TYPE_WRAPPER, false)) {
                parser.nextToken();
                countDownTokens++;
            }
            for (RootMapper rootMapper : rootMappersOrdered) {
                rootMapper.preParse(context);
            }
            if (!emptyDoc) {
                rootObjectMapper.parse(context);
            }
            for (int i = 0; i < countDownTokens; i++) {
                parser.nextToken();
            }
            for (RootMapper rootMapper : rootMappersOrdered) {
                rootMapper.postParse(context);
            }
        } catch (Throwable e) {
            // if its already a mapper parsing exception, no need to wrap it...
            if (e instanceof MapperParsingException) {
                throw (MapperParsingException) e;
            }
            // Throw a more meaningful message if the document is empty.
            if (source.source() != null && source.source().length() == 0) {
                throw new MapperParsingException("failed to parse, document is empty");
            }
            throw new MapperParsingException("failed to parse", e);
        } finally {
            // only close the parser when its not provided externally
            if (source.parser() == null && parser != null) {
                parser.close();
            }
        }
        // reverse the order of docs for nested docs support, parent should be last
        if (context.docs().size() > 1) {
            Collections.reverse(context.docs());
        }
        // apply doc boost
        if (context.docBoost() != 1.0f) {
            Set<String> encounteredFields = Sets.newHashSet();
            for (ParseContext.Document doc : context.docs()) {
                encounteredFields.clear();
                for (IndexableField field : doc) {
                    if (field.fieldType().indexed() && !field.fieldType().omitNorms()) {
                        if (!encounteredFields.contains(field.name())) {
                            ((Field) field).setBoost(context.docBoost() * field.boost());
                            encounteredFields.add(field.name());
                        }
                    }
                }
            }
        }
        ParsedDocument doc = new ParsedDocument(context.uid(), context.version(), context.id(), context.type(), source.routing(), source.timestamp(), source.ttl(), context.docs(), context.analyzer(),
                context.source(), context.mappingsModified()).parent(source.parent());
        // reset the context to free up memory
        context.reset(null, null, null, null);
        return doc;
    }

將整條數(shù)據(jù)解析成ParsedDocument,解析后的數(shù)據(jù)才能進(jìn)行后面的Field解析建立索引。

總結(jié)

以上就是Mapping的結(jié)構(gòu)和相關(guān)功能概括,Mapper賦予了elasticsearch索引的更強(qiáng)大功能,使得索引和搜索可以支持更多數(shù)據(jù)類型,靈活性更高,更多關(guān)于elasticsearch索引index Mapping關(guān)系結(jié)構(gòu)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring中最常用的注解之一@Autowired詳解

    Spring中最常用的注解之一@Autowired詳解

    本文講解了Spring中最常用的注解之一@Autowired, 平時我們可能都是使用屬性注入的,但是后續(xù)建議大家慢慢改變習(xí)慣,使用構(gòu)造器注入。同時也講解了這個注解背后的實現(xiàn)原理,需要的朋友可以參考下
    2023-01-01
  • Java通俗易懂系列設(shè)計模式之代理模式

    Java通俗易懂系列設(shè)計模式之代理模式

    這篇文章主要介紹了Java通俗易懂系列設(shè)計模式之代理模式,對設(shè)計模式感興趣的同學(xué),一定要看下
    2021-04-04
  • MyBatis的mapper.xml文件中入?yún)⒑头祷刂档膶崿F(xiàn)

    MyBatis的mapper.xml文件中入?yún)⒑头祷刂档膶崿F(xiàn)

    這篇文章主要介紹了MyBatis的mapper.xml文件中入?yún)⒑头祷刂档膶崿F(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 基于mybatis進(jìn)行批量更新兩種方法

    基于mybatis進(jìn)行批量更新兩種方法

    這篇文章主要給大家介紹了關(guān)于如何基于mybatis進(jìn)行批量更新的兩種方法,批量更新的使用,mybatis中批量更新有很多種方法,可以把數(shù)據(jù)一條條更新,也可以傳入一個數(shù)據(jù)集一次性更新,需要的朋友可以參考下
    2023-08-08
  • 淺談JAVA工作流的優(yōu)雅實現(xiàn)方式

    淺談JAVA工作流的優(yōu)雅實現(xiàn)方式

    這篇文章主要介紹了淺談JAVA工作流的優(yōu)雅實現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • 詳解Java編譯優(yōu)化之循環(huán)展開和粗化鎖

    詳解Java編譯優(yōu)化之循環(huán)展開和粗化鎖

    之前在講JIT的時候,有提到在編譯過程中的兩種優(yōu)化循環(huán)展開和粗化鎖,今天從Assembly的角度來驗證一下這兩種編譯優(yōu)化方法,快來看看吧。
    2021-06-06
  • 如何在Java中使用正則表達(dá)式API

    如何在Java中使用正則表達(dá)式API

    這篇文章主要介紹了如何在Java中使用正則表達(dá)式API,我們將討論java正則表達(dá)式API,以及如何在Java編程語言中使用正則表達(dá)式。具體詳細(xì)介紹,需要的小伙伴可以參考下面文章內(nèi)容
    2022-06-06
  • java中Swing五種常見的布局方式

    java中Swing五種常見的布局方式

    本文通過代碼示例給大家詳細(xì)講解了java中Swing五種常見的布局方式,以及相關(guān)注意知識點,有興趣的朋友參考學(xué)習(xí)下。
    2018-03-03
  • Java判斷兩個集合是否具有交集及如何獲得交集詳解

    Java判斷兩個集合是否具有交集及如何獲得交集詳解

    這篇文章主要給大家介紹了關(guān)于Java判斷兩個集合是否具有交集及如何獲得交集的相關(guān)資料,文中通過圖文以及實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • IntelliJ IDEA JRebel 安裝使用圖文教程(熱部署插件)

    IntelliJ IDEA JRebel 安裝使用圖文教程(熱部署插件)

    IDEA 全稱 IntelliJ IDEA,是java語言開發(fā)的集成環(huán)境,IntelliJ在業(yè)界被公認(rèn)為最好的java開發(fā)工具之一。這篇文章主要介紹了IntelliJ IDEA 熱部署插件JRebel 安裝使用圖文教程,需要的朋友可以參考下
    2018-03-03

最新評論