在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中。比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它是否在已知的字典中);在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新元素时,将它和集合中的元素直接比较即可。一般来讲,计算机中的集合是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当集合比较小时,这个问题不显著,但是当集合巨大时,哈希表存储效率低的问题就显现出来了。比如说,一个象 Yahoo,Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。如果用哈希表,每存储一亿个 email 地址, 就需要 1.6GB 的内存(用哈希表实现的具体办法是将每一个 email 地址对应成一个八字节的信息指纹
googlechinablog.com/2006/08/blog-post.html,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email 地址需要占用十六个字节。一亿个地址大约要 1.6GB, 即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB 的内存。除非是超级计算机,一般服务器是无法存储的。
今天,我们介绍一种称作布隆过滤器的数学工具,它只需要哈希表 1/8 到 1/4 的大小就能解决同样的问题。
布隆过滤器是由巴顿.布隆于一九七零年提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。我们通过上面的例子来说明起工作原理。
假定我们存储一亿个电子邮件地址,我们先建立一个十六亿二进制(比特),即两亿字节的向量,然后将这十六亿个二进制全部设置为零。对于每一个电子邮件地址 X,我们用八个不同的随机数产生器(F1,F2, ...,F8) 产生八个信息指纹(f1, f2, ..., f8)。再用一个随机数产生器 G 把这八个信息指纹映射到 1 到十六亿中的八个自然数 g1, g2, ...,g8。现在我们把这八个位置的二进制全部设置为一。当我们对这一亿个 email 地址都进行这样的处理后。一个针对这些 email 地址的布隆过滤器就建成了。(见下图)
现在,让我们看看如何用布隆过滤器来检测一个可疑的电子邮件地址 Y 是否在黑名单中。我们用相同的八个随机数产生器(F1, F2, ..., F8)对这个地址产生八个信息指纹 s1,s2,...,s8,然后将这八个指纹对应到布隆过滤器的八个二进制位,分别是 t1,t2,...,t8。如果 Y 在黑名单中,显然,t1,t2,..,t8 对应的八个二进制一定是一。这样在遇到任何在黑名单中的电子邮件地址,我们都能准确地发现。
布隆过滤器决不会漏掉任何一个在黑名单中的可疑地址。但是,它有一条不足之处。也就是它有极小的可能将一个不在黑名单中的电子邮件地址判定为在黑名单中,因为有可能某个好的邮件地址正巧对应个八个都被设置成一的二进制位。好在这种可能性很小。我们把它称为误识概率。在上面的例子中,误识概率在万分之一以下。
布隆过滤器的好处在于快速,省空间。但是有一定的误识别率。常见的补救办法是在建立一个小的白名单,存储那些可能别误判的邮件地址。
posted @
2008-08-31 08:48 雨中漫步的太阳 阅读(79) |
评论 (0) |
编辑
如果数据库字段中含有单引号 这个时候以该字段包含单引号作为查询条件 如 where url like "%'%" 此时数据库会提示如下错误
服务器: 消息 207,级别 16,状态 3,行 1
列名 '%'%' 无效。
我试着使用转义字符 也还是不行 通过翻阅资料发现下面方法可以查询 在此记录下:
首先执行
SET QUOTED_IDENTIFIER OFF
然后再执行比如where url like "%'%" 就可以执行通过了 本操作必须在查询分析器中进行
否则就会报错的
不过还是建议自动中不要存在单引号
posted @
2008-08-25 18:00 雨中漫步的太阳 阅读(94) |
评论 (0) |
编辑
<script language="JavaScript">
function Replace(replaceStr , oldchar , newchar , flag)
{
if(typeof(flag)=="undefined") flag = "g" ;
var re = new RegExp(oldchar,[flag]) ;
return replaceStr.replace(re,newchar);
}
alert(Replace("abcdeAbcdef",'a','777','ig'));
</script>
posted @
2008-08-22 19:55 雨中漫步的太阳 阅读(64) |
评论 (0) |
编辑
DiskFileUpload upload = new DiskFileUpload();
upload.setSizeMax(size);
try{
items = upload.parseRequest(request);
}catch(Exception _ex){
error = "附件太大!";
request.setAttribute("error", error);
return mapping.findForward("failure");
}
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) { //如果是普通表单
if(item.getFieldName().equals("board_id")) {
board_id = item.getString();
}else if(item.getFieldName().equals("TZNR")) {
article_content=item.getString();
}else if(item.getFieldName().equals("artice_title")) {
artice_title=item.getString();
}else if(item.getFieldName().equals("article_id")){
re_artice_id=item.getString();
//System.out.println("re_artice_id="+re_artice_id);
}
} else { //如果是文件域表单
is=item.getInputStream();//获得上传文件的输入流
size=item.getSize();//文件大小
filename=item.getName();
if(!filename.equals("")){
filename=filename.substring(filename.lastIndexOf("\\")+1);
filename_exec = filename.substring(filename.lastIndexOf(".")+1);
}
}
}
posted @
2008-08-18 18:15 雨中漫步的太阳 阅读(57) |
评论 (0) |
编辑
lucene 搜索时候,为增加用户体验一般都会加代码高亮显示, lucene提供了代码高亮显示的插件--highlighter 这个插件相信很多人都用过,所以此处我们不做讨论,我们这里自己写代码实现类似的效果,经过努力俺实现了.
这里我先说说我的思路 最后上代码:
1.首先将搜索结果过滤掉所有的html标签,搜索结果里如果包含标签对于截取字符长度等非常麻烦,甚至会造成你的页面结构混乱,所以索性全部过滤掉.
2.在符合搜索关键字的地方套红 比如 搜索:"博客园,程序员的家园",搜索博客园 套红后的结果就是 "<font color=red>博客园</font>,程序员的家园"
3.对套红后的字符串进行分割得到String[] ,这里要说明下分割的方式 比如 abcd 假如我们用 b作为分割点 则分割后的结果是 string[0] = a ;string[1]= cd
而我这里所说的分割要得到的结果是:string[0] = a ;string[1]= bcd 也就是分割点包含在数组中,这里是关键.
4.将分割的各个段合并得到结果.
以上就是我的思路 怎么? 是不是看到迷迷糊糊啊,呵呵 我的文笔有限啊 可能说的不清楚,我们来套着代码说:
protected String startTag = "<font color=red>";
protected String endTag = "</font>";
这里就是定义套红的方式 我这里不啰嗦了
protected int maxNumFragmentsRequired=40;
protected int maxNumFragmentsRequired=5;
这里定义分割后每段最大长度和最多显示几段,应该能够理解吧
protected String PatternText ="(?=(?:"+startTag+"[\\s\\S]+?"+endTag+")+)";;
这里可是关键哦 呵呵 这个正则的作用就是来分割字符串用的.
public String gettextfragmenter(String input)
{
//最多保留几段
int _maxNumFragmentsRequired = maxNumFragmentsRequired;
String result = "";
Pattern pattern = Pattern.compile(PatternText,Pattern.MULTILINE);
//使用上面定义的正则将文本分割,关键部分
String[] textfragmenter = pattern.split(input);
//如果定义的段数大于分割后的实际段数
if(textfragmenter.length<_maxNumFragmentsRequired)
{
_maxNumFragmentsRequired = textfragmenter.length;
}
//下面一个循环将结果重组成我们需要的结果
for(int i=0;i<_maxNumFragmentsRequired;i++)
{
String str = textfragmenter[i].length()>textFragmenterlegth ? textfragmenter[i].substring(0, textFragmenterlegth)+"
": textfragmenter[i];
result +=str;
}
return result;
}
//doc :document fields:搜索的fieldsname的集合 words:搜索的关键词集合
public Document highlighter(Document doc,String[] fields,String[] words)
{
if(words!=null)
{
String deleteTag = endTag + startTag;
String[] hlwords = new String[words.length];
for(int i=0;i<words.length;i++)
{
hlwords[i] = startTag + words[i] + endTag;
}
for(String field : fields)
{
int j=0;
Field fField = doc.getField(field);
//这里就是我说的替换掉所有的html标签
String value = fField.stringValue().replaceAll("<[^>]+>|&[^;]+;","");
for(int i=0;i<words.length;i++)
{
if(value != null && value.length() > words[i].length()) {
value = value.replaceAll(words[i],hlwords[i]);
j++;
}
}
if(j > 0) {
if(j > 1) value = value.replaceAll(deleteTag, "");
//调用我说 的分割重组方法
value = gettextfragmenter(value);
fField.setValue(value);
}
}
}
return doc;
}
public String gettextfragmenter(String input)
{
int _maxNumFragmentsRequired = maxNumFragmentsRequired;
String result = "";
Pattern pattern = Pattern.compile(PatternText,Pattern.MULTILINE);
String[] textfragmenter = pattern.split(input);
if(textfragmenter.length<_maxNumFragmentsRequired)
{
_maxNumFragmentsRequired = textfragmenter.length;
}
for(int i=0;i<_maxNumFragmentsRequired;i++)
{
String str = textfragmenter[i].length()>textFragmenterlegth ? textfragmenter[i].substring(0, textFragmenterlegth)+"
": textfragmenter[i];
result +=str;
}
return result;
}
public Document highlighter(Document doc,String[] fields,String[] words)
{
if(words!=null)
{
String deleteTag = endTag + startTag;
String[] hlwords = new String[words.length];
for(int i=0;i<words.length;i++)
{
hlwords[i] = startTag + words[i] + endTag;
}
for(String field : fields)
{
int j=0;
Field fField = doc.getField(field);
String value = fField.stringValue().replaceAll("<[^>]+>|&[^;]+;","");
for(int i=0;i<words.length;i++)
{
if(value != null && value.length() > words[i].length()) {
value = value.replaceAll(words[i],hlwords[i]);
j++;
}
}
if(j > 0) {
if(j > 1) value = value.replaceAll(deleteTag, "");
value = gettextfragmenter(value);
fField.setValue(value);
}
}
}
return doc;
}
OK 就是这样了 我认为需要加注释的地方,我也都加了注释了.怎么样这样实现是不是很简单呢,比起 highlighter 来说仅仅两个方法搞定,呵呵自己动手丰衣足食啊
当然我没有测试这样做的性能上会比highlighter快或者慢,因为时间紧迫呵呵 如果哪个兄台测试了麻烦告诉我一声.
下面看看我用的搜索结果的截图:

