【SparkSQL】DataFrame入门(重点:df代码操作、数据清洗API、通过JDBC读写数据库)

【大家好,我是爱干饭的猿,本文重点介绍DataFrame的组成、DataFrame的代码构建、DataFrame的入门操作、词频统计案例、电影数据分析、SparkSQL Shuffle 分区数目、SparkSQL 数据清洗API、DataFrame数据写出、DataFrame 通过JDBC读写数据库(MySQL示例)

后续会继续分享其他重要知识点总结,如果喜欢这篇文章,点个赞👍,关注一下吧】

上一篇文章:《【SparkSQL】基础入门(重点:SparkSQL和Hive的异同、SparkSQL数据抽象)》

3. DataFrame入门

3.1 DataFrame的组成

DataFrame是一个二维表结构, 那么表格结构就有无法
绕开的三个点:

  • 表结构描述

比如,在MySQL中的一张表:

  • 由许多行组成
  • 数据也被分成多个列
  • 表也有表结构信息(列、列名、列类型、列约束等)

基于这个前提,DataFrame的组成如下:

  • 在结构层面:
    • StructType对象描述整个DataFrame的表结构
    • StructField对象描述一个列的信息
  • 在数据层面
    • Row对象记录一行数据
    • Column对象记录一列数据并包含列的信息

在这里插入图片描述
如图, 在表结构层面,DataFrame的表结构由:
StructType描述,如下图:

在这里插入图片描述
一个StructField记录:列名、列类型、列是否运行为空
多个StructField组成一个StructType对象。
一个StructType对象可以描述一个DataFrame:有几个列、每个列的名字和类型、每个列是否为空

同时,一行数据描述为Row对象,如Row(1, 张三, 11)
一列数据描述为Column对象,Column对象包含一列数据和列的信息

3.2 DataFrame的代码构建

1. 基于RDD方式1

DataFrame对象可以从RDD转换而来,都是分布式数据集
其实就是转换一下内部存储的结构,转换为二维表结构

通过SparkSession对象的createDataFrame方法来将RDD转换为DataFrame
这里只传入列名称,类型从RDD中进行推断,是否允许为空默认为允许(True)

# coding:utf8from pyspark.sql import SparkSessionif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# 基于RDD转换成DataFramerdd = sc.textFile("rent.txt").\map(lambda x: x.split(",")).\map(lambda x: (x[0], x[1], int(x[2])))# 构建DataFrame对象# 参数1 被转换的RDD# 参数2 指定列名, 通过list的形式指定, 按照顺序依次提供字符串名称即可df = spark.createDataFrame(rdd, schema=['address', 'area', 'price'])# 打印DataFrame的表结构df.printSchema()# 打印df中的数据# 参数1 表示 展示出多少条数据, 默认不传的话是20# 参数2 表示是否对列进行截断, 如果列的数据长度超过20个字符串长度, 后续的内容不显示以...代替# 如果给False 表示不阶段全部显示, 默认是Truedf.show(20, False)# 将DF对象转换成临时视图表, 可供sql语句查询df.createOrReplaceTempView("people")spark.sql("select * from people where price > 2000").show()

2. 基于RDD方式2

将RDD转换为DataFrame方式2:
通过StructType对象来定义DataFrame的“表结构”转换RDD

# coding:utf8from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# 基于RDD转换成DataFramerdd = sc.textFile("rent.txt").\map(lambda x: x.split(",")).\map(lambda x: (x[0], x[1], int(x[2])))# 构建表结构的描述对象: StructType对象schema = StructType().\add("address", StringType(), nullable=True).\add("area", StringType(), nullable=True).\add("price", IntegerType(), nullable=True)# 基于StructType对象去构建RDD到DF的转换df = spark.createDataFrame(rdd, schema=schema)df.printSchema()df.show()

3. 基于RDD方式3

将RDD转换为DataFrame方式3:
使用RDD的toDF方法转换RDD

