精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

海量數(shù)據(jù)處理利器 Roaring BitMap 原理介紹

開發(fā)
本文結(jié)合個人理解梳理了BitMap及Roaring BitMap的原理及使用,分別主要介紹了Roaring BitMap的存儲方式及三種container類型及Java中Roaring BitMap相關(guān)API使用。

一、引言

在進行大數(shù)據(jù)開發(fā)時,我們可以使用布隆過濾器和Redis中的HyperLogLog來進行大數(shù)據(jù)的判重和數(shù)量統(tǒng)計,雖然這兩種方法節(jié)省內(nèi)存空間并且效率很高,但是也存在一些誤差。如果需要100%準確的話,我們可以使用BitMap來存儲數(shù)據(jù)。

BitMap 位圖索引數(shù)據(jù)結(jié)構(gòu)被廣泛地應(yīng)用于數(shù)據(jù)存儲和數(shù)據(jù)搜索中,但是對于存儲較為分散的數(shù)據(jù)時,BitMap會占用比較大的內(nèi)存空間,因此我們更偏向于使用 Roaring BitMap稀疏位圖索引進行存儲。同時,Roaring BitMap廣泛應(yīng)用于數(shù)據(jù)庫存儲和大數(shù)據(jù)引擎中,例如Hive,Spark,Doris,Kylin等。

下文將分別介紹 BitMap 和 Roaring BitMap 的原理及其相關(guān)應(yīng)用。

二、BitMap原理

BitMap的基本思想就是用bit位來標記某個元素對應(yīng)的value,而key就是這個元素。

例如,在下圖中,是一個字節(jié)代表的8位,下標為1,2,4,6的bit位的值為1,則該字節(jié)表示{1,2,4,6}這幾個數(shù)。

圖片

在Java中,1個int占用4個字節(jié),如果用int來存儲這四個數(shù)字的話,那么將需要4 * 4 = 16字節(jié)。

BitMap可以用于快速排序,查找,及去重等操作。優(yōu)點是占用內(nèi)存少(相較于數(shù)組)和運算效率高,但是缺點也非常明顯,無法存儲重復的數(shù)據(jù),并且在存儲較為稀疏的數(shù)據(jù)時,浪費存儲空間較多。

三、Roaring BitMap 原理

3.1 存儲方式

為了解決BitMap存儲較為稀疏數(shù)據(jù)時,浪費存儲空間較多的問題,我們引入了稀疏位圖索引Roaring BitMap。Roaring BitMap 有較高的計算性能及壓縮效率。下面簡單介紹一下Roaring BitMap的基本原理。

Roaring BitMap處理int型整數(shù),將32位的int型整數(shù)分為高16位和低16位分別進行處理,高16位作為索引分片,而低16位用于存儲實際數(shù)據(jù)。其中每個索引對應(yīng)一個數(shù)據(jù)桶(bucket),那么一共可以包含2^16 = 65536個數(shù)據(jù)塊。每個數(shù)據(jù)桶使用container容器來存儲低16位的部分,每個數(shù)據(jù)桶最多存儲2^16 = 65536個數(shù)據(jù)。

圖片

如上圖所示,高16位作為索引查找具體的數(shù)據(jù)塊,當前索引值為0,低16位作為value進行存儲。

Roaring BitMap在進行數(shù)據(jù)存儲時,會先根據(jù)高16位找到對應(yīng)的索引key(二分查找),低16位作為key對應(yīng)的value,先通過key檢查對應(yīng)的container容器,如果發(fā)現(xiàn)container不存在的話,就先創(chuàng)建一個key和對應(yīng)的container,否則直接將低16位存儲到對應(yīng)的container中。

Roaring BitMap的精妙之處在于使用不同類型的container,接下來將對其進行介紹。

3.2 container類型

1.ArrayContainer

顧名思義,ArrayContainer直接采用數(shù)組來存儲低16位數(shù)據(jù),沒有采用任何數(shù)據(jù)壓縮算法,適合存儲比較稀疏的數(shù)據(jù),在Java中,使用short數(shù)組來存儲,并且占用的內(nèi)存空間大小和數(shù)據(jù)量成線性關(guān)系。由于short為2字節(jié),因此n個數(shù)據(jù)為2n字節(jié)。ArrayContainer采用二分查找定位有序數(shù)組中的元素,因此時間復雜度為O(logN)。ArrayContainer的最大數(shù)據(jù)量為4096, 4096 * 2b = 8kb。

