ARTS-5(关于hive的基础学习)

本文探讨了一种优化的解法,利用双指针技巧降低LeetCode 16题——最接近三数之和的时间复杂度,从O(n²)提升到O(n)。通过实例和代码实现,深入解析Hive在大数据处理中的角色,以及Java 8的Lambda表达式在简化编程中的应用。
摘要由CSDN通过智能技术生成

Algorithm

【Leecode-16 最接近的三数之和】
题目描述
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

解题思路
先排序, 然后遍历, 然后内部使用双指针, 时间复杂度应该是O(n²),

代码实现

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        // 排序
        Arrays.sort(nums);
        int closestNum = nums[0] + nums[1] + nums[2];
        for (int i = 0; i < nums.length - 2; i++) {
            int l = i + 1, r = nums.length - 1;
            while (l < r){
                int threeSum = nums[l] + nums[r] + nums[i];
                if (Math.abs(threeSum - target) < Math.abs(closestNum - target)) {
                    closestNum = threeSum;
                }
                if (threeSum > target) {
                    r--;
                } else if (threeSum < target) {
                    l++;
                } else {
                    // 如果已经等于target的话, 肯定是最接近的
                    return target;
                }
            }
        }
        return closestNum;
    }
}

Review

什么是hive?

1、Hive是基于Hadoop的一个数据仓库工具。
2、可以将结构化的数据文件映射为一张表,并提供完整的sql查询功能。
3、底层是将sql语句转换为MapReduce任务进行运行。
4、Hive提供了一系列的工具,可以用来进行数据提取、转化、加载(ETL Extract-Transform-Load ),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。本质上是一种大数据离线分析工具
5、提供HQL(Hive SQL)查询功能
6、底层数据存储在HDFS上
7、实质就是一款基于HDFS的MapReduce分布式计算框架,对存储在HDFS上的数据进行分析和管理
在这里插入图片描述
在这里插入图片描述

show databases; #查数据库
create database park; #创建park数据库
use park; #进入park数据库
show tables; 查看表
create table stu (id int,name string); #创建stu表
create table stu2 like stu; #创建一个和表stu结构一样的stu2表
insert into stu values(1,'zhang'); #向表stu插入数据
select * from stu; #查看表stu数据
desc stu; #查看表stu结构
drop table stu; #删除表stu
create table stu(id int,name string) row format delimited fields terminated by ' '; #创建stu表,并指定分割符 空格
load data local inpath '/opt/software/1.txt' into table stu; #通过加载文件数据到指定的表stu里
insert overwrite table stu1 select * from stu; #把stu表数据插入到stu1表中
insert overwrite local directory '/opt/stu' row format delimited fields terminated by ' ' select * from stu; #将stu表中查询的数据写到本地的/opt/stu目录下
insert overwrite directory '/stu' row format delimited fields terminated by ' ' select * from stu; #将stu表中查询的数据写到HDFS的stu目录下
from stu insert overwrite table stu1 select * insert overwrite table stu2 select *; #将stu表中查询的数据写到stu1以及stu2两张表中
alter table stu rename to stu2; #为表stu重命名为stu2
alter table stu add columns (age int); #为表stu增加一个列字段age,类型为int
exit; #退出Hive

注意点:
1、创建的数据库,实际是在Hadoop的HDFS文件系统里创建一个目录节点,统一存在:/user/hive/warehouse目录下
2、hive里,表示字符串用的是string,不用char和varchar
3、所创建的表,也是HDFS里的一个目录节点
4、HDFS不支持数据的修改和删除,因此已经插入的数据不能够再进行任何的改动
5、insert into 语句执行的实际上是追加操作
6、hive支持查询,行级别的插入。不支持行级别的删除和修改
7、Hive的操作实际是执行一个job任务,调用的是Hadoop的MR
8、插入完数据之后,发现HDFS stu目录节点下多了一个文件,文件里存了插入的数据,因此,hive存储的数据,是通过HDFS的文件来存储的
9、Hive的工作原理实际上就是在管理hdfs上的文件,把文件里数据抽象成二维表结构,然后提供hql语句供程序员查询文件数据
10、like只复制表结构,不复制数据
11、Hive 只适合用来做海量离线数 据统计分析,也就是数据仓库。