# coding:utf8from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# 基于RDD转换成DataFramerdd = sc.textFile("rent.txt").\map(lambda x: x.split(",")).\map(lambda x: (x[0], x[1], int(x[2])))# 1. toDF的方式构建DataFramedf1 = rdd.toDF(["address", "area", "price"])df1.printSchema()df1.show()# 2. toDF的方式2 通过StructType来构建schema = StructType().\add("address", StringType(), nullable=True).\add("area", StringType(), nullable=True).\add("price", IntegerType(), nullable=True)df2 = rdd.toDF(schema=schema)df2.printSchema()df2.show()

4. 基于Pandas的DataFrame

将Pandas的DataFrame对象,转变为分布式的SparkSQL DataFrame对象

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# 基于Pandas的DataFrame构建SparkSQL的DataFrame对象pdf = pd.DataFrame({"id": [1, 2, 3],"name": ["张大仙", "王晓晓", "吕不为"],"age": [11, 21, 11]})df = spark.createDataFrame(pdf)df.printSchema()df.show()

5. 读取外部数据-test

读取text数据源
使用format(“text”)读取文本数据
读取到的DataFrame只会有一个列,列名默认称之为:value

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# 构建StructType, text数据源, 读取数据的特点是, 将一整行只作为`一个列`读取, 默认列名是value 类型是Stringschema = StructType().\add("data", StringType(), nullable=True)df = spark.read.format("text").schema(schema=schema).load("rent.txt")df.printSchema()df.show()

6. 读取外部数据-json

读取json数据源
使用format(“json”)读取json数据

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# JSON类型自带有Schema信息df = spark.read.format("json").load("rent.json")df.printSchema()df.show()

7. 读取外部数据-csv

读取csv数据源
使用format(“csv”)读取csv数据

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# 读取csv文件df = spark.read.format("csv").\option("sep", ",").\option("header", True).\option("encoding", "utf-8").\schema("address STRING, area STRING, price INT").\load("rent.csv")df.printSchema()df.show()

8. 读取外部数据-parquet

parquet: 是Spark中常用的一种列式存储文件格式,和Hive中的ORC差不多, 他俩都是列存储格式
parquet对比普通的文本文件的区别:

  • parquet 内置schema (列名\ 列类型\ 是否为空)
  • 存储是以列作为存储格式
  • 存储是序列化存储在文件中的(有压缩属性体积小)

pycharm查看parquet文件插件:Avro and Parquet Viewer

读取parquet数据源
使用format(“parquet”)读取parquet数据

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# 读取parquet类型的文件df = spark.read.format("parquet").load("rent.parquet")df.printSchema()df.show()

3.3 DataFrame的入门操作

DataFrame支持两种风格进行编程,分别是:

  • DSL风格
  • SQL风格
  1. DSL语法风格
    DSL称之为:领域特定语言。
    其实就是指DataFrame的特有API
    DSL风格意思就是以调用API的方式来处理Data
    比如:df.where().limit()

  2. SQL语法风格
    SQL风格就是使用SQL语句处理DataFrame的数据
    比如:spark.sql(“SELECT * FROM xxx)

1. DSL风格代码演示

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContextdf = spark.read.format("csv").\schema("address STRING, area STRING, price INT").\load("rent.txt")# Column对象的获取address_column = df['address']price_column = df['price']# TODO: DLS风格演示df.select(["address", "price"]).show()df.select("address", "price").show()df.select(address_column, price_column).show()# 1. filter APIdf.filter("price > 2500").show()df.filter(df['price'] > 2500).show()# 2. where APIdf.where("price > 2500").show()df.where(df['price']> 2500).show()# 3. group By APIdf.groupBy("address").count().show()df.groupBy(df['address']).count().show()# df.groupBy API的返回值 GroupedData# GroupedData对象 不是DataFrame# 它是一个 有分组关系的数据结构, 有一些API供我们对分组做聚合# SQL: group by 后接上聚合: sum avg count min man# GroupedData 类似于SQL分组后的数据结构, 同样有上述5种聚合方法# GroupedData 调用聚合方法后, 返回值依旧是DataFrame# GroupedData 只是一个中转的对象, 最终还是要获得DataFrame的结果r = df.groupBy("address")

