Redis系列第四篇之Bitmap

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis系列第四篇之Bitmap相关的知识,希望对你有一定的参考价值。

参考技术A Bitmap实际上并不是一种数据类型,而是定义在 String 类型上的面向位的操作。因为String是二进制安全的并且最大长度为512MB,所以String可以建立2^32个不同的位。位操作被分为两种:

Bitmap最大的一个优点是当存储信息时可以节省极大的空间。例如一个系统中的用户ID由递增的ID表示,只需使用512MB的内存,就可以记住40亿用户的单比特信息(例如,知道用户是否想收到通讯)。

Bitmap使用 SETBIT 和 GETBIT 命令设置和获取位的值:

SETBIT 命令第一个参数表示需要被设置的位,第二个参数表示需要设置的值(1或者0)。需要注意的是,当被设置的位超过字符串当前的长度时, SETBIT 命令将会自动增加字符串的长度。 GETBIT 返回指定位上的值,对于超过字符串当前长度范围的位,总是被视为0。

Bitmap有三个命令是基于对一组位进行操作的命令:

BITPOS 和 BITCOUNT 都可以对字符串的字节范围进行操作,Bitmap的常见使用场景有:

比如想统计网站最长的用户连续访问天数,可以使用Bitmap,每个位的值作为该天是否访问网站的标志(第一位表示第一天,第二位表示第二天,以此类推),每当用户访问网站时可以使用 SETBIT 设置该天对应的位为1,最后统计连续设置为1的位的数量即可。使用 BITCOUNT 可以统计出用户访问网站的天数,使用 BITPOS 即可统计出最长的连续访问天数。为了分片数据集,最好避免使用大键,可以让每个键存储M个位,将(位数/M)的值与键名关联,将(位数%M)可以获取位数处于键内的位置。

下面是Bitmap相关命令。

Redis Bitmap
原文连接

好玩的ES--第四篇之聚合查询和集群

好玩的ES--第四篇之聚合查询和集群


聚合查询

简介

聚合:英文为Aggregation,是es除搜索功能外提供的针对es数据做统计分析的功能。聚合有助于根据搜索查询提供聚合数据。聚合查询是数据库中重要的功能特性,ES作为搜索引擎兼数据库,同样提供了强大的聚合分析能力。它基于查询条件来对数据进行分桶、计算的方法。有点类似于 SQL 中的 group by 再加一些函数方法的操作。

注意事项:text类型是不支持聚合的。


测试数据

# 创建索引 index 和映射 mapping
PUT /fruit

  "mappings": 
    "properties": 
      "title":
        "type": "keyword"
      ,
      "price":
        "type":"double"
      ,
      "description":
        "type": "text",
        "analyzer": "ik_max_word"
      
    
  

-
# 放入测试数据
PUT /fruit/_bulk
"index":
  "title" : "面包","price" : 19.9,"description" : "小面包非常好吃"
"index":
  "title" : "旺仔牛奶","price" : 29.9,"description" : "非常好喝"
"index":
  "title" : "日本豆","price" : 19.9,"description" : "日本豆非常好吃"
"index":
  "title" : "小馒头","price" : 19.9,"description" : "小馒头非常好吃"
"index":
  "title" : "大辣片","price" : 39.9,"description" : "大辣片非常好吃"
"index":
  "title" : "透心凉","price" : 9.9,"description" : "透心凉非常好喝"
"index":
  "title" : "小浣熊","price" : 19.9,"description" : "童年的味道"
"index":
  "title" : "海苔","price" : 19.9,"description" : "海的味道"

使用

根据某个字段分组

# 根据某个字段进行分组 统计数量
GET /fruit/_search

  "query": 
    "term": 
      "description": 
        "value": "好吃"
      
    
  , 
  "aggs": 
    "price_group": 
      "terms": 
        "field": "price"
      
    
  

求最大值

# 求最大值 
GET /fruit/_search

  "aggs": 
    "price_max": 
      "max": 
        "field": "price"
      
    
  

求最小值

# 求最小值
GET /fruit/_search

  "aggs": 
    "price_min": 
      "min": 
        "field": "price"
      
    
  

求平均值

# 求平均值
GET /fruit/_search

  "aggs": 
    "price_agv": 
      "avg": 
        "field": "price"
      
    
  

求和

# 求和
GET /fruit/_search

  "aggs": 
    "price_sum": 
      "sum": 
        "field": "price"
      
    
  

整合应用