2.BitMapContainer

BitMapContainer采用BitMap的原理,就是一個沒有經(jīng)過壓縮處理的普通BitMap,適合存儲比較稠密的數(shù)據(jù),在Java中使用Long數(shù)組存儲低16位數(shù)據(jù),每一個bit位表示一個數(shù)字。由于每個container需要存儲2^16 = 65536個數(shù)據(jù),如果通過BitMap進行存儲的話,需要使用2^16個bit進行存儲,即8kb的數(shù)據(jù)空間。

可以從下圖中看出ArrayContainer和BitMapContainer的內(nèi)存空間使用關(guān)系,當數(shù)據(jù)量小于4096時,使用ArrayContainer比較合適,當數(shù)據(jù)量大于等于4096時,使用BitMapContainer更佳。

圖片

因為BitMap直接使用位運算,所以BitMapContainer的時間復雜度為O(1)。

3.RunContainer

RunContainer采用Run-Length Encoding 行程長度編碼進行壓縮,適合存儲大量連續(xù)數(shù)據(jù)。Java中使用short數(shù)組進行存儲。連續(xù)bit位程度越高的話越節(jié)省存儲空間,最佳場景下(65536個數(shù)據(jù)全為1)只需要存儲4字節(jié)。最差場景為所有數(shù)據(jù)都不連續(xù),所有存儲數(shù)據(jù)位置為奇數(shù)或者偶數(shù),這種場景需要存儲128kb。由于采用二分查找算法定位元素,因此時間復雜度為O(logN)。

行程長度編碼即的原理是對連續(xù)出現(xiàn)的數(shù)字進行壓縮,只記錄初始數(shù)字和后續(xù)連續(xù)數(shù)量。

例如:[1,2,3,4,5,8,9,10]使用編碼后的數(shù)據(jù)為[1,4,8,2]。

Java 里可以使用runOptinize()方法來對比RunContainer和其他兩個Container存儲空間大小,如果使用RunContainer存儲空間更佳則會進行轉(zhuǎn)化。

根據(jù)上面三個Container類型我們可以得知如何進行選擇:

  1. Container默認使用ArrayContainer,當元素數(shù)量超過4096時,會由ArrayContainer轉(zhuǎn)換BitMapContainer。
  2. 當元素數(shù)量小于等于4096時,BitMapContainer會逆向轉(zhuǎn)換回ArrayContainer。
  3.  正常增刪元素不會使Container直接變成RunContainer,而需要用戶進行優(yōu)化方法調(diào)用才會轉(zhuǎn)換為最節(jié)省空間的Container。

3.3 Roaring BitMap 相關(guān)源碼

介紹完Roaring BitMap的三種container類型以后,讓我們了解一下,Roaring BitMap的相關(guān)源碼。這里介紹一下Java中增加元素的源碼實現(xiàn)。

public void add(final int x) {
    final short hb = Util.highbits(x);
    final int i = highLowContainer.getIndex(hb);
    if (i >= 0) {
      highLowContainer.setContainerAtIndex(i,
          highLowContainer.getContainerAtIndex(i).add(Util.lowbits(x)));
    } else {
      final ArrayContainer newac = new ArrayContainer();
      highLowContainer.insertNewKeyValueAt(-i - 1, hb, newac.add(Util.lowbits(x)));
    }
  }

Roaring BitMap首先獲取添加元素的高16位,然后再調(diào)用getIndex獲取高16位對應(yīng)的索引,如果索引大于0,表示已經(jīng)創(chuàng)建該索引對應(yīng)的container,故直接添加相應(yīng)的元素低16位即可;否則的話,說明該索引對應(yīng)的container還沒有被創(chuàng)建,先創(chuàng)建對應(yīng)的ArrayContainer,再進行元素添加。值得一提的是,在getIndex方法中,使用了二分查找來獲取索引值,所以時間復雜度為O(logn)。

// 包含一個二分查找
protected int getIndex(short x) {
  // 在二分查找之前,我們先對常見情況優(yōu)化。
  if ((size == 0) || (keys[size - 1] == x)) {
    return size - 1;
  }
  // 沒有碰到常見情況,我們只能遍歷這個列表。
  return this.binarySearch(0, size, x);
}