2. SQL风格代码演示

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringTypeif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContextdf = spark.read.format("csv").\schema("address STRING, area STRING, price INT").\load("rent.txt")# 注册成临时表df.createTempView("rent")  # 注册临时视图(表)df.createOrReplaceTempView("rent_2")  # 注册 或者 替换  临时视图df.createGlobalTempView("rent_3")  # 注册全局临时视图 全局临时视图在使用的时候 需要在前面带上global_temp. 前缀# 可以通过SparkSession对象的sql api来完成sql语句的执行spark.sql("SELECT area, COUNT(*) AS cnt FROM rent GROUP BY area").show()spark.sql("SELECT area, COUNT(*) AS cnt FROM rent_2 GROUP BY area").show()spark.sql("SELECT area, COUNT(*) AS cnt FROM global_temp.rent_3 GROUP BY area").show()

3.4 词频统计案例

我们来完成一个单词计数需求,使用DSL和SQL两种风格来实现。

# coding:utf8
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, IntegerType, StringType
from pyspark.sql import functions as Fif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\getOrCreate()sc = spark.sparkContext# words.txt:# hello hadoop# hello spark# hello flink# TODO 1: SQL 风格进行处理rdd = sc.textFile("words.txt").\flatMap(lambda x: x.split(" ")).\map(lambda x: [x])df = rdd.toDF(["word"])# 注册DF为表格df.createTempView("words")spark.sql("select word, count(*) as cnt from words group by word order by cnt desc").show()# TODO 2: DSL 风格处理df = spark.read.format("text").load("words.txt")# withColumn方法# 方法功能: 对已存在的列进行操作, 返回一个新的列, 如果名字和老列相同, 那么替换, 否则作为新列存在df2 = df.withColumn("value", F.explode(F.split(df["value"], " ")))df2.groupBy("value").\count().\withColumnRenamed("value", "word").\withColumnRenamed("count", "cnt").\orderBy("cnt", ascending=False).\show()

3.5 电影数据分析

MovieLens数据集
MovieLens数据集包含多个用户对多部电影的评级数据,也包括电影元数据信息和用户属性信息。
下载地址: http://files.grouplens.org/datasets/movielens
介绍:下面以ml-10Ok数据集为例进行。
介绍:下载u.data文件。
u.data -由943个用户对1682个电影的10000条评分组成。每个用户至少评分20部电影。用户和电影从1号开始连续编号。数据是随机排序的。
在这里插入图片描述

需求:

  1. 查询用户平均分
  2. 查询电影平均分
  3. 查询大于平均分的电影的数量
  4. 查询高分电影中(>3)打分次数最多的用户,并求出此人打的平均分
  5. 查询每个用户的平均打分,最低打分,最高打分
  6. 查询被评分超过100次的电影,的平均分排名TOP10
