Spark-SQL之DataFrame基本操作

这篇文章将带大家一起学习Spark中DataFrame的基本操作。

1、创建DataFrame

本文所使用的DataFrame是通过读取mysql数据库获得的,代码如下:

val spark = SparkSession
      .builder()
      .appName("Spark SQL basic example")
      .enableHiveSupport()
      //.config("spark.some.config.option", "some-value")
      .getOrCreate()
    import spark.implicits._
    val url = "jdbc:mysql://localhost:3306/test"
    val df = spark.read
      .format("jdbc")
      .option("url", url)
      .option("dbtable", "pivot")
      .option("user", "root")
      .option("password", "admin")
      .load()

2、DataFrame基本动作运算

2.1 show展示数据

可以用show() 方法来展示数据,show有以下几种不同的使用方式:
show():显示所有数据
show(n) :显示前n条数据
show(true): 最多显示20个字符,默认为true
show(false): 去除最多显示20个字符的限制
show(n, true):显示前n条并最多显示20个自负

代码为:

df.show()
df.show(3)
df.show(true)
df.show(false)
df.show(3,true)

上面的输出为:

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  1|   1| 助手1|2017-08-10 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
|  4|   2| 助手1|2017-08-07 13:44:...|
|  5|   3|APP1|2017-08-02 13:44:...|
|  6|   3|APP1|2017-08-01 13:44:...|
|  7|   3| 助手2|2017-08-14 13:44:...|
|  8|   3|APP2|2017-08-03 13:44:...|
|  9|   2|APP2|2017-08-11 13:44:...|
| 10|   2| 助手1|2017-07-14 13:44:...|
| 11|   1|APP1|2017-07-15 13:45:...|
| 12|   1| 助手2|2017-07-07 13:45:...|
+---+----+----+--------------------+

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  1|   1| 助手1|2017-08-10 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
+---+----+----+--------------------+
only showing top 3 rows

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  1|   1| 助手1|2017-08-10 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
|  4|   2| 助手1|2017-08-07 13:44:...|
|  5|   3|APP1|2017-08-02 13:44:...|
|  6|   3|APP1|2017-08-01 13:44:...|
|  7|   3| 助手2|2017-08-14 13:44:...|
|  8|   3|APP2|2017-08-03 13:44:...|
|  9|   2|APP2|2017-08-11 13:44:...|
| 10|   2| 助手1|2017-07-14 13:44:...|
| 11|   1|APP1|2017-07-15 13:45:...|
| 12|   1| 助手2|2017-07-07 13:45:...|
+---+----+----+--------------------+

+---+----+----+---------------------+
|id |user|type|visittime            |
+---+----+----+---------------------+
|1  |1   |助手1 |2017-08-10 13:44:19.0|
|2  |1   |APP1|2017-08-04 13:44:26.0|
|3  |2   |助手1 |2017-08-05 13:44:29.0|
|4  |2   |助手1 |2017-08-07 13:44:32.0|
|5  |3   |APP1|2017-08-02 13:44:38.0|
|6  |3   |APP1|2017-08-01 13:44:41.0|
|7  |3   |助手2 |2017-08-14 13:44:48.0|
|8  |3   |APP2|2017-08-03 13:44:45.0|
|9  |2   |APP2|2017-08-11 13:44:53.0|
|10 |2   |助手1 |2017-07-14 13:44:57.0|
|11 |1   |APP1|2017-07-15 13:45:03.0|
|12 |1   |助手2 |2017-07-07 13:45:08.0|
+---+----+----+---------------------+

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  1|   1| 助手1|2017-08-10 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
+---+----+----+--------------------+
only showing top 3 rows

2.2 collect获取所有数据到数组

不同于前面的show方法,这里的collect方法会将df中的所有数据都获取到,并返回一个Array对象。

df.collect().foreach(println)

输出为:

[1,1,助手1,2017-08-10 13:44:19.0]
[2,1,APP1,2017-08-04 13:44:26.0]
[3,2,助手1,2017-08-05 13:44:29.0]
[4,2,助手1,2017-08-07 13:44:32.0]
[5,3,APP1,2017-08-02 13:44:38.0]
[6,3,APP1,2017-08-01 13:44:41.0]
[7,3,助手2,2017-08-14 13:44:48.0]
[8,3,APP2,2017-08-03 13:44:45.0]
[9,2,APP2,2017-08-11 13:44:53.0]
[10,2,助手1,2017-07-14 13:44:57.0]
[11,1,APP1,2017-07-15 13:45:03.0]
[12,1,助手2,2017-07-07 13:45:08.0]

