Elasticsearch

55 阅读21分钟

相关软件安装

安装 Elasticsearch

  1. 首先需要安装jdk,推荐 jdk8、jdk11
  2. 官网:www.elastic.co/cn/start 下载安装
  3. 启动命令,注意 Linux 环境下使用 root 用户不能直接启动 es,可以添加用户使用别的用户启动
> adduser elasticsearch # 添加用户<br>
> passwd elasticsearch # 设置密码<br>
> su elasticsearch 切换用户,也可以使用这个用户连接 linux 服务器执行
> **./elasticsearch -d**    #到 es 的 bin 文件夹里输入,后台方式启动 es

4. 如果需要外网访问,需要修改 /config/elasticsearch.yml,两行数据

network.host:0.0.0.0 放开注释 

如果遇到问题

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

使用sudo用户修改文件:

sudo vim /etc/sysctl.conf

添加一行配置:

vm.max_map_count=655360

再执行

sudo sysctl -p

如果遇到问题

[2]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured

那么找到下面的代码,注释去掉

cluster.initial_master_nodes: ["node-1", "node-2"]

节点名称配置一下

node.name: node-1

5. 连接的时候设置用户名密码

www.cnblogs.com/snail90/p/1…

blog.csdn.net/donlian/art…

安装 Kibana

  1. 尽量用和 ES 一个版本的
  2. 下载 Kibana
  3. 如果需要外网访问,需要修改 /config/kibana.yml
server.host: "0.0.0.0" 放开注释

elasticsearch.hosts: ["<http://localho>st:9200"] 要改为 elasticsearch.hosts: ["http://es配置的IP:es配置的端口号,默认9200"]

4. 启动

./kibana &     # 到 kibana 的 bin 文件夹里输入, 带 & 可以后台启动  如果要关闭,无法通过jps/ps查到进程,需要 lsof -i :5601  然后 kill pid

5. 连接的时候设置用户名密码

kibana.yml 文件里添加:

elasticsearch.username: "kibana_system"

elasticsearch.password: "your_password"

登录的时候可以使用配置的 ES 任意账户。

Head 插件安装

一个针对 es 可视化操作的插件。

  1. 安装 Node.js

官网: nodejs.org/en/download… 

教程 www.cnblogs.com/sirdong/p/1…

  1. 安装 grunt

    ① 执行“npm install -g grunt-cli”命令等待安装完成

    ② 输入 grunt -version 检查是否安装成功

  2. 下载 Head 插件

    ① 官网 :github.com/mobz/elasti… 下载 zip 压缩包

    ② 解压,然后在 Gruntfile.js 文件里层级里加 host:'*',

connect: {
			server: {
				options: {
					// 加上的,所有的域名可以访问
					host:'*',
					port: 9100,
					base: '.',
					keepalive: true
				}
			}
		}

④ 访问 IP:5601 查看是否启动成功
⑤ 把整个文件夹移动到服务器上,cd 到文件夹里执行 npm install
npm run start 启动插件,需要后台启动需要 grunt server &,接着输入 exit 退出 shell,关闭使用 lsof -i :9100  然后 kill pid ⑦ 在 es 的 yml 文件里添加,重新启动

# ES 允许跨域访问,不然 head 插件无法发现节点
http.cors.enabled: true
http.cors.allow-origin: "*"

⑧ 访问 IP:9100,配置连接地址,查看是否启动成功

  1. 如果 ES 设置了用户名密码,进行以下操作

blog.csdn.net/yulei6/arti…

elasticsearch.yml 文件加上 http.cors.allow-headers: Content-Type,Accept,Authorization, x-requested-with

访问的时候 http://xxx:9100/?auth_user=用户名&auth_password=密码

集群

  • 主节点:通过node.master=true的配置,可以把一个节点设置为候选主节点。候选主节点经过集群选举,如果成功,就会成为主节点。
    • 主节点负责索引的创建和删除,分配分片,追踪集群中的节点状态等工作。
  • 数据节点:通过node.data=true的配置,可以把一个节点设置为数据节点。
    • 数据节点主要负责数据的读写相关操作,如CRUD,搜索,聚合等。
  • 客户端节点:如果某个节点的node.master和node.data都为false,那么,该节点将既不参与竞选主节点,也不会读写数据。那么,它在集群中还有用吗?有。
    • 它也可以处理客户的请求,只是处理的方式是:把收到的请求分发到相关节点,并把得到的结果汇总返回。这种节点,称之为客户端节点。
  • 协调节点:协调节点不是一个具体的节点类型,它更像是一个节点所扮演的角色。如上面提到的客户端节点,就是一个协调节点的角色,客户端节点的工作内容也正是承担了协调节点角色的工作内容。当然了,主节点,候选主节点或者数据节点,都可以承担起这样的角色。

  主节点的选取:所有 node.master=true 的节点都可以参与主节点的竞选。
  es集群中的每个节点都可以投票。