對于元素添加,三種Container提供了不同的實現(xiàn)方式,下面將分別介紹。

1. ArrayContainer

if (cardinality == 0 || (cardinality > 0
          && toIntUnsigned(x) > toIntUnsigned(content[cardinality - 1]))) {
    if (cardinality >= DEFAULT_MAX_SIZE) {
      return toBitMapContainer().add(x);
    }
    if (cardinality >= this.content.length) {
      increaseCapacity();
    }
    content[cardinality++] = x;
  } else {
    int loc = Util.unsignedBinarySearch(content, 0, cardinality, x);
    if (loc < 0) {
      // 當標簽中元素數(shù)量等于默認最大值時,把ArrayContainer轉(zhuǎn)換為BitMapContainer
      if (cardinality >= DEFAULT_MAX_SIZE) {
        return toBitMapContainer().add(x);
      }
      if (cardinality >= this.content.length) {
        increaseCapacity();
      }
      System.arraycopy(content, -loc - 1, content, -loc, cardinality + loc + 1);
      content[-loc - 1] = x;
      ++cardinality;
    }
  }
  return this;
}

ArrayContainer把添加元素分成兩種場景,一種走二分查找,另外一種不走二分查找。

第一種場景:不走二分查找。

當基數(shù)為0或者值大于container中的最大值,可以直接添加,因為content數(shù)組是有序的,最后一個是最大值。

當基數(shù)大于等于默認最大值4096時,ArrayContainer將轉(zhuǎn)換為BitMapContainer。如果基數(shù)大于content的數(shù)組長度的話,需要將content進行擴容。最后進行賦值即可。

第二種場景:走二分查找。

先通過二分查找找到對應(yīng)的插入位置,如果返回loc大于等于0,說明存在,直接返回即可,如果小于0才進行后續(xù)插入。后續(xù)操作同上,當基數(shù)大于等于默認最大值4096時,ArrayContainer將轉(zhuǎn)換為BitMapContainer。如果基數(shù)大于content的數(shù)組長度的話,需要將content進行擴容。最后通過拷貝數(shù)組將元素插入到content數(shù)組中。

2. BitMapContainer

public Container add(final short i) {
  final int x = Util.toIntUnsigned(i);
  final long previous = BitMap[x / 64];
  long newval = previous | (1L << x);   BitMap[x / 64] = newval;
  if (USE_BRANCHLESS) {
    cardinality += (previous ^ newval) >>> x;
  } else if (previous != newval) {
    ++cardinality;
  }
  return this;
}

BitMap數(shù)組為BitMapContainer的存儲容器存放數(shù)據(jù)的內(nèi)容,數(shù)據(jù)類型為long,在這里我們只需要找到x在BitMap中的位置,并且把相應(yīng)的bit位置1即可。x/64就是找到對應(yīng)long的舊值,1L<<x 就是把對應(yīng)的bit位置為1,再跟舊值進行或操作,就可以得到新值,再將這個新值存回到bitmap數(shù)組即可。<="" span="">

3. RunContainer

public Container add(short k) {
   
  int index = unsignedInterleavedBinarySearch(valueslength, 0, nbrruns, k);
  if (index >= 0) {
    return this;// already there
  }
  index = -index - 2;
  if (index >= 0) {
    int offset = toIntUnsigned(k) - toIntUnsigned(getValue(index));
    int le = toIntUnsigned(getLength(index));
    if (offset <= le) {
      return this;
    }
    if (offset == le + 1) {
      // we may need to fuse
      if (index + 1 < nbrruns) {
        if (toIntUnsigned(getValue(index + 1)) == toIntUnsigned(k) + 1) {
          // indeed fusion is needed
          setLength(index,
              (short) (getValue(index + 1) + getLength(index + 1) - getValue(index)));
          recoverRoomAtIndex(index + 1);
          return this;
        }
      }
      incrementLength(index);
      return this;
    }
    if (index + 1 < nbrruns) {
      // we may need to fuse
      if (toIntUnsigned(getValue(index + 1)) == toIntUnsigned(k) + 1) {
        // indeed fusion is needed
        setValue(index + 1, k);
        setLength(index + 1, (short) (getLength(index + 1) + 1));
        return this;
      }
    }
  }
  if (index == -1) {
    // we may need to extend the first run
    if (0 < nbrruns) {
      if (getValue(0) == k + 1) {
        incrementLength(0);
        decrementValue(0);
        return this;
      }
    }
  }
  makeRoomAtIndex(index + 1);
  setValue(index + 1, k);
  setLength(index + 1, (short) 0);
  return this;
}

