hbase java api 的使用

[TOC]

1 hbase java api的使用

hbase的java api在windows中使用,第一次连接时,会有点慢,大概需要二十秒左右,连接上去就很快了,在linux没有这个问题

1.1 初始化连接

private Connection connection;
private HTable table;
HBaseAdmin admin;
 
@Before
public void init() throws IOException {
    Configuration configuration = HBaseConfiguration.create();
    //设置zookeeper的地址,可以有多个,以逗号分隔
    configuration.set("hbase.zookeeper.quorum","server1,server2");
    //设置zookeeper的端口
    configuration.set("hbase.zookeeper.property.clientPort","2181");
    //创建hbase的连接,这是一个分布式连接
    connection = ConnectionFactory.createConnection(configuration);
    //获取hbase中的表
    table = (HTable) connection.getTable(TableName.valueOf("user"));
 
    //这个admin是管理table时使用的,比如说创建表
    admin = (HBaseAdmin) connection.getAdmin();
}

1.2 创建表

创建表只需要指定列族名就行了,不需要指定列名,列名可以动态添加

    /**
     * 创建表,创建表只需要指定列族,不需要指定列
     * 其实用命令真的会更快,create 'user','info1','info2'
     */
    @Test
    public void createTable() throws IOException {
        //声明一个表名
        TableName tableName = TableName.valueOf("user");
        //构造一个表的描述
        HTableDescriptor desc = new HTableDescriptor(tableName);
        //创建列族
        HColumnDescriptor family1 = new HColumnDescriptor("info1");
        HColumnDescriptor family2 = new HColumnDescriptor("info2");
        //添加列族
        desc.addFamily(family1);
        desc.addFamily(family2);
        //创建表
        admin.createTable(desc);
    }

1.3 插入数据(修改数据)

这里之所以还带了修改数据,是因为对于同一个key的指定列族中的列重新插入数据,就是修改数据

    /**
     * 添加数据
     * 对同一个row key进行重新put同一个cell就是修改数据
     */
    @Test
    public void insertUpdate() throws IOException {
        //构造参数是row key,必传
        Put put = new Put(Bytes.toBytes("zhangsan_123" + i));
        //put.add()已经被弃用了
        //这里的参数依次为,列族名,列名,值
        put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("name"),Bytes.toBytes("lisi" + i));
        put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("age"),Bytes.toBytes(22 + i));
        put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("sex"),Bytes.toBytes("男"));
        put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("address"),Bytes.toBytes("天堂" + i));
        table.put(put);
        //table.put(List<Put>); //通过一个List集合,可以添加一个集合
 
    }

1.4 删除数据

删除数据使用Delete对象就行了,我们可以删除一行,或者删除一个列族,或者删除一个列族中的指定列

    /**
     * 删除数据
     */
    @Test
    public void delete() throws IOException {
        Delete deleteRow = new Delete(Bytes.toBytes("zhangsan_1235")); //删除一个行
 
        Delete delete = new Delete(Bytes.toBytes("zhangsan_1235"));
        delete.addFamily(Bytes.toBytes("info1"));//删除该行的指定列族
        delete.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//删除指定的一个单元
 
 
        table.delete(deleteRow);
 
        //table.delete(List<Delete>); //通过添加一个list集合,可以删除多个
    }

1.5 查询单条数据

    /**
     * 查询单条数据
     * @throws IOException
     */
    @Test
    public void queryByKey() throws IOException {
        String rowKey = "zhangsan_1235";
        Get get = new Get(Bytes.toBytes(rowKey));
        Result result = table.get(get);
        byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
        byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
        byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
        byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
        System.out.print(Bytes.toString(name) + ",");
        System.out.print(Bytes.toString(sex) + ",");
        System.out.print(Bytes.toString(address) + ",");
        System.out.print(Bytes.toInt(age) + ",");
        System.out.println();
    }

1.6 全表扫描

完整的全表扫描要慎用,不过全表扫描中可以指定很多过滤器,我们可以很好的使用它

    /**
     * 全表扫描
     */
    @Test
    public void scanData() throws IOException {
        Scan scan = new Scan();
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }

我们看到上方扫描后得到一个ResultScanner,这是一个扫描结果,我们来看一下要如何使用它

    private void printResult(ResultScanner resultScanner) {
        for (Result result : resultScanner) {
            byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
            byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
            byte[] rowKey = result.getRow(); //获取rowKey
            System.out.print(Bytes.toString(rowKey) + ",");
            System.out.print(Bytes.toString(name) + ",");
            System.out.print(Bytes.toString(sex) + ",");
            System.out.print(Bytes.toString(address) + ",");
            System.out.print((age == null ? null : Bytes.toInt(age)) + ",");
            System.out.println();
        }
    }

我们已经把这个打印结果的代码封装成为了一个方法了,我们接下来很多地方都会用到它

1.7 区间扫描

区间扫描我们用处也很多,因为row key是按照字典序来排列的,我们可以根据这个特性,查找某一个用户指定时间段的数据,比如查询用户A昨天到今天的数据

在查询的过程中,我们还可以指定返回的结果,比如指定返回一个列族,以及返回指定的列,这样可以增加查询速度

    /**
     * 区间扫描
     */
    @Test
    public void areaScanData() throws IOException {
        Scan scan = new Scan();
        scan.withStartRow(Bytes.toBytes("zhangsan_1232")); //设置开始行
        scan.withStopRow(Bytes.toBytes("zhangsan_12352")); //设置结束行
        //scan.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//查询指定列
        scan.addFamily(Bytes.toBytes("info1"));//查询指定列族
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }

1.8 列值过滤器

列值过滤器也是我们很常用的操作,它提供了一种甚至值的条件查询。类似sql中的where field = 'xxx',这极大的扩展了hbase的查询方式,因为如果只是根据row key来查询,那么很多产景都不适用hbase

    /**
     * 全表扫描时加过滤器 --> 列值过滤器
     */
    @Test
    public void scanDataByFilter1() throws IOException {
        Scan scan = new Scan();
        /*
         * 第一个参数: 列族
         * 第二个参数: 列名
         * 第三个参数: 是一个枚举类型
         *              CompareOp.EQUAL  等于
         *              CompareOp.LESS  小于
         *              CompareOp.LESS_OR_EQUAL  小于或等于
         *              CompareOp.NOT_EQUAL  不等于
         *              CompareOp.GREATER_OR_EQUAL  大于或等于
         *              CompareOp.GREATER  大于
         */
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.GREATER_OR_EQUAL, Bytes.toBytes("zhangsan8"));
    //这个方法很重要,需要注意,当此过滤器过滤时,如果遇到该列值为NULL的情况,如果设置的参数为true,则会过滤掉这一行,如果设置的参数为false,那么则会把这一行的结果返回,默认为false
    singleColumnValueFilter.setFilterIfMissing(true);
        scan.setFilter(singleColumnValueFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
 
    }

由上面的代码可以看到,我们使用的的是SingleColumnValueFilter,它传入了四个参数,我们分别介绍一下

  • 第一个:列族
  • 第二个:列名
  • 第三个:是一个枚举类型,告诉列值匹配条件,类型如下
    • CompareOp.EQUAL 等于
    • CompareOp.LESS 小于
    • CompareOp.LESS_OR_EQUAL 小于或等于
    • CompareOp.NOT_EQUAL 不等于
    • CompareOp.GREATER_OR_EQUAL 大于或等于
    • CompareOp.GREATER 大于
  • 第四个:是匹配的值

1.9 前缀过滤器