一个四个省略号哦.
有些朋友仅仅使用了套红也就是仅仅replaceall 那样会造成假如你的文本太长 你想substr的时候,很可能你的套红根本没有显示出来 原因很简单 被你cut掉了 呵呵 而这个就不会,可以避免上述情况.
ok 就到这里了
protected static final String HL_FORMATER_START_TAG_DEFAAULT = "<font color=red>";
protected static final String HL_FORMATER_END_TAG_DEFAAULT = "</font>";
posted @
2008-07-30 21:11 雨中漫步的太阳 阅读(1208) |
评论 (8) |
编辑
摘要: 很多时候我们的应用程序或者web程序需要用到xml文件进行配置,而最终的程序是需要给客户使用的,所以xml或者也需要客户来写,而客户来写的话的,就不能保证xml文件绝对的正确,于是我写了这个类,主要功能就是验证xml书写文件是否符合定义的xsd规范.[代码]类的使用方法如下:[代码]xsd文件定义如下:[代码]被验证的xml 实例如下:[代码]这个是java版本的类,C# 的类文件如下(是一个老美...
阅读全文
posted @
2008-07-25 17:45 雨中漫步的太阳 阅读(110) |
评论 (0) |
编辑
最近再看servlet ,我们经常会继承 HttpServlet ,而HttpServlet 中要求我们必须实现下面几个方法,看api的介绍
doget ,dopost ,doput,dodelete 这些get post 我们肯定不会觉得陌生,而后面的两个,我记得我在IIS中配置的时候见过,突然想到有一次面试的时候,人家问我:我们网页的请求都有哪些? 网页请求,其实就是http请求了,我当时之说了 get 和post ,其他的就不知道了,今天看到这里,突然觉得应该是补一补这个方面的知识了,百度google了一通,发现介绍此类知识的资料很少,后来在csdn中发现了下面的文章, 才知道原来有这么多的请求方式,呵呵,如果你也不清楚就好好看看哦
posted @
2008-07-24 10:52 雨中漫步的太阳 阅读(71) |
评论 (0) |
编辑
OK 简单的说明下,目前使用.net 连接Oracle的数据时候,总是提示需要Oracle的客户端的支持,而一个Oracle客户端压缩格式至少450M 如此庞大的安装程序在我们部署项目的时候非常的不方便. 通过网上看到有朋友提取了最精简的Oracle的客户端,但是需要配置注册表和环境变量, 感觉比较麻烦.
于是我做了这个安装程序,使用非常的方便,安装程序仅32M 携带方便,傻瓜式安装,自动完成注册表环境变量的配置.
好了废话就不多说了 直接给下载地址
点此下载 下载提取码 : 778a58ae
下载地址2 下载提取码 0692369831170687
如果有什么问题 可以发邮件 suyuan19 # qq.com
posted @
2008-07-19 22:10 雨中漫步的太阳 阅读(1647) |
评论 (31) |
编辑
这个是一个js的考题,我刚开始接触到这个题的时候第一想法是用数组,然后将数组排序 下面是我的代码,前提是字符串已经被我按照一定顺序排列好了
function check()