RunContainer中的兩個數(shù)據(jù)結(jié)構(gòu),nbrruns表示有多少段行程,數(shù)據(jù)類型為int,valueslength數(shù)組表示所有的行程,數(shù)據(jù)類型為short。

  1. 首先,使用二分查找+順序查找在valueslength數(shù)組中查找元素k的插入位置index。如果查找到的index結(jié)果大于等于0那就說明k是某個行程起始值,已經(jīng)存在,直接返回。
  2. -index-2是為了指向前一個行程起始值的索引。
  3. 接下來是一些偏移量和索引值的判斷,主要是為了確認k是否落在上一個行程里,或者外面,如果落在上一個行程里,則直接返回,否則需要新建一個行程或者就近與一個行程混合并且將行程長度加1。

3.4 BitMap 和 Roaring BitMap 存儲情況對比

public static void count(Integer inputSize) {         RoaringBitMap BitMap = new RoaringBitMap();         BitMap.add(0L, inputSize);
 
        //獲取BitMap個數(shù)
        int cardinality = BitMap.getCardinality();
 
        //獲取BitMap壓縮大小
        int compressSizeIntBytes = BitMap.getSizeInBytes();
 
        //刪除壓縮(移除行程編碼,將container退化為BitMapContainer 或 ArrayContainer)         BitMap.removeRunCompression();
 
        //獲取BitMap不壓縮大小
        int uncompressSizeIntBytes = BitMap.getSizeInBytes();
 
        System.out.println("Roaring BitMap個數(shù):" + cardinality);
        System.out.println("最好情況,BitMap壓縮大小:" + compressSizeIntBytes / 1024 + "KB");
        System.out.println("最壞情況,BitMap不壓縮大小:" + uncompressSizeIntBytes / 1024 / 1024 + "MB");
 
        BitSet bitSet = new BitSet();
        for (int i = 0; i < inputSize; i++) {
            bitSet.set(i);
        }
        //獲取BitMap大小
        int size = bitSet.size();
 
        System.out.println("BitMap個數(shù):" + bitSet.length());
        System.out.println("BitMap大小:" + size / 8 / 1024 / 1024 + "MB");
    }

上述代碼使用了Java內(nèi)置的BitMap(BitSet) 和 Roaring BitMap進行存儲大小對比,輸出結(jié)果如下所示。

  • Roaring BitMap個數(shù):1000000000
  • 最好情況,BitMap壓縮大小:149KB
  • 最壞情況,BitMap不壓縮大小:119MB
  • Roaring BitMap個數(shù):1000000000
  • BitMap大小:128MB

可以發(fā)現(xiàn),Roaring BitMap的壓縮性能效果非常好,同等情況下,是BitMap占用內(nèi)存的近一千分之一。在退化成BitMapContainer/arrayContainer之后也仍然比使用基本的BitMap存儲效果好一些。

四、Roaring BitMap 使用

4.1 Java 中相關(guān) API 使用

在Java中,Roaring BitMap提供了交并補差集等操作,如下代碼所示,列舉了Java中roaing BitMap的相關(guān)API使用方式。

//添加單個數(shù)字
public void add(final int x)


//添加范圍數(shù)字
public void add(final long rangeStart, final long rangeEnd)


//移除數(shù)字
public void remove(final int x)


//遍歷RBM
public void forEach(IntConsumer ic)


//檢測是否包含
public boolean contains(final int x)


//獲取基數(shù)
public int getCardinality()


//位與,取兩個RBM的交集,當前RBM會被修改
public void and(final RoaringBitMap x2)


//同上,但是會返回一個新的RBM,不會修改原始的RBM,線程安全
public static RoaringBitMap and(final RoaringBitMap x1, final RoaringBitMap x2)


//位或,取兩個RBM的并集,當前RBM會被修改
public void or(final RoaringBitMap x2)


