这两天改变了关键词库,要求将以前的旧资料包括新闻问答商机等的所有数据的关键词重新匹配生成一遍。
先让老喻做了个功能页出来,生成12条数据大概要30、40秒左右,感觉太慢了,就自己再想想有没有更优的方法。
基本情况是:
总数据大概有300多万,分布在10来个表里。
关键词库约有4万。
关键词库已经存在Cache里了,对性能没什么影响。
- public string[] KeyWordStrs = null;
- /// <summary>
- /// 获取缓存中的关键词组
- /// </summary>
- private void GetKeyWordStrs()
- {
- if (KeyWordStrs != null) { return; }
- if (HttpContext.Current.Cache["keywords"] == null)
- {
- string sql = "Select [Name] From [KeyWords]";
- DataSet dSet1 = GetDataSet(sql);
- if (dSet1 == null || dSet1.Tables.Count <= 0) { return; }
- string[] str = new string[dSet1.Tables[0].Rows.Count];
- for (int i = 0; i < dSet1.Tables[0].Rows.Count; i++)
- {
- str[i] = dSet1.Tables[0].Rows[i][0].ToString();
- }
- dSet1.Dispose();
- dSet1 = null;
- HttpContext.Current.Cache.Insert("keywords",str);
- return;
- }
- KeyWordStrs = (string[])HttpContext.Current.Cache["keywords"];
- }
反复测试,发现最浪费时间的就是每次的4万次匹配。
一开始是用IndexOf方法来验证,从数据表里将记录读出来,每次1000条左右,循环中再从4万个词库里判断是否大于0,组合成关键词组:
- /// <summary>
- /// 返回关键词字符串,不超过100个字符
- /// </summary>
- /// <param name="title">标题</param>
- /// <param name="content">内容</param>
- /// <returns>返回关键词字符串</returns>
- public string GetKeyWords(string title, string content)
- {
- GetKeyWordStrs();
- if (KeyWordStrs == null) { return ""; }
- if (content.Length < 2 && title.Length < 2) { return ""; }
- string keywords = string.Empty;
- //如果标题长度小于2,只匹配内容
- if (title.Length < 2)
- {
- foreach (string s in KeyWordStrs)
- {
- if (content.IndexOf(s) >= 0)
- {
- keywords = keywords + "," + s;
- }
- //如果长度大于99则中止循环
- if (keywords.Length > 99) { break; }
- }
- }
- else
- {
- foreach (string s in KeyWordStrs)
- {
- //如果标题已经匹配
- if (title.IndexOf(s)>= 0)
- {
- keywords = keywords + "," + s;
- }
- //标题未能匹配时再按内容匹配
- else if (content.IndexOf(s)>= 0)
- {
- keywords = keywords + "," + s;
- }
- //如果长度大于99则中止循环
- if (keywords.Length > 99) { break; }
- }
- }
- }
随机取了1 2条数据,总费时34-40秒左右。
这种效果肯定不行,于是自己找了找字符串查找的相关优化方法,GOOGLE和BAIDU也没提到什么,想了一下用正则的试试看看,改了一下代码:
- /// <summary>
- /// 返回关键词字符串,不超过100个字符
- /// </summary>
- /// <param name="title">标题</param>
- /// <param name="content">内容</param>
- /// <returns>返回关键词字符串</returns>
- public string GetKeyWords(string title, string content)
- {
- GetKeyWordStrs();
- if (KeyWordStrs == null) { return ""; }
- if (content.Length < 2 && title.Length < 2) { return ""; }
- string keywords = string.Empty;
- Regex r;
- //如果标题长度小于2,只匹配内容
- if (title.Length < 2)
- {
- foreach (string s in KeyWordStrs)
- {
- //先过滤特殊字符
- r = new Regex(s.Replace(".", @"/.").Replace("(", "").Replace(")", ""));
- if (r.IsMatch(content))
- {
- keywords = keywords + "," + s;
- }
- //如果长度大于99则中止循环
- if (keywords.Length > 99) { break; }
- }
- }
- else
- {
- foreach (string s in KeyWordStrs)
- {
- //先过滤特殊字符
- r = new Regex(s.Replace(".", @"/.").Replace("(", "").Replace(")", ""));
- //如果标题已经匹配
- if (r.IsMatch(title))
- {
- keywords = keywords + "," + s;
- }
- //标题未能匹配时再按内容匹配
- else if (r.IsMatch(content))
- {
- keywords = keywords + "," + s;
- }
- //如果长度大于99则中止循环
- if (keywords.Length > 99) { break; }
- }
- }
- }
有提高了,同样的12条数据花了12秒左右,有了明显的提升呢。
不知道还有没更快的方式呢?
乱找了一下,发现String有个Contains方法,试了一下,时间一下子就缩短到4左右,看来这个效率是最快的了。
- public string GetKeyWords(string title, string content)
- {
- GetKeyWordStrs();
- if (KeyWordStrs == null) { return ""; }
- if (content.Length < 2 && title.Length < 2) { return ""; }
- //如果标题长度小于2,只匹配内容
- if (title.Length < 2)
- {
- foreach (string s in KeyWordStrs)
- {
- //如果标题已经匹配
- if (title.Contains(s))
- {
- keywords = keywords + "," + s;
- }
- //标题未能匹配时再按内容匹配
- else if (content.Contains(s))
- {
- keywords = keywords + "," + s;
- }
- //如果长度大于99则中止循环
- if (keywords.Length > 99) { break; }
- }
- }
- else
- {
- foreach (string s in KeyWordStrs)
- {
- //如果标题已经匹配
- if (title.Contains(s))
- {
- keywords = keywords + "," + s;
- }
- //标题未能匹配时再按内容匹配
- else if (content.Contains(s))
- {
- keywords = keywords + "," + s;
- }
- //如果长度大于99则中止循环
- if (keywords.Length > 99) { break; }
- }
- }
- }
不知道还没有更好的方式来处理呢?