2.3 collectAsList:获取所有数据到List

功能和collect类似,只不过将返回结构变成了List对象,使用方法如下:

println(df.collectAsList())

输出为:

[[1,1,助手1,2017-08-10 13:44:19.0], [2,1,APP1,2017-08-04 13:44:26.0], [3,2,助手1,2017-08-05 13:44:29.0], [4,2,助手1,2017-08-07 13:44:32.0], [5,3,APP1,2017-08-02 13:44:38.0], [6,3,APP1,2017-08-01 13:44:41.0], [7,3,助手2,2017-08-14 13:44:48.0], [8,3,APP2,2017-08-03 13:44:45.0], [9,2,APP2,2017-08-11 13:44:53.0], [10,2,助手1,2017-07-14 13:44:57.0], [11,1,APP1,2017-07-15 13:45:03.0], [12,1,助手2,2017-07-07 13:45:08.0]]

2.4describe(cols: String*):获取指定字段的统计信息

这个方法可以动态的传入一个或多个String类型的字段名,结果仍然为DataFrame对象,用于统计数值类型字段的统计值,比如count, mean, stddev, min, max等。

df .describe("user" ).show()

输出为:

+-------+------------------+
|summary|              user|
+-------+------------------+
|  count|                12|
|   mean|               2.0|
| stddev|0.8528028654224418|
|    min|                 1|
|    max|                 3|
+-------+------------------+

2.5first, head, take, takeAsList:获取若干行记录

这里列出的四个方法比较类似,其中
(1)first获取第一行记录
(2)head获取第一行记录,head(n: Int)获取前n行记录
(3)take(n: Int)获取前n行数据
(4)takeAsList(n: Int)获取前n行数据,并以List的形式展现
以Row或者Array[Row]的形式返回一行或多行数据。first和head功能相同。
take和takeAsList方法会将获得到的数据返回到Driver端,所以,使用这两个方法时需要注意数据量,以免Driver发生OutOfMemoryError

3、单个DataFrame操作

3.1 使用where筛选条件

where(conditionExpr: String):SQL语言中where关键字后的条件 ,传入筛选条件表达式,可以用and和or。得到DataFrame类型的返回结果, 比如我们想得到用户1或者使用助手1的操作记录:

df.where("user=1 or type ='助手1'").show()

输出为

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  1|   1| 助手1|2017-08-10 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
|  4|   2| 助手1|2017-08-07 13:44:...|
| 10|   2| 助手1|2017-07-14 13:44:...|
| 11|   1|APP1|2017-07-15 13:45:...|
| 12|   1| 助手2|2017-07-07 13:45:...|
+---+----+----+--------------------+

3.2 filter:根据字段进行筛选

传入筛选条件表达式,得到DataFrame类型的返回结果。和where使用条件相同,比如我们想得到用户1或者使用助手1的操作记录:

df.filter("user=1 or type ='助手1'").show()

结果和上面相同:

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  1|   1| 助手1|2017-08-10 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
|  4|   2| 助手1|2017-08-07 13:44:...|
| 10|   2| 助手1|2017-07-14 13:44:...|
| 11|   1|APP1|2017-07-15 13:45:...|
| 12|   1| 助手2|2017-07-07 13:45:...|
+---+----+----+--------------------+

3.3 select:获取指定字段值

根据传入的String类型字段名,获取指定字段的值,以DataFrame类型返回,比如我们想要查找user和type两列:

df.select("user","type").show()

结果为:

+----+----+
|user|type|
+----+----+
|   1| 助手1|
|   1|APP1|
|   2| 助手1|
|   2| 助手1|
|   3|APP1|
|   3|APP1|
|   3| 助手2|
|   3|APP2|
|   2|APP2|
|   2| 助手1|
|   1|APP1|
|   1| 助手2|
+----+----+

还有一个重载的select方法,不是传入String类型参数,而是传入Column类型参数,Column类型即DataFrame中的一列。可以实现select id, id+1 from pivot这种逻辑。