集群的健康检查

健康值状态

  • Green:所有的 Primary(主分片) 和 Replica(副本)都能使用,集群健康。
  • Yellow:至少一个 Replica 不能使用,所有的 Primary 都能使用,数据仍可保持完整性。
  • Red:至少有一个 Primary 不能使用,数据不完整,集群不可用。

  Primary 在 head 插件看到是加粗的边框,Replica 是细边框。

Elasticsearch 核心概念

什么是搜索引擎

  • 全文搜索引擎

自然语言处理(NLP)、爬虫、网页处理、大数据处理,如谷歌、百度、搜狗、必应等。

  • 垂直搜索引擎

有明确搜索目的的搜索引擎,如各大电商网站、站内搜索、视频网站等。

Elasticsearch 简介

  Elasticserach 是基于 Lucene 的搜索服务器,它提供了一个分布式多用户能力的全文搜索引擎。是用 Java 语言开发的。

  ES 并不是一个标准的数据库,它不像 MongoDB,它侧重于对存储的数据进行搜索。因此要注意到它不是实时读写的,这也就意味着,刚刚存储的数据,并不能马上查询到。缺省配置下,shard(分片)每秒自动更新,所以会有 1S 的延时。

一些基本概念

www.biaodianfu.com/elasticsear…

正排索引和倒排索引的区别

mapping

  mapping 就是 ES 数据字段 field 的 type 元数据,ES 在创建索引的时候,dynamic mapping 会自动为不同的数据指定相应 mapping,mapping 中包含了字段的类型、搜索方式(exact value或者full text)、分词器等。

  类似于数据库里的字段类型,比如新建一个 mapping: age 的 type 是 text,那么添加数据 {"age" : 123},123 存储的时候数据就是 text,而不是 long。一个字段 一个 type。

kibana 操作 mapping

  查看指定 Index 里的 mapping

GET /product/_mappings
// GET /Index 名/_mappings

  在新建 Index 的时候手工创建 mapping

// PUT /Index 名
PUT /product
{
  "mappings": {
    "properties": {
        "field 字段名": {
          "type" : "type 类型"
          "mapping_parameter": "parameter_value"
        }
      }
  }
}

  修改 mapping

// PUT /Index 名/_mapping
PUT /product/_mapping 
{
  "properties":{
    "字段名" : {
      "type" : "type 类型"
    }
  }
}

Dynamic mapping

数据类型
Elasticsearchaaaaatext/keyword
123456long
123.123float
true / falseboolean
2020-05-20date
对象object
数组取决数组中第一个有效值

ES数据类型

核心类型

1)数字类型
  1. long, integer, short, byte, double, float, half_float, scaled_float
  2. 在满足需求的情况下,尽可能选择范围小的数据类型。
2) 字符串:string
  1. keyword:适用于索引结构化的字段,可以用于过滤、排序、聚合。keyword 类型的字段只能通过精确值(exact value)搜索到。Id 应该用 keyword
  2. text:当一个字段是要被全文搜索的,比如 Email 内容、产品描述,这些字段应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。

  text 类型的字段不用于排序,很少用于聚合。(解释一下为啥不会为 text 创建正排索引:字段数据会占用大量堆空间,尤其是在加载高基数 text 字段时。字段数据一旦加载到堆中,就在该段的生命周期内保持在那里。同样,加载字段数据是一个昂贵的过程,可能导致用户遇到延迟问题。这就是默认情况下禁用字段数据的原因)

  1. 有时,在同一字段中同时具有全文本(text)和关键字(keyword)版本会很有用:一个用于全文本搜索,另一个用于聚合和排序。
3) date(时间类型)
4) 布尔类型:boolean
5) binary(二进制):binary
6) range(区间类型):

  integer_range、float_range、long_range、double_range、date_range

复杂类型

  1. Object:用于单个JSON对象

  2. Nested:用于JSON对象数组 nested 介绍与使用

地理位置

  1. Geo-point:纬度/经度积分
  2. Geo-shape:用于多边形等复杂形状