// 求不同价格的数量
@Test
public void testAggsPrice() throws IOException 
  SearchRequest searchRequest = new SearchRequest("fruit");
  SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
  sourceBuilder.aggregation(AggregationBuilders.terms("group_price").field("price"));
  searchRequest.source(sourceBuilder);
  SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  Aggregations aggregations = searchResponse.getAggregations();
  ParsedDoubleTerms terms = aggregations.get("group_price");
  List<? extends Terms.Bucket> buckets = terms.getBuckets();
  for (Terms.Bucket bucket : buckets) 
    System.out.println(bucket.getKey() + ", "+ bucket.getDocCount());
  

// 求不同名称的数量
@Test
public void testAggsTitle() throws IOException 
  SearchRequest searchRequest = new SearchRequest("fruit");
  SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
  sourceBuilder.aggregation(AggregationBuilders.terms("group_title").field("title"));
  searchRequest.source(sourceBuilder);
  SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  Aggregations aggregations = searchResponse.getAggregations();
  ParsedStringTerms terms = aggregations.get("group_title");
  List<? extends Terms.Bucket> buckets = terms.getBuckets();
  for (Terms.Bucket bucket : buckets) 
  	System.out.println(bucket.getKey() + ", "+ bucket.getDocCount());
  

// 求和
@Test
public void testAggsSum() throws IOException 
  SearchRequest searchRequest = new SearchRequest("fruit");
  SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
  sourceBuilder.aggregation(AggregationBuilders.sum("sum_price").field("price"));
  searchRequest.source(sourceBuilder);
  SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  ParsedSum parsedSum = searchResponse.getAggregations().get("sum_price");
  System.out.println(parsedSum.getValue());


集群

ES集群类似Redis的分片集群加主从集群架构

集群 Cluster

相关概念

集群

一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是elasticsearch。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。

节点

一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。

索引

一组相似文档的集合

映射

用来定义索引存储文档的结构如:字段、类型等。

文档

索引中一条记录,可以被索引的最小单元

分片

Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置 到集群中的任何节点上。

复制

Index的分片中一份或多份副本。

搭建集群

集群规划

# 1.准备3个ES节点和一个kibana 节点  ES 9200 9300 
- web: 9201 tcp:9301  node-1  elasticsearch.yml   
- web: 9202 tcp:9302  node-2  elasticsearch.yml
- web: 9203 tcp:9303  node-3  elasticsearch.yml
- kibana: 5602
  • 注意
    • 所有节点集群名称必须一致 cluster.name
    • 每个节点必须有一个唯一名字 node.name
    • 开启每个节点远程连接 network.host: 0.0.0.0
    • 指定使用 IP地址进行集群节点通信 network.publish_host:
    • 修改 web 端口 tcp 端口 http.port: transport.tcp.port
    • 指定集群中所有节点通信列表 discovery.seed_hosts: node-1 node-2 node-3 相同
    • 允许集群初始化 master 节点节点数: cluster.initial_master_nodes: [“node-1”, “node-2”,“node-3”]
    • 集群最少几个节点可用 gateway.recover_after_nodes: 2
    • 开启每个节点跨域访问http.cors.enabled: true http.cors.allow-origin: “*”

配置文件

# node-1 配置文件
# 指定集群名称 3个节点必须一致
cluster.name: es-cluster
# 指定节点名称 每个节点名字唯一
node.name: node-1
# 开放远程链接
network.host: 0.0.0.0
# 指定使用发布地址进行集群间通信
network.publish_host: 192.168.124.3
# 指定 web 端口
http.port: 9201
# 指定 tcp 端口
transport.tcp.port: 9301
# 指定所有节点的 tcp 通信
discovery.seed_hosts: ["192.168.124.3:9301", "192.168.124.3:9302","192.168.124.3:9303"]
# 指定可以初始化集群的节点名称
cluster.initial_master_nodes: ["node-1", "node-2","node-3"]
# 集群最少几个几点可用
gateway.recover_after_nodes: 2
# 解决跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"
# node-2 配置文件
# 指定集群名称 3个节点必须一致
cluster.name: es-cluster
# 指定节点名称 每个节点名字唯一
node.name: node-2
# 开放远程链接
network.host: 0.0.0.0
# 指定使用发布地址进行集群间通信
network.publish_host: 192.168.124.3
# 指定 web 端口
http.port: 9202
# 指定 tcp 端口
transport.tcp.port: 9302
# 指定所有节点的 tcp 通信
discovery.seed_hosts: ["192.168.124.3:9301", "192.168.124.3:9302","192.168.124.3:9303"]
# 指定可以初始化集群的节点名称
cluster.initial_master_nodes: ["node-1", "node-2","node-3"]
# 集群最少几个几点可用
gateway.recover_after_nodes: 2
# 解决跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"
# node-3 配置文件
# 指定集群名称 3个节点必须一致
cluster.name: es-cluster
# 指定节点名称 每个节点名字唯一
node.name: node-2
# 开放远程链接
network.host: 0.0.0.0
# 指定使用发布地址进行集群间通信
network.publish_host: 192.168.124.3
# 指定 web 端口
http.port: 9202
# 指定 tcp 端口
transport.tcp.port: 9302
# 指定所有节点的 tcp 通信
discovery.seed_hosts: ["192.168.124.3:9301", "192.168.124.3:9302","192.168.124.3:9303"]
# 指定可以初始化集群的节点名称
cluster.initial_master_nodes: ["node-1", "node-2","node-3"]
# 集群最少几个几点可用
gateway.recover_after_nodes: 2
# 解决跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"

