2011年2月17日
摘要: Reactor 模式的 JAVA NIO 多线程服务器,这是比较完善的一版了。Java 的 NIO 网络模型实在是不好用,还是使用现成的好。Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class NIOServer...
阅读全文
posted @
2013-05-14 16:31 nianzai 阅读(2714) |
评论 (1) |
编辑 收藏
我学东西通常是通过动手的方式来学习,比如最近学习分布式服务协议paxos,自己就动手开发了一个该协议的实现版本。如果不动手实现只是靠学习理论是很难理解这个理论的本身。理解它最好的方式就是实践它。
根据理论或者原理就来做实现确实很难,这需要很强的代码功底、极高的理解能力以及持久的耐心。
扎实的功底是一切的开始,没有扎实的功底就无法下手。没有很好的悟性就很难保证事情的正确性。没有良好的耐心就很难保证事情的结果。一次性就能将事情做成做好的,这种人实在太少了。做成一件事情就是在无数的失败、错误中来接近成功,通过失败来纠正、从而一步一步的接近成功。这就注定了需要持久的耐心才能保证成功。
posted @
2013-04-27 10:13 nianzai 阅读(1958) |
评论 (0) |
编辑 收藏
1、提出者向leader发出询问消息
2、leader向所有的QuorumPeer发出投票请求
3、QuorumPeer对该请求进行投票,如果消息的txid大于QuorumPeer的txid则通过该投票,否则反对该投票
4、leader根据所有的QuorumPeer投票结果进行计算,如果有一半以上的QuorumPeer通过则接受提出者的请求,否则拒绝提出者的请求
switch (message.getType())
{
case QuorumCode.ask://询问类型
//询问该事务是否可操作
Ask task=new Ask(message,sc);
My.executor.execute(task);
m.setCode(JuiceCode.OK);
break;
case QuorumCode.vote://投票类型
if(My.txid>=message.getTxid())
//拒绝
m.setCode(JuiceCode.ERROR);
else
{
//通过
m.setCode(JuiceCode.OK);
My.updateMyTxid(message.getTxid());
}
break;
case QuorumCode.ping://ping
m.setCode(JuiceCode.OK);
m.setMyid(message.getMyid());
break;
}
public static boolean sendAndVote(Message m) throws IOException
{
m.setType(QuorumCode.vote);
Map<Integer,Response> mp=new TreeMap<Integer,Response>();
for(Map.Entry<Integer,NIOClient> entry:voteClientMap.entrySet())
{
NIOClient client=entry.getValue();
Response response=client.send(ByteUtil.getBytes(m));
mp.put(entry.getKey(), response);
}
Map<Integer,Message> vote=new TreeMap<Integer,Message>();
for(Map.Entry<Integer,Response> entry:mp.entrySet())
vote.put(entry.getKey(), (Message)ByteUtil.getObject(entry.getValue().getData()));
int ok=0;
for(Map.Entry<Integer,Message> entry:vote.entrySet())
{
Message f=entry.getValue();
if(f.getCode()==JuiceCode.OK)
ok++;
}
if(ok/(vote.size()*1.0)>1/2.0)
return true;
return false;
}
posted @
2013-04-23 13:19 nianzai 阅读(1746) |
评论 (0) |
编辑 收藏
1、收集第一轮投票结果
2、统计投票数,计算出投票数最大的id
3、如果投票数超过1/2则选该id为leader
4、如果最大投票数id没有超过1/2,则推荐txid最大的id为leader
5、计算出最大的txid及其服务器id
6、计算出最大的txid有几个
7、如果最大txid超过一个,则比较服务器id,推荐服务id最大的为leader
8、发起第二轮投票
Java实现代码如下:
/** *//**
* 选举leader
* @param vote 投票信息
* @return
*/
public int forLeader(Map<Integer,Notification> vote)
{
//统计leader投票数
TreeMap<Integer,Integer> tmap=new TreeMap<Integer,Integer>();
for(Map.Entry<Integer,Notification> entry:vote.entrySet())
{
Notification nf=entry.getValue();
if(tmap.containsKey(nf.leader))
tmap.put(nf.leader, tmap.get(nf.leader)+1);
else
tmap.put(nf.leader, 1);
}
//计算出投票数最大的id
int a=0;
int l=0;
for(Map.Entry<Integer,Integer> entry:tmap.entrySet())
{
if(entry.getValue()>a)
{
a=entry.getValue();
l=entry.getKey();
}
}
//如果投票数超过1/2则选该id为leader
if(a/(My.serverList.size()*1.0)>1/2.0)
{
//选出leader
if(l==My.myid)
My.myServerState=ServerState.LEADING;
else
My.myServerState=ServerState.FLLOWING;
My.leader=l;
return -1;
}
//如果最大投票数leader没有超过1/2,则推荐txid最大的id为leader
//计算出最大的txid及其服务器id
long txid=0;
int leader=0;
for(Map.Entry<Integer,Notification> entry:vote.entrySet())
{
if(entry.getValue().txid>txid)
{
leader=entry.getKey();
txid=entry.getValue().txid;
}
}
//计算出最大的txid有几个
Map<Integer,Notification> vte=new TreeMap<Integer,Notification>();
for(Map.Entry<Integer,Notification> entry:vote.entrySet())
{
if(entry.getValue().txid==txid)
{
vte.put(entry.getValue().id, entry.getValue());
}
}
//如果超过一个,则比较服务器id,推荐服务id最大的为leader
if(vte.size()>1)
{
for(Map.Entry<Integer,Notification> entry:vte.entrySet())
{
if(entry.getValue().id>leader)
leader=entry.getKey();
}
}
return leader;
}
}
posted @
2013-04-17 11:15 nianzai 阅读(1867) |
评论 (0) |
编辑 收藏
原理:通过浏览器去访问要抓取的Ajax、脚本网页地址,通过读取浏览器内存document来得到脚本执行以后的网页内容
在原有的基础上增加 自定义命令脚本 抓取功能。该功能能够通过用户自定义的脚本来实现与网页的交互,比如填写内容,点击网页上的提交按钮。
这样便能抓取需要提交的网页内容了,特别是需要提交的ajax网页。
Ajax、脚本网页内容抓取工具(第二版)
点这下载
posted @
2012-09-29 14:26 nianzai 阅读(1825) |
评论 (1) |
编辑 收藏
摘要: 本隐马可夫(HMM)中文分词词性标注程序 中的 隐马可夫(HMM)概率模型 是由 PFR人民日报标注语料199801语料库 生成Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class HMM{  ...
阅读全文
posted @
2012-09-14 17:08 nianzai 阅读(3830) |
评论 (0) |
编辑 收藏
wikipedia上有个java版的Viterbi(维特比)实现程序(
http://en.wikipedia.org/wiki/Viterbi_algorithm),但是3个观察序列会标注出4个状态序列。
下面本人写的这个Viterbi(维特比)实现程序就没这个问题,3个观察序列就只标注出3个状态序列。
public class Viterbi
{
public static void main(String[] args)
{
String[] states = {"Rainy", "Sunny"};
String[] observations = {"walk", "shop", "clean"};
double[] start_probability = {0.6, 0.4};
double[][] transition_probability = {{0.7, 0.3}, {0.4, 0.6}};
double[][] emission_probability = {{0.1, 0.4, 0.5}, {0.6, 0.3, 0.1}};
forward_viterbi(observations,states,start_probability,transition_probability,emission_probability);
}
public static void forward_viterbi(String[] observations, String[] states,double[] start_probability, double[][] transition_probability, double[][] emission_probability)
{
int[][] path=new int[observations.length][states.length];
double[][] r=new double[observations.length][states.length];
for(int j=0;j<states.length;j++)
{
r[0][j]=start_probability[j]*emission_probability[j][0];
path[0][j]=0;
}
for(int t=1;t<observations.length;t++)
{
for(int i=0;i<states.length;i++)
{
double tmp=0;int m=0;
for(int j=0;j<states.length;j++)
{
double tem=r[t-1][j]*transition_probability[j][i]*emission_probability[i][t];
if(tem>tmp)
{
tmp=tem;
m=j;
}
}
r[t][i]=tmp;
path[t][i]=m;
}
}
double p=0;int m=0;
for(int i=0;i<r[0].length;i++)
{
if(r[r.length-1][i]>p)
{
p=r[r.length-1][i];
m=i;
}
}
System.out.println("p="+p);
int[] trace=new int[observations.length];
trace[observations.length-1]=m;
for(int t=observations.length-1;t>0;t--)
{
trace[t-1]=path[t][m];
m=path[t][m];
}
for(int i=0;i<trace.length;i++)
System.out.println(states[trace[i]]);
}
} 。
posted @
2012-09-07 16:43 nianzai 阅读(1973) |
评论 (0) |
编辑 收藏
摘要: 最大概率分词程序,在所有可能分词路径中选择概率最大的一条路径最为分词结果Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class MPM extends M{ &...
阅读全文
posted @
2012-08-31 10:12 nianzai 阅读(2436) |
评论 (0) |
编辑 收藏
最短路径分词法
public class SPM2 extends M
{
public static final HashMap<Character,TreeNode> dic = Dictionary.loadFreqDictionary("sogou.txt");
/** *//**
* @return 返回可能匹配词的长度, 没有找到返回 0.
*/
public ArrayList<Integer> maxMatch(TreeNode node,char[] sen, int offset)
{
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=offset; i<sen.length; i++)
{
node = node.subNode(sen[i]);
if(node != null)
{
if(node.isAlsoLeaf())
list.add(i+1);
}
else
break;
}
return list;
}
@Override
public ArrayList<Token> getToken(ArrayList<Sentence> list)
{
ArrayList<Token> tokenlist=new ArrayList<Token>();
for(Sentence sen:list)
{
AdjList g = new AdjList(sen.getText().length+1);//存储所有被切分的可能的词
int i=0;
while(i<sen.getText().length)
{
Token token = new Token(new String(sen.getText(),i,1),i,i+1);
token.setWeight(1);
g.addEdge(token);
TreeNode n=dic.get(sen.getText()[i]);
if(n!=null)
{
ArrayList<Integer> ilist =maxMatch(n, sen.getText(),i);
if(ilist.size()>0)
for(int j=0;j<ilist.size();j++)
{
token = new Token(new String(sen.getText(),i,ilist.get(j)-i),i,ilist.get(j));
token.setWeight(1);
g.addEdge(token);
}
}
i++;
}
//System.out.println(g);
ArrayList<Integer> ret=maxProb(g);
Collections.reverse(ret);
int first=0;
for(Integer last:ret)
{
Token token = new Token(new String(sen.getText(),first,last-first),sen.getStartOffset()+first,sen.getStartOffset()+last);
tokenlist.add(token);
first=last;
}
}
return tokenlist;
}
int[] prevNode;
double[] prob;
//计算出路径最短的数组
public ArrayList<Integer> maxProb(AdjList g)
{
prevNode = new int[g.verticesNum]; //最佳前驱节点
prob = new double[g.verticesNum]; //节点路径
prob[0] = 0;//节点0的初始路径是0
//按节点求最佳前驱
for (int index = 1; index < g.verticesNum; index++)
getBestPrev(g,index);//求出最佳前驱
ArrayList<Integer> ret = new ArrayList<Integer>();
for(int i=(g.verticesNum-1);i>0;i=prevNode[i]) // 从右向左找最佳前驱节点
ret.add(i);
return ret;
}
//计算节点i的最佳前驱节点
void getBestPrev(AdjList g,int i)
{
Iterator<Token> it = g.getPrev(i);//得到前驱词集合,从中挑选最佳前趋词
double maxProb = 1000;
int maxNode = -1;
while(it.hasNext())
{
Token itr = it.next();
double nodeProb = prob[itr.getStart()]+itr.getWeight();//候选节点路径
//System.out.println(itr.getWord()+","+nodeProb);
if (nodeProb < maxProb)//路径最短的算作最佳前趋
{
maxNode = itr.getStart();
maxProb = nodeProb;
}
}
prob[i] = maxProb;//节点路径
prevNode[i] = maxNode;//最佳前驱节点
}
}
posted @
2012-08-24 14:57 nianzai 阅读(1962) |
评论 (0) |
编辑 收藏
全切分分词程序。中华人民共和国切分成 {中华人民共和国|中华|华人|人民|共和国}。
能实现中英文数字混合分词。比如能分出这样的词:bb霜、3室、乐phone、touch4、mp3、T恤。
public class FMW extends M
{
public static final HashMap<Character,TreeNode> dic = Dictionary.getFmmdic();
/** *//**
* @return 返回可能匹配词的长度, 没有找到返回 0.
*/
public ArrayList<Integer> maxMatch(TreeNode node,char[] sen, int offset)
{
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=offset; i<sen.length; i++)
{
node = node.subNode(sen[i]);
if(node != null)
{
if(node.isAlsoLeaf())
list.add(i+1);
}
else
break;
}
if(list.size()==0)
list.add(offset);
return list;
}
public ArrayList<Token> getToken(ArrayList<Sentence> list)
{
ArrayList<Token> tokenlist=new ArrayList<Token>();
for(Sentence sen:list)
{
int i=0;
while(i<sen.getText().length)
{
TreeNode n=dic.get(sen.getText()[i]);
if(n!=null)
{
ArrayList<Integer> ilist =maxMatch(n, sen.getText(),i);
if(ilist.size()>1)
{
for(int j=0;j<ilist.size();j++)
{
Token token = new Token(new String(sen.getText(),i,ilist.get(j)-i),sen.getStartOffset()+i,sen.getStartOffset()+ilist.get(j));
tokenlist.add(token);
}
}
else
{
if(ilist.get(0)>i)
{
Token token = new Token(new String(sen.getText(),i,ilist.get(0)-i),sen.getStartOffset()+i,sen.getStartOffset()+ilist.get(0));
tokenlist.add(token);
}
else
{
if(tokenlist.size()==0 || tokenlist.get(tokenlist.size()-1).getEnd()<=i+sen.getStartOffset())
{
Token token = new Token(new String(sen.getText(),i,1),sen.getStartOffset()+i,sen.getStartOffset()+i+1);
tokenlist.add(token);
}
}
}
}
else
{
if(tokenlist.size()==0 || tokenlist.get(tokenlist.size()-1).getEnd()<=i+sen.getStartOffset())
{
Token token = new Token(new String(sen.getText(),i,1),sen.getStartOffset()+i,sen.getStartOffset()+i+1);
tokenlist.add(token);
}
}
i++;
}
}
return tokenlist;
}
}
posted @
2012-07-02 14:17 nianzai 阅读(3062) |
评论 (4) |
编辑 收藏
推翻了第一版,参考了其他分词程序,重新写的第二版。
逆向最大匹配中文分词程序,能实现中英文数字混合分词。比如能分出这样的词:bb霜、3室、乐phone、touch4、mp3、T恤
public class RMM2 extends M
{
public static final HashMap<Character,TreeNode> dic = Dictionary.getRmmdic();
/** *//**
* @return 返回匹配最长词的长度, 没有找到返回 0.
*/
public int maxMatch(TreeNode node,char[] sen, int offset)
{
int idx = offset;
for(int i=offset; i>=0; i--)
{
node = node.subNode(sen[i]);
if(node != null)
{
if(node.isAlsoLeaf())
idx = i;
}
else
break;
}
return idx ;
}
public ArrayList<Token> getToken(ArrayList<Sentence> list)
{
Collections.reverse(list);
ArrayList<Token> tokenlist=new ArrayList<Token>();
for(Sentence sen:list)
{
int i=sen.getText().length-1;
while(i>-1)
{
TreeNode n=dic.get(sen.getText()[i]);
if(n!=null)
{
int j=maxMatch(n, sen.getText(),i);
if(j<i)
{
Token token = new Token(new String(sen.getText(),j,i-j+1),sen.getStartOffset()+j,sen.getStartOffset()+i+1);
tokenlist.add(token);
i=j-1;
}
else
{
Token token = new Token(new String(sen.getText(),i,1),sen.getStartOffset()+i,sen.getStartOffset()+i+1);
tokenlist.add(token);
i--;
}
}
else
{
Token token = new Token(new String(sen.getText(),i,1),sen.getStartOffset()+i,sen.getStartOffset()+i+1);
tokenlist.add(token);
i--;
}
}
}
Collections.reverse(tokenlist);
return tokenlist;
}
}
posted @
2012-06-29 17:29 nianzai 阅读(1363) |
评论 (0) |
编辑 收藏
推翻了第一版,参考了其他分词程序,重新写的第二版。
正向最大匹配中文分词程序,能实现中英文数字混合分词。比如能分出这样的词:bb霜、3室、乐phone、touch4、mp3、T恤
public class FMM2 extends Seg
{
public static final HashMap<Character,TreeNode> dic = Dictionary.getFmmdic();
/** *//**
* @return 返回匹配最长词的长度, 没有找到返回 0.
*/
public static int maxMatch(TreeNode node,char[] sen, int offset)
{
int idx = offset - 1;
for(int i=offset; i<sen.length; i++)
{
node = node.subNode(sen[i]);
if(node != null)
{
if(node.isAlsoLeaf())
idx = i;
}
else
break;
}
return idx + 1;
}
public ArrayList<Token> getToken(ArrayList<Sentence> list)
{
ArrayList<Token> tokenlist=new ArrayList<Token>();
for(Sentence sen:list)
{
int i=0;
while(i<sen.getText().length)
{
TreeNode n=FMM2.dic.get(sen.getText()[i]);
if(n!=null)
{
int j=FMM2.maxMatch(n, sen.getText(),i);
if(j>i)
{
Token token = new Token(new String(sen.getText(),i,j-i),sen.getStartOffset()+i,sen.getStartOffset()+j);
tokenlist.add(token);
i=j;
}
else
{
Token token = new Token(new String(sen.getText(),i,1),sen.getStartOffset()+i,sen.getStartOffset()+i+1);
tokenlist.add(token);
i++;
}
}
else
{
Token token = new Token(new String(sen.getText(),i,1),sen.getStartOffset()+i,sen.getStartOffset()+i+1);
tokenlist.add(token);
i++;
}
}
}
return tokenlist;
}
}
posted @
2012-06-27 13:39 nianzai 阅读(1265) |
评论 (0) |
编辑 收藏
摘要: Reactor 模式的 JAVA NIO 多线程服务器
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class MiniServer extends Thread{ &nb...
阅读全文
posted @
2011-08-29 18:35 nianzai 阅读(3093) |
评论 (3) |
编辑 收藏
摘要: 基于词典的逆向最大匹配中文分词算法,能实现中英文数字混合分词。比如能分出这样的词:bb霜、3室、乐phone、touch4、mp3、T恤。实际分词效果比正向分词效果好 查看第2版:逆向最大匹配分词程序,能实现中英文数字混合分词 (第二版)
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://w...
阅读全文
posted @
2011-08-19 13:22 nianzai 阅读(4482) |
评论 (2) |
编辑 收藏
摘要: 基于词典的正向最大匹配中文分词算法,能实现中英文数字混合分词。比如能分出这样的词:bb霜、3室、乐phone、touch4、mp3、T恤第一次写中文分词程序,欢迎拍砖。查看第2版:正向最大匹配分词程序,能实现中英文数字混合分词 (第二版)
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.Code...
阅读全文
posted @
2011-08-04 15:31 nianzai 阅读(3452) |
评论 (1) |
编辑 收藏
原理:通过浏览器去访问要抓取的Ajax、脚本网页地址,通过读取浏览器内存document来得到脚本执行以后的网页内容
1、文件路径为带抓取网页地址,格式如下:
1,http://www.google.com
2,http://www.baidu.com
......
......
2、保存路径为抓取下来的网页保存路径
Ajax、脚本网页内容抓取小工具
点这下载
posted @
2011-04-27 13:37 nianzai 阅读(2163) |
评论 (1) |
编辑 收藏
blog: http://www.blogjava.net/nianzai/
code: http://code.google.com/p/nutla/
一、安装
1、 安装虚拟机 Oracle VM VirtualBox4.0.4
2、 在虚拟机下安装 Red Hat 6.0
3、 安装jdk jdk-6u24-linux-i586.bin 安装路径为:/home/nianzai/jdk1.6.0_24
4、 安装hadoop hadoop-0.20.2.tar.gz 安装路径为:/home/nianzai/hadoop-0.20.2
5、 安装zookeeper zookeeper-3.3.3.tar.gz 安装路径为:/home/nianzai/zookeeper-3.3.3
6、 安装hbase hbase-0.90.2.tar.gz 安装路径为:/home/nianzai/hbase-0.90.2
二、配置
1、Linux配置
ssh-keygen –t rsa -P ''
cd .ssh
cp id_rsa.pub authorized_keys
/etc/hosts里增加 192.168.195.128 master
/etc/profile 里增加
export JAVA_HOME=/home/nianzai/jdk1.6.0_24
export PATH=$PATH:$JAVA_HOME/bin
2、hadoop配置
hadoop-env.sh
JAVA_HOME=/home/nianzai/jdk1.6.0._24
core-site.xml
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/nianzai/hadoop</value>
</property>
<property>
<name>fs.default.name</name>
<value>hdfs://master:9000</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>master:9001</value>
</property>
</configuration>
masters
master
sh hadoop namenode -format
sh start-all.sh
sh hadoop fs -mkdir input
3、zookeeper配置
zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/nianzai/zkdata
clientPort=2181
sh zkServer.sh start
4、hbase配置
hbase-env.sh
export JAVA_HOME=/home/nianzai/jdk1.6.0_24
export HBASE_MANAGES_ZK=false
将hbase0.90.2 lib目录下hadoop-core-0.20-append-r1056497.jar删除,替换成hadoop0.20.2 下的hadoop-0.20.2-core.jar
hbase-site.xml
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://master:9000/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.master.port</name>
<value>60000</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>master</value>
</property>
</configuration>
regionservers
master
sh start-hbase.sh
posted @
2011-04-19 11:32 nianzai 阅读(4067) |
评论 (6) |
编辑 收藏
http://code.google.com/p/nutla/
1、概述
不管程序性能有多高,机器处理能力有多强,都会有其极限。能够快速方便的横向与纵向扩展是Nut设计最重要的原则,以此原则形成以分布式并行计算为核心的架构设计。以分布式并行计算为核心的架构设计是Nut区别于Solr、Katta的地方。
Nut是一个Lucene+Hadoop分布式并行计算搜索框架,能对千G以上索引提供7*24小时搜索服务。在服务器资源足够的情况下能达到每秒处理100万次的搜索请求。
Nut开发环境:jdk1.6.0.23+lucene3.0.3+eclipse3.6.1+hadoop0.20.2+zookeeper3.3.2+hbase0.20.6+memcached+mongodb+linux
2、特新
a、热插拔
b、可扩展
c、高负载
d、易使用,与现有项目无缝集成
e、支持排序
f、7*24服务
g、失败转移
3、搜索流程
Nut由Index、Search、Client、Cache和DB五部分构成。(Cache实现了对memcached的支持,DB实现了对hbase,mongodb的支持)
Client处理用户请求和对搜索结果排序。Search对请求进行搜索,Search上只放索引,数据存储在DB中,Nut将索引和存储分离。Cache缓存的是搜索条件和结果文档id。DB存储着数据,Client根据搜索排序结果,取出当前页中的文档id从DB上读取数据。
用户发起搜索请求给由Nut Client构成的集群,由某个Nut Client根据搜索条件查询Cache服务器是否有该缓存,如果有缓存根据缓存的文档id直接从DB读取数据,如果没有缓存将随机选择一组搜索服务器组(Search Group i),将查询条件同时发给该组搜索服务器组里的n台搜索服务器,搜索服务器将搜索结果返回给Nut Client由其排序,取出当前页文档id,将搜索条件和当前文档id缓存,同时从DB读取数据。
4、索引流程
Hadoop Mapper/Reducer 建立索引。再将索引从HDFS分发到各个索引服务器。
对索引的更新分为两种:删除和添加(更新分解为删除和添加)。
a、删除
在HDFS上删除索引,将生成的*.del文件分发到所有的索引服务器上去或者对HDFS索引目录删除索引再分发到对应的索引服务器上去。
b、添加
新添加的数据用另一台服务器来生成。
删除和添加步骤可按不同定时策略来实现。
5、Nut分布式并行计算特点
Nut分布式并行计算虽然也是基于M/R模型,但是与Hadoop M/R模型是不同的。在Hadoop M/R模型中 Mapper和Reducer是一个完整的流程,Reducer依赖于Mapper。数据源通过Mapper分发本身就会消耗大量的I/O,并且是消耗I/O最大的部分。所以Hadoop M/R 并发是有限的。
Nut M/R模型是将Mapper和Reducer分离,各自独立存在。在Nut中 索引以及索引管理 构成M,搜索以及搜索服务器组 构成 R。
以一个分类统计来说明Nut分布式并行计算的流程。假设有10个分类,对任意关键词搜索要求统计出该关键词在这10个分类中的总数。同时假设有10组搜索服务器。索引以及索引管理进行索引数据的Mapper,这块是后台独自运行管理的。Nut Client将这10个分类统计分发到10组搜索服务器上,每组搜索服务器对其中一个分类进行Reducer,并且每组搜索服务器可进行多级Reducer。最后将最终结果返回给Nut Client。
6、设计图
7、Zookeeper服务器状态管理策略
在架构设计上通过使用多组搜索服务器可以支持每秒处理100万个搜索请求。
每组搜索服务器能处理的搜索请求数在1万—1万5千之间。如果使用100组搜索服务器,理论上每秒可处理100万个搜索请求。
假如每组搜索服务器有100份索引放在100台正在运行中搜索服务器(run)上,那么将索引按照如下的方式放在备用中搜索服务器(bak)上:index 1,index 2,index 3,index 4,index 5,index 6,index 7,index 8,index 9,index 10放在B 1 上,index 6,index 7,index 8,index 9,index 10,index 11,index 12,index 13,index 14,index 15放在B 2上。。。。。。index 96,index 97,index 98,index 99,index 100,index 5,index 4,index 3,index 2,index 1放在最后一台备用搜索服务器上。那么每份索引会存在3台机器中(1份正在运行中,2份备份中)。
尽管这样设计每份索引会存在3台机器中,仍然不是绝对安全的。假如运行中的index 1,index 2,index 3同时宕机的话,那么就会有一份索引搜索服务无法正确启用。这样设计,作者认为是在安全性和机器资源两者之间一个比较适合的方案。
备用中的搜索服务器会定时检查运行中搜索服务器的状态。一旦发现与自己索引对应的服务器宕机就会向lock申请分布式锁,得到分布式锁的服务器就将自己加入到运行中搜索服务器组,同时从备用搜索服务器组中删除自己,并停止运行中搜索服务器检查服务。
为能够更快速的得到搜索结果,设计上将搜索服务器分优先等级。通常是将最新的数据放在一台或几台内存搜索服务器上。通常情况下前几页数据能在这几台搜索服务器里搜索到。如果在这几台搜索服务器上没有数据时再向其他旧数据搜索服务器上搜索。
优先搜索等级的逻辑是这样的:9最大为搜索全部服务器并且9不能作为level标识。当搜索等级level为1,搜索优先级为1的服务器,当level为2时搜索优先级为1和2的服务器,依此类推。
posted @
2011-02-17 13:20 nianzai 阅读(5373) |
评论 (9) |
编辑 收藏