private void retrieval(final Class<?> clazz,
                           final String modelName,
                           final List<ModelColumn> modelColumns,
                           final int scopeId,
                           SeriesIDChecker seriesIDChecker,
                           ShardingKeyChecker shardingKeyChecker,
                           final SQLDatabaseModelExtension sqlDBModelExtension,
                           final BanyanDBModelExtension banyanDBModelExtension) {
        if (log.isDebugEnabled()) {
            log.debug("Analysis {} to generate Model.", clazz.getName());
        }

        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class)) {
                if (field.isAnnotationPresent(SQLDatabase.AdditionalEntity.class)) {
                    if (!Record.class.isAssignableFrom(clazz)) {
                        throw new IllegalStateException(
                            "Model [" + modelName + "] is not a Record, @SQLDatabase.AdditionalEntity only supports Record.");
                    }
                }

                Column column = field.getAnnotation(Column.class);
                // Use the column#length as the default column length, as read the system env as the override mechanism.
                // Log the error but don't block the startup sequence.
                int columnLength = column.length();

                // SQL Database extension
                SQLDatabaseExtension sqlDatabaseExtension = new SQLDatabaseExtension();
                List<SQLDatabase.CompositeIndex> indexDefinitions = new ArrayList<>();
                if (field.isAnnotationPresent(SQLDatabase.CompositeIndex.class)) {
                    indexDefinitions.add(field.getAnnotation(SQLDatabase.CompositeIndex.class));
                }

                if (field.isAnnotationPresent(SQLDatabase.CompositeIndices.class)) {
                    Collections.addAll(
                        indexDefinitions, field.getAnnotation(SQLDatabase.CompositeIndices.class).value());
                }

                indexDefinitions.forEach(indexDefinition -> {
                    sqlDatabaseExtension.appendIndex(new SQLDatabaseExtension.MultiColumnsIndex(
                        column.name(),
                        indexDefinition.withColumns()
                    ));
                });

                // ElasticSearch extension
                final var elasticSearchAnalyzer = field.getAnnotation(ElasticSearch.MatchQuery.class);
                final var elasticSearchColumn = field.getAnnotation(ElasticSearch.Column.class);
                final var keywordColumn = field.getAnnotation(ElasticSearch.Keyword.class);
                final var routingColumn = field.getAnnotation(ElasticSearch.Routing.class);
                final var enableDocValues = field.getAnnotation(ElasticSearch.EnableDocValues.class);
                final var elasticSearchExtension = new ElasticSearchExtension(
                    elasticSearchAnalyzer == null ? null : elasticSearchAnalyzer.analyzer(),
                    elasticSearchColumn == null ? null : elasticSearchColumn.legacyName(),
                    keywordColumn != null,
                    routingColumn != null,
                    enableDocValues != null
                );

                // BanyanDB extension
                final BanyanDB.SeriesID banyanDBSeriesID = field.getAnnotation(
                    BanyanDB.SeriesID.class);
                final BanyanDB.ShardingKey banyanDBShardingKey = field.getAnnotation(
                    BanyanDB.ShardingKey.class);
                final BanyanDB.NoIndexing banyanDBNoIndex = field.getAnnotation(
                    BanyanDB.NoIndexing.class);
                final BanyanDB.IndexRule banyanDBIndexRule = field.getAnnotation(
                    BanyanDB.IndexRule.class);
                final BanyanDB.MeasureField banyanDBMeasureField = field.getAnnotation(
                    BanyanDB.MeasureField.class);
                final BanyanDB.TopNAggregation topNAggregation = field.getAnnotation(
                    BanyanDB.TopNAggregation.class);
                final BanyanDB.MatchQuery analyzer = field.getAnnotation(
                    BanyanDB.MatchQuery.class);
                final BanyanDB.EnableSort enableSort = field.getAnnotation(
                    BanyanDB.EnableSort.class);
                final boolean shouldIndex = (banyanDBNoIndex == null) && !column.storageOnly();
                BanyanDBExtension banyanDBExtension = new BanyanDBExtension(
                    banyanDBSeriesID == null ? -1 : banyanDBSeriesID.index(),
                    banyanDBShardingKey == null ? -1 : banyanDBShardingKey.index(),
                    shouldIndex,
                    banyanDBIndexRule == null ? BanyanDB.IndexRule.IndexType.INVERTED : banyanDBIndexRule.indexType(),
                    banyanDBMeasureField != null,
                    analyzer == null ? null : analyzer.analyzer(),
                    enableSort != null
                );

                if (topNAggregation != null) {
                    BanyanDBModelExtension.TopN topN = new BanyanDBModelExtension.TopN();
                    topN.setLruSize(topNAggregation.lruSize());
                    topN.setCountersNumber(topNAggregation.countersNumber());
                    topN.setGroupByTagNames(Collections.singletonList(column.name()));
                    banyanDBModelExtension.setTopN(topN);
                }

                final ModelColumn modelColumn = new ModelColumn(
                    new ColumnName(column),
                    field.getType(),
                    field.getGenericType(),
                    column.storageOnly(),
                    column.indexOnly(),
                    column.dataType().isValue(),
                    columnLength,
                    sqlDatabaseExtension,
                    elasticSearchExtension,
                    banyanDBExtension
                );
                if (banyanDBExtension.isSeriesID()) {
                    seriesIDChecker.accept(modelName, modelColumn);
                }
                if (banyanDBExtension.isShardingKey()) {
                    shardingKeyChecker.accept(modelName, modelColumn);
                }

                if (field.isAnnotationPresent(SQLDatabase.AdditionalEntity.class)) {
                    final var additionalEntity = field.getAnnotation(SQLDatabase.AdditionalEntity.class);
                    final var additionalTableNames = additionalEntity.additionalTables();
                    for (final var tableName : additionalTableNames) {
                        sqlDBModelExtension.appendAdditionalTable(tableName, modelColumn);
                    }
                    if (!additionalEntity.reserveOriginalColumns()) {
                        sqlDBModelExtension.appendExcludeColumns(modelColumn);
                    }
                }

                modelColumns.add(modelColumn);
                if (log.isDebugEnabled()) {
                    log.debug("The field named [{}] with the [{}] type", column.name(), field.getType());
                }
                if (column.dataType().isValue()) {
                    ValueColumnMetadata.INSTANCE.putIfAbsent(
                        modelName, column.name(),
                        column.dataType(), column.defaultValue(), scopeId, column.multiIntValues());
                }
            }
        }

        if (Objects.nonNull(clazz.getSuperclass())) {
            retrieval(
                clazz.getSuperclass(), modelName, modelColumns, scopeId, seriesIDChecker, shardingKeyChecker,
                sqlDBModelExtension, banyanDBModelExtension
            );
        }
    }
Read model column metadata based on the class level definition.
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java