Solr 创建索引的原理 源码分析
本次分析以Solr3.3是最新的版本为准,
Solr3.3接收客户端的查询索引,新建索引请求都是通过过滤器SolrDispatchFilter来提交给SolrCore的Eexecute方法的。而WEB
.xml文件里的Servlet都不取作用的。SolrDispatchFilter主要是根据当前请求路径的PATH,客户端发起的请求PATH主要如下几类:
1/admin以adinm开头的则到Solr的管理页面。
2/select,/update这类的为对应的Handler/select即搜索请求,对应的handler为SearchHandler,/update新建,更新索引对应的handler为XmlUpdateRequestHandler,这里主要讲一下Solr是怎么对新建索引的XML格式的请求做解析的。
新建索引的命令如下:
<add><docboost=2.1><fieldname="id">222</field></doc></add>
XmlUpdateRequestHandler类是ContentStreamHandlerBase的子类,处理的方法在ContentStreamHandlerBase类的
handleRequestBody方法,该方法的代码有:
//创建一个xml的解析器,实类为XMLLoaderXMLLoader继承抽象的ContentStreamLoader
ContentStreamLoaderdocumentLoader=newLoader(req,processor);
documentLoader.load(req,rsp,stream);//开始读取要创建的doc信息。
主要代码如下:
对<add>标签的处理如下:
StringcurrTag=parser.getLocalName();
if(currTag.equals(XmlUpdateRequestHandler.ADD)){
XmlUpdateRequestHandler.log.trace("SolrCore.update(add)");
addCmd=newAddUpdateCommand();
booleanoverwrite=true;//thedefault
BooleanoverwritePending=null;
BooleanoverwriteCommitted=null;
//判断add标签是否有其他的属性,主要包过如下几个:
//overwrite,allowDups,commitWithin,overwritePending,overwriteCommitted
for(inti=0;i<parser.getAttributeCount();i++){
StringattrName=parser.getAttributeLocalName(i);
StringattrVal=parser.getAttributeValue(i);
if(XmlUpdateRequestHandler.OVERWRITE.equals(attrName)){
overwrite=StrUtils.parseBoolean(attrVal);
}elseif(XmlUpdateRequestHandler.ALLOW_DUPS.equals(attrName)){
overwrite=!StrUtils.parseBoolean(attrVal);
}elseif(XmlUpdateRequestHandler.COMMIT_WITHIN.equals(attrName)){
addCmd.commitWithin=Integer.parseInt(attrVal);
}elseif(XmlUpdateRequestHandler.OVERWRITE_PENDING.equals(attrName)){
overwritePending=StrUtils.parseBoolean(attrVal);
}elseif(XmlUpdateRequestHandler.OVERWRITE_COMMITTED.equals(attrName)){
overwriteCommitted=StrUtils.parseBoolean(attrVal);
}else{
XmlUpdateRequestHandler.log.warn("Unknownattributeidinadd:"+attrName);
}
}
//checkiftheseflagsareset
if(overwritePending!=null&&overwriteCommitted!=null){
if(overwritePending!=overwriteCommitted){
thrownewSolrException(SolrException.ErrorCode.BAD_REQUEST,
"can'thavedifferentvaluesfor'overwritePending'and'overwriteCommitted'");
}
overwrite=overwritePending;
}
//通过下面三行代码,起作用的就是overwrite
addCmd.overwriteCommitted=overwrite;
addCmd.overwritePending=overwrite;
addCmd.allowDups=!overwrite;
对<doc>标签的处理如下:
elseif("doc".equals(currTag)){
XmlUpdateRequestHandler.log.trace("addingdoc...");
addCmd.clear();
addCmd.solrDoc=readDoc(parser);
}
readDoc方法主要是读取<doc>标签和<field>的读取<doc>代码如下:
//Solr把Luence的Doc封装为SolrInputDocument
SolrInputDocumentdoc=newSolrInputDocument();
Stringattrname="";
for(inti=0;i<parser.getAttributeCount();i++){
attrName=parser.getAttributeLocalName(i);
if("boost".equals(attrName)){
doc.setDocumentBoost(Float.parseFloat(parser.getAttributeValue(i)));
}else{
XmlUpdateRequestHandler.log.warn("Unknownattributedoc/@"+attrName);
}
}
从上面的代码可以看出,<doc>标签可以有属性boost,(<docboost="2">)即可以给该doc设置权重。以改变评分。
读取field的代码就不贴了,相信读者也会想到和上面的是一个模式,会读取field的name,boost,属性,像<doc>一样,
我们也可以给特定的field设置权重。遇到</field>标签时,代码如下:
doc.addField(name,text.toString(),boost);
boost=1.0f;
从上面两行代码可以看出,每一个field字段默认的boost为1.0.
Solr解析完<add>命令,创建一个SolrInputDocument对象,那Solr是怎么把SolrInputDocument对象转变为luence
的doc对象的呢,在创建时,Solr创建了一个process这个process是RunUpdateProcessor的实例,上面readDoc方法完成后,返回SolrInputDocument实例,然后调用RunUpdateProcessor的processAdd方法。把SolrInputDocument对象转变为luence
doc对象。代码如下:
publicvoidprocessAdd(AddUpdateCommandcmd)throwsIOException{
//转变doc对象
cmd.doc=DocumentBuilder.toDocument(cmd.getSolrInputDocument(),req.getSchema());
//主要是把luencedoc写到内存索引
updateHandler.addDoc(cmd);
super.processAdd(cmd);
}