df.select(df("user"),df("user")+1).show()

输出为

+----+----------+
|user|(user + 1)|
+----+----------+
|   1|       2.0|
|   1|       2.0|
|   2|       3.0|
|   2|       3.0|
|   3|       4.0|
|   3|       4.0|
|   3|       4.0|
|   3|       4.0|
|   2|       3.0|
|   2|       3.0|
|   1|       2.0|
|   1|       2.0|
+----+----------+

3.4selectExpr:可以对指定字段进行特殊处理

可以直接对指定字段调用UDF函数,或者指定别名等。传入String类型参数,得到DataFrame对象。 比如,将type字段重新命名为visittype,同时截取visittime的date:

df.selectExpr("user","type as visittype","to_date(visittime)").show()

输出为:

+----+---------+--------------------------------+
|user|visittype|to_date(CAST(visittime AS DATE))|
+----+---------+--------------------------------+
|   1|      助手1|                      2017-08-10|
|   1|     APP1|                      2017-08-04|
|   2|      助手1|                      2017-08-05|
|   2|      助手1|                      2017-08-07|
|   3|     APP1|                      2017-08-02|
|   3|     APP1|                      2017-08-01|
|   3|      助手2|                      2017-08-14|
|   3|     APP2|                      2017-08-03|
|   2|     APP2|                      2017-08-11|
|   2|      助手1|                      2017-07-14|
|   1|     APP1|                      2017-07-15|
|   1|      助手2|                      2017-07-07|
+----+---------+--------------------------------+

3.5 col/apply:获取指定字段

只能获取一个字段,返回对象为Column类型。 示例略

3.6 drop:去除指定字段,保留其他字段

返回一个新的DataFrame对象,其中不包含去除的字段,一次只能去除一个字段。比如我们去除type字段:

df.drop("type").show()

输出为:

+---+----+--------------------+
| id|user|           visittime|
+---+----+--------------------+
|  1|   1|2017-08-10 13:44:...|
|  2|   1|2017-08-04 13:44:...|
|  3|   2|2017-08-05 13:44:...|
|  4|   2|2017-08-07 13:44:...|
|  5|   3|2017-08-02 13:44:...|
|  6|   3|2017-08-01 13:44:...|
|  7|   3|2017-08-14 13:44:...|
|  8|   3|2017-08-03 13:44:...|
|  9|   2|2017-08-11 13:44:...|
| 10|   2|2017-07-14 13:44:...|
| 11|   1|2017-07-15 13:45:...|
| 12|   1|2017-07-07 13:45:...|
+---+----+--------------------+

3.7 limit

limit方法获取指定DataFrame的前n行记录,得到一个新的DataFrame对象。和take与head不同的是,limit方法不是Action操作。比如获得前3条记录:

df.limit(3).show()

输出为

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  1|   1| 助手1|2017-08-10 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
+---+----+----+--------------------+

3.8 orderBy和sort

orderBy和sort:按指定字段排序,默认为升序 ,例如,按照时间字段进行排序:

df.orderBy("visittime").show(false)

输出为:

+---+----+----+---------------------+
|id |user|type|visittime            |
+---+----+----+---------------------+
|12 |1   |助手2 |2017-07-07 13:45:08.0|
|10 |2   |助手1 |2017-07-14 13:44:57.0|
|11 |1   |APP1|2017-07-15 13:45:03.0|
|6  |3   |APP1|2017-08-01 13:44:41.0|
|5  |3   |APP1|2017-08-02 13:44:38.0|
|8  |3   |APP2|2017-08-03 13:44:45.0|
|2  |1   |APP1|2017-08-04 13:44:26.0|
|3  |2   |助手1 |2017-08-05 13:44:29.0|
|4  |2   |助手1 |2017-08-07 13:44:32.0|
|1  |1   |助手1 |2017-08-10 13:44:19.0|
|9  |2   |APP2|2017-08-11 13:44:53.0|
|7  |3   |助手2 |2017-08-14 13:44:48.0|
+---+----+----+---------------------+

如果想要降序排序,可以使用如下的方法:

df.orderBy(df("visittime").desc).show(false)

输出为:

+---+----+----+---------------------+
|id |user|type|visittime            |
+---+----+----+---------------------+
|7  |3   |助手2 |2017-08-14 13:44:48.0|
|9  |2   |APP2|2017-08-11 13:44:53.0|
|1  |1   |助手1 |2017-08-10 13:44:19.0|
|4  |2   |助手1 |2017-08-07 13:44:32.0|
|3  |2   |助手1 |2017-08-05 13:44:29.0|
|2  |1   |APP1|2017-08-04 13:44:26.0|
|8  |3   |APP2|2017-08-03 13:44:45.0|
|5  |3   |APP1|2017-08-02 13:44:38.0|
|6  |3   |APP1|2017-08-01 13:44:41.0|
|11 |1   |APP1|2017-07-15 13:45:03.0|
|10 |2   |助手1 |2017-07-14 13:44:57.0|
|12 |1   |助手2 |2017-07-07 13:45:08.0|
+---+----+----+---------------------+

3.9 group by数据分组

groupBy方法有两种调用方式,可以传入String类型的字段名,也可传入Column类型的对象。
使用方法如下:

df.groupBy("user")
df.groupBy(df("user"))

groupBy方法之后得到的是GroupedData类型对象,不能直接接show方法来展示DataFrame,还需要跟一些分组统计函数,常用的统计函数有:
max(colNames: String)方法,获取分组中指定字段或者所有的数字类型字段的最大值,只能作用于数字型字段
min(colNames: String
)方法,获取分组中指定字段或者所有的数字类型字段的最小值,只能作用于数字型字段
mean(colNames: String)方法,获取分组中指定字段或者所有的数字类型字段的平均值,只能作用于数字型字段
sum(colNames: String
)方法,获取分组中指定字段或者所有的数字类型字段的和值,只能作用于数字型字段
count()方法,获取分组中的元素个数
例如下面的例子:

df.groupBy("user").max("id").show()
df.groupBy(df("user")).max("id").show()

输出为:

+----+-------+
|user|max(id)|
+----+-------+
|   3|      8|
|   1|     12|
|   2|     10|
+----+-------+

我们还经常想要实现一个类似excel数据透视表的功能,这里就需要用到pivot函数,比如要统计每个用户通过各种渠道下单的次数:

df.groupBy(df("user")).pivot("type").count().show()

输出为:

+----+----+----+----+----+
|user|APP1|APP2| 助手1| 助手2|
+----+----+----+----+----+
|   3|   2|   1|null|   1|
|   1|   2|null|   1|   1|
|   2|null|   1|   3|null|
+----+----+----+----+----+

3.10 distinct数据去重

使用distinct:返回当前DataFrame中不重复的Row记录。该方法和接下来的dropDuplicates()方法不传入指定字段时的结果相同。

3.11 dropDuplicates:根据指定字段去重

跟distinct方法不同的是,此方法可以根据指定字段去重。例如我们想要去掉相同用户通过相同渠道下单的数据:

df.dropDuplicates("user","type").show()

输出为:

+---+----+----+--------------------+
| id|user|type|           visittime|
+---+----+----+--------------------+
|  8|   3|APP2|2017-08-03 13:44:...|
|  1|   1| 助手1|2017-08-10 13:44:...|
|  7|   3| 助手2|2017-08-14 13:44:...|
| 12|   1| 助手2|2017-07-07 13:45:...|
|  3|   2| 助手1|2017-08-05 13:44:...|
|  5|   3|APP1|2017-08-02 13:44:...|
|  9|   2|APP2|2017-08-11 13:44:...|
|  2|   1|APP1|2017-08-04 13:44:...|
+---+----+----+--------------------+

3.11 agg方法实现聚合操作

聚合操作调用的是agg方法,该方法有多种调用方式。一般与groupBy方法配合使用。
比如我们查找最大的id,并把所有的user值相加,这里只是为了演示代码的作用:

df.agg("id"->"max","user"->"sum").show()

输出为:

+-------+---------+
|max(id)|sum(user)|
+-------+---------+
|     12|     24.0|
+-------+---------+

3.12 withColumn添加新的一列

我们可以使用withColumn方法为DataFrame添加新的一列,这个方法指定两个参数,一个是列名,一个是值,值需要是Column对象:

df.withColumn("sex",df("user")%2).show()

输出为

