写点什么

35 | Trie 树:如何实现搜索引擎的搜索关键词提示功能

作者:鲁米
  • 2023-12-13
    北京
  • 本文字数:2481 字

    阅读完需:约 8 分钟

我们今天有讲到,Trie 树应用场合对数据要求比较苛刻,比如字符串的字符集不能太大,前缀重合比较多等。如果现在给你一个很大的字符串集合,比如包含 1 万条记录,如何通过编程量化分析这组字符串集合是否比较适合用 Trie 树解决呢?也就是如何统计字符串的字符集大小,以及前缀重合的程度呢?


量化分析字符串集合是否适合使用 Trie 树可以通过以下步骤:


  1. 统计字符串的字符集大小:

  2. 遍历所有字符串,将每个字符添加到一个集合中。

  3. 集合的大小即为字符集的大小。

  4. 计算前缀重合程度:

  5. 对于每一对字符串,计算它们的最长公共前缀(LCP)。

  6. 计算平均或总的 LCP 长度,以衡量前缀重合的程度。


public class TrieAnalysis {    // 统计字符集大小    private static int calculateCharacterSetSize(Set<String> strings) {        Set<Character> charSet = new HashSet<>();        for (String str : strings) {            for (char c : str.toCharArray()) {                charSet.add(c);            }        }        return charSet.size();    }
// 计算最长公共前缀长度 private static int calculateAverageLCP(Set<String> strings) { int totalLCP = 0; int totalPairs = 0;
for (String str1 : strings) { for (String str2 : strings) { if (!str1.equals(str2)) { int lcp = longestCommonPrefix(str1, str2); totalLCP += lcp; totalPairs++; } } }
return totalPairs > 0 ? totalLCP / totalPairs : 0; }
// 计算两个字符串的最长公共前缀长度 private static int longestCommonPrefix(String str1, String str2) { int minLength = Math.min(str1.length(), str2.length()); int i; for (i = 0; i < minLength; i++) { if (str1.charAt(i) != str2.charAt(i)) { break; } } return i; }
public static void main(String[] args) { Set<String> stringSet = new HashSet<>(); // 添加字符串到集合中 stringSet.add("ABABDABACDABABCABAB"); stringSet.add("ABABCABAB");
int charSetSize = calculateCharacterSetSize(stringSet); int averageLCP = calculateAverageLCP(stringSet);
System.out.println("Character Set Size: " + charSetSize); System.out.println("Average Longest Common Prefix: " + averageLCP); }}
复制代码


我刚讲的思路是针对英文的搜索关键词提示,对于更加复杂的中文来说,词库中的数据又该如何构建成 Trie 树呢?


对于中文文本,构建 Trie 树需要考虑中文字符的特性,因为中文是基于字符而不是单个字母构成的。以下是构建中文 Trie 树的一般步骤:


  1. 分词: 将中文文本进行分词,将文本划分为一个一个的词语。分词是构建中文 Trie 树的第一步,可以使用现有的分词工具(如 jieba 分词)或者一些开源的中文分词库。

  2. 构建 Trie 树: 将分词后的词语插入到 Trie 树中。在 Trie 树中,每个节点代表一个字符,从根节点到叶子节点的路径组成一个词语。在中文 Trie 树中,一个节点可能代表一个字或者一个完整的词。


package com.controller.bootweb.demo.dsa;
import java.util.HashMap;import java.util.Map;
public class ChineseTrieNode { private Map<Character, ChineseTrieNode> children; private boolean isEndOfWord;
public ChineseTrieNode() { this.children = new HashMap<>(); this.isEndOfWord = false; }
public void insert(String word) { ChineseTrieNode current = this; for (char c : word.toCharArray()) { current.children.putIfAbsent(c, new ChineseTrieNode()); current = current.children.get(c); } current.isEndOfWord = true; }
public boolean search(String word) { ChineseTrieNode node = searchNode(word); return node != null && node.isEndOfWord; }
private ChineseTrieNode searchNode(String word) { ChineseTrieNode current = this; for (char c : word.toCharArray()) { if (!current.children.containsKey(c)) { return null; } current = current.children.get(c); } return current; }
public static void main(String[] args) { ChineseTrieNode trie = new ChineseTrieNode(); // 将分词后的词语插入到Trie树中 trie.insert("你好"); trie.insert("中国"); trie.insert("中文");
// 查找词语 System.out.println(trie.search("你好")); // true System.out.println(trie.search("世界")); // false }}
复制代码


如果词库中有很多关键词,在搜索提示的时候,用户输入关键词,作为前缀在 Trie 树中可以匹配的关键词也有很多,如何选择展示哪些内容呢?


  1. 热门关键词: 可以基于关键词的热度或点击量进行排序,展示热门的关键词。这样可以提高用户体验,让用户更容易找到他们可能想要的内容。

  2. 匹配度高的关键词: 对于用户输入的前缀,可以计算每个匹配的关键词与输入的前缀的相似度或匹配度,然后按照匹配度高低进行排序展示。这有助于向用户展示最相关的关键词。

  3. 按照词频排序: 如果有相关的词频信息,可以根据词频对匹配的关键词进行排序,展示高词频的关键词。

  4. 按照权重排序: 为关键词赋予权重,根据权重进行排序。这可以根据业务逻辑和用户行为等因素来确定关键词的权重。

  5. 根据用户历史记录: 如果有用户的历史搜索记录,可以根据用户的搜索习惯和历史记录进行个性化推荐,向用户展示他们可能感兴趣的内容。

用户头像

鲁米

关注

生活黑客35 2019-06-11 加入

起点不重要,迭代很重要,就需要保持充分的开放和积累;而信息越充分,结果越可靠,又要求随时调整、不断逼近真相。

评论

发布
暂无评论
35 | Trie树:如何实现搜索引擎的搜索关键词提示功能_鲁米_InfoQ写作社区