{ if(newstr.length>0)


{ tempstr = newstr.charAt(0);
tempnum=nextstart = newstr.lastIndexOf(tempstr)+1;
if(nextstart<newstr.length)


{ maxstr = newstr.charAt(nextstart);
maxnum = newstr.lastIndexOf(maxstr)+1-nextstart;
if(tempnum>maxnum)


{ maxnum = tempnum; maxstr = tempstr; }
newstr=newstr.substr(nextstart);
check();
}
}
}
当然这个代码没有调通就被我放弃了 ,感觉太繁琐了.放到这里只是为了说明下我的思路.
其次我还想到一个方法就是用 Dictionary 对象 ,但是对这个对象不是很熟悉,所以刚开始并没有想用这个,不过当发现上面的路走不通的时候,就决定用这个来搞了.通过查阅api,发现并不是很复杂,下面直接上代码:
var str = "abkfjdskfjdskafdsjhfjA9aaaaaaaaaaaaaaaaa";
var dir = new ActiveXObject("Scripting.Dictionary");
for(i=0;i<str.length;i++)

{
tmp = str.charAt(i);
if(!dir.Exists(tmp))

{
dir.add(tmp, 1);


}else
{
num = dir.Item(tmp)+1;
dir.Remove(tmp);
dir.add(tmp,num);
}
}
a = (new VBArray(dir.Keys()));
maxstr ="";
maxnum =0;
for (i = 0; i < dir.Count; i++)