//同上,但是會返回一個新的RBM,不會修改原始的RBM,線程安全
public static RoaringBitMap or(final RoaringBitMap x1, final RoaringBitMap x2)


//異或,取兩個RBM的對稱差,當前RBM會被修改
public void xor(final RoaringBitMap x2)


//同上,但是會返回一個新的RBM,不會修改原始的RBM,線程安全
public static RoaringBitMap xor(final RoaringBitMap x1, final RoaringBitMap x2)


//取原始值和x2的差集,當前RBM會被修改
public void andNot(final RoaringBitMap x2)


//同上,但是會返回一個新的RBM,不會修改原始的RBM,線程安全
public static RoaringBitMap andNot(final RoaringBitMap x1, final RoaringBitMap x2)


//序列化
public void serialize(DataOutput out) throws IOException
public void serialize(ByteBuffer buffer)


//反序列化
public void deserialize(DataInput in) throws IOException
public void deserialize(ByteBuffer bbf) throws IOException

對于序列化來說,Roaring BitMap官方定義了一套序列化規(guī)則,用來保證不同語言實現(xiàn)的兼容性。

圖片

Java中可以使用serialize方法進行序列化,deserialize方法進行反序列化。

4.2 業(yè)務(wù)實際場景應(yīng)用

Roaring BitMap可以用來構(gòu)建大數(shù)據(jù)標簽,針對類型特征來創(chuàng)建對應(yīng)的標簽。

在我們的業(yè)務(wù)場景中,有很多需要基于人群標簽進行交并補集運算的場景,下面以一個場景為例,我們需要計算每天某個設(shè)備接口 在設(shè)備標簽A上的查詢成功率,因為設(shè)備標簽A中的設(shè)備不是所有都活躍在網(wǎng)的,所以我們需要將設(shè)備標簽A與每日日活人群標簽取交集,得到的交集大小才能用作成功率計算的分母,另外拿查詢成功的標簽人群做分子來進行計算即可,查詢時長耗時為1s。

假如沒有使用標簽保存集合之前,我們需要在hive表中查詢出同時滿足當天在網(wǎng)的活躍用戶和設(shè)備A的用戶數(shù)量,查詢時長耗時在幾分鐘以上。兩種方式相比之下,使用Roaring BitMap查詢的效率更高。

圖片

五、總結(jié)

本文結(jié)合個人理解梳理了BitMap及Roaring BitMap的原理及使用,分別主要介紹了Roaring BitMap的存儲方式及三種container類型及Java中Roaring BitMap相關(guān)API使用,如有不足和優(yōu)化建議,也歡迎大家批評指正。

參考資料:

責任編輯:龐桂玉 來源: vivo互聯(lián)網(wǎng)技術(shù)
相關(guān)推薦

2025-06-16 07:07:03

Java數(shù)據(jù)Jackson

2012-06-26 10:03:06

海量數(shù)據(jù)處理

2011-08-18 09:43:45

Bloom Filte海量數(shù)據(jù)

2024-02-07 09:25:52

數(shù)據(jù)處理快手大模型

2023-11-29 13:56:00

數(shù)據(jù)技巧

2023-10-05 12:43:48

數(shù)據(jù)處理

2025-01-15 00:00:00

存儲整數(shù)集Roaring

2011-08-19 13:28:25

海量數(shù)據(jù)索引優(yōu)化

2012-02-22 15:32:11

海量數(shù)據(jù)

2010-09-06 09:24:56

網(wǎng)格數(shù)據(jù)庫

2013-12-27 16:15:11

Hadoop大數(shù)據(jù)處理

2013-12-30 10:40:12

大數(shù)據(jù)處理大數(shù)據(jù)Hadoop

2019-08-19 18:42:43

大數(shù)據(jù)海量數(shù)據(jù)

2016-06-16 10:52:25

IBM

2017-10-18 13:31:56

存儲超融合架構(gòu)數(shù)據(jù)中心

2022-06-28 13:41:43

京東數(shù)據(jù)處理

2015-10-16 09:50:10

2013-01-08 14:29:03

阿里云開放數(shù)據(jù)處理ODPS

2023-12-05 08:47:30

Pandas數(shù)據(jù)處理

2013-10-12 16:53:46