编写 compose 文件

version: "3.8"
networks:
  escluster:
services:
  es01:
    image: elasticsearch:7.14.0
    ports:
      - "9201:9201"
      - "9301:9301"
    networks:
      - "escluster"
    volumes:
      - ./node-1/data:/usr/share/elasticsearch/data
      - ./node-1/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
      - ./node-1/plugins/ik:/usr/share/elasticsearch/plugins/ik
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"

  es02:
    image: elasticsearch:7.14.0
    ports:
      - "9202:9202"
      - "9302:9302"
    networks:
      - "escluster"
    volumes:
      - ./node-2/data:/usr/share/elasticsearch/data
      - ./node-2/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
      - ./node-2/plugins/ik:/usr/share/elasticsearch/plugins/ik
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"

  es03:
    image: elasticsearch:7.14.0
    ports:
      - "9203:9203"
      - "9303:9303"
    networks:
      - "escluster"
    volumes:
      - ./node-3/data:/usr/share/elasticsearch/data
      - ./node-3/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
      - ./node-3/plugins/ik:/usr/share/elasticsearch/plugins/ik
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"

  kibana:
    image: kibana:7.14.0
    ports:
      - "5602:5601"
    networks:
      - "escluster"
    volumes:
      - ./kibana.yml:/usr/share/kibana/config/kibana.yml

kibana 配置文件

# kibana配置文件 连接到ES
server.host: "0"
server.shutdownTimeout: "5s"
elasticsearch.hosts: [ "http://192.168.124.3:9201" ] #链接任意节点即可
monitoring.ui.container.elasticsearch.enabled: true

查看集群状态

http://10.102.115.3:9200/_cat/health?v

安装head插件

1. 访问github网站
	搜索: elasticsearch-head 插件
	
2. 安装git
	yum install git
	
3. 将elasticsearch-head下载到本地
	git clone git://github.com/mobz/elasticsearch-head.git

4. 安装nodejs
	#注意: 没有wget的请先安装yum install -y wget
	wget http://cdn.npm.taobao.org/dist/node/latest-v8.x/node-v8.1.2-linux-x64.tar.xz

5. 解压缩nodejs
	xz -d node-v10.15.3-linux-arm64.tar.xz
	tar -xvf node-v10.15.3-linux-arm64.tar

6. 配置环境变量
	mv node-v10.15.3-linux-arm64 nodejs
	mv nodejs /usr/nodejs
	vim /etc/profile
		export NODE_HOME=/usr/nodejs
		export PATH=$wPATH:$JAVA_HOME/bin:$NODE_HOME/bin

7.	进入elasticsearch-head的目录
	npm config set registry https://registry.npm.taobao.org
	npm install
	npm run start


8.  启动访问head插件 默认端口9100
	http://ip:9100  查看集群状态

以上是关于Redis系列第四篇之Bitmap的主要内容,如果未能解决你的问题,请参考以下文章

Linux从青铜到王者第二十四篇:Linux网络基础第四篇之WebSocket协议

Linux从青铜到王者第二十三篇:Linux网络基础第四篇之kcp协议

高级程序员必须精通的Redis,第四篇之——set(集合)

好玩的ES--第四篇之聚合查询和集群

好玩的ES--第四篇之聚合查询和集群

好玩的ES--第四篇之聚合查询和集群