二十五 type底层存储方式

本文详细介绍了Elasticsearch中索引(index)与类型(type)的概念,解释了不同类型数据如何在同一索引下共存,以及底层Lucene的存储机制。通过具体示例,展示了上层定义与底层存储的差异,强调了最佳实践——相似结构类型应置于同一索引下,以避免性能问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

type,是一个index中用来区分类似的数据的,类似的数据,但是可能有不同的fields,而且有不同的属性来控制索引建立、分词器;
field的value,在底层的lucene中建立索引的时候,全部是opaque bytes类型,不区分类型的;
lucene是没有type的概念的,在document中,实际上将type作为一个document的field来存储,即_type,es通过_type来进行type的过滤和筛选;
一个index中的多个type,实际上是放在一起存储的,因此一个index下,不能有多个type重名,而类型或者其他设置不同的,因为那样是无法处理的。

上层定义形式为:

{
   "ecommerce": { ---index
      "mappings": {
         "elactronic_goods": { ---type
            "properties": {
               "name": {
                  "type": "string",
               },
               "price": {
                  "type": "double"
               },
               "service_period": {
                   "type": "string"
               }            
            }
         },
         "fresh_goods": { ---type
            "properties": {
               "name": {
                  "type": "string",
               },
               "price": {
                  "type": "double"
               },
               "eat_period": {
                 "type": "string"
                }
            }
         }
      }
   }
}

底层存储方式为:

{
   "ecommerce": {
      "mappings": {
        "_type": {
          "type": "string",
          "index": "not_analyzed"
        },
        "name": {
          "type": "string"
        }
        "price": {
          "type": "double"
        }
        "service_period": {
          "type": "string"
        }
        "eat_period": {
          "type": "string"
        }
      }
   }
}

 

举例:

上层数据:

{
  "name": "geli kongtiao",
  "price": 1999.0,
  "service_period": "one year"
}

{
  "name": "aozhou dalongxia",
  "price": 199.0,
  "eat_period": "one week"
}

底层存储形式:

{
  "_type": "elactronic_goods",
  "name": "geli kongtiao",
  "price": 1999.0,
  "service_period": "one year",
  "eat_period": ""
}

{
  "_type": "fresh_goods",
  "name": "aozhou dalongxia",
  "price": 199.0,
  "service_period": "",
  "eat_period": "one week"
}


最佳实践,将类似结构的type放在一个index下,这些type应该有多个field是相同的
假如说,你将两个type的field完全不同,放在一个index下,那么就每条数据都至少有一半的field在底层的lucene中是空值,会有严重的性能问题

### Redis 五种数据类型的底层实现原理 Redis 支持五种主要的数据类型:String、Hash、List、Set 和 Zset。这些数据类型的底层实现依赖于 Redis 的对象系统和不同的数据结构。 #### 1. String 类型 Redis 中的字符串类型(String)底层使用简单动态字符串(SDS,Simple Dynamic String)实现[^3]。SDS 是一种改进的 C 字符串,具有以下三个属性: - `len`:记录当前字符串的长度。 - `free`:记录未使用的字节数量。 - `buf`:保存字符串的字节数组。 这种设计使得 SDS 能够高效地处理字符串的增长和缩减操作,同时避免了传统 C 字符串的内存浪费问题。此外,Redis 中的字符串不仅可以存储文本数据,还可以存储整数或浮点数,并支持原生数值操作。 #### 2. Hash 类型 Redis 的 Hash 类型底层使用字典(dict)来实现[^4]。字典是一种哈希表结构,其定义如下: ```c typedef struct dict { dictType *type; /* 指向自定义类型的指针 */ void *privdata; /* 私有数据的指针 */ dictht ht[2]; /* 两个哈希表,一般只有 ht[0] 有效,ht[1] 只在 rehash 时使用 */ long rehashidx; /* -1 表示没有进行 rehash,大于等于 0 表示 rehash 到第几步 */ unsigned long iterators; /* 正在遍历的迭代器个数 */ } dict; ``` Hash 类型中的每个字段和值都存储为键值对,通过哈希表实现快速查找。当元素数量较多时,Redis 会自动进行 rehash 操作以优化性能。 #### 3. List 类型 Redis 的 List 类型底层使用双向链表(quicklist)实现。每个节点包含一个 ziplist(压缩列表),用于存储多个元素。这种设计结合了链表和数组的优点,既支持高效的插入和删除操作,又减少了内存开销。 #### 4. Set 类型 Redis 的 Set 类型底层实现依赖于集合中的元素类型和数量: - 如果集合中的元素均为整数且元素个数小于 512(默认值,由配置项 `set-maxintset-entries` 控制),则使用整数集合(intset)作为底层数据结构[^1]。 - 如果集合中的元素不满足上述条件,则使用哈希表(dict)作为底层数据结构。 整数集合是一种紧凑的数组结构,能够高效存储和操作整数元素。而哈希表则提供了更通用的支持,适用于任意类型的元素。 #### 5. Zset(Sorted Set)类型 Redis 的 Zset 类型底层使用两种数据结构实现: - 有序集合(skip list):用于按分值(score)排序存储元素。 - 哈希表(dict):用于快速查找成员及其对应的分值。 Skip list 是一种多层链表结构,能够在 O(log N) 时间复杂度内完成插入、删除和查找操作。哈希表则确保了成员与分值之间的映射关系。 --- ### 示例代码 以下是一个简单的 Redis 数据类型操作示例: ```python import redis # 连接 Redis r = redis.Redis(host='localhost', port=6379, decode_responses=True) # String 类型 r.set('key', 'value') print(r.get('key')) # 输出: value # Hash 类型 r.hset('user:1000', mapping={'name': 'Alice', 'age': '25'}) print(r.hgetall('user:1000')) # 输出: {'name': 'Alice', 'age': '25'} # List 类型 r.lpush('queue', 'task1', 'task2') print(r.lrange('queue', 0, -1)) # 输出: ['task2', 'task1'] # Set 类型 r.sadd('fruits', 'apple', 'banana', 'cherry') print(r.smembers('fruits')) # 输出: {'apple', 'banana', 'cherry'} # Zset 类型 r.zadd('leaderboard', {'Alice': 100, 'Bob': 200, 'Charlie': 150}) print(r.zrange('leaderboard', 0, -1, withscores=True)) # 输出: [('Alice', 100), ('Charlie', 150), ('Bob', 200)] ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值