本次分析以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><doc boost=2.1><field name="id">222</field></doc></add>
XmlUpdateRequestHandler 类是ContentStreamHandlerBase的子类,处理的方法在ContentStreamHandlerBase类的
handleRequestBody方法,该方法的代码有:
//创建一个xml的解析器,实类为XMLLoader XMLLoader继承抽象的ContentStreamLoader
ContentStreamLoader documentLoader = newLoader(req, processor);
documentLoader.load(req, rsp, stream);//开始读取要创建的doc信息。
主要代码如下:
对<add>标签的处理如下:
String currTag = parser.getLocalName();
if (currTag.equals(XmlUpdateRequestHandler.ADD)) {
XmlUpdateRequestHandler.log.trace("SolrCore.update(add)");
addCmd = new AddUpdateCommand();
boolean overwrite = true; // the default
Boolean overwritePending = null;
Boolean overwriteCommitted = null;
//判断add标签是否有其他的属性,主要包过如下几个:
//overwrite,allowDups,commitWithin,overwritePending,overwriteCommitted
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attrName = parser.getAttributeLocalName(i);
String attrVal = parser.getAttributeValue(i);
if (XmlUpdateRequestHandler.OVERWRITE.equals(attrName)) {
overwrite = StrUtils.parseBoolean(attrVal);
} else if (XmlUpdateRequestHandler.ALLOW_DUPS.equals(attrName)) {
overwrite = !StrUtils.parseBoolean(attrVal);
} else if (XmlUpdateRequestHandler.COMMIT_WITHIN.equals(attrName)) {
addCmd.commitWithin = Integer.parseInt(attrVal);
} else if (XmlUpdateRequestHandler.OVERWRITE_PENDING.equals(attrName)) {
overwritePending = StrUtils.parseBoolean(attrVal);
} else if (XmlUpdateRequestHandler.OVERWRITE_COMMITTED.equals(attrName)) {
overwriteCommitted = StrUtils.parseBoolean(attrVal);
} else {
XmlUpdateRequestHandler.log.warn("Unknown attribute id in add:" + attrName);
}
}
// check if these flags are set
if (overwritePending != null && overwriteCommitted != null) {
if (overwritePending != overwriteCommitted) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"can't have different values for 'overwritePending' and 'overwriteCommitted'");
}
overwrite = overwritePending;
}
//通过下面三行代码,起作用的就是overwrite
addCmd.overwriteCommitted = overwrite;
addCmd.overwritePending = overwrite;
addCmd.allowDups = !overwrite;
对<doc>标签的处理如下:
else if ("doc".equals(currTag)) {
XmlUpdateRequestHandler.log.trace("adding doc...");
addCmd.clear();
addCmd.solrDoc = readDoc(parser);
}
readDoc方法主要是读取<doc>标签和<field>的读取<doc>代码如下:
//Solr 把Luence的Doc封装为SolrInputDocument
SolrInputDocument doc = new SolrInputDocument();
String attrName = "";
for (int i = 0; i < parser.getAttributeCount(); i++) {
attrName = parser.getAttributeLocalName(i);
if ("boost".equals(attrName)) {
doc.setDocumentBoost(Float.parseFloat(parser.getAttributeValue(i)));
} else {
XmlUpdateRequestHandler.log.warn("Unknown attribute doc/@" + attrName);
}
}
从上面的代码可以看出,<doc>标签可以有属性boost,(<doc boost="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对象。代码如下:
public void processAdd(AddUpdateCommand cmd) throws IOException {
//转变doc对象
cmd.doc = DocumentBuilder.toDocument(cmd.getSolrInputDocument(), req.getSchema());
//主要是把luence doc写到内存索引
updateHandler.addDoc(cmd);
super.processAdd(cmd);
}
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><doc boost=2.1><field name="id">222</field></doc></add>
XmlUpdateRequestHandler 类是ContentStreamHandlerBase的子类,处理的方法在ContentStreamHandlerBase类的
handleRequestBody方法,该方法的代码有:
//创建一个xml的解析器,实类为XMLLoader XMLLoader继承抽象的ContentStreamLoader
ContentStreamLoader documentLoader = newLoader(req, processor);
documentLoader.load(req, rsp, stream);//开始读取要创建的doc信息。
主要代码如下:
对<add>标签的处理如下:
String currTag = parser.getLocalName();
if (currTag.equals(XmlUpdateRequestHandler.ADD)) {
XmlUpdateRequestHandler.log.trace("SolrCore.update(add)");
addCmd = new AddUpdateCommand();
boolean overwrite = true; // the default
Boolean overwritePending = null;
Boolean overwriteCommitted = null;
//判断add标签是否有其他的属性,主要包过如下几个:
//overwrite,allowDups,commitWithin,overwritePending,overwriteCommitted
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attrName = parser.getAttributeLocalName(i);
String attrVal = parser.getAttributeValue(i);
if (XmlUpdateRequestHandler.OVERWRITE.equals(attrName)) {
overwrite = StrUtils.parseBoolean(attrVal);
} else if (XmlUpdateRequestHandler.ALLOW_DUPS.equals(attrName)) {
overwrite = !StrUtils.parseBoolean(attrVal);
} else if (XmlUpdateRequestHandler.COMMIT_WITHIN.equals(attrName)) {
addCmd.commitWithin = Integer.parseInt(attrVal);
} else if (XmlUpdateRequestHandler.OVERWRITE_PENDING.equals(attrName)) {
overwritePending = StrUtils.parseBoolean(attrVal);
} else if (XmlUpdateRequestHandler.OVERWRITE_COMMITTED.equals(attrName)) {
overwriteCommitted = StrUtils.parseBoolean(attrVal);
} else {
XmlUpdateRequestHandler.log.warn("Unknown attribute id in add:" + attrName);
}
}
// check if these flags are set
if (overwritePending != null && overwriteCommitted != null) {
if (overwritePending != overwriteCommitted) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"can't have different values for 'overwritePending' and 'overwriteCommitted'");
}
overwrite = overwritePending;
}
//通过下面三行代码,起作用的就是overwrite
addCmd.overwriteCommitted = overwrite;
addCmd.overwritePending = overwrite;
addCmd.allowDups = !overwrite;
对<doc>标签的处理如下:
else if ("doc".equals(currTag)) {
XmlUpdateRequestHandler.log.trace("adding doc...");
addCmd.clear();
addCmd.solrDoc = readDoc(parser);
}
readDoc方法主要是读取<doc>标签和<field>的读取<doc>代码如下:
//Solr 把Luence的Doc封装为SolrInputDocument
SolrInputDocument doc = new SolrInputDocument();
String attrName = "";
for (int i = 0; i < parser.getAttributeCount(); i++) {
attrName = parser.getAttributeLocalName(i);
if ("boost".equals(attrName)) {
doc.setDocumentBoost(Float.parseFloat(parser.getAttributeValue(i)));
} else {
XmlUpdateRequestHandler.log.warn("Unknown attribute doc/@" + attrName);
}
}
从上面的代码可以看出,<doc>标签可以有属性boost,(<doc boost="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对象。代码如下:
public void processAdd(AddUpdateCommand cmd) throws IOException {
//转变doc对象
cmd.doc = DocumentBuilder.toDocument(cmd.getSolrInputDocument(), req.getSchema());
//主要是把luence doc写到内存索引
updateHandler.addDoc(cmd);
super.processAdd(cmd);
}