hive的数据组织

1、Hive的存储结构包括数据库、表、视图、分区和表数据等。数据库,表,分区等等都对应HDFS上的一个目录。表数据对应HDFS对应目录下的文件
2、Hive中所有的数据都存储在HDFS中,没有专门的数据存储格式,因为Hive是读模式,可支持 TextFile,SequenceFile,RCFile 或者自定义格式等
3、只需要在创建表的时候告诉 Hive 数据中的列分隔符和行分隔符,Hive 就可以解析数据
 Hive 的默认列分隔符:控制符 Ctrl + A,\x01 Hive 的
Hive 的默认行分隔符:换行符 \n
4、Hive 中包含以下数据模型:
 database:在 HDFS 中表现为${hive.metastore.warehouse.dir}目录下一个文件夹
 table:在 HDFS 中表现所属 database 目录下一个文件夹
 external table:与 table 类似,不过其数据存放位置可以指定任意 HDFS 目录路径
 partition:在 HDFS 中表现为 table 目录下的子目录
 bucket:在 HDFS 中表现为同一个表目录或者分区目录下根据某个字段的值进行 hash 散 列之后的多个文件
 view:与传统数据库类似,只读,基于基本表创建
5、Hive 的元数据存储在 RDBMS 中,除元数据外的其它所有数据都基于 HDFS 存储。默认情 况下,Hive 元数据保存在内嵌的 Derby 数据库中,只能允许一个会话连接,只适合简单的 测试。实际生产环境中不适用,为了支持多用户会话,则需要一个独立的元数据库,使用 MySQL 作为元数据库,Hive 内部对 MySQL 提供了很好的支持。
6、Hive 中的表分为内部表、外部表、分区表和 Bucket 表
1)、内部表和外部表
内部表:先在hive里建一张表,然后向这个表插入数据(用insert可以插入数据,也可以通过加载外部文件方式来插入数据),这样的表称之为hive的内部表
外部表:HDFS里已经有数据了,然后,通过hive创建一张表来管理这个文件数据。则这样表称之为外部表。需要注意的是,hive外部表管理的是HDFS里的某一个目录下的文件数据
外部表创建命令:

create external table stu (id int,name string) row format delimited fields terminated by ' ' location '/目录路径';

对于内部表,在删除该表的时候,HDFS对应的目录节点会被删除
对于外部表,在删除该表的时候,HDFS对应的目录节点不会删除
2)、分区表
分区表可以通过添加指定的字段来提高Hive的查询效率,在数据量较大的情况下,往往会添加分区表来避免全表查询
指令:
#创建book表,以category作为分区(在创建分区表时候,partitioned字段可以不在字段列表中)。生成的表自动就会具有该字段

create table book (id int,name String) partitioned by (category String) row format delimited fields terminated by '\t'

#将本地文件cn.txt添加到book表中,分区字段为cn(在HDFS下会生成category=cn目录)

load data local inpath '/home/cn.txt' overwrite into table partition (category='cn')

#查看分区为cn的数据

select * from book where category='cn';

#将指定的目录添加为分区字段

ALTER TABLE book add PARTITION (category = 'jp') location '/user/hive/warehouse/park.db/book/category=jp';

#查看分区

show partitons iteblog

#修复分区

msck repair table book

#删除分区

alter table book drop partition(category='cn')

#修改分区的名字

alter table book partition(category='french') rename to partition (category='hh');

Tips

java8函数式编程

Lambda表达式
首先,在java8之前,如果需要建立一个线程,很大可能会写出下面的代码:

new Thread(new Runnable()) {
	@Override
	public void run() {
		System.out.println("Hello World!");
	}
}).start();

但是Java8引入Lambda之后,也许这样写会更好:

new Thread(
	() -> System.out.println("Hello world!");
);

举例:

String[] atp = {"Rafael Nadal", "Novak Djokovic",  
       "Stanislas Wawrinka",  
       "David Ferrer","Roger Federer",  
       "Andy Murray","Tomas Berdych",  
       "Juan Martin Del Potro"};  
List<String> players =  Arrays.asList(atp);  
  
// 以前的循环方式  
for (String player : players) {  
     System.out.print(player + "; ");  
}
//使用lambda表达式以及函数操作
players.forEach((player) -> System.out.print(player+";"));  
//java8中使用双冒号操作符
players.forEach(System.out::println);

