Der Wachstumspfad von Redis (6) für Programmierer – Einführung in die Bitmap-Typ-Redis-Datenstruktur

Bitmap, auch Bitmap genannt, ist eine Datenstruktur in Redis. Welche Bedeutung hat ihr Aussehen für Redis, welche Funktionen hat sie und wie wird sie verwendet? Was ist sein Realisierungsmechanismus? Lassen Sie uns nun in die Welt der Bitmap eintauchen.

Einführung in Bitmap

Was sind Bitmaps?
Schauen wir uns vor der Textbeschreibung ein Bild an.
Dieses stellt die Zahl 7 im Binärformat dar (00000111) 2 = (7) 10.
Fügen Sie hier eine Bildbeschreibung ein
Was stellt das also in einer Bitmap dar?
Fügen Sie hier eine Bildbeschreibung ein
Es zeigt an, dass die Bits 6, 7 und 8 in der Bitmap alle 1 sind, was bedeutet, dass die Bits 6, 7 und 8 Daten enthalten. [Hinweis: Das niedrige Bit der Bitmap befindet sich links und das hohe Bit rechts.]
Zusammenfassung: Jedes Bit in der Bitmap stellt die Zahl 1 dar, und der Index des Arrays ist das Speicherbit der Bitdaten. Beispielsweise bedeutet 0010, dass Daten auf Bit 2 vorhanden sind, 0100 bedeutet, dass Daten auf Bit 3 vorhanden sind, und 1000 bedeutet, dass Daten auf Bit 4 vorhanden sind. Dann können Sie sich vorstellen, dass es in Situationen, in denen große Datenmengen gespeichert werden müssen, bequemer und platzsparender ist, Bitmaps anstelle von Zeichenfolgen zu verwenden.

Der Implementierungsmechanismus von Bitmap?

Die unterste Ebene der Bitmap ist ein Byte-Array, und das Array unterstützt die automatische Erweiterung. Wenn eine bestimmte Versatzposition über den vorhandenen Inhaltsbereich hinaus festgelegt wird, wird das Bit-Array automatisch erweitert. Das Speichermodell ist wie folgt
Fügen Sie hier eine Bildbeschreibung ein

Wie verwende ich Bitmap?

Redis hat einige Betriebsfunktionen für Bitmap offiziell konfiguriert

  1. Bitmap abrufen / Bitmap-Wert festlegen Alle Bitmap-Daten suchen/festlegen.
    Zum Beispiel
set bitmap1 hello   
ok
get bitmap1 
"hello"
  1. bitcount bitmap [startIndex endIndex] zählt die Anzahl der Einsen in der Bitmap.
    Beispiel:
# hello二进制(低位在左): 
# 01101000 01100101 01101100 01101100 01101111
bitcount bitmap1
(Integer) 21       
bitcount  bitmap 0 1  # 取0-1字符上1的个数(注意不是0、1位)
(Integer)7

  1. bitpos Bitmap Bit [startIndex endIndex] Zählt die Position des ersten Bits (0 oder 1) in der Bitmap.
    Zum Beispiel:
bitpos bitmap1 0
(Integer)0	#第一个0在最左边的0号位
bitpos bitmap 0  1  
(Integer)8 	#从第一个字符开始算起,第一个0在8号位(从左往右数)
  1. getbit Bitmap-Index /setbit Bitmap-Indexwert Suchen Sie die Daten an einer bestimmten Position in der Bitmap/setzen Sie die Daten an einer bestimmten Position in der Bitmap.
    Zum Beispiel:
getbit bitmap1 0 
(Integer) 0
# 下面两步将hello 改成 heolo (“l” -----01101100,  “0” ------01101111)
setbit bitmap1 22 1
(Integer) 0
setbit bitmap1 23 1
(Integer) 0
get bitmap1
"heolo"
  1. Neue Funktionen von Redis 3.2+: Bitfield, hauptsächlich um den Nachteil zu beheben, dass Setbit/Getbit nur ein einzelnes Bit bedienen kann.
  1. Holen Sie sich
    ein Beispiel:
# 从bitmap1二进制数的0号位开始取4位无符号数【注意:高位在左边】
bitfield bitmap1 get u4 0 #(0110)2
(integer) 6
# 从bitmap1二进制数的1号位开始取4位无符号数【注意:高位在左边】
bitfield bitmap1 get u4 1  
(integer) 13   #(1101)2
# 从bitmap1二进制数的1号位开始取4位有符号数【注意:高位在左边】
bitfield bitmap1 get i4 1  
(integer) -3   #(1101)2
特殊用法【语法糖】:
bitfield bitmap1 get u4 0 get u4 1 get i4 1
(integer) 6
(integer) 13
(integer) -3

  1. Beispiel setzen :
# 将第八位开始的一个字符替换成‘a’
bitfield bitmap1 set u8 8 97  
(integer) 101
Get bitmap1
”haolo”

Bitmap-Anwendung und -Funktion

