Skip to content

Commit

Permalink
使用字典前缀树来实现快速主题匹配
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Mar 18, 2024
1 parent b34e3a3 commit 42ea4f6
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
56 changes: 56 additions & 0 deletions NewLife.MQTT/Models/SubscriptionManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
namespace NewLife.MQTT.Models;

/// <summary>使用哈希表存储订阅者信息</summary>
/// <remarks>
/// <code>
/// Trie trie = new Trie();
/// SubscriptionManager manager = new SubscriptionManager();
///
/// // 订阅者订阅主题
/// manager.Subscribe("sports/football", "subscriber1");
/// manager.Subscribe("sports/basketball", "subscriber2");
/// manager.Subscribe("news", "subscriber3");
///
/// // 插入订阅主题到前缀树
/// trie.Insert("sports/football", "subscriber1");
/// trie.Insert("sports/basketball", "subscriber2");
/// trie.Insert("news", "subscriber3");
/// // 匹配发布消息
/// List<string> matchedSubscribers = manager.MatchSubscribers("sports/football/match");
/// Console.WriteLine("Matched subscribers: " + string.Join(", ", matchedSubscribers));
/// // 使用前缀树匹配
/// List<string> matchedSubscribersTrie = trie.Match("sports/football/match");
/// Console.WriteLine("Matched subscribers using Trie: " + string.Join(", ", matchedSubscribersTrie));
/// </code>

Check warning on line 24 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'End tag 'code' does not match the start tag 'string'.'

Check warning on line 24 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'End tag 'code' does not match the start tag 'string'.'

Check warning on line 24 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'End tag 'code' does not match the start tag 'string'.'
/// </remarks>

Check warning on line 25 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'End tag 'remarks' does not match the start tag 'string'.'

Check warning on line 25 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'End tag 'remarks' does not match the start tag 'string'.'

Check warning on line 25 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'End tag 'remarks' does not match the start tag 'string'.'
public class SubscriptionManager

Check warning on line 26 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'Expected an end tag for element 'code'.'

Check warning on line 26 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'Expected an end tag for element 'remarks'.'

Check warning on line 26 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'Expected an end tag for element 'code'.'

Check warning on line 26 in NewLife.MQTT/Models/SubscriptionManager.cs

View workflow job for this annotation

GitHub Actions / build-publish

XML comment has badly formed XML -- 'Expected an end tag for element 'remarks'.'
{
private readonly Dictionary<String, List<String>> subscriptions;

public SubscriptionManager() => subscriptions = [];

// 订阅主题
public void Subscribe(String topic, String subscriber)
{
if (!subscriptions.ContainsKey(topic))
{
subscriptions[topic] = [];
}
subscriptions[topic].Add(subscriber);
}

// 发布消息匹配订阅者
public List<String> MatchSubscribers(String topic)
{
List<String> matchedSubscribers = [];
foreach (var kvp in subscriptions)
{
// 可以根据实际需求修改匹配逻辑
if (topic.StartsWith(kvp.Key))
{
matchedSubscribers.AddRange(kvp.Value);
}
}
return matchedSubscribers;
}
}
51 changes: 51 additions & 0 deletions NewLife.MQTT/Models/Trie.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
namespace NewLife.MQTT.Models;

/// <summary>前缀树</summary>
/// <remarks>
/// 当涉及到在海量订阅主题中快速匹配当前发布消息的订阅者时,可以使用基于哈希表和前缀树(Trie)的算法来实现。以下是一个简单的算法示例:
/// 1,构建前缀树(Trie):将所有订阅主题按照层级拆分,构建前缀树,每个节点代表一个主题层级,每个节点的子节点代表下一级主题层级,直到叶子节点代表完整的订阅主题。
/// 2,哈希表存储订阅者信息:使用哈希表来存储每个订阅主题对应的订阅者列表,键为订阅主题,值为订阅者列表。
/// 3,匹配发布消息:当有新的发布消息时,将消息的主题按照层级拆分,然后在前缀树中进行匹配,找到所有匹配的订阅主题。
/// 4,查找订阅者:根据匹配的订阅主题,在哈希表中查找对应的订阅者列表,即为当前发布消息相匹配的订阅者。
///
/// 这种算法利用了前缀树的高效匹配能力和哈希表的快速查找特性,能够快速地匹配发布消息和订阅者,提高系统的性能和响应速度。
/// 同时,可以通过优化前缀树的构建和查询算法,以及哈希表的存储和查找方式来进一步提高匹配的速度。
/// </remarks>
public class Trie
{
private readonly TrieNode root;

public Trie() => root = new TrieNode();

// 插入订阅主题
public void Insert(String topic, String subscriber)
{
var node = root;
foreach (var c in topic)
{
if (!node.Children.ContainsKey(c))
{
node.Children[c] = new TrieNode();
}
node = node.Children[c];
node.Subscribers.Add(subscriber);
}
}

// 匹配订阅主题
public List<String> Match(String topic)
{
var node = root;
foreach (var c in topic)
{
// 没有匹配的订阅者
if (!node.Children.ContainsKey(c))
return [];

node = node.Children[c];
}

// 返回匹配的订阅者
return node.Subscribers;
}
}
15 changes: 15 additions & 0 deletions NewLife.MQTT/Models/TrieNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NewLife.MQTT.Models;

/// <summary>前缀树节点</summary>
public class TrieNode
{
public Dictionary<Char, TrieNode> Children { get; set; } = [];

public List<String> Subscribers { get; set; } = [];
}

0 comments on commit 42ea4f6

Please sign in to comment.