+---+----+----+--------------------+---+
| id|user|type|           visittime|sex|
+---+----+----+--------------------+---+
|  1|   1| 助手1|2017-08-10 13:44:...|1.0|
|  2|   1|APP1|2017-08-04 13:44:...|1.0|
|  3|   2| 助手1|2017-08-05 13:44:...|0.0|
|  4|   2| 助手1|2017-08-07 13:44:...|0.0|
|  5|   3|APP1|2017-08-02 13:44:...|1.0|
|  6|   3|APP1|2017-08-01 13:44:...|1.0|
|  7|   3| 助手2|2017-08-14 13:44:...|1.0|
|  8|   3|APP2|2017-08-03 13:44:...|1.0|
|  9|   2|APP2|2017-08-11 13:44:...|0.0|
| 10|   2| 助手1|2017-07-14 13:44:...|0.0|
| 11|   1|APP1|2017-07-15 13:45:...|1.0|
| 12|   1| 助手2|2017-07-07 13:45:...|1.0|
+---+----+----+--------------------+---+

4、两个DataFrame操作

首先,我们先来创建一个用户性别表,并读入新的DataFrame中。

val df2 = spark.read
      .format("jdbc")
      .option("url", url)
      .option("dbtable", "user")
      .option("user", "root")
      .option("password", "admin")
      .load()

df2.show()
+----+---+
|user|sex|
+----+---+
|   1|  男|
|   2|  女|
|   5|  男|
+----+---+

4.1 join链接

首先,我们可以通过join函数实现两个DataFrame的链接操作,并要指定链接字段:

df.join(df2,"user").show()

输出为:

+----+---+----+--------------------+---+
|user| id|type|           visittime|sex|
+----+---+----+--------------------+---+
|   1|  1| 助手1|2017-08-10 13:44:...|  男|
|   1|  2|APP1|2017-08-04 13:44:...|  男|
|   1| 11|APP1|2017-07-15 13:45:...|  男|
|   1| 12| 助手2|2017-07-07 13:45:...|  男|
|   2|  3| 助手1|2017-08-05 13:44:...|  女|
|   2|  4| 助手1|2017-08-07 13:44:...|  女|
|   2|  9|APP2|2017-08-11 13:44:...|  女|
|   2| 10| 助手1|2017-07-14 13:44:...|  女|
+----+---+----+--------------------+---+

如果我们有多个字段,可以使用:

df.join(df2,Seq("id","user"))

上面两个指定链接字段的形式称为using形式,因为类似于a join b using column1的形式,当然也可以使用Column类型来join,注意是三个等号:

df.join(df2,df("user")===df2("user"))

我们可以看到,默认的链接方式是内链接,当然我们已可以使用其他的方式,通过第三个参数来指定。我们可以指定的类型有inner, outer, left_outer, right_outer, leftsemi类型,不过只有using形式指定两个及以上字段以及使用Column类型来链接的时候可以指定链接方式。

比如下面的方式是错误的:

df.join(df2,"user","outer").show()

比如我们使用外链接:

df.join(df2,df("user")===df2("user"),"outer").show()

结果为:

+----+----+----+--------------------+----+----+
|  id|user|type|           visittime|user| sex|
+----+----+----+--------------------+----+----+
|   1|   1| 助手1|2017-08-10 13:44:...|   1|   男|
|   2|   1|APP1|2017-08-04 13:44:...|   1|   男|
|  11|   1|APP1|2017-07-15 13:45:...|   1|   男|
|  12|   1| 助手2|2017-07-07 13:45:...|   1|   男|
|   5|   3|APP1|2017-08-02 13:44:...|null|null|
|   6|   3|APP1|2017-08-01 13:44:...|null|null|
|   7|   3| 助手2|2017-08-14 13:44:...|null|null|
|   8|   3|APP2|2017-08-03 13:44:...|null|null|
|   3|   2| 助手1|2017-08-05 13:44:...|   2|   女|
|   4|   2| 助手1|2017-08-07 13:44:...|   2|   女|
|   9|   2|APP2|2017-08-11 13:44:...|   2|   女|
|  10|   2| 助手1|2017-07-14 13:44:...|   2|   女|
|null|null|null|                null|   5|   男|
+----+----+----+--------------------+----+----+

未完待续,在学习过程中不断补充!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容