• 数据开发工程师-面试题


    1、数据仓库的结构?

    数据仓库是一个用于存储、管理和分析大规模数据的集中式数据存储系统。它的结构通常包括以下主要组件和层次。

    • 数据源:数据仓库的数据源包括各种不同的数据系统,如关系数据库、日志文件、外部API、云存储等。数据从这些源头采集、抽取、转换和加载到数据仓库种。
    • 数据抽取:在这个阶段,数据从各个数据源中提取出来,以备后续处理。抽取的数据可能包括原始数据、历史数据、事务数据等。
    • 数据转换:在数据仓库中,数据通常需要经过清洗、转换和整合,以满足分析和报告需求。数据转换的任务包括数据清洗、字段映射、数据合并、计算指标等。
    • 数据加载:转换后的数据被加载到数据仓库中的不同层次,通常包括原始数据存储、中间数据存储和数据仓库数据存储。数据加载过程可以是批处理或实时流处理。
    • 数据存储层次:数据仓库包括多个存储层次,其中包括①原始数据存储,保留未经处理的原始数据,以备不同的分析需求;②数据仓库存储,包含已经经过清洗、转换和整合的数据,用于执行高级分析和报告。③数据汇总存储:包含已经汇总和预计算的数据,用于提高查询性能和执行复杂的分析任务。
    • 元数据管理:数据仓库需要维护元数据,以描述存储在其中的数据的结构、来源、定义、变换规则等信息。元数据对于数据仓库的管理和查询优化非常重要。
    • 数据访问层:数据仓库提供不同的方式供用户和应用程序访问数据,包括SQL查询、OLAP(在线分析处理)工具、报告工具和API等。
    • 查询和分析工具:数据仓库通常于各种查询和分析工具集成,以支持用户进行数据探索、查询和报告。
    • 安全性和权限控制:数据仓库需要实施严格的安全行和权限控制,以确保只有经过授权的用户可以访问和操作数据。
    • 监控和性能优化:数据仓库需要实时监控,以确保性能和可用性。性能优化是一个持续的过程,包括索引、分区、缓存等技术。

    2、python-逆序对取模

    逆序对取模通常需要使用归并排序算法。逆序对在一个数组中,如果一个数比其后面的数大,则称这两个数构成一个逆序对。

    1. def merge_sort(arr, mod):
    2. if len(arr) > 1:
    3. mid = len(arr) // 2
    4. left_half = arr[:mid]
    5. right_half = arr[mid:]
    6. left_half, left_inv_count = merge_sort(left_half, mod)
    7. right_half, right_inv_count = merge_sort(right_half, mod)
    8. merged_arr, split_inv_count = merge(left_half, right_half, mod)
    9. inv_count = left_inv_count + right_inv_count + split_inv_count
    10. return merged_arr, inv_count
    11. else:
    12. return arr, 0
    13. def merge(left, right, mod):
    14. merged_arr = []
    15. inv_count = 0
    16. i = j = 0
    17. while i < len(left) and j < len(right):
    18. if left[i] <= right[j]:
    19. merged_arr.append(left[i])
    20. i += 1
    21. else:
    22. merged_arr.append(right[j])
    23. j += 1
    24. inv_count += len(left) - i
    25. merged_arr.extend(left[i:])
    26. merged_arr.extend(right[j:])
    27. return merged_arr, inv_count
    28. def count_inverse_pairs(arr, mod):
    29. _, inv_count = merge_sort(arr, mod)
    30. return inv_count % mod
    31. # 示例用法
    32. arr = [2, 4, 1, 3, 5]
    33. mod = 1000000007
    34. result = count_inverse_pairs(arr, mod)
    35. print("逆序对数取模结果:", result)

    3、Python-合并两个已排序的数组

    方法:使用双指针的方法,遍历两个输入数组,逐个比较元素,将较小的元素添加到新数组中。

    1. def merge_sorted_arrays(arr1, arr2):
    2. merged_arr = []
    3. i = j = 0
    4. while i < len(arr1) and j < len(arr2):
    5. if arr1[i] < arr2[j]:
    6. merged_arr.append(arr1[i])
    7. i += 1
    8. else:
    9. merged_arr.append(arr2[j])
    10. j += 1
    11. # 将剩余的元素添加到新数组中
    12. while i < len(arr1):
    13. merged_arr.append(arr1[i])
    14. i += 1
    15. while j < len(arr2):
    16. merged_arr.append(arr2[j])
    17. j += 1
    18. return merged_arr
    19. # 示例用法
    20. arr1 = [1, 3, 5, 7]
    21. arr2 = [2, 4, 6, 8]
    22. result = merge_sorted_arrays(arr1, arr2)
    23. print("合并后的已排序数组:", result)

    4、Spark和Hadoop是大数据处理领域的两个重要框架,它们有一些异同点。

    相同点:

    • 都为开源框架,可以免费使用和修改。
    • 两者都旨在处理大规模数据,采用分布式计算模型,能够在多台计算节点上并行执行任务。
    • 容错性:两者都具备容错性,能够处理节点故障,并保证任务的完成。
    • 支持多种数据源:两者都可以处理不同的数据源,包括结构化数据(如关系型数据)、半结构化数据(XML,JSON)和非结构化数据(文本、日志等)
    • 支持多种编程语言:包括Java、Python、Scala等,使开发者可以使用他们熟悉的语言进行大数据处理。

    不同点:

    • 数据处理模型:①Hadoop使用MapReduce模型,这是一种批处理模型,适用于离线的数据处理。MapReduce任务通常需要将数据写入磁盘中间存储,因此对于迭代算法或实时处理来说效率较低。②spark使用基于内存的计算模型,可以更高效地进行迭代处理和实时处理,因为它可以将中间数据存储在内存中。
    • 性能:①Spark通常比Hadoop的Mapreduce更快,尤其在迭代算法(如机器学习)和实时数据处理方面。这是因为spark充分利用了内存计算,减少了磁盘IO。②Hadoop的MapReduce更适合一次性、批处理式的任务。
    • API和生态系统:①Spark提供了更多的高级API,包括支持SQL查询的Spark SQL、机器学习库MLib、图处理库GraphX等,使得开发更加方便。②Hadoop生态系统包括Hive(支持SQL查询、pig(数据流脚本语言)、HBase(NoSQL数据库)等,但需要更多的工具和库来实现类似的功能。
    • 复杂度:①Spark通常更容易使用,因为它提供了高级API和更友好的编程模型。②Hadoop的MapReduce需要更多的手工编码和配置。
    • 资源管理器:①Hadoop使用YARN(Yet Another Resource Negotiator)作为资源管理器,负责分配集群资源给不同的任务。②Spark自带了一个资源管理器,称为Cluster Manager,也可以与YARN和Mesos等外部资源管理器集成。

    5、Java-二分查找

    1. public int search(int[] nums, int left, int right, int target) {
    2. while (left <= right){
    3. int mid = left + (right - left) / 2;
    4. if (nums[mid] == target){
    5. return mid;
    6. }else if (nums[mid]< target){
    7. return search(num, mid + 1, right, target);
    8. }else{
    9. return search(num, left, mid - 1, target);
    10. }
    11. }
    12. return -1;
    13. }

    6、Java-双指针

    递增数组,判断数组中是否存在两个数之和为target,思路为双指针,一个begin,一个end,每次移动一个指针

    1. public int[] twoSum(int[] numbers, int target) {
    2. int p1 = 0;
    3. int p2 = numbers.length - 1;
    4. while (p1 < p2){
    5. int sum = numbers[p1] + numbers[p2];
    6. if (sum == target){
    7. return new int[]{p1 + 1, p2 + 1};
    8. } else if (sum < target){
    9. p1++;
    10. } else {
    11. p2--;
    12. }
    13. }
    14. //无解
    15. return new int[]{-1, -1};
    16. }

    7、Java-最长递增子序列LIS(动态规划)

     给一个整数数组nums,找到其中最长严格递增子序列的长度。最优时间复杂度为O(nlogn)

    1. public int lengthOfLIS(int[] nums) {
    2. int dp[] = new int[nums.length];
    3. dp[0] = 1;
    4. int maxSeqLen = 1;
    5. for (int i=1; i
    6. //初始化为1
    7. dp[i] = 1;
    8. for (int j = 0; j <= i; j++) {
    9. //对dp[i]进行更新,严格递增
    10. if (nums[i] > nums[j]){
    11. dp[i] = Math.max(dp[i], dp[j]+1);
    12. }
    13. }
    14. maxSeqLen = Math.max(maxSeqLen, dp[i]);
    15. }
    16. return maxSeqLen;
    17. }

    8、逆序链表两数求和

    给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

    1. /**
    2. * Definition for singly-linked list.
    3. * public class ListNode {
    4. * int val;
    5. * ListNode next;
    6. * ListNode(int x) { val = x; }
    7. * }
    8. */
    9. class Solution {
    10. public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    11. ListNode pre = new ListNode(0);
    12. ListNode cur = pre;
    13. int carry = 0;
    14. while(l1 != null || l2 != null) {
    15. int x = l1 == null ? 0 : l1.val;
    16. int y = l2 == null ? 0 : l2.val;
    17. int sum = x + y + carry;
    18. carry = sum / 10;
    19. sum = sum % 10;
    20. cur.next = new ListNode(sum);
    21. cur = cur.next;
    22. if(l1 != null)
    23. l1 = l1.next;
    24. if(l2 != null)
    25. l2 = l2.next;
    26. }
    27. if(carry == 1) {
    28. cur.next = new ListNode(carry);
    29. }
    30. return pre.next;
    31. }
    32. }

    9、Mysql的三范式

    • 第一范式(1NF):数据表中的每一列都包含不可再分的原子数据,也就是每个单元格中只能存储一个值。所有的数据必须是原子的,不能包含集合、数组、嵌套表格等非原子数据。

    • 第二范式(2NF):数据表必须符合第一范式(1NF)。所有非主键列(非关键字列)都必须完全依赖于候选键(主键)。 这意味着没有部分依赖,即表中的每一列都应该与主键有关系,而不是只与主键的一部分有关。

    • 第三范式(3NF):数据表必须符合第二范式(2NF)。所有非主键列都不应该传递依赖于主键。换句话说,非主键列之间不应该存在传递依赖关系。如果一个非主键列依赖于另一个非主键列,而后者又依赖于主键,那么就存在传递依赖,这需要通过分解表来消除。非主键都和主键直接相关,不存在间接相关。

    10、Mysql的InnoDB和MyIsam的区别

    • InnoDB支持事务,MyISAM不支持事务。
    • InnoDB支持外键
    • InnoDB是聚集索引,MyISAM是非聚集索引
    • InnoDB不支持具体的行数;InnoDB的最小锁的粒度是行锁,MyISAM的最小粒度是表锁。

    11、MySQL的隔离级别

    • 未提交读:即未提交也读,事务中间也可以读,容易产生脏读、幻读、不可重复读。
    • 已提交读:只有在事务提交后才可以读,避免了脏读,但是无法避免不可重复读、幻读。
    • 可重复读:在事务提交的时候,不可以读和修改数据,避免了脏读和不可重复读。
    • 串行读:隔离级别最高,所有的事务都是串行化执行,避免了脏读、幻读和不可重复读。

  • 相关阅读:
    Debian 11 更新 Node.js 版本
    华为中兴FPGA面试题总结
    【送面试题】深入理解Netty与NIO:原理与关键组件解析
    算法补天系列之有序表的四种实现方式——AVL树,SB树,红黑树,跳表(重点)介绍说明
    千兆以太网(一)——RGMII与GMII接口
    操作系统之信号量机制
    ThreadLocal
    堆排序算法---C语言实现(超详细解析!!!!)
    DRF 学习
    【ICE】2:基于webrtc的 ice session设计及实现
  • 原文地址:https://blog.csdn.net/qq_43687860/article/details/133217780