{
if(dir(a.getItem(i)) > maxnum)

{
maxnum = dir(a.getItem(i));
maxstr = a.getItem(i);
}
else
if(dir(a.getItem(i)) == maxnum)

{
maxstr =maxstr +" and "+ a.getItem(i);
}
}
alert(maxstr+":"+maxnum);
这个看起来是不是清晰的多了 呵呵,只是我是这么认为的.同时这个问题被我发到群里讨论,群里兄弟给出了另外一个代码,也是使用数组排序的方式,不同的是他用的正则,以下是他的代码

function clac()
{
var dest_char;
var index = -1;

var str = "abkfjdskfjdskafdsjhfjA9";
var arr = str.split("");
arr.sort();
str = arr.join("").toString();

str.replace(/(\w)(\1)+/g,function($0,$1,$2)
{

if($0.length > index)
{
index = $0.length;
dest_char = $1;
}
})

alert("dest_char:"+dest_char + "\n" + "index: " + index);
}
clac();
这个代码给我的感觉就是简洁,的确写的很漂亮 这个不由让我想到上一篇博文中我也提到正则能给我们省很多事情,让我们的程序更加简洁.以后要多学习正则啊 呵呵
群里还有一个朋友给出了他的代码
代码如下:
function showMax(str)


{
var temp = str;
var curNum = 0;
var curLetter = "";
while (temp != "")


{
var tempLetter = temp.substring(0,1);
var tempNum = str.split(tempLetter).length;
if(tempNum > curNum) // 未判断相等时


{
curNum = tempNum;
curLetter = tempLetter;
}
temp = temp.substring(1);
}
alert("CurLetter:" + curLetter + " CurNum:" + curNum);

}
这个代码在这里str.split(tempLetter).length;会出现问题,但是我这里说的是思路,他的这个是另外一种思路.
OK就总结到这里吧.
还有一个在这里贴一下,以后警示自己不要犯类似的错误:
var i=0,j=0,k=0;
for(i=0;i<6,j<10;i++,j++)

