我有一张关键字表:tblKeywords(字段 fldKeyword <varchar>),一共有100-200万条记录。
同时我每天要处理10000封email,要对每一封email做关键字匹配,凡是email的Body中存在tblKeywords表中任意一条fldKeyword记录的字符串值,就算匹配成功,否则不成功。我要做个程序实现上面功能。
我想到的算法是:
1.把关键字表tblKeywords所有记录读到内存变量datatable中
2.对每一封email,遍历内存变量datatable,对当前fldKeyword的字符串值,搜索email的Body,如果有此Keyword,成功,跳出;如果没有此Keyword,继续匹配下一个fldKeyword记录,直到匹配到或匹配完退出。但是这个算法貌似很费时间,2个循环嵌套,最大可能须比较100-200万 * 10000 = 100亿次。请教高手有没有更快速的算法?
谢谢!
在线等!

解决方案 »

  1.   


    我前几天自己测试了一下。一个while循环1秒钟做简单的3次判断, 可以循环300多万次吧,如果对于一100亿级别的数据100/0.03 = 30000秒,所以在我个人电脑上做简单的运算也要8,9个小时。。 所以我向服务器也快不到那里去把
      

  2.   

    http://wenku.baidu.com/view/edb7b30879563c1ec5da710b.html
      

  3.   

    如果email可以断字(比如英文,用空格断字),那就很简单了:把关键词放入一个HashSet或者Dictionary中,然后遍历email中的每个词,判断HastSet中是否存在。如果email不好断字,可以把关键词做成一个"前缀树(Trie,或叫Prefix Tree)",然后对email从头到尾,渐进判断是否可能存在。前缀树介绍见 - http://zh.wikipedia.org/wiki/Trie这里有个简单例子,对100万个关键字(随机2-6个字母),判断一个1万字长的字符串约为毫秒级别。
    class Form1 : Form
    {
        private void button1_Click(object sender, EventArgs e)
        {
            string[] keywords = { "房价畸形", "房奴谁之过?", "生活质量" };
            string text = "沦为房奴谁之过?为房憔悴伤神是何原因";        Trie trie = new Trie();
            foreach (string keyword in keywords) trie.Add(keyword);        string foundKeyword = null;
            for (int i = 0; i < text.Length && foundKeyword == null; i++)
            {
                object token = null;
                for (int j = i; j < text.Length; j++)
                {
                    if (trie.Exist(text[j], ref token))
                    {
                        foundKeyword = text.Substring(i, j - i + 1);
                        MessageBox.Show(foundKeyword);
                        break;
                    }
                    if (token == null) break;
                }
            }
        }
    }public class Trie
    {
        TrieNode root = new TrieNode((char)0);
        public void Add(string word)
        {
            TrieNode node = root;
            foreach (char c in word)
            {
                node = node.AddChild(c);
            }
            node.AddChild((char)0);
        }
        public bool Exist(string word)
        {
            TrieNode node = root;
            foreach (char c in word)
            {
                node = node.GetChild(c);
                if (node == null) return false;
            }
            return node.GetChild((char)0) != null;
        }
        public bool Exist(char c, ref object token)
        {
            TrieNode node = (token as TrieNode ?? this.root).GetChild(c);
            token = node;
            return node !=null && node.Terminated;
        }
        class TrieNode
        {
            private char value;
            private SortedList<char, TrieNode> childNodes = new SortedList<char, TrieNode>();        public TrieNode(char c) 
            { 
                this.value = c; 
            }
            public TrieNode GetChild(char c)
            {
                TrieNode node = null;
                childNodes.TryGetValue(c, out node);
                return node;
            }
            public TrieNode AddChild(char c)
            {
                TrieNode node = GetChild(c);
                if (node == null)
                {
                        this.childNodes.Add(c, node = new TrieNode(c));
                }
                return node;
            }
            public bool Terminated { get { return this.childNodes.ContainsKey((char)0); } } 
        }
    }
      

  4.   


    email是不好断字的。谢谢,gomoku的高手算法!关于前缀树,我还有一个问题,如果我想把email中的所有匹配的关键词都找出来,而不是找到一个就终止,请教您上面的代码该如何修改啊?谢谢!!