特有类型

  1. IP地址:ip 用于IPv4和IPv6地址
  2. Completion:提供自动完成建议
  3. Tocken_count:计算字符串中令牌的数量
  4. Murmur3:在索引时计算值的哈希并将其存储在索引中
  5. Annotated-text:索引包含特殊标记的文本(通常用于标识命名实体)
  6. Percolator:接受来自query-dsl的查询
  7. Join:为同一索引内的文档定义父/子关系
  • 适用场景
    • join 类型不能像关系数据库中的表链接那样去用,不论是 has_child 或者是 has_parent 查询都会对索引的查询性能有严重的负面影响。并且会触发globalordinals。
    • join 唯一合适应用场景是︰当索引数据包含一对多的关系,并且其中一个实体的数量远远超过另一个的时候。比如:老师有一万个学生。
  • join 类型的使用
  1. Rank features:记录数字功能以提高查询时的点击率。
  2. Dense vector:记录浮点值的密集向量。
  3. Sparse vector:记录浮点值的稀疏向量。
  4. Search-as-you-type:针对查询优化的文本字段,以实现按需输入的完成
  5. Alias:为现有字段定义别名。
  6. Flattened:允许将整个JSON对象索引为单个字段。
  7. Shape:shape 对于任意笛卡尔几何。
  8. Histogram:histogram 用于百分位数聚合的预聚合数值。
  9. Constant keyword:keyword当所有文档都具有相同值时的情况的 专业化。

Array(数组)

在 Elasticsearch 中,数组不需要专用的字段数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值都必须具有相同的数据类型。

ES 7新增

  1. Date_nanos:date plus 纳秒
  2. Features:
  3. Vector:as

Mapping parameters

  这些和 type 是同一层级的

  1. index :是否对创建对当前字段创建倒排索引,默认 true,如果不创建索引,该字段不会通过索引被搜索到,但是仍然会在 source 元数据中展示
  2. analyzer : 指定分析器(character filter、tokenizer、Token filters)。
  3. boost :对当前字段相关度的评分权重,默认1
  4. coerce :是否允许强制类型转换,默认true,在 PUT 并且 coerce 为 true 的时候 :“1”=> 1 , false 的时候“1”不能转换为 1,报错
  5. copy_to :该参数允许将多个字段的值复制到组字段中,然后可以将其当作单个字段进行查询。
"field": {
	"type": "text",
	"copy_to": "other_field_name" 
},

6. doc_values :为了提升排序和聚合效率,默认 true,如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用 doc 值以节省磁盘空间(不支持 text 和 annotated_text) 7. dynamic :控制是否可以动态添加新字段 1. true 新检测到的字段将添加到映射中。(默认) 2. false 新检测到的字段将被忽略。这些字段将不会被索引,因此将无法搜索,但仍会出现在_source返回的 3. 匹配项中。这些字段不会添加到映射中,必须显式添加新字段。 4. strict 如果检测到新字段,则会引发异常并拒绝文档。必须将新字段显式添加到映射中 8. eager_global_ordinals:用于聚合的字段上,优化聚合性能。 9. Frozen indices(冻结索引):有些索引使用率很高,会被保存在内存中,有些使用率特别低,宁愿在使用 的时候重新创建,在使用完毕后丢弃数据,Frozen indices 的数据命中频率小,不适用于高搜索负载,数 据不会被保存在内存中,堆空间占用比普通索引少得多,Frozen indices 是只读的,请求可能是秒级或者分钟级。eager_global_ordinals 不适用于 Frozen indices 10. enable:是否创建倒排索引,可以对字段操作,也可以对索引操作,如果不创建索引,仍然可以检索并在_source 元数据中展示,谨慎使用,该状态无法修改。

PUT my_index{
	"mappings": {
		"enabled": false 
	}
}

PUT my_index{
	"mappings": {
		"properties": {
			"session_data": {
				"type": "object",
				"enabled": false
			}
		}
	}
}

10. fielddata:查询时内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为 fielddata 数据结构,并且创建正排索引保存到堆中。 11. fields:给 field 创建多字段,用于不同目的(全文检索或者聚合分析排序)。 12. format:格式化

"date": {
	"type":   "date",
	"format": "yyyy-MM-dd"
}

13. ignore_above:超过长度将被忽略 14. ignore_malformed:忽略类型错误 - 常用于数据同步

PUT my_index{
"mappings": {
	"properties": {
			"number_one": {
				"type": "integer",
				"ignore_malformed": true
			},
			"number_two": {
			"type": "integer"
			}
		}
	}
}