{
k = i+j;
//alert("i"+i);
//alert("j"+j);
}
alert(k);

一直以为for循环中i<6,j<10 是并且的关系,才知道原来是或者的关系,你知道么?呵呵
posted @
2008-07-11 19:11 雨中漫步的太阳 阅读(1289) |
评论 (8) |
编辑
问题:客户输入1000,自动就分1,000,边输入边分割.
边输入变分割好办 直接使用onkeyup 触发我们的function就可以了,分割比较麻烦
我写的代码如下:
<script language="JavaScript">
function toFormant(obj)
{
var numstr = obj.value;
var num =numstr.replace(/,| /g,"");
if(num.length>1)
{
num = num.replace(/\b[0*]/g,"");
}
if(!num.match(/[^0-9]/g))
{
//alert(num);
var a = new Array();
if(num.length>3)
{
for(i=num.length;i>0;i=i-3)
{
a.push(num.substring(i-3,i));
}
obj.value=a.reverse().join(",");
}
else
{
obj.value = num.replace(/,/g,"");
}
}
else
{
alert("NOT A No.");
}
}
</script>
论坛里面的一个大牛的代码如下:
<script language="javascript">
function show(obj)
{
obj.value=obj.value.replace(/,/g,"")
if(/^[1-9]\d*$/.test(obj.value))
obj.value = obj.value.replace(/(?=(?!\b)(?:\d{3})+(?!\d))/g,',');
}
</script>
哎,还是很有差距的啊,继续努力吧,记录+自勉下
posted @
2008-07-09 16:25 雨中漫步的太阳 阅读(24) |
评论 (0) |
编辑
这几天一直在看公司分配的工作及项目代码,我负责的工作主要是对lucene api的进一步封装,使其在日后的使用更加的快捷方便. 代码是技术总监写好的一部分,交由我来管理优化.主要实现的目的是通过配置文件(xml) 快速的将lucene应用到项目中,要做的仅仅是一些配置文件和数据的获取工作,数据主要是通过数据库来获取,使用ibatis作用orm框架.
今天上网翻阅资料,发现了compass, 发现这个开源的lucene框架几乎将我的需要完全的封装到了一起,只是对于我来说他似乎有点臃肿,呵呵 提供了hibernate ibatis 等orm接口,包括jdbc数据接口 甚至还包括了spring 接口 把我的工作基本上全部都做了,下一步研究这个框架,结合目前正在做的项目整合整合......消化掉 呵呵
目前版本是2.0,整个项目 包括demo,doc 一共57M多 呵呵 是不是比较庞大啊
网站 http://www.compass-project.org/
posted @
2008-05-29 22:05 雨中漫步的太阳 阅读(118) |
评论 (0) |
编辑
摘要: <html><head><metahttp-equiv="Content-Type"content="text/html;charset=GB2312"/><scriptlanguage="JavaScript"><!--/**//*作者:梅雪香日期:2006-7-29功能:生成与中文字符串相对映的拼音首字母串版本:V1.0alpha*///汉...
阅读全文
posted @
2008-05-28 15:07 雨中漫步的太阳 阅读(81) |
评论 (0) |
编辑
使用lucene,首先要做的就是建立索引文件,这是一个非常耗时的工作,特别是针对大数据量进行索引的时候更是如此.
Lucene 提供了几个优化参数
mergeFactor,maxMergeDocs,minMergeDocs,首先说的是mergeFactor, 默认值为10,控制索引段的合并频率和大小,即每当有10个Document对象添加到索引段时,lucene就会在磁盘建立一个新的段,当创建了10个这样的段之后就会将这10个段合并为一个段,以此类推下去,当这个段内的Document对象数量没有超过maxMergeDocs的值的时候,会一直按照这个规则合并下去,同时磁盘目录内的索引段数量控制在10个以内.
当制定了较小的mergeFactor时,也就意味着将进行大量的磁盘操作,但是带来的好处是生成较少个数的索引文件.于是矛盾就产生了
mergeFactor较小 则制作索引文件非常慢,但是搜索相对会快.
我们如何来解决这样的矛盾呢? 我提出如下的解决方案,并且已经在我们项目中使用了这样的方式.
我先说明下我们的需求.
我们是将数据库中的内容制作成索引文件并提供搜索,数据库中有上百万的数据,制作一次索引大概需要1个半小时时间(数据库和索引制作程序在一个机器上)
好了,不废话了,说我们的方式
lucene 提供了FsDirectory和RamDirectory两种方式,这里我们首先使用RamDirectory,也就是说我们在内存中创建索引文件,存储的Document个数根据你内存而定了,这样不管mergefactor 指定多少,索引段合并多少次,都是在内存中操作了,减少了IO操作, 当Document的个数比如大于5000时 将RamDirectory 中的内容合并到FsDirectory中,通过fsDirectory.addIndexes(Directory[] {RamDirectory});实现.
这样也就意味着每添加5000个Document 才进行了一次IO操作,而假如把mergeFactor设置为5000的话,带来的问题就是,假如你的数据量足够大,而使你产生更多的索引段.
以上就是我的方式,希望有更好的方式可以交流
posted @
2008-05-21 18:36 雨中漫步的太阳 阅读(241) |
评论 (4) |
编辑
首先,在安装ORACLE服务器的机器上搜索下列文件,
oci.dll
ocijdbc10.dll
ociw32.dll
orannzsbb10.dll
oraocci10.dll
oraociei10.dll
sqlnet.ora
tnsnames.ora
classes12.jar
ojdbc14.jar
制作成压缩文件,配置目标计算机使用。
1.将oracleinstantclient.rar解压缩到一个目录, 如d:\oracleinstantclient
2.配置d:\oracleinstantclient的tnsnames.ora文件,只需要修改其中的服务器地址、服务名称和端口。
3、配置环境变量,在PATH变量中加入d:\oracleinstantclient
4、注册表加入下面键值
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment]
"LD_LIBRARY_PATH"="d:\OracleInstantClient"
"NLS_LANG"="AMERICAN_AMERICA.ZHS16GBK"
"TNS_ADMIN"="d:\OracleInstantClient"
5、如果是ASP.NET应用,则要为ASPNET用户分配d:\oracleinstantclient文件夹的读写权限。
通过上面的设置后,即可实现免安装ORACLE客户端,连接到ORACLE数据库服务器。
也可以将上面解压缩后的文件和手动过程制作成安装包,实现自动安装。
注意:
1、用上面的方法,连接oracle9.2,应该也没有问题。
2、如果使用JDBC连接,需要到官网下载instantclient-jdbc-win32-10.1.0.2.zip: 包含JDBC Driver的包
posted @
2008-05-21 09:02 雨中漫步的太阳 阅读(149) |
评论 (0) |
编辑
有时候需要修改path系统环境变量, 不多说,代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;//注册表操作要引用的空间
using System.Runtime.InteropServices;//调用API函数需要的引用,来加载非托管类user32.dll


namespace 用程序修改环境变量


{
public partial class Form1 : Form

{