//使用Lambdas排序集合
//原先的方式
String[] players = {"Rafael Nadal", "Novak Djokovic",   
    "Stanislas Wawrinka", "David Ferrer",  
    "Roger Federer", "Andy Murray",  
    "Tomas Berdych", "Juan Martin Del Potro",  
    "Richard Gasquet", "John Isner"};  
   
// 1.1 使用匿名内部类根据 name 排序 players  
Arrays.sort(players, new Comparator<String>() {  
    @Override  
    public int compare(String s1, String s2) {  
        return (s1.compareTo(s2));  
    }  
});  
//使用lambdas
Comparator<String> sortName = (String s1, String s2) -> (s1.compareTo(s2));
Arrays.sort(players,sortByName);
//或者
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));

函数式接口:有且只有一个未实现的方法的接口

使用Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept,这个方法只有输入而无输出。
传统定义:

Consumer c = new Consumer(){
	public void accept(Object o){
		System.out.println(o);
	}
}

java8中,针对函数式编程接口,可以这样定义:

Consumer c = (o) -> {
	System.out.println(o);
}

java函数式接口

1、Consumer
Consumer是一个函数式编程接口;Consumer的意思就是消费,即针对某个东西我们来使用它,因此它包含有一个有输入而无输出的accept接口方法;
除accept方法,它还包含有andThen这个方法;
2、Function
Function也是一个函数式编程接口;它代表的含义是“函数”,而函数经常是有输入输出的,因此它含有一个apply方法,包含一个输入与一个输出;
除apply方法外,它还有compose与andThen及indentity三个方法,其使用见下述示例;
3、Predicate
Predicate为函数式接口,predicate的中文意思是“断定”,即判断的意思,判断某个东西是否满足某种条件; 因此它包含test方法,根据输入值来做逻辑判断,其结果为True或者False。
4、Stream
Stream可以对多个元素进行一系列的操作,也可以支持对某些操作进行并发处理。
Stream对象的创建:
a、创建空的Stream对象

Stream stream = Stream.empty();

b、通过集合类中的stream或者parallelStream方法创建

List<String> list = Arrays.asList("a", "b", "c", "d");
Stream listStream = list.stream();//获取串行的Stream对象
Stream parallelListStream() = list.parallelStream(); //获取并行的Stream对象

c. 通过Stream中的of方法创建:

Stream s = Stream.of("test");
Stream s1 = Stream.of("a", "b", "c", "d");

Stream对象的使用
Stream对象提供多个非常有用的方法,这些方法可以分成两类:
中间操作:将原始的Stream转换成另外一个Stream;如filter返回的是过滤后的Stream。
终端操作:产生的是一个结果或者其它的复合操作;如count或者forEach操作。

//filter使用,用于对Stream中的元素进行过滤,返回一个过滤后的Stream
Stream<String> s = Stream.of("test", "t1", "t2", "teeeee", "aaaa");
//查找所有包含t的元素并进行打印
s.filter(n -> n.contains("t")).forEach(System.out::println);

//map使用元素一对一转换。它接收一个Funcation参数,用其对Stream中的所有元素进行处理,返回的Stream对象中的元素为Function对原元素处理后的结果
//方法定义
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//实际使用
transform(result, list -> list.stream().map(this::apply).collect(Collectors.toList()));

private <T, K> DxpResult<K> transform(DxpResult<T> result, Function<T, K> dataTransform) {
        if (!result.isSuccess()) {
            return DxpResult.error(ErrorCodeEnum.PROCESS_FAILED, result.getMessage());
        }
        return DxpResult.success(dataTransform.apply(result.getData()));
    }
private FolderInfoVO apply(String path) {
        if (StringUtils.isBlank(path)) {
            return new FolderInfoVO("????", "", "");
        }
        path = StringUtils.strip(path, "/");
        int i = path.lastIndexOf('/');
        return new FolderInfoVO(i < 0 ? path : path.substring(i + 1), "/" + path + "/", getParentPath(path));
    }
Arrays.stream(request.getCookies())
                .filter(c -> key.equals(c.getName()))
                .map(Cookie::getValue)
                .findFirst()
                .orElse(null);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值