前缀过滤器和表里面的内容没有关系,它只是用来匹配指定的列的,,比如有这样两个列 name1 和name2 ,通过这个过滤器,就会查询这两个列的所有数据,当然,其实这个方式和scan.addColumn差不多,并且它会匹配到多个列族

 
    /**
     * 全表扫描时加过滤器 --> 前缀过滤器
     *
     * 这里的查询和单元内容没有关系,仅仅是匹配列名,比如有这样两个列 name1 和name2  ,通过这个过滤器,就会查询这两个列的所有数据,当然,其实这个方式和scan.addColumn差不多,
     * 且并会匹配到其它列族的列名
     *
     */
    @Test
    public void scanDataByFilter2() throws IOException {
        ColumnPrefixFilter columnPrefixFilter = new ColumnPrefixFilter(Bytes.toBytes("name"));
        Scan scan = new Scan();
        scan.setFilter(columnPrefixFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }

1.10 多列值前缀过滤器

好吧,这个过滤器和上面的前缀过滤器ColumnPrefixFilter差不多,区别就是可以匹配多个,其实作用并不大

    /**
     * 全表扫描时添加过滤器  --> 多个列值前缀过滤器
     *
     *  这个过滤器和 ColumnPrefixFilter 过滤器差不多,但是能匹配多个前缀
     */
 
    @Test
    public void scanDataFilter3() throws IOException {
        Scan scan = new Scan();
        byte[][] prefix = new byte[][]{Bytes.toBytes("name"),Bytes.toBytes("add")};
        MultipleColumnPrefixFilter multipleColumnPrefixFilter = new MultipleColumnPrefixFilter(prefix);
 
        scan.setFilter(multipleColumnPrefixFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }

1.11 按row key正则表达式查找

这个也是hbase查找中经常用到的功能

    /**
     * row key查找
     */
    @Test
    public void scanByRowKey() throws IOException {
        //查找以指定内容开头的
        Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
        Scan scan = new Scan();
        scan.setFilter(rowKeyFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }

1.12 同时使用多个过滤器

我们可能有这样的情况,我们想扫描指定row key范围的,又想指定address为深圳的,或者是更多的一些条件,我们要怎么做呢?我们需要组合一些过滤器

    /**
     * 使用多个过滤器,并合查找,可以同时设置多个过滤器
     *
     * 这里查找row key中,name列等于指定值的
     */
    @Test
    public void scanByFilterList() throws IOException {
        /*
        * 我们需要注意Operator这个参数,这是一个枚举类型,里面有两个类型
        *   Operator.MUST_PASS_ALL   需要通过全部的条件,也就是并且,and &&
        *   Operator.MUST_PASS_ONE   任何一个条件满足都可以,也就是或者,or ||
        */
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
 
        //row key正则表达式的过滤器
        Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
        //列值过滤器
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL, Bytes.toBytes("zhangsan9"));
 
 
        //把两个filter添加进filterList中
        filterList.addFilter(rowKeyFilter);
        filterList.addFilter(singleColumnValueFilter);
 
 
        Scan scan = new Scan();
        scan.setFilter(filterList);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }

我们可以通过FilterList来添加多个过滤器,然后把这个对象设置进去,我们看下这个对象的构造方法,Operator也是一个枚举类型,类型如下

  • Operator.MUST_PASS_ALL 需要通过全部的条件,也就是并且,and &&
  • Operator.MUST_PASS_ONE 任何一个条件满足都可以,也就是或者,or ||

1.13 完整代码

之前所有代码的java类如下

package com.xiaojiezhu.hbase.demo;
 
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.Test;
 
import java.io.IOException;
import java.util.List;
 
/**
* @author xiaojie.zhu
*/
public class HbaseTest {
    private Connection connection;
    private HTable table;
    HBaseAdmin admin;
    @Before
    public void init() throws IOException {
        Configuration configuration = HBaseConfiguration.create();
        //设置zookeeper的地址,可以有多个,以逗号分隔
        configuration.set("hbase.zookeeper.quorum","dockerServer");
        //设置zookeeper的端口
        configuration.set("hbase.zookeeper.property.clientPort","2181");
        //创建hbase的连接,这是一个分布式连接
        connection = ConnectionFactory.createConnection(configuration);
        //获取hbase中的表
        table = (HTable) connection.getTable(TableName.valueOf("user"));
 
        //这个admin是管理table时使用的,比如说创建表
        admin = (HBaseAdmin) connection.getAdmin();
    }
 
    /**
     * 创建表,创建表只需要指定列族,不需要指定列
     * 其实用命令真的会更快,create 'user','info1','info2'
     */
    @Test
    public void createTable() throws IOException {
        //声明一个表名
        TableName tableName = TableName.valueOf("user");
        //构造一个表的描述
        HTableDescriptor desc = new HTableDescriptor(tableName);
        //创建列族
        HColumnDescriptor family1 = new HColumnDescriptor("info1");
        HColumnDescriptor family2 = new HColumnDescriptor("info2");
        //添加列族
        desc.addFamily(family1);
        desc.addFamily(family2);
        //创建表
        admin.createTable(desc);
    }
 
 
    /**
     * 添加数据
     * 对同一个row key进行重新put同一个cell就是修改数据
     */
    @Test
    public void insertUpdate() throws IOException {
        //构造参数是row key,必传
        for(int i = 0 ; i < 100 ; i ++){
            Put put = new Put(Bytes.toBytes("zhangsan_123" + i));
            //put.add()已经被弃用了
            //这里的参数依次为,列族名,列名,值
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("name"),Bytes.toBytes("lisi" + i));
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("age"),Bytes.toBytes(22 + i));
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("sex"),Bytes.toBytes("男"));
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("address"),Bytes.toBytes("天堂" + i));
            table.put(put);
            //table.put(List<Put>); //通过一个List集合,可以添加一个集合
        }
 
    }
 
    /**
     * 删除数据
     */
    @Test
    public void delete() throws IOException {
        Delete deleteRow = new Delete(Bytes.toBytes("zhangsan_1235")); //删除一个行
 
        Delete delete = new Delete(Bytes.toBytes("zhangsan_1235"));
        delete.addFamily(Bytes.toBytes("info1"));//删除该行的指定列族
        delete.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//删除指定的一个单元
 
 
        table.delete(deleteRow);
 
        //table.delete(List<Delete>); //通过添加一个list集合,可以删除多个
    }
 
 
    /**
     * 查询单条数据
     * @throws IOException
     */
    @Test
    public void queryByKey() throws IOException {
        String rowKey = "zhangsan_1235";
        Get get = new Get(Bytes.toBytes(rowKey));
        Result result = table.get(get);
        byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
        byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
        byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
        byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
        System.out.print(Bytes.toString(name) + ",");
        System.out.print(Bytes.toString(sex) + ",");
        System.out.print(Bytes.toString(address) + ",");
        System.out.print(Bytes.toInt(age) + ",");
        System.out.println();
    }
 
    /**
     * 全表扫描
     */
    @Test
    public void scanData() throws IOException {
        Scan scan = new Scan();
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }
 
 
    /**
     * 区间扫描
     */
    @Test
    public void areaScanData() throws IOException {
        Scan scan = new Scan();
        scan.withStartRow(Bytes.toBytes("zhangsan_1232")); //设置开始行
        scan.withStopRow(Bytes.toBytes("zhangsan_12352")); //设置结束行
        //scan.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//查询指定列
        scan.addFamily(Bytes.toBytes("info1"));//查询指定列族
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }
 
 
    /**
     * 全表扫描时加过滤器 --> 列值过滤器
     */
    @Test
    public void scanDataByFilter1() throws IOException {
        Scan scan = new Scan();
        /*
         * 第一个参数: 列族
         * 第二个参数: 列名
         * 第三个参数: 是一个枚举类型
         *              CompareOp.EQUAL  等于
         *              CompareOp.LESS  小于
         *              CompareOp.LESS_OR_EQUAL  小于或等于
         *              CompareOp.NOT_EQUAL  不等于
         *              CompareOp.GREATER_OR_EQUAL  大于或等于
         *              CompareOp.GREATER  大于
         */
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.GREATER_OR_EQUAL, Bytes.toBytes("zhangsan8"));
        scan.setFilter(singleColumnValueFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
 
    }
 
 
    /**
     * 全表扫描时加过滤器 --> 前缀过滤器
     *
     * 这里的查询和单元内容没有关系,仅仅是匹配列名,比如有这样两个列 name1 和name2  ,通过这个过滤器,就会查询这两个列的所有数据,当然,其实这个方式和scan.addColumn差不多,
     * 且并会匹配到其它列族的列名
     *
     */
    @Test
    public void scanDataByFilter2() throws IOException {
        ColumnPrefixFilter columnPrefixFilter = new ColumnPrefixFilter(Bytes.toBytes("name"));
        Scan scan = new Scan();
        scan.setFilter(columnPrefixFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }
 
    /**
     * 全表扫描时添加过滤器  --> 多个列值前缀过滤器
     *
     *  这个过滤器和 ColumnPrefixFilter 过滤器差不多,但是能匹配多个前缀
     */
 
    @Test
    public void scanDataFilter3() throws IOException {
        Scan scan = new Scan();
        byte[][] prefix = new byte[][]{Bytes.toBytes("name"),Bytes.toBytes("add")};
        MultipleColumnPrefixFilter multipleColumnPrefixFilter = new MultipleColumnPrefixFilter(prefix);
 
        scan.setFilter(multipleColumnPrefixFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }
 
 
    /**
     * row key查找
     */
    @Test
    public void scanByRowKey() throws IOException {
        //查找以指定内容开头的
        Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
        Scan scan = new Scan();
        scan.setFilter(rowKeyFilter);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }
 
 
    /**
     * 使用多个过滤器,并合查找,可以同时设置多个过滤器
     *
     * 这里查找row key中,name列等于指定值的
     */
    @Test
    public void scanByFilterList() throws IOException {
        /*
        * 我们需要注意Operator这个参数,这是一个枚举类型,里面有两个类型
        *   Operator.MUST_PASS_ALL   需要通过全部的条件,也就是并且,and &&
        *   Operator.MUST_PASS_ONE   任何一个条件满足都可以,也就是或者,or ||
        */
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
 
        //row key正则表达式的过滤器
        Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
        //列值过滤器
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL, Bytes.toBytes("zhangsan9"));
 
 
        //把两个filter添加进filterList中
        filterList.addFilter(rowKeyFilter);
        filterList.addFilter(singleColumnValueFilter);
 
 
        Scan scan = new Scan();
        scan.setFilter(filterList);
 
        ResultScanner resultScanner = table.getScanner(scan);
        printResult(resultScanner);
    }
 
 
    private void printResult(ResultScanner resultScanner) {
        for (Result result : resultScanner) {
            byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
            byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
            byte[] rowKey = result.getRow(); //获取rowKey
            System.out.print(Bytes.toString(rowKey) + ",");
            System.out.print(Bytes.toString(name) + ",");
            System.out.print(Bytes.toString(sex) + ",");
            System.out.print(Bytes.toString(address) + ",");
            System.out.print((age == null ? null : Bytes.toInt(age)) + ",");
            System.out.println();
        }
    }
}
 
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,192评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,186评论 1 303
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,844评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,471评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,876评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,891评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,068评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,791评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,539评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,772评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,250评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,577评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,244评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,146评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,949评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,995评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,812评论 2 276

推荐阅读更多精彩内容

  • 原创文章,转载请注明原作地址:http://www.jianshu.com/p/0f9578df7fbc 一. 架...
    EchoZhan阅读 15,061评论 4 33
  • [TOC] 摘录一 hbase.rootdir 这个目录是region server的共享目录,用来持久化HBas...
    昨夜今夕阅读 11,001评论 1 8
  • 目录: 引言 -- 参数基础 1. 结构(Structural)过滤器--FilterList 2.列值过滤器--...
    磊宝万岁阅读 1,429评论 0 2
  • 如果这本书的作者不是东野圭吾,那它应该能获得更多的关注和更好的评价。比如它的作者是个新人,那它完全可以成为一个时段...
    fan花阅读 779评论 0 2
  • 我习惯于站在道德的制高点批判他人, 却忘了自己也很差劲。 但那些声讨确实缘于愤怒、同情, 也许只有做这些, 才能证...
    落花思绪阅读 247评论 0 0