PUT my_index/_doc/1{
		"text":       "Some text value",
		"number_one": "foo" 
}   //虽然有异常 但是不抛出
PUT my_index/_doc/2{
		"text":       "Some text value",
		"number_two": "foo" 
}   //数据格式不对	

15. index_options:控制将哪些信息添加到反向索引中以进行搜索和突出显示。仅用于 text 字段 16. Index_phrases:提升 exact_value 查询速度,但是要消耗更多磁盘空间 17. Index_prefixes:前缀搜索
1. min_chars:前缀最小长度,>0,默认2(包含) 2. max_chars:前缀最大长度,<20,默认5(包含)

"index_prefixes": {
	"min_chars" : 1,
	"max_chars" : 10
}	

18. meta:附加元数据 19. normalizer 20. norms:是否禁用评分(在 filter 和聚合字段上应该禁用)。 21. null_value:为 null 值设置默认值 22. position_increment_gap: 23. proterties:除了 mapping 还可用于 object 的属性设置 24. search_analyzer:设置单独的查询时分析器:

PUT my_index{
"settings": {
	"analysis": {
		"filter": {
			"autocomplete_filter": {
				"type": "edge_ngram",
				"min_gram": 1,
				"max_gram": 20
				}
			},
			"analyzer": {
				"autocomplete": { 
				"type": "custom",
				"tokenizer": "standard",
				"filter": [
					"lowercase",
					"autocomplete_filter"
        ]
			}
		}
	}
},
"mappings": {
	"properties": {
		"text": {
			"type": "text",
			"analyzer": "autocomplete", 
			"search_analyzer": "standard" 
			}
		}
	}
}

PUT my_index/_doc/1
{
	"text": "Quick Brown Fox" 
}

GET my_index/_search
{
	"query": {
		"match": {
			"text": {
				"query": "Quick Br", 
				"operator": "and"
			}
		}
	}
}

25. similarity:为字段设置相关度算法,支持BM25、claassic(TF-IDF)、boolean 26. store:设置字段是否仅查询 27. term_vector

ES 的操作

文档的操作类型(op_type)

  • create:不存在新增,存在就报错。
  • delete:懒删除模式,删除首先会标记为删除,version + 1。
  • update
  • index:不存在就创建,存在就全量替换。
  • noop:不做任何操作。

  加上 filter_path=items..error 只输出错误信息,在大批量操作数据的时候方便,可能某几条数据出错。
  PUT /product/_doc/1?op_type=index&filter_path=items.
.error

Kibana 操作 ES

  在 7.0 以及之后的版本中 Type 被废弃了。一个 index 中只有一个默认的 type,即 _doc。   www.yuque.com/u2106867/kr…

Kibana 查询

  _analyze 是 Elasticsearch 一个非常有用的 API,它可以帮助你分析每一个 field 或者某个 analyzer/tokenizer 是如何分析和索引一段文字。

GET _analyze
{
  "analyzer": "english", 
  "text": "我也包含2021-12-04"
}

Elasticsearch 提供了基于 JSON 的完整查询 DSL(特定于域的语言)来定义查询

简单查询

简单查询

聚合查询

聚合查询

分词器

  anaylyzer,分词器,专门处理分词的组件,有三部分组成:

  • Character filters,原始文本的预处理,通常完成HTML元素删除,替换指定字符等功能;
  • Tokenizer,分词,按照预设的规则切分文本;
  • Token filter,切分后处理,例如大小写转换,删除停用词/stopwords,增加同义词;

normalizer(规范化)

  规范一些大小写、书名号、语气词等数据规范成统一的形式,提高召回率。

召回率:你查出来的正确的数量除以所有正确的数量。

character filter(字符过滤器)

  原始文本的预处理,通常完成HTML元素删除,替换指定字符等功能;

HTML Strip Character Filter(html 字符过滤)

DELETE my_index
# 创建一个索引,索引里自定义一个分析器与字符过滤器,escaped_tags不处理的标签
PUT my_index
{
  "settings": {
    "analysis": {
      "char_filter": {
        "my_char_filter": {
          "type": "html_strip",
          "escaped_tags": [
            "a"
          ]
        }
      },
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "keyword",
          "char_filter": ["my_char_filter"]
        }
      }
    }
  }
}

GET my_index/_analyze
{
  "text":"<p>I&apos;m so <a>happy</a>!</p>'", 
  "analyzer": "my_analyzer"
}

Mapping Character Filter(自定义映射过滤器)