SAP
點贊
收藏

51CTO技術(shù)棧公眾號

欧美另类极品videosbestfree| 一区二区激情视频| 国产成人精品国内自产拍免费看| 国产精品成人无码免费| 欧美综合社区国产| 亚洲一区二区三区四区不卡| 韩国成人动漫在线观看| 中文字幕在线播| 欧美在线1区| 亚洲精品国产电影| 中文字幕成人免费视频| av美女在线观看| 久久久av毛片精品| 91丨九色丨国产| 无码人妻精品一区二区三区不卡| 一区二区三区中文| 亚洲亚裔videos黑人hd| 少妇丰满尤物大尺度写真| 欧美gay囗交囗交| 夜夜爽夜夜爽精品视频| 日本在线高清视频一区| 亚洲国产精品国自产拍久久| 日韩1区2区日韩1区2区| 午夜精品久久久久久99热| 欧美成人久久久免费播放| 欧美爱爱网站| 日韩欧美色综合| 手机版av在线| 性感美女一区二区在线观看| 亚洲福利一二三区| 精品国产三级a∨在线| 免费播放片a高清在线观看| 国产精品888| 国产欧美精品在线| 免费又黄又爽又猛大片午夜| 日韩香蕉视频| 久久久久久久久爱| 波多野结衣在线网址| 精品一区二区三区在线| 亚洲精品一区二三区不卡| 中文字幕在线国产| 日韩av综合| 91麻豆精品国产91久久久| 手机看片福利盒子久久| 韩国成人动漫| 一本色道a无线码一区v| 国产91在线视频观看| av最新在线| 亚洲综合色成人| 欧美一区二区三区综合| 男女羞羞视频在线观看| 亚洲妇女屁股眼交7| 久久亚洲国产成人精品无码区| 黄色av电影在线观看| 中文字幕一区视频| 中国成人亚色综合网站 | 久久国内精品视频| 国产热re99久久6国产精品| 中文字幕人妻精品一区| 麻豆极品一区二区三区| 成人性生交大片免费看小说| 国产乱人乱偷精品视频| 国产精品18久久久久久久久久久久 | 精品午夜福利在线观看| 极品av少妇一区二区| 欧美激情视频在线| 久久99久久98精品免观看软件| 亚洲第一伊人| 欧美亚洲国产日本| 无码人妻精品一区二区| 久久精品噜噜噜成人av农村| 亚洲bt天天射| 天堂在线观看免费视频| 久久久久一区二区三区四区| 婷婷久久青草热一区二区| 免费在线观看av| 亚洲国产日韩一区二区| 国产精品97在线| 久久影视精品| 精品国产一二三区| 97人妻精品一区二区免费| 欧美aaaaaaaaaaaa| 欧美激情国内偷拍| 无码一区二区三区在线观看| 久久电影国产免费久久电影| 成人一区二区在线| 久草视频在线看| 日韩一区有码在线| 婷婷无套内射影院| 51一区二区三区| 91精品国产91久久久久久最新毛片| 91人人澡人人爽| 国产一区二区三区站长工具| 久久天堂电影网| 久久久蜜桃一区二区| 国产精品1区二区.| 日韩电影在线播放| 丁香花在线高清完整版视频| 欧美在线色视频| 日韩精品――色哟哟| 国产成人av| 久久久天堂国产精品女人| 天天综合久久综合| 成人动漫中文字幕| 亚洲一区三区| 一区二区精品伦理...| 欧美一区三区二区| 这里只有久久精品| 国内揄拍国内精品久久| 国产精品电影在线观看| 人人妻人人澡人人爽久久av| 国产精品久久久久永久免费观看| 国产亚洲欧美在线视频| 视频一区日韩| 日韩在线一区二区三区免费视频| 国产高清中文字幕| 成人午夜在线视频| 在线国产精品网| free欧美| 亚洲美女又黄又爽在线观看| 久久成人国产精品入口| 美女在线视频一区| 清纯唯美一区二区三区| 无遮挡在线观看| 精品999久久久| 草视频在线观看| 久久91精品国产91久久小草| 日韩精品一区二区三区四区五区 | h视频在线免费观看| 欧美三级韩国三级日本一级| 在线观看福利片| 欧美综合国产| 九九九九精品| 春色校园综合激情亚洲| 欧美大片国产精品| 欧美日韩三级在线观看| 韩国三级电影一区二区| 在线观看成人一级片| 伊人亚洲精品| 久久偷看各类女兵18女厕嘘嘘 | 免费不卡在线视频| 午夜精品区一区二区三| 亚洲四虎影院| 在线观看久久久久久| 99re热视频| 中文字幕 久热精品 视频在线| 可以免费观看av毛片| 国产精品免费大片| 国产精品久久久久久av福利| www.在线播放| 欧美精品自拍偷拍动漫精品| 国产亚洲精品久久久久久豆腐| 美国一区二区三区在线播放| 亚洲欧美日韩不卡一区二区三区| 亚洲国产伊人| 欧美黄色片在线观看| 国产免费高清av| 亚洲黄色在线视频| 国产熟女高潮一区二区三区| 国产欧美日韩亚洲一区二区三区| 久久久福利视频| 网友自拍亚洲| 精品国产一区二区三区久久| 国产成人精品一区二区无码呦| 亚洲香蕉伊在人在线观| 波多野结衣先锋影音| 国产精品日韩久久久| 日韩精品在在线一区二区中文| 91大神在线观看线路一区| 久久精品夜夜夜夜夜久久| 国产av无码专区亚洲av| 亚洲成人免费av| 新91视频在线观看| 美洲天堂一区二卡三卡四卡视频 | 内射毛片内射国产夫妻| 久久99深爱久久99精品| 成人黄色大片网站| 久久av影视| 91精品视频在线免费观看| 污污在线观看| 亚洲图片欧美日产| 99产精品成人啪免费网站| 亚洲国产日日夜夜| 337人体粉嫩噜噜噜| 国产精品69毛片高清亚洲| 国产日产欧美视频| 91精品国产自产在线观看永久∴ | 国语对白精品一区二区| 欧美日韩日本网| 欧美经典影片视频网站| 国产精品www网站| 人妖欧美1区| 中文字幕亚洲欧美日韩高清| 好吊色一区二区| 欧美色精品在线视频| 国产精品第一页在线观看| 国产视频视频一区| www.四虎精品| 久久99精品久久久久久动态图| 可以看毛片的网址| 欧美激情电影| 欧美第一黄网| 日本一区精品视频| 国产精品一区二区三区成人| 国产精品xx| 九九精品视频在线| 日韩伦理在线观看| 国产视频久久久久| 欧美特黄一级视频| 日韩一区二区免费在线观看| 在线视频播放大全| 一本色道久久综合亚洲精品按摩| 久久久久久久久久久久久久免费看 | 99精品一级欧美片免费播放| 国产成人影院| 久久福利电影| 丁香5月婷婷久久| 91国产在线播放| 日韩黄色三级在线观看| 国产精品91在线| 日本在线高清| 97视频在线观看免费高清完整版在线观看| av中文字幕在线播放| 色一区av在线| 成人性生交大片免费看午夜| 亚洲男子天堂网| 日本私人网站在线观看| 亚洲国产成人爱av在线播放| 亚洲av无码一区二区三区性色| 欧美精品第1页| 亚洲视频久久久| 欧美影视一区在线| 欧美高清69hd| 欧洲亚洲国产日韩| 九九热最新视频| 色久综合一二码| 日韩在线播放中文字幕| 欧美网站在线观看| 成人午夜淫片100集| 污片在线观看一区二区| 久久精品人妻一区二区三区| 亚洲一区二区成人在线观看| 久久免费视频99| 艳妇臀荡乳欲伦亚洲一区| 欧美爱爱小视频| 亚洲国产三级在线| 亚洲天堂日韩av| 欧美视频在线免费| 青青草视频在线观看免费| 99久久免费国产精精品| 亚洲图片激情小说| 日本黄色免费片| 亚洲免费在线观看| 亚洲国产美女视频| 亚洲综合自拍偷拍| 国产性xxxx高清| 一本色道久久综合亚洲aⅴ蜜桃 | 日韩极品视频在线观看| 黄色一区二区三区四区| 国内精品视频一区二区三区| 亚洲欧美日韩在线观看a三区| 国产综合免费视频| 免费观看一级特黄欧美大片| www.久久久精品| 国产很黄免费观看久久| 制服丝袜第一页在线观看| 久久久久久久久99精品| 精品熟妇无码av免费久久| 日韩一区欧美一区| 日本三级免费看| 色av综合在线| 国产伦精品一区二区三区视频痴汉| 日韩欧美黄色影院| 天堂成人在线| 日韩在线观看精品| av日韩国产| 国产精品永久免费| 视频一区在线| 色噜噜狠狠色综合网| 亚洲精品网址| 亚欧无线一线二线三线区别| 免费成人小视频| 亚洲国产欧美日韩在线| 91小视频免费观看| 三级黄色免费观看| 婷婷开心激情综合| 小泽玛利亚一区二区三区视频| 91精品国产色综合久久不卡蜜臀 | 欧美高清视频在线| 中文字幕一区久| 91九色蝌蚪国产| 亚洲天堂日韩在线| 浴室偷拍美女洗澡456在线| 妖精视频成人观看www| 不用播放器的免费av| 91麻豆国产在线观看| www.av免费| 色国产精品一区在线观看| 国产富婆一级全黄大片| 尤物yw午夜国产精品视频明星| 日本高清在线观看视频| 国产精品久久久久久久久免费看| japanese色系久久精品| 亚洲黄色一区二区三区| 先锋影音久久久| 国产精品偷伦视频免费观看了| 国产拍揄自揄精品视频麻豆| 日本一区二区不卡在线| 欧美一级久久久久久久大片| a√在线中文网新版址在线| 97在线视频观看| 日韩第一区第二区| 亚洲韩国在线| 丝袜诱惑制服诱惑色一区在线观看| 无码人妻aⅴ一区二区三区玉蒲团| 国产精品久久久久影视| www.久久久久久久| 亚洲国产精品嫩草影院久久| 中文字幕有码在线观看| 国产精品视频午夜| 精品欧美久久| 国产极品美女高潮无套久久久| 成人精品免费视频| 日本妇女毛茸茸| 777午夜精品视频在线播放| av网站在线免费播放| 国产成人午夜视频网址| 亚洲精品3区| 狠狠97人人婷婷五月| av电影一区二区| 国产真人真事毛片| 欧美大胆人体bbbb| 在线你懂的视频| 亚洲自拍偷拍在线| 亚洲最新色图| 在线免费黄色网| 亚洲色图都市小说| 国产片在线播放| 欧美超级乱淫片喷水| 久久9999免费视频| 成人在线免费观看视频网站| 国产揄拍国内精品对白| 麻豆明星ai换脸视频| 正在播放亚洲一区| 性欧美video高清bbw| 99久久无色码| 亚洲高清不卡| 久久人人妻人人人人妻性色av| 激情成人中文字幕| 日本高清中文字幕二区在线| 日韩av电影国产| 欧美先锋资源| 小早川怜子一区二区三区| 亚洲猫色日本管| 精品女同一区二区三区| 欧美极品少妇xxxxⅹ免费视频| 欧美黑人做爰爽爽爽| 亚洲人成色77777| 国产精品青草久久| 91午夜交换视频| 色综合久久88| 日韩三级毛片| 国产真人无码作爱视频免费| 国产精品久99| www.久久精品.com| 91精品国产电影| 欧美偷拍自拍| 天堂网成人在线| 亚洲国产日韩a在线播放性色| 日韩在线无毛| 国产精品一区二区三区久久| 欧美不卡一区| 国产熟妇搡bbbb搡bbbb| 欧美日韩精品福利| 爱福利在线视频| 欧美精品一区二区三区在线四季| 美女看a上一区| 国产性70yerg老太| 亚洲午夜激情免费视频| 亚洲高清国产拍精品26u| 日本丰满少妇xxxx| 中文字幕av一区 二区| 亚洲高清精品视频| 国产成人精品在线观看| 午夜视频一区| 久久成人激情视频| 91精品国产乱码| 午夜激情成人网| 日韩一二区视频| 国产亚洲精品bt天堂精选| 午夜精品久久久久久久99| 日韩美女免费视频| 午夜久久福利| www.99热| 亚洲福利小视频| 一区二区三区无毛| 无码精品国产一区二区三区免费| 亚洲日本欧美天堂| 免费观看成年在线视频网站| 鬼打鬼之黄金道士1992林正英|