# coding:utf8
import timefrom pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
import pandas as pd
from pyspark.sql import functions as Fif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\config("spark.sql.shuffle.partitions", 2).\getOrCreate()sc = spark.sparkContext"""spark.sql.shuffle.partitions 参数指的是, 在sql计算中, shuffle算子阶段默认的分区数是200个.对于集群模式来说, 200个默认也算比较合适如果在local下运行, 200个很多, 在调度上会带来额外的损耗所以在local下建议修改比较低 比如2\4\10均可这个参数和Spark RDD中设置并行度的参数 是相互独立的."""# 1. 读取数据集schema = StructType().\add("user_id", StringType(), nullable=True).\add("movie_id", IntegerType(), nullable=True).\add("rank", IntegerType(), nullable=True).\add("ts", StringType(), nullable=True)df = spark.read.format("csv").\option("sep", "\t").\option("header", False).\schema(schema=schema).\load("u.data")df.printSchema()# TODO 1: 用户平均分df.groupBy("user_id").\avg("rank").\withColumnRenamed("avg(rank)", "avg_rank").\withColumn("avg_rank", F.round("avg_rank", 2)).\orderBy("avg_rank", ascending=False).\show()df.createTempView("movie")spark.sql("select user_id, round(avg(rank), 2) as avg_rank from movie group by user_id").show()# TODO 2: 电影的平均分查询df.groupBy("movie_id").\avg("rank").\withColumnRenamed("avg(rank)", "avg_rank").\withColumn("avg_rank", F.round("avg_rank", 2)).\orderBy("avg_rank", ascending=False).\show()spark.sql("select movie_id, round(avg(rank), 2) as avg_rank from movie group by movie_id order by avg_rank desc").show()# TODO 3: 查询大于平均分的电影的数量 # Rowprint("大于平均分电影的数量: {}".format(df.where(df['rank'] > df.select(F.avg(df['rank'])).first()['avg(rank)']).count()))spark.sql("select count(*) as cnt from movie where rank > (select avg(rank) from movie)").show()# TODO 4: 查询高分电影中(>3)打分次数最多的用户, 此人打分的平均分user_id = df.where("rank > 3").\groupBy("user_id").\count().\withColumnRenamed("count", "cnt").\orderBy("cnt", ascending=False).\limit(1).\first()["user_id"]print("user_id: {}".format(user_id))df.filter(df["user_id"] == user_id).\select(F.round(F.avg("rank"), 2)).show()spark.sql("select movie.user_id, round(avg(rank), 2) as avg_rank from movie, (select user_id from movie where rank > 3 group by user_id order by count(*) desc limit 1) as u where u.user_id == movie.user_id group by movie.user_id").show()# TODO 5: 查询每个用户的平局打分, 最低打分, 最高打分df.groupBy("user_id").\agg(F.round(F.avg("rank"), 2).alias("avg_rank"),F.min("rank").alias("min_rank"),F.max("rank").alias("max_rank")).orderBy("avg_rank", ascending=False).\show()spark.sql("select user_id, round(avg(rank), 2) as avg_rank, min(rank) as min_rank, max(rank) as max_rank from movie group by user_id order by avg_rank desc limit 10").show()# TODO 6: 查询评分超过100次的电影, 的平均分 排名 TOP10df.groupBy("movie_id").\agg(F.count("movie_id").alias("cnt"),F.round(F.avg("rank"), 2).alias("avg_rank")).where("cnt > 100").\orderBy("avg_rank", ascending=False).\limit(10).\show()spark.sql("select movie_id, count(rank) as cnt, round(avg(rank), 2) as avg_rank from movie group by movie_id having count(rank) > 100 order by avg_rank desc limit 10").show()# time.sleep(10000) 可以打开spark运行地址查看task任务执行情况 127.0.0.1:4040"""
1. agg: 它是GroupedData对象的API, 作用是 在里面可以写多个聚合
2. alias: 它是Column对象的API, 可以针对一个列 进行改名
3. withColumnRenamed: 它是DataFrame的API, 可以对DF中的列进行改名, 一次改一个列, 改多个列 可以链式调用
4. orderBy: DataFrame的API, 进行排序, 参数1是被排序的列, 参数2是 升序(True) 或 降序 False
5. first: DataFrame的API, 取出DF的第一行数据, 返回值结果是Row对象.
# Row对象 就是一个数组, 你可以通过row['列名'] 来取出当前行中, 某一列的具体数值. 返回值不再是DF 或者GroupedData 或者Column而是具体的值(字符串, 数字等)
"""

3.6 SparkSQL Shuffle 分区数目

在这里插入图片描述

3.7 SparkSQL 数据清洗API

前面我们处理的数据实际上都是已经被处理好的规整数据,但是在大数据整个生产过程中,需要先对数据进行数据清洗,将杂乱无章的数据整理为符合后面处理要求的规整数据。

# coding:utf8from pyspark.sql import SparkSessionif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\config("spark.sql.shuffle.partitions", 2).\getOrCreate()sc = spark.sparkContext"""读取数据"""df = spark.read.format("csv").\option("sep", ";").\option("header", True).\load("../data/input/sql/people.csv")# TODO 1: 数据清洗: 数据去重# dropDuplicates 是DataFrame的API, 可以完成数据去重# 无参数使用, 对全部的列 联合起来进行比较, 去除重复值, 只保留一条df.dropDuplicates().show()df.dropDuplicates(['age', 'job']).show()# TODO 2: 数据清洗: 缺失值处理# dropna api是可以对缺失值的数据进行删除# 无参数使用, 只要列中有null 就删除这一行数据df.dropna().show()# thresh = 3表示, 最少满足3个有效列,  不满足 就删除当前行数据df.dropna(thresh=3).show()df.dropna(thresh=2, subset=['name', 'age']).show()# TODO 3: 缺失值处理也可以完成对缺失值进行填充# DataFrame的 fillna 对缺失的列进行填充df.fillna("loss").show()# 指定列进行填充df.fillna("N/A", subset=['job']).show()# 设定一个字典, 对所有的列 提供填充规则df.fillna({"name": "未知姓名", "age": 1, "job": "worker"}).show()

3.8 DataFrame数据写出

SparkSQL统一API写出DataFrame数据

# coding:utf8
import timefrom pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
import pandas as pd
from pyspark.sql import functions as Fif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\config("spark.sql.shuffle.partitions", 2).\getOrCreate()sc = spark.sparkContext# 1. 读取数据集schema = StructType().add("user_id", StringType(), nullable=True). \add("movie_id", IntegerType(), nullable=True). \add("rank", IntegerType(), nullable=True). \add("ts", StringType(), nullable=True)df = spark.read.format("csv"). \option("sep", "\t"). \option("header", False). \option("encoding", "utf-8"). \schema(schema=schema). \load("u.data")# 2. Write text 写出, 只能写出一个列的数据, 需要将df转换为单列dfdf.select(F.concat_ws("---", "user_id", "movie_id", "rank", "ts")).\write.\mode("overwrite").\format("text").\save("./sql/text")# 3. Write csvdf.write.mode("overwrite").\format("csv").\option("sep", ";").\option("header", True).\save("./sql/csv")# 4. Write jsondf.write.mode("overwrite").\format("json").\save("./sql/json")# 5. Write parquetdf.write.mode("overwrite").\format("parquet").\save("./sql/parquet")

3.9 DataFrame 通过JDBC读写数据库(MySQL示例)

读取JDBC 是需要有驱动的,我们读取的是 jdbc:mysql://

这个协议,也就是读取的是mysql的数据,既然如此,就需要有mysql的驱动jar包给spark程序用.
如果不给驱动jar包,会提示:No suitable Driver
在这里插入图片描述

  • 对于windows系统(使用本地解释器)(以Anaconda环境演示)
    将jar包放在: Anaconda3的安装路径下\envs\虚拟环境\Liblsite-packages\pyspark\jars

  • 对于Linux系统(使用远程解释器执行)(以Anaconda环境演示)
    将jar包放在:Anaconda3的安装路径下/envs/虚拟环境/lib/python3.8/site-packages/pyspark/jars

# coding:utf8
import timefrom pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
import pandas as pd
from pyspark.sql import functions as Fif __name__ == '__main__':# 0. 构建执行环境入口对象SparkSessionspark = SparkSession.builder.\appName("test").\master("local[*]").\config("spark.sql.shuffle.partitions", 2).\getOrCreate()sc = spark.sparkContext# 1. 读取数据集schema = StructType().add("user_id", StringType(), nullable=True). \add("movie_id", IntegerType(), nullable=True). \add("rank", IntegerType(), nullable=True). \add("ts", StringType(), nullable=True)df = spark.read.format("csv"). \option("sep", "\t"). \option("header", False). \option("encoding", "utf-8"). \schema(schema=schema). \load("u.data")# TODO 1: 写出df到mysql数据库中df.write.mode("overwrite").\format("jdbc").\option("url", "jdbc:mysql://127.0.0.1:3306/python_learn?useSSL=false&useUnicode=true").\option("dbtable", "movie_date").\option("user", "root").\option("password", "123456").\save()# TODO 2: 读取MySQL数据df2 = spark.read.\format("jdbc").\option("url", "jdbc:mysql://127.0.0.1:3306/python_learn?useSSL=false&useUnicode=true").\option("dbtable", "movie_date").\option("user", "root").\option("password", "123456").\load()df2.printSchema()df2.show()"""
JDBC写出, 会自动创建表的.
因为DataFrame中有表结构信息, StructType记录的 各个字段的 名称 类型  和是否运行为空
"""

3.10 总结

  1. DataFrame 在结构层面上由StructField组成列描述,由StructType构造表描述。在数据层面上,Column对象记录列数据,Row对象记录行数据
  2. DataFrame可以从RDD转换、Pandas DF转换、读取文件、读取JDBC等方法构建
  3. spark.read.format()和df.write.format() 是DataFrame读取和写出的统一化标准API
  4. SparkSQL默认在Shuffle阶段200个分区,可以修改参数获得最好性能
  5. dropDuplicates可以去重、dropna可以删除缺失值、fillna可以填充缺失值
  6. SparkSQL支持JDBC读写,可用标准API对数据库进行读写操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/185605.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DHCP、ARP、FTP、DNS、VRRP、STP、报文交互流程

目录 一、DHCP 1、DHCP终结 1、DHCP discover 2、DHCP offer 3、DHCP request 4、DHCP ack 5、DHCP request 6、DHCP 续租 2、DHCP终结 二、ARP 1、ARP类型 动态ARP 静态ARP ARP代理 ARP代理的分类:路由式代理、VLAN内的ARP代理、VLAN间的ARP代理。 6…

行情分析——加密货币市场大盘走势(11.30)

大饼已经形成了底背离,即MACD往下走,而价格还在往上走,这种往往后续会大跌。我们继续把空单拿好,已经持仓的无需加仓。多次上涨都一直不能突破,也说明多空和空军力量都很强,等待后续出方向,而笔…

HarmonyOS入门开发(三) 持久化存储Preferences

接入鸿蒙几天以来,发现各种和Android不一样的地方,今天来看一下Preferences存储 在Android中比如有ShardPreferences、Mmkv这些持久化存储方式,开发起来很方便,读取速度也很快,在鸿蒙里面也提供了对应的持久化存储方案…

‘tsc‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

最近在用nodejs typescript 某游戏服务器在做一些研究 nodejs-tcs 问题描述: 1.使用命令npm install -g typescript安装typescript后,输入 tsc命令,一直报错 tsc 不是内部或外部命令,也不是可运行的程序 或批处理文件。 2.目…

VBA代码解决方案第8讲:用FindPrevious进行重复搜索及利用LIKE查找

《VBA代码解决方案》(版权10028096)这套教程是我最早推出的教程,目前已经是第三版修订了。这套教程定位于入门后的提高,在学习这套教程过程中,侧重点是要理解及掌握我的“积木编程”思想。要灵活运用教程中的实例像搭积木一样把自己喜欢的代码…

LeetCode(44)存在重复元素 II【哈希表】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 存在重复元素 II 1.题目 给你一个整数数组 nums 和一个整数 k &#xff0c;判断数组中是否存在两个 不同的索引 i 和 j &#xff0c;满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在&#xff0c;返回 true &#xf…

【UE】UEC++委托代理

【UE】UEC委托代理 一、委托的声明与定义 #pragma once#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "DelegateGameMode.generated.h"// // Declare DECLARE_DELEGATE // DECLARE_DELEGATE(FDeclareDelegate_…

【Linux】:信号(一)产生

信号 一.前台进程和后台进程1.前台进程2。后台进程3.总结 二.自定义信号动作接口三.信号的产生1.键盘组合键2.kill信号进程pid3.系统调用1.kill函数2.raise函数3.abort函数 四.异常五.软件条件六.core文件 一.前台进程和后台进程 1.前台进程 一个简单的代码演示 像这种程序在…

java中反射知识点概念

这里写自定义目录标题 1.什么是反射--动态注入&#xff1f;2.反射的诞生背景3.反射的意义4.反射后可以做些什么5.反射相关的主要API6.反射的优缺点7.反射和不反射基础使用8.工厂模式使用反射8.1首先我们来看看不使用反射的情况&#xff1a;8.2使用反射的情况&#xff1a; 9.Jav…

Cesium.CustomShader颜色值显示错误

官方示例&#xff1a; Cesium Sandcastle 测试过程&#xff1a; 1、修改示例&#xff0c;把customshader中的fragmentShaderText替换为如下代码 void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {//注意&#xff1a;下述颜色的b值是0.1&#x…

智能配电箱监控系统

智能配电箱监控系统是一种用于实时监控配电箱运行状态和电能质量的系统。它通过集成应用物联网技术&#xff0c;实现对配电箱的数据采集、整合和处理&#xff0c;从而让工作人员能够远程了解和掌握配电箱的情况。通过电力设备的数字化&#xff0c;依托电易云-智慧电力物联网&am…

数字孪生3D场景开发工具:弥补不足,开拓全新可能

随着数字化时代的来临&#xff0c;越来越多的企业和行业开始探索数字孪生技术的应用。数字孪生是指通过数字技术将现实世界中的物体、场景等复制到虚拟世界中&#xff0c;以实现实时监测、预测和优化。然而&#xff0c;在数字孪生的发展过程中&#xff0c;一些不足也逐渐浮现。…

如何去选择合适的线缆测试仪?CAT8网线认证测试

如何去选择合适的线缆测试仪? 如果你是第三方检测单位&#xff0c;系统集成商&#xff0c;或者线缆生产厂家&#xff0c;我个人建议选择福禄克DSX系列无疑是比较保险的做法&#xff0c;因为考虑到福禄克在国内耕耘多年所积累起来的品牌知名度和口碑&#xff0c;选择一款大家都…

PHP程序员必备技能:OSS云存储实现教程!

近些年来&#xff0c;云存储的应用越来越广泛&#xff0c;阿里云的OSS云存储服务也在国内市场中占据了一席之地。在此基础上&#xff0c;本文将分享如何使用PHP实现OSS云存储。 首先&#xff0c;我们需要在阿里云官网上注册一个账号并创建一个OSS存储空间。创建步骤在官方文档…

振南技术干货集:各大平台串口调试软件大赏(4)

注解目录 &#xff08;串口的重要性不言而喻。为什么很多平台把串口称为 tty&#xff0c;比如 Linux、MacOS 等等&#xff0c;振南告诉你。&#xff09; 1、各平台上的串口调试软件 1.1Windows 1.1.1 STCISP &#xff08;感谢 STC 姚老板设计出 STCISP 这个软件。&#xf…

相机标定张正友、opencv和halcon对比(1)

本文将从基本标定开始&#xff0c;结合实际工作经验&#xff0c;分析张正友、opencv和halcon三者相机标定的深层原理与不同之处&#xff0c;内容比较多&#xff0c;如果出现错误请指正。 相机光学模型 我们使用的镜头都是由多组镜片组成&#xff0c;它实际上是一种厚透镜模型…

羊大师提问,为什么吃得越咸越容易出现健康问题?

羊大师提问&#xff0c;为什么吃得越咸越容易出现健康问题&#xff1f; 在现代社会中&#xff0c;有一种追求咸味食物的趋势&#xff0c;许多人都钟爱于吃咸味食物。吃咸味食物往往容易导致健康问题&#xff0c;引发各种疾病。那么为什么吃的越咸越容易生病呢&#xff1f; 今…

C++二分查找算法:132 模式枚举3

说明 本篇是视频课程的讲义&#xff0c;可以看直接查看视频。也可以下载源码&#xff0c;包括空源码。 本文涉及的基础知识点 二分查找算法合集 本题不同解法 包括题目及代码C二分查找算法&#xff1a;132 模式解法一枚举3C二分查找算法&#xff1a;132 模式解法二枚举2代码…

黑洞:宇宙中最神秘的天体

黑洞&#xff1a;宇宙中最神秘的天体 一、引言 在浩瀚的宇宙中&#xff0c;有一种神秘的天体&#xff0c;它强大到连光也无法逃逸&#xff0c;这就是黑洞。自从黑洞理论被提出以来&#xff0c;它一直是物理学家和天文学家研究的焦点。尽管我们还无法直接看到黑洞&#xff0c;…

使用 Redis Zset 有序集合实现排行榜功能(SpringBoot环境)

目录 一、前言二、Redis Zset 的基本操作三、通过Redis 命令模拟排行榜功能3.1、排行榜生成3.2、排行榜查询 四、SpringBoot 使用 Redis Zset 有序集合实现排行榜功能 一、前言 排行榜功能是非常常见的需求&#xff0c;例如商品售卖排行榜单、游戏中的积分排行榜、配送员完单排…