# 创建一个索引,索引里自定义一个分析器与自定义映射过滤器,可以把指定的字符替换为别的字符
PUT my_index
{
  "settings": {
    "analysis": {
      "char_filter": {
        "my_char_filter": {
          "type": "mapping",
          "mappings" :
          [
            "垃圾 => 真美丽",
            "恶 => 开"
          ]
        }
      },
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "keyword",
          "char_filter": ["my_char_filter"]
        }
      }
    }
  }
}
GET my_index/_analyze
{
  "text":"你垃圾,真让我恶心", 
  "analyzer": "my_analyzer"
}

Pattern Replace Character Filter

  模式替换字符筛选器使用正则表达式来匹配应替换为指定替换字符串的字符。写得不好的正则表达式可能运行得非常慢,甚至引发 stackoverflowError,并导致运行它的节点突然退出。

# 创建一个索引,索引里自定义一个分析器与字符过滤器
DELETE my_index
PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "keyword",
          "char_filter": [
            "my_char_filter"
          ]
        }
      },
      "char_filter": {
        "my_char_filter": {
          "type": "pattern_replace",
          "pattern": "(\d+)-(?=\d)",
          "replacement": "$1_"
        }
      }
    }
  }
}

GET my_index/_analyze
{
  "analyzer": "my_analyzer",
  "text": "My credit card is 123-456-789"
}

token filter(词项过滤器)

  词项过滤器,切分后处理,例如大小写转换,删除停用词/stopwords,增加同义词。

官网链接

常用分词器

  1. standard analyzer:默认分词器,中文支持的不理想,会逐字拆分。
  2. pattern tokenizer:以正则匹配分隔符,把文本拆分成若干词项。
  3. simple pattern tokenizer:以正则匹配词项,速度比 pattern tokenizer 快。
  4. whitespace analyzer:以空白符分割。

自定义分词器:custom analyzer

  1. char_filter:内置或自定义字符过滤器。
  2. token filter:内置或自定义 token filter。
  3. tokenizer:内置或自定义分词器。

IK 中文分词器

分词器地址

要注意分词器的版本要与 ES 版本一致

IK 分词器的安装使用与热更新

Scripting

概念

  Scripting 是 ES 支持的一种专门用于复杂场景下支持自定义变成的强大的脚本功能,ES 支持多种脚本语言。

  在首次执行脚本的时候,会对目前的脚本进行编译,然后放到缓冲区里,缓冲区默认只有 100 M ,编译很浪费性能。

支持的语言

  1. groovy:ES 1.4.x - 5.0 的默认脚本语言
  2. painless:JavaEE 使用 java 语开发,.Net 使用 C#/F# 语言开发,同样 ES 5.0+ 版本的 Scripting 使用的脚本语言是 painless,painless 是一种专用于 ES 的简单,安全的用于内联和存储脚本,是 ES 5.0+的默认脚本语言,类似于 Java,有注释、关键字、函数等,是一种安全的脚本语言。
  3. 其他的
    1. xpression:每个文的开销较低,表达式的作用更多,可以非常快速的执行,甚至比编写 native 脚本还要快,支持 javascript 语言的子集:单个表达式。缺点:只访问数字、布尔值、日期和 geo_point 字段,存储的字段不可用。
    2. mustache:提供模块参数化查询。

脚本操作

倒排索引

倒排索引的数据结构

  首先每个数据都对应一个 Document,而且每个 Document 都有一个 ID,可以指定也可以自动生成。

  • Team:收到 Document 后进行切分、去重、规范化后获取到一个个 Team。
  • Team Dictionary(单词字典):维护着所有 Team,相当于 Team 的集合。
  • Team Index:为了更快的找到某个 Team,为 Team 创建的索引。
  • Posting List(倒排表):有序的整形数组,有序的存储着符合该 Team 的Document ID 还有一些其他的信息,如:词频(Term出现的次数)、偏移量(offset)等。

  如果类比现代汉语词典的话,那么 Term 就相当于词语,Term Dictionary 相当于汉语词典本身,Term Index 相当于词典的目录索引。

倒排表核心算法

