如有轉載,請註明出處,謝謝合作!
solr中的data-config.xml這個配置文件大家都知道,但是我對其中query,deltaQuery,parentDeltaQuery,deletedPkQuery的執行過程有點迷惑,所以自己探索學習了一下,我先說自己得出來的結論(其中關於deletedPkQuery是怎麼執行的任然不解),然後說明得出結論的方法。
對於data-config.xml這個配置文件,我舉個簡單的例子:
<dataConfig>
<dataSource>
........(這裏是配置數據源的)
</dataSource>
<document>
<entity name="member" pk="id" query="select id, ...... from Member where isDeleted=false"
deletedPkQuery="select id , ...... from Member where isDeleted=true"
deltaQuery="selected id from Member where lastModifyTime>'${dataimporter.last_index_time}' ">
<entity name="connection" pk="...." query="......."
deltaQuery="......."
parentDeltaQuery="........">
<\entity>
<entity name="groupMember" pk="...." query="......."
deltaQuery="......."
parentDeltaQuery="........">
<\entity>
<\entity>
</document>
</dataConfig>
(配置文件中的isDeleted是我表中的一個字段,是用來標記刪除的,true表示該條數據被刪除,false表示沒有被刪除)
上面的配置文件只是列出了大致的結構。
我通常都是用2種http請求:一種就是fullImport,還有一種就是deltaImport。
如果是fullImport,那麼就執行上面配置文件中的query語句(其他的語句不執行),並且主實體和子實體是嵌套的關係,即主實體query得到的每一行數據都將要被子實體拿去執行。
如果是deltaImport,那麼執行順序是這樣的:
(簡單起見,首先假設現在沒有要更新的數據)首先從子實體的detaQuery開始,如上面配置文件的connection實體,先執行該實體的detaQuery,發現沒有數據要更新(那麼就不會執行parentDeltaQuery),然後在繼續執行下一個實體groupMember裏面的deltaQuery,發現也沒有要更新的數據。最後執行deletedPkQuery。
首先到此爲止,我覺得,當我向solr服務請求deltaImport命令的時候,它就會先執行子實體的deltaQuery(我測試的例子裏面只有2層,但我相信,如果還有更多層,那麼它還是會先執行子實體的deltaQuery)
你有可能會問:當我請求deltaImport命令的時候,難道只有deltaQuery和deletedPkQuery被執行嗎?那parentDeltaQuery和query就不執行了嗎?
我之前說了,那是在沒有數據要更新的時候,它是這樣一種執行順序(當然,如果有數據要更新,它還是這種執行順序,但情況會不一樣)。
當任何一個表裏面的數據有更新時。我請求delteImport命令時,它任然按照上面討論的那種順序執行,比如說,我在執行connection實體裏面的deltaQuery時,發現了一條數據被更新了,那麼這時,parentDeltaQuery就會根據這條數據的id查出它的父實體的id,我的理解是,子實體會將這變化了的數據的id告知他的父實體(請注意:deltaQuery和parentDeltaQuery也是一種嵌套關係,即deltaQuery執行的到的每一條數據都將被parentDeltaQuery執行,這在solr wiki裏面有介紹)。當執行完了parentDeltaQuery後,他將繼續執行下一個實體connection裏面的deltaQuery,假如發現了有數據更新了,那麼也一樣要執行parentDeltaQuery。
綜上所述,當有deltaImport請求的時候,他都是先執行deltaQuery,如果在該實體中沒有發現要更新的數據,那就不執行parentDeltaQuery,直接執行下一個實體裏面的deltaQuery了,如果發現了更新了數據,那麼就執行parentDeltaQurery,然後繼續下一個實體....
你可能會問:“照你這麼說,當所有的子實體執行完了,各個實體裏面的parentDeltaQuery找到的數據都到哪裏去了?你不是說他會提交給相應實體的父實體嗎?那這麼提交的呢?”
對於第一個問題,“找到的數據到哪裏去了?”,我不太確定,因爲我沒有看過這部分的源代碼,但在測試的過程中給我的感覺是這樣子的:可能會有這樣的一個堆棧,把每一個實體找到的更新了的數據都壓到這個堆棧裏面,等所有的子實體都執行完了之後,然後執行主實體中的deletedPkQuery(爲什麼這時會執行這句?這是我在上面討論過的,就是這樣。先不要問我這句是怎麼執行的!),然後在最後執行主實體的Query,這時主實體的query就依次取出堆棧裏面的id,每次取到一個id,就嵌套執行所有子實體的query。這時就和你請求fullImport命令的時候的情況差不多了。
對於第二個問題:“你不是說他會提交給相應實體的父實體嗎?那這麼提交的呢?”
我想說的是,當我所謂的“堆棧”裏面充滿了更新了的數據的id的時候,這時就輪到主實體的query來這裏取數據了,這時我發現,我的主實體裏面的query的select語句被瞧瞧的改變了,比如上面data-config.xml裏面主實體是member,他的query="select id, ...... from Member where isDeleted=false"在你看不見的地方改成了query="select id, ...... from Member where isDeleted=false and id=13" 而這裏面的id爲13的那條數據正是更新了的數據的id。所以我覺得,父實體裏面的query就是通過把“堆棧”裏面的id取出來,然後把“我寫的query語句”拼接上這個id,然後向下一級一級執行query語句的。
假如你夠細心,你一定還會問我:“那主實體裏面的deletedPkQuery是不是也是和他的Query一樣,被拼接上了一個id,然後將之從索引裏面刪除?”
唉~~問題就出在這裏啊,我在測試的時候,預期也是以爲被拼接上了一個id,可是結果沒有,我就鬱悶了,當子實體數據有更新的時候,他是怎麼拿到這些數據的id然後將他的索引刪除的呢?我也不知道,在網上找了一些資料,發現講的最詳細的就是這位大哥的博客了:http://blog.sina.com.cn/s/blog_539d361e0100nca5.html
可我還是不太明白,請知道的大哥解釋一下!!!!
最後說明一下我是怎樣得出這個結論的?
我的方法就是讓這個data-import.xml出錯,最簡單的我將上面的配置文件做如下修改:
<document>
<entity name="member" pk="id" query="select id, ...... from Member where isDeleted=false1111"
deletedPkQuery="select id , ...... from Member where isDeleted=true2222"
deltaQuery="selected id from Member where lastModifyTime>'${dataimporter.last_index_time}' 3333">
<entity name="connection" pk="...." query=".......4444"
deltaQuery=".......5555"
parentDeltaQuery="........6666">
<\entity>
<entity name="groupMember" pk="...." query=".......7777"
deltaQuery=".......8888"
parentDeltaQuery="........9999">
<\entity>
<\entity>
</document>
我就是在每一條語句後面編號,這明顯是有錯的,當我進行deltaImport命令請求時,在命令提示符裏面就會出現相關的錯誤報告,你去找第一個錯誤,他會說:“deltaQuery=".......5555”無法執行,那麼你就知道他先執行的哪句?然後你在去掉”5555”,重啓solr服務,繼續請求deltaImport命令,然後又會出現別的錯誤,就這樣,你就知道他的執行順序了,我不知道我這樣的方法合理不合理,如果已經有大哥明確了他的原理請指教!!謝謝。