Solr整体请求过程详细分析Word文件下载.docx
- 文档编号:4465734
- 上传时间:2023-05-03
- 格式:DOCX
- 页数:34
- 大小:37.07KB
Solr整体请求过程详细分析Word文件下载.docx
《Solr整体请求过程详细分析Word文件下载.docx》由会员分享,可在线阅读,更多相关《Solr整体请求过程详细分析Word文件下载.docx(34页珍藏版)》请在冰点文库上搜索。
这段代码的作用是什么呢?
它是创建一个请求头的载体,然后将其加入到响应类中,
这样我们就可以在响应中获得我们请求头,这个请求头中包含我们的请求参数。
关于
NameList
这个类,说明文件说明中说它是一个
name/value
对的有序表,具有如下
特性:
∙name
可以重复
∙name/value
对的有序
∙可以通过
index
访问
和
value
都可以为空
看看它的谱系图:
再看这样一段代码:
NamedList
toLog
rsp.getToLog();
//toLog.add("
core"
getName());
toLog.add("
webapp"
req.getContext().get("
));
path"
params"
"
{"
+
req.getParamString()
}"
);
是什么呢?
它是
类的一个属性,定义如下:
protected
SimpleOrderedMap();
上面我们已经看到了
SimpleOrderedMap
类是
的子类,这里通过属性的名字不
难
想象它是记录需要写入日志中的内容的
载体。
的确我们在打印出来的日志中很容易找
到如下内容:
信息:
[database]
webapp=null
path=null
params={}
status=0
QTime=1438
执行更新关键的代码是这里:
handler.handleRequest(req,rsp);
setResponseHeaderValues(handler,req,rsp);
第一句执行更新过程,第二句只是将
req
中的参数部分以及经过处理后的
rsp
中的
中的内容写如到
中的请求头
(responseHeader
)中来。
我们来看最关键的第一句:
关于handler.handleRequest(req,rsp)。
更新常用的
是
XmlUpdateRequestHandler,所
以我们
进入该类的
handleRequest
方法中查看究竟。
我们发现
XmlUpdateRequestHandler
中
并没有该方法,我们猜想该方法可以在父类中,果然。
于是我们就研究父类的
方法。
SolrPluginUtils.setDefaults(req,defaults,appends,invariants);
该方法内部的代码如下:
SolrParams
p
req.getParams();
if
(defaults
!
null)
{
DefaultSolrParams(p,defaults);
}
(appends
AppendedSolrParams(p,appends);
(invariants
DefaultSolrParams(invariants,p);
req.setParams(p);
AppendedSolrParams
DefaultSolrParams
的子类,可以看出来,这段代码的作用是设
置
使其具有实质性的参数内容。
代码:
rsp.setHttpCaching(httpCaching);
作用:
设置是否进行缓存功能。
handleRequestBody(
这段代码是处理体,由于我们获得的是
的实例,所以我们
又要跳到
类的
handleRequestBody
方法中了。
handleRequestBody
所做事情如下:
∙SolrParams
params
获得请求参数内容。
∙UpdateRequestProcessorChain
processingChain
=
req.getCore().getUpdateProcessingChain(params.get(
UpdateParams.UPDATE_PROCESSOR
)
获得更新请求处理链。
∙UpdateRequestProcessor
processor
processingChain.createProcessor(req,
rsp);
获得更
新请求处理器。
∙Iterable<
streams
req.getContentStreams();
获得更新请求的内容流。
∙如果
为空,进行提交的尝试处理,处理失败抛出错误。
如果不为空,如下
处理:
for(
stream
:
req.getContentStreams()
Reader
reader
stream.getReader();
try
XMLStreamReader
parser
inputFactory.createXMLStreamReader(reader);
this.processUpdate(
processor,
finally
IOUtils.closeQuietly(reader);
这段处理的本质是循环获取每部分内容流,然后获得内容流的
实例。
接下构
建
实例并调用
来完成更新。
最后
尝试进行提交(仅仅是可能,因为我们可能在更新的同时在请求参数中加入
commit
参数,
并设其值为
true)。
∙processor.finish();
我们一步一步来观察这个详细的过程。
首先是获得处理链,版本的
solrconfig.xml
配置文件,所以没有添加处理链的配置参
数。
所以我们在eq.getCore().getUpdateProcessingChain
方法中传入的参数是
null,但是尽
管如此依然获得了一个包含两个
UpdateRequestProcessorFactory
的处理链。
虽然我们知道
Map
类型中可以包含键为
null
的内容,但是这个内容是怎么获得的呢?
实际上
的构造函数中调用了
loadUpdateProcessorChains
方法,
这就是加载处理链的地方。
在这
段代码中我们看到这两个
UpdateRequestProcessorFactory
的原型:
RunUpdateProcessorFactory(),
LogUpdateProcessorFactory()。
也就是说在没有进行处理链配置的时候,就使用它们作为默认值。
我们从
RunUpdateProcessorFactory
来看更新处理器工厂的本质。
它是
RunUpdateProcessor
的工厂,工厂的本质是产生实例,所以它最重要的方法是
getInstance(SolrQueryRequest,
SolrQueryResponse,
UpdateRequestProcessor),这里的最后一个
参数是下一个更新请求处理器,这就是“链”的由来。
那么RunUpdateProcessor
请看下面。
实质是处理添加,提交,删除的地方,每个更新方法的参数是
UpdateCommand
的子类。
也就是最终我们的更新请求都会通过这里来进行处理。
而
LogUpdateProcessorFactory
又有所不同,它是关于日志处理器(LogUpdateProcessor)的
一个工厂类。
然后,我们利用获得的处理链来构建处理器:
UpdateRequestProcessor
在
createProcessor
方法的内部,我们看到每个处理器工厂都被轮流调用了,也就是最
终返回的
是和一连串的处理器相关的。
最后,我们来看如何利用获得的处理器以及多个内容流
来处理更新请求的。
我们在一个
for
循环中对每个
ContentStream作如下处理。
先获得其
的实例,
然后利用
分析工具构建对
的解析字符流。
使用
来处理更新。
的
processUpdate(
)做了什么事情呢?
请跟随
我来看一看。
主要到
while
(true)这样一个循环,在循环内部是对
:
的循
环读取与处理。
这个循环中有一个
switch
语句,:
int
event
parser.next();
(event){
case
XMLStreamConstants.END_DOCUMENT:
parser.close();
return;
XMLStreamConstants.START_ELEMENT:
String
currTag
parser.getLocalName();
//获取当前标签名
(currTag.equals(ADD))
............
//这里主要是设置
addCmd
的一些属性
else
("
doc"
.equals(currTag))
......
processor.processAdd(addCmd);
(
COMMIT.equals(currTag)
||
OPTIMIZE.equals(currTag))
processor.processCommit(
cmd
(DELETE.equals(currTag))
processDelete(
parser);
break;
在这个过程中,我们看到
解析时,发现当前标签,然后判断其内容。
如果内容
为
add,那么使用
addCmd=newAddUpdateCommand()来创建新的
实例,并设置其
overwriteCommitted
等属性。
如果标签内容为
doc,使用如
下代码先清空
的内容,
然后从
数据中读取一
个新的
Doc
并将其放如
中。
addCmd.clear();
addCmd.solrDoc
readDoc(
然后调用
processor.processAdd(addCmd)方法来进行处理,至于
与
delete
也是类
似的方法处理。
下面我们来看
processor.processAdd(addCmd)做了些什么,清楚它的实质以后,关于提
交与删除的处理就可以用同样的方法来进行处
理了。
通过简单的信息输入发现,这里有三个类的
processAdd
方法被调用了。
首先调用的是
方法,在这个方法中调用了父类
(UpdateRequestProcessor)的
方法,调用父类的方法的时候我们注意到方法中
有
(next
next.processAdd(cmd)代码,正是这个代码的调用使得
LogUpdateProcessor
中的
得以调用,这正是处理得以实现的根本。
也就是说之前构造时候的链式
仅仅时使其具有链式的能力,而调用父类(UpdateRequestProcessor)的
方法
使得链式真正发挥了作用。
下面我们沿着
RunUpdateProcessor、UpdateRequestProcessor、LogUpdateProcessor
这条
主线一步
一步来看。
方法中。
通过如下的代码获得了
doc
属
性,这就是说将原来的SolrInputDocument
引入了
schema
信息建立了
lucene
下的
docement。
cmd.doc
DocumentBuilder.toDocument(cmd.getSolrInputDocument(),
req.getSchema());
然后通过下面的代码来实现
下的文档对象的更新。
updateHandler.addDoc(cmd);
这里的
updateHandler
是什么东西呢?
输出
updateHandler.getClass().getName()信息很容
易发现该类是org.apache.solr.update.DirectUpdateHandler2。
这是更新默认的处理器,也可
以在配置文件中进行设定。
我们进入该类看个究竟吧。
简单浏览代码概要发现所有的更新处理最终都落实到这里,常常惹人头痛的“两把锁”-
-提交锁与访问锁也都在这里。
暂且先不管这么多吧,我们先来看看我们关心的
addDoc
方
法。
我们进入了
DirectUpdateHandler2中的
方法,现在我们来看看里面发生了什么
惊天动地的事情吧。
前面几行代码是增加一些记录添加的文档有多少等的一些信息以及如果当前
ID
域不存
在的情况下允许重复的处理,暂且别管它。
我们从读索引访问加锁开始。
iwAccess.lock();
获得锁以后我们在一个
语句中有如下的代码:
synchronized
(this)
//
adding
document
--
prep
writer
closeSearcher();
openWriter();
tracker.addedDocument();
这段代码做了什么呢?
一个一个的分析。
closeSearcher()
关闭搜索器,这样使得没有搜索器会从索引文件读取内容。
我试图证明
这个观点,但
是还没有找到直接的证据,暂时保留意见吧。
这个过程先后经过了下面的方法:
DirectUpdateHandler2的
openWriter()
UpdateHandler
createMainIndexWriter("
DirectUpdateHandler2"
false)方法。
第二个参数
表示是否
removeAllExisting。
SolrIndexWriter(name,core.getIndexDir(),removeAllExisting,schema,
core.getSolrConfig().mainIndexConfig);
参数分别为名字,索引目录路径,是否移去所有已经
存在的内容,代表
schema.xml
内容的实例,代表索引的相关配置属性的实例。
最后就是调用
IndexWriter
的构建方法了。
这一切的目的就是使得当前
DirectUpdateHandler2的实例具备一个可用的
IndexWriter
的实例,注意这里是
下的
了。
tracker.addedDocument()
tracker
CommitTracker
的实例,作为
DirectUpdateHandler2的属性,我把它叫做提交
跟踪器。
代码说明中这样介绍:
这是一个跟踪自动提交的帮助类。
为了保持思路的完整性暂且别管这个类,后面再来理它。
先来看看后面的代码。
后面其实是先获得
以及
的值来决定
如何添加文档到索引中。
一种是允许重复
的添加,另外一种是不允许重复的添加。
代
码如下:
(cmd.overwriteCommitted
cmd.overwritePending)
(cmd.indexedId
==
cmd.indexedId
getIndexedId(cmd.doc);
//id
唯一的添加方式
writer.updateDocument(idTerm.createTerm(cmd.indexedId),
cmd.getLuceneDocument(schema));
}
allow
duplicates
writer.addDocument(cmd.getLuceneDocument(schema));
了解一下
SOLR
的跟踪器。
先来看看构造函数。
public
CommitTracker()
docsSinceCommit
0;
pending
null;
docsUpperBound
core.getSolrConfig().getInt("
updateHandler/autoCommit/maxDocs"
-
1);
timeUpperBound
updateHandler/autoCommit/maxTime"
SolrCore.log.info("
AutoCommit:
this);
记录自上一次提交以来已经具有的
的数目,pending是
ScheduledFuture
的对象,显然这个类里面用到了多线程。
和
是从配置文件获得的提交条件,doc
的上界以及时间的上界。
再来看看
addedDocument
方法吧,这个方法没有参数。
首先利用下面的两行代码来对
已经添加的
数目进行递增,同时设置当前时间给
lastAddedTime
,也就是获得最近添
加
时的系统时间。
docsSinceCommit++;
System.currentTimeMillis();
下面是一个条件为
>
0
&
(docsSinceCommit
docsUpperBound)的
if
语句,这个语句的意思是,在
数目上界大于0且自上次提交以来的
数目已经超过了
允许的上界,那么做以下事情:
如果上次提交延迟,中断上次提交延迟的任务。
分配一个新的任务(这里
就是
本身)。
这段代码的本质就是在
已经超过允许的值的情况下进行提
交。
接下来就是分配一个超时触发的提交任务,也就是在设定的时间到了以后触发提交过
程。
既然
schedule
方法中的
Runnable
参数是
this,也就是提交跟踪器,那么我们就有必要
来看一看它的
run
方法了。
这个方法包括提交的所有过程。
CommitUpdateCommand
command
CommitUpdateCommand(
false
command.waitFlush
true;
command.waitSearcher
//no
need
command.maxOptimizeSegments
1;
since
it
is
not
optimizing
commit(
autoCommitCount++;
这里首先创建一个提交更新命令的对象,并设置构造函数的参数为
false,意思是
optimize(优化)为
false。
r
然后设置其两个属性
waitFlush
waitSearcher
true,然后
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Solr 整体 请求 过程 详细 分析