FOR : Frame Of Reference

  1 个 int 类型占用 4 byte 即 32 bit ,int 的取值范围是 -2^31 - 2^31-1,这就是因为计算机中数据都是以 01 二进制的形式存储的,而 int 就最多可以存储 31 个 1,还有一位表示正或负数,所以有时在存储小点的数,没必要占用那么大的空间。

  由于 Posting List 是有序的整形数组,这样就有一个好处:可以通过增量编码来进行压缩。

  而倒排表使用了 FOR 压缩算法:存储不再直接存储原来的数字,而是改为存后一位与前一位的差值,存储也不再按照 int 来存储,而是以下步骤:

  1. 进行增量编码;
  2. 因为虽然是增量,但是可能两个增量相差数据也较大,所以还有压缩的可能性,那么就需要按照合适的方式分区,分成多个 block;
  3. 需要用到里面的数字的时候,还需要解码成原来的数字,所以需要记录这个数组里每个数字占用多少空间,ES 规定每个数组里的数字占用空间不能大于 255(1byte),然后用这 1byte 的空间存储这个数组里每个数据所占的空间;
  4. 按 bit 排好队(进行位压缩),最后按照 byte 来存储,最后不足 8 bit 也占用 8 bit。

  FOR 的步骤可以总结为:

  比如现在有 id 列表 [73, 300, 302, 332, 343, 372],那么进行 FOR 压缩的步骤为:

  FOR 压缩算法的缺点,当各个差值也很大的时候,那么用这个方式就不行了。

RMB : RoaringBitMap

RMB 的核心步骤是把数组里的数据处理一下,把每个文档 ID 拆成高 16 位和低 16 位,根据高位的 16 位放在不同的 block 上 ,低位的 16 位使用不同的 container 存储,keys 和 values 通过下标一一对应。size则标示了当前包含的key-value 的数量,即keys和values中有效数据的数量。

又因为文档 ID 是不重复的,所以表示 short[] 上最多存 2 的 16 次方个数据,即最多分为 65536 块(0-65535),而每个块中也是最多可以存 65536 个数据(0-65535)。

short[] keys;
Container[] values;
int size;

ArrayContainer
  //ArrayContainer允许的最大数据量
  static final int DEFAULT_MAX_SIZE = 4096;// containers with DEFAULT_MAX_SZE or less integers
                                           // should be ArrayContainers

  //记录基数
  protected int cardinality = 0;

  //用short数组存储数据
  short[] content;

  采用 short 数组存储数据,content 有序且不重复,所以存的数据越多,占用空间越多,N 个数据占用的空间是:2N byte = 2N * 8bit。

BitmapContainer
  //最大容量
  protected static final int MAX_CAPACITY = 1 << 16;
  
  //用一个定长的long数组按bit存储数据
  final long[] bitmap;

  //记录基数
  int cardinality;

  采用 long 数组存储 16 位数据,其实就是把这个 long 数组当做一个位图,每个 Bit 位置代表一个数字,而一个 Container 最多存 2 的 16 次方个数,一个 long 类型是 8 byte = 64 bit,65536 / 64 = 1024 所以在 long[] 初始化 1024 个 long,不管 BitmapContainer 中有几个数据,都是种占据着 8 kb 的空间。

ArrayContainer 4096 个之后转为 BitmapContainer 的原因:

红色为 ArrayContainer 的内存与存储数量曲线,蓝色的为 BitContainer 的曲线。
value 的最大总数是为2^16=65536。假设以 bitmap 方式存储需要 65536bit=8kb, 而直接存值的方式,一个值 2 byte,4K 个总共需要2byte*4k=8kb。所以当 value 总量 <4k 时,使用直接存值的方式更节省空间。

RunContainer

  RunContainer 是后来加入的,主要处理大连续数据。<br   举例说明:3,4,5,10,20,21,22,23 这样一组数据会被优化成 3,2,10,0,20,3,原理很简单,就是记录初始数字以及连续的数量,并把压缩后的数据记录在short数组中。

  显而易见,这种压缩方式对于数据的疏密程度非常敏感,举两个最极端的例子:如果这个 Container 中所有数据都是连续的,也就是 [0,1,2.....65535],压缩后为 0,65535,即 2个 short,4 字节。若这个Container中所有数据都是间断的(都是偶数或奇数),也就是 [0,2,4,6....65532,65534],压缩后为 0,0,2,0.....65534,0,这不仅没有压缩反而膨胀了一倍,65536 个 short,即 128kb,所以是否选择 RunContainer 是需要判断的。

blog.csdn.net/tonywu1992/…

词项索引的检索原理

FST : Finit state Transducers

可以演示 FST 的网站

  可以把重复利用Term Index 的前缀和后缀,使Term Index小到可以放进内存,减少存储空间,不过相对的也会占用更多的cpu资源。

www.cnblogs.com/cangqiongbi…

LSM 树

www.cnblogs.com/luxiaoxun/p…