在数字化和互联网迅速发展的今天,短链接已经成为现代网络应用中不可或缺的一部分。短链接不仅能够节省空间,提高用户体验,还能在社交媒体、短信和二维码中方便地进行分享。然而,生成高效且唯一的短链接并非易事。本文将介绍如何结合 MurmurHash
和 Base62
编码,生成高效、短小且唯一的短链接。
1. 短链接的需求背景
短链接的生成技术广泛应用于以下场景:
- 社交媒体:长网址在社交平台上显得冗长和不美观,短链接可以提高可读性和点击率。
- 二维码:短链接更适合嵌入二维码,使得二维码更加简洁。
- 营销和广告:短链接便于跟踪和统计点击数据,有助于分析广告效果。
- 数据存储:生成唯一的短标识符用于数据库中的索引和缓存键值。
2. 什么是 MurmurHash?
MurmurHash
是一种非加密的高效哈希函数,由 Austin Appleby 开发。它主要用于哈希表和数据分布等场景。
2.1 MurmurHash 的特点
- 高性能:MurmurHash 提供了快速的哈希计算,适合大规模数据处理。
- 低碰撞概率:在大量数据的哈希计算中,MurmurHash 具有较低的碰撞概率。
- 一致性:在不同平台和操作系统上,MurmurHash 生成的哈希值是一致的。
2.2 为什么选择 MurmurHash?
在短链接生成中,我们需要一个快速且具有良好分布性的哈希算法。MurmurHash
之所以适合这个任务,主要有以下几个原因:
- 速度:
MurmurHash
设计目标之一就是高效,它能够快速地处理大量数据,适合需要高性能的应用场景。 - 低碰撞率:对于短链接生成来说,我们希望哈希函数能够尽可能地避免碰撞,即不同的输入 URL 尽可能地生成不同的短链接。
MurmurHash
提供了良好的碰撞概率特性,能够满足这一需求。 - 简单性:
MurmurHash
的实现简单,易于集成,减少了复杂度并提高了系统的稳定性。
3. 什么是 Base62 编码?
Base62
编码是一种将数据压缩成更短字符串的编码方式,它使用 62 个字符:0-9、A-Z 和 a-z。Base62 编码广泛用于生成简短、可读性强的标识符。
3.1 Base62 编码的优点
- 短小:相比于十六进制编码,Base62 编码生成的字符串更短。
- 兼容性强:避免了 URL 中可能出现的特殊字符,使得编码后的字符串在 URL 中使用更为可靠。
- 易于阅读:由常见的字符组成,易于用户记忆和分享。
4. 利用 MurmurHash 和 Base62 生成短链接
结合 MurmurHash
和 Base62
编码,可以实现高效的短链接生成。以下是一个简单的实现工具类。
4.1 代码实现
package com.mps.shortLink.project.toolkit;
import cn.hutool.core.lang.hash.MurmurHash;
/**
* HASH 工具类
*/
public class HashUtil {
private static final char[] CHARS = new char[]{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
private static final int SIZE = CHARS.length;
private static String convertDecToBase62(long num) {
if (num == 0) return "0"; // 特殊情况处理:当数字为0时,返回"0"
StringBuilder sb = new StringBuilder();
while (num > 0) {
int i = (int) (num % SIZE); // 计算余数
sb.append(CHARS[i]); // 将余数映射到 Base62 字符
num /= SIZE; // 更新数字
}
return sb.reverse().toString(); // 逆序返回 Base62 编码结果
}
public static String hashToBase62(String str) {
int i = MurmurHash.hash32(str); // 使用 MurmurHash 计算字符串的 32 位哈希值
long num = i < 0 ? Integer.MAX_VALUE - (long) i : i; // 将负数转换为非负数
return convertDecToBase62(num); // 将哈希值转换为 Base62 编码的短链接
}
}
4.2 代码解析
convertDecToBase62
方法详解
-
处理特殊情况:
if (num == 0) return "0";
当
num
为0时,直接返回 “0”。这是为了处理边界情况,确保在所有输入条件下都能返回一个有效的 Base62 编码字符串。 -
计算 Base62 编码:
StringBuilder sb = new StringBuilder(); while (num > 0) { int i = (int) (num % SIZE); sb.append(CHARS[i]); num /= SIZE; }
通过取模运算 (
num % SIZE
) 和除法运算 (num /= SIZE
) 将数字转换为 Base62 编码。余数i
被映射到字符数组CHARS
上,从而生成相应的字符。这个过程反复进行直到num
变为0。 -
返回结果:
return sb.reverse().toString();
由于字符是从最低有效位开始添加的,因此需要将字符串反转,以得到正确的 Base62 编码结果。
hashToBase62
方法详解
-
int i = MurmurHash.hash32(str);
- 使用
MurmurHash.hash32
方法计算输入字符串str
的 32 位哈希值。MurmurHash
提供了高效的哈希计算,这里生成的哈希值是一个整数,可能是负数。
- 使用
-
long num = i < 0 ? Integer.MAX_VALUE - (long) i : i;
- 将哈希值
i
转换为非负数。如果i
是负数,则通过Integer.MAX_VALUE - (long) i
将其映射到正范围内。这一步的目的是确保后续的 Base62 编码操作在非负数上进行。
- 将哈希值
-
return convertDecToBase62(num);
- 调用
convertDecToBase62
方法将非负的哈希值num
转换为 Base62 编码的字符串。convertDecToBase62
方法通过将数字逐步除以 Base62 的基数(62),并将余数映射到字符数组CHARS
,最终生成短链接。
- 调用
4.3 示例使用
public class ShortLinkService {
public String createShortLink(String longUrl) {
return HashUtil.hashToBase62(longUrl);
}
public static void main(String[] args) {
ShortLinkService service = new ShortLinkService();
String shortLink = service.createShortLink("https://www.example.com");
System.out.println("Short link: " + shortLink);
}
}
在这个示例中,我们通过 HashUtil.hashToBase62
方法生成了一个短链接。生成的短链接字符串更短、更易于使用和分享。
4.4 生成短链接的结果
生成的短链接是原始 URL 的哈希值经过 Base62 编码后的结果。例如,将 https://www.example.com
转换为短链接可能得到类似于 aB3kLz
的结果。这个短链接比原始 URL 更短,适合在各种需要短标识符的场景中使用,如社交媒体、二维码和广告追踪等。
4.5 使用场景
- 短链接生成:将长 URL 转换为短链接,方便在社交媒体和二维码中使用。
- 唯一标识符生成:为各种资源生成唯一的短标识符,简化管理和查询。
- 缓存键生成:在分布式缓存系统中生成短小的缓存键,提高效率。
4.6 优势分析
- 高效生成:结合
MurmurHash
的速度和Base62
编码的短小特点,能够快速生成短链接。 - 兼容性强:生成的短链接字符串适合在 URL 和其他需要短标识符的场景中使用。
- 扩展性:可以根据需求调整编码方式或哈希算法,灵活适应不同应用场景。
5. 总结
通过结合使用 MurmurHash
和 Base62
编码,我们可以高效生成短链接,解决长 URL 带来的不便。这种方法不仅适用于 URL 缩短,还可以广泛应用于生成唯一标识符和缓存键等场景。如果你对短链接生成有更深入的需求或遇到问题,欢迎在评论区与我讨论!