Da sich Bitmaps zum Speichern großer Datenmengen eignen, kann es auf Szenarien wie das Speichern aktueller Online-Benutzer, das Berechnen der Anzahl aktueller Online-Benutzer, das Speichern des täglichen Check-ins von Benutzern und das Berechnen der Anzahl aufeinanderfolgender Tage von Benutzern angewendet werden einchecken. Darüber hinaus kann es auch zum Filtern von URL-Black- und Whitelists verwendet werden, und die berühmte Anwendung ist der Bloom-Filter.
Szenenanalyse:

  1. Berechnen Sie die Anzahl der aktuellen Online-Benutzer.
    Jeder Kunde hat eine Benutzer-ID (der Standardwert ist eine Zahl und erhöht sich selbst). Da jede Benutzer-ID unterschiedlich ist, ist auch die konvertierte Binärdatei unterschiedlich. Dann können wir jedes Bit der Bitmap zum Speichern verwenden aktuelle user_id Benutzerstatus, 0 – zeigt an, dass der Kunde offline ist, 1 – zeigt an, dass der Kunde online ist, und realisiert dann die Statistiken der Online-Benutzer über die Bitcount-Funktion in der Bitmap.
  2. Berechnen Sie die Anzahl der aufeinanderfolgenden Check-in-Tage eines Benutzers
    für 365 Tage im Jahr. Dann können wir ein 365-Bit-Bit-Array verwenden, um die Anzahl der aufeinanderfolgenden Check-in-Tage des aktuellen Benutzers zu speichern. Wenn wir eine Million Benutzer haben, Dann werden zum Speichern der Daten nur etwa 365 MB Speicherplatz benötigt. Im Vergleich zur String-String-Datenstruktur bietet sie Speichervorteile.

Java-Implementierung von Bitmap

package bitmap;

import java.util.Arrays;

/**
 * 尝试实现一下redis的bitmap
 */
public class MyBitmap {
    
    
	/**
	 * init_factor 初始化因子,模仿hashmap
	 */
	private static final int INIT_FACTOR = 16;
	/** 
	 *  bitmap扩容临界点1M
	 *  为了防止浪费内存,1M前每次扩容两倍扩容,否则就1M扩容
	 */
	private static final int RESIZE_THRESHOLD = 1 * 1024 * 1024 * 8;
	/**
	 *  myBits - 位数组  
	 */
	private byte[] myBits;
	
	public MyBitmap() {
    
    
		myBits = new byte[INIT_FACTOR];
	}
	
	
	/**
	 * 存放位数组
	 * @param numb 位的索引
	 * @param bit 当前的位
	 * @return this
	 */
	public MyBitmap setBit(int numb, byte bit) {
    
    
		if (numb > myBits.length) {
    
    
			resize(numb);
		}
		myBits[numb] = bit;
		return this;
	}
	
	/**
	 * 获取位数组长度
	 * @return 位数组长度
	 */
	public int getLength() {
    
    
		return myBits.length;
	}
	
	/**
	 * 存放位数组
	 * @param numb 位的索引
	 * @param bit 当前的位
	 * @return this
	 */
	public byte getBit(int numb) {
    
    
		if (numb > myBits.length) {
    
    
			return -1;
		}
		return myBits[numb];
	}

	/**
	 * 扩容
	 * @param newSize 新的内存空间
	 */
	private void resize(int newSize) {
    
    
		byte[] temp;
		if (newSize < RESIZE_THRESHOLD) {
    
    
			// 两倍扩容
			newSize = bitTableSizeFor(newSize);
		} else if (newSize < Integer.MAX_VALUE) {
    
    
			// 每次增加1M
			newSize = bitTableSizeForOverThreshold(newSize);
		} else {
    
     
			// integer的最大值
			newSize = Integer.MAX_VALUE;
		}
		temp = new byte[newSize];
		//复制数据
		for (int i = 0; i < myBits.length; i++) {
    
    
			temp[i] |= myBits[i];
		}
		myBits = temp;
	}

	/**
	 * 获取离目标容量最近的1M的倍数
	 * @param newSize
	 * @return 离目标容量最近的1M的倍数
	 */
	private int bitTableSizeForOverThreshold(
			int newSize
	) {
    
    
		int temp = (newSize - 1) >> 23; // 获取高位
		return (temp + 1) << 23;
	}


	/**
	 * 获取离目标容量最近的2的幂次方,模仿hashmap jdk7.0
	 * @param newSize
	 * @return 离目标容量最近的2的幂次方
	 */
	private int bitTableSizeFor(int newSize) {
    
    
		int temp = newSize - 1;
		temp |= temp >> 1;
		temp |= temp >> 2;
		temp |= temp >> 4;
		temp |= temp >> 8;
		temp |= temp >> 16;
		return (temp < 0) ? 1 : (temp + 1);
	}

	public static void main(String[] args) {
    
    
		MyBitmap map = new MyBitmap();
		Stopwatch sw = new Stopwatch();
		System.out.println(map.setBit(1000000200,(byte) 1).getBit(1000000200));
		System.out.println(map.getLength());
		System.out.println("持续时间: " + sw.countTime());
	}
}

Ausgabeergebnis

1
1006632960
持续时间: 0.391

Supongo que te gusta

Origin blog.csdn.net/qq_31236027/article/details/123308642
Recomendado
Clasificación