上一篇的配置說明主要是說明solrconfig.xml配置中的查詢部分配置,在solr的功能中另一個重要的功能是建索引,這是提供快速查詢的核心。java
按照Solr學習之一所述關於搜索引擎的原理中說明了創建索引,其實就須要通過分詞組件處理,語言組件處理最後創建成一個倒排索引表,linux
經過這個索引表,來進行查詢,本篇就是說明solr如何創建索引的也便是solrconfig.xml中關於更新索引的部分,另外因爲創建索引須要涉及到web
schemal.xml相關內容定義,這裏面也一塊兒說明。數據庫
在solr的基本概念中,有個文檔的概念。solr在創建索引的時候,是按照文檔的方式添加到索引中的。那麼咱們如何設計一個文檔那。apache
舉個簡單的例子,假設你對圖書館的圖書創建索引,你是按照每一個圖書的信息來創建索引,仍是按照全部圖書的全部章節來創建索引那,json
這其實要看你的應用程序要求。若是你的客戶要求查詢的時候,出來是一條條書目的信息,那麼就比較適合按照一本本圖書這個級別來創建windows
文檔,那可能涉及到的文檔字段(field) 有書名、做者、出版社、價格等基本信息。數組
那在搜索的時候,若是用戶想查詢的是哪些書包含某些內容的信息是查不到的。 若是 想查到,可能要對書的每篇文章都做爲一個索引信息,服務器
固然你要承受大索引的數據了。併發
因此簡單的總結來講,文檔定義爲一個個客戶想查詢到的信息粒度比較合適。
文檔是由字段組成的,相似於數據庫的一條記錄,在數據庫中記錄通常都有一個主鍵,文檔也相似,文檔經過惟一鍵id來在分佈式部署的時候路由到
相應的shard上去,也便於索引確認惟一的文檔,若是你兩次發的id是同樣的,solr將會覆蓋上一個文檔。
solr的字段定義通常形如:
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
若是是惟一鍵,則配置爲: <uniqueKey>id</uniqueKey>
經過上面字段的定義咱們看到字段有幾個重要屬性:
name: 標示這個字段的名稱;
type:標示字段的類型,注意這裏面的類型不一樣於java的類型,是solr本身定義的,經過這個類型solr知道這個字段
該是否分詞等,注意定義爲string類型通常是不作分詞的,作分詞能夠定義爲text*類型。
indexed:定義文檔是否被索引,這個能夠理解爲咱們是否在此字段上進行搜索,若是在,這個定義爲true,不然爲false;另外若是你須要在這個字段上進行排序、分組、切片、 提供建議、或者執行一個查詢函數,你也須要定義這個索引爲true。
舉個例子,你假設定義一個test1字段,這個值爲true,你就能夠能夠經過q=test1:foo這種方式來進行查詢;若是定義爲false,
即便你的文檔中有這個字段並且值就是foo,那麼也查不到數據。
stored :定義這個字段內容是否能夠做爲返回結果的一部分,若是是,則定義爲true,不然爲false。
舉個例子,你若是想提取test1字段能夠經過制定fl=test1來提取,若是配置爲true則能夠提取到這個值,若是是false則提取不到。
這個indexed和stored能夠都配置爲false,通常在你動態字段中定義,通常用來忽略某個值。
docValues:表示此域是否須要添加一個 docValues 域,這對 facet 查詢, group 分組,排序, function 查詢有好處,儘管這個屬性不是必須的,
但他能加快索引數據加載,對 NRT 近實時搜索比較友好,且更節省內存,但它也有一些限制,好比當前docValues 域只支持 strField,UUIDField,
Trie*Field 等類型,且要求域的域值是單值並且是必須有值的或者有默認值的,不能是多值域
solrMissingFirst/solrMissingLast:在查詢結果排序的時候,若是這個字段沒有值的話,這個文檔是放在查詢結果有值字段的前面/後面。
multValued: 這個字段是否存在多個值,若是存在多個值設置爲true,sorlj用add而不是set來設置這個字段。
omitNorms: 此屬性若設置爲 true ,即表示將忽略域值的長度標準化,忽略在索引過程當中對當前域的權重設置,且會節省內存。
只有全文本域或者你須要在索引建立過程當中設置域的權重時才須要把這個值設爲 false, 對於基本數據類型且不分詞的域(field)
如intFeild,longField,StrField 等默認此屬性值就是 true, 不然默認就是 false.
這個若是設置爲false,能夠起到增強短文章的boost做用,好比你有一個100個單詞的文檔含有這個詞,還有一個1000個單詞的文檔
一樣只含有一次這個值,那麼在比較相關性的時候,100個單詞的文章相關性更強。若是你的文章長度大小差很少能夠不設置這個值。
required: 添加文檔時,該字段必須存在,相似於數據庫的非空。
termVectors: 設置爲 true 即表示須要爲該 field 存儲項向量信息,當你須要MoreLikeThis 功能時,則須要將此屬性值設爲 true ,這樣會帶來一些性能提高。
說明下,在文檔和查詢語句進行匹配的時候,須要用到相關度判斷,就是經過單詞向量來處理的。
這個設置爲true會記錄詞出現的頻次和位置,能夠提取出來。
termPositions: 是否termVectors中在存儲 Term 的起始位置信息,這會增大索引的體積,但高亮功能須要依賴此項設置,不然沒法高亮,
能夠經過positions提取出來,目前沒測試過。
termOffsets: 設置爲true則記錄詞的偏移量。
default: 若是這個字段沒有指定值的時候,使用的默認值。
所謂的動態字段,是爲了簡化字段的定義,設想下一個文檔的字段有幾十個,定義起來很是麻煩,有不少屬性是相同的,solr支持經過字段名匹配的字段能夠通用一個配置,
這就是動態字段.
舉個例子:
<dynamicField name="*_txt" type="text_general" indexed="true" stored="true" multiValued="true"/>
標示,以_txt結尾的字段都匹配這個配置,其餘屬性同通常字段。這樣能夠不用常常修改這個字段。
複製字段的做用就是能夠將多個字段複製到一個字段中,這樣便於搜索,固然你要保證兩個字段間類型的兼容性。
注意
1)只能從定義其餘其餘字段複製到複製字段,不能從複製 字段到複製字段,能夠限制複製多少個字段長度。
2) 通常複製字段須要定義爲多值存儲。
3)複製字段通常不用再存儲了,存儲無心義。
定義以下:
<copyField source="head" dest="teaser" maxChars="300"/>
一個總體定義:
<dynamicField name="*_company" type="string" indexed="true" stored="true"/>
<dynamicField name="*_entity" type="string" indexed="true" stored="true"/>
<field name="database_ids" type="string" indexed="true" stored="false"/>
複製字段定義以下:
<copyField source="*_company" dest="database_ids"/>
<copyField source="*_entity" dest="database_ids"/>
有6種基本類型都是不分詞的:
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
說明: 不被分詞,支持docvalue,不能是多值,不能爲空或有默認值。
<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
說明: 只能取true或false
<fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>
說明:一、支持docvalue字段,一樣不能爲空或者有默認值不能爲多值。
二、若是支持快速範圍搜索的話,建議用tint等。
三、precisionStep 這個是字段劃分幾個範圍,這個值設置越小,劃分的範圍就多,範圍查詢速度更快,更佔索引空間。
positionIncrementGap: 這個是多值使用,多個值之間間隔,經常使用語複製字段防止誤匹配。
<fieldType name="date" class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0"/>
說明: 日期類型,支持格式:1995-12-31T23:59:59Z,默認存儲的是UTC-0區的時間。
北京時間存儲的時候通常須要+8個小時存儲。
<field name=」timestamp」 type=」date」 indexed=」true」 stored=」true」 default=」NOW+8HOUR」 multiValued=」false」/>
<fieldtype name="binary" class="solr.BinaryField"/>
說明:通過base64編碼的二進制數據,查詢的時候,查詢的內容也要通過base64編碼來查詢。
<fieldType name="random" class="solr.RandomSortField" indexed="true" />
說明:隨機數字段,須要僞隨機數排序的時候使用。
<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
xxx
</fieldType>
說明: text字段,須要分詞的定義爲這種類型,xxx標示中間還有不少內容,好比定義分詞器等。
按照前面文章所述,咱們知道solr是能夠經過HTTP的接口發送JSON或者XML或者Javabin(一種二進制+文本混合模式)的http報文來進行solr的索引的更新的。
經過xml的格式以下,在json格式中,多個文檔用數組形式每一個文檔必須是json報文格式,多值也採用文檔形式。另外solr還能夠經過DIH(Data Import Handler)的
方式來從數據庫、json格式的報文或者xml報文導入數據。還能夠從二進制文件,好比PDF、好比MS office提取數據。
<add> <doc> <field name="id">1</field> <field name="test_s">hello</field> <field name="type_s">post</field> <field name="mutilvalue_s">value1</field> <field name="mutilvalue_s">value2</field> </doc> <doc> <field name="id">2</field> <field name="test_s">hello2</field> <field name="type_s">get</field> <field name="mutilvalue_s">value3</field> <field name="mutilvalue_s">value4</field> </doc> </add>
更新索引在solrconfig.xml中的配置以下:
<updateHandler class="solr.DirectUpdateHandler2"> <updateLog> <str name="dir">${solr.ulog.dir:}</str> </updateLog> <autoCommit> <maxTime>60000</maxTime> <maxDocs>30000</maxDocs> <openSearcher>false</openSearcher> </autoCommit> <autoSoftCommit> <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime> </autoSoftCommit> <!-- <listener event="postCommit" class="solr.RunExecutableListener"> <str name="exe">solr/bin/snapshooter</str> <str name="dir">.</str> <bool name="wait">true</bool> <arr name="args"> <str>arg1</str> <str>arg2</str> </arr> <arr name="env"> <str>MYVAR=val1</str> </arr> </listener> --> </updateHandler>
在配置中有autoCommit 相關配置,在說明以前先說下commit,通常說的commit是指硬提交,目的是使全部在這個collection上的未提交的內容刷新到可持久化設備上去,
而且打開新的搜索器,預熱搜索器,使搜索可見。
簡單來講軟提交softCommit的目的是爲了使搜索可見,並不保證數據被持久化,在服務器崩潰的時候可能數據會丟失。
這裏面的自動提交,默認是硬提交,新的搜索器是否打開是經過:openSearcher 控制的,若是爲true就打開,那麼這時候提交的數據可見,這裏面能夠配置固定的詩句進行
自動提交(<maxTime>60000</maxTime> 單位是毫秒)或者未提交的文檔數量( <maxDocs>30000</maxDocs>)達到多少進行提交,兩個都配置的時候,第一個達到的起效。
自動軟提交的配置相似。
整個更新的流程:
說明:
一、客戶端經過http發送xml、json或javabin格式文檔給jetty服務器。
二、jetty服務器根據地址路由到solr這個web程序。
三、solr根據/update 經過solrconfig.xml的配置:
<requestHandler name="/update" class="solr.UpdateRequestHandler">
</requestHandler>
來選定處理的handler。
四、更新的handler根據schemal.xml配置的文檔字段類型進行具體的分析處理。
五、將添加文檔操做記錄到事務日誌中。
六、將數據記錄到事務日誌後,只要成功了,不管是否作了commit均可以返回了,即便後面沒有作commit,服務器有問題,在啓動的時候仍然能夠經過事務日誌進行恢復。
事務日誌是保障索引數據不丟失的策略之一,只要你更新索引,好比在solrJ中使用了solrJ服務的相關add方法,雖然沒提交數據,可是這些數據仍然被記錄在了solr的事務日誌中,前文配置爲:
<updateLog>
<str name="dir">${solr.ulog.dir:}</str>
</updateLog>
事務日誌的做用:
一、事務日誌在客戶端未發送commit並且沒有進行自動提交的時候,若是客戶端崩潰了,能夠經過事務日誌進行恢復。
二、事務日誌在實時搜索中被使用,經過文檔id查詢,自動更新時候也是用這個文檔。
三、事務日誌在solrColud部署中,由副本更新時候使用。
事務日誌內容:
我去看過,基本上是記錄文檔的信息,操做的基本信息。事務日誌在提交前都保留,一旦進行了硬提交,老的事務日誌會刪除,新的事務日誌會創建起來。
事務日誌的大小:
事務日誌的大小,要看你的提交的頻率,若是你設置了自動提交,那麼自動提交的最大文檔數量,也就是一個事務日誌的最大大小,更大的事務日誌可能
會形成在服務器恢復的時候耗費更長的時間來恢復。
solr中不存在update操做,是經過先delete後add操做完成的,solr能夠經過本身的內部機制,設置了update的具體一個文檔字段的操做,其實也是經過先提取出來這個文檔的信息,再更新的。
<add>
<doc>
<field name ="id">1</field>
<field update="set" name ="count">10</field>
</doc></add>
併發更新:
在solr運行的時候,若是存在多個客戶端來更新同一個文檔的時候,可能會存在着併發問題,這個問題,solr是經過_version_來控制的,併發更新的時候,爲了防止重複更新或者更新錯誤的狀況,在更新的時候帶上這個字段(<field name="_version_">1234567890</field>),則solr在作具體的操做的時候,會從索引或事務日誌中提取版本信息,若是是這個版本則更新,不是則拋出異常。
版本信息能夠經過id和版本號來獲得。
這個版本信息字段_version_還能夠作其餘做用。
1: 僅僅標示這個文檔必須存在。
>1:則標示爲正式的版本號,必須存在並且是這個版本,不然失敗;
0:無併發控制,若是存在則重寫;
<0:文檔必須不存在。
段合併:
由前面文章咱們知道,solr的索引是由段組成,更新索引的時候是寫入一個段的信息,幾個段共同組成一個索引,在solr優化索引的時候或其餘的時候,solr的段是會合並的。
因此有很多相關段控制的信息。
<mergeFactor>10</mergeFactor>
說明:合併因子,有兩層含義:
一、內存中有10個文檔的時候,會建立一個段;
二、當一個索引中段的個數達到10的時候,這10個段會合併成一個段,簡單的說,一個索引中最多隻能有9個段。
注意,若是一味的這樣合併可能會致使一個段的內容過多,索引變慢,因此solr經過maxMergeDocs 這個參數來指定一個段的最大文檔數量,即便之後solr的段的個數超過了
10的,若是合併後不知足一個段的最大文檔個數爲:maxMergeDocs的條件,則不進行合併。
minMergeSize: 指定最小的合併段大小,若是段的大小小於這個值,則能夠參加合併。
maxMergeSize:當一個段的大小大於這個值的時候就不參與合併了。
maxMergeDocs:當文檔數據量大於這個的時候,這個段就不參與合併了。
合併段默認經過: <mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler"/>配置類來處理。
底層更新:
<updateHandler class="solr.DirectUpdateHandler2">是配置底層更新的相關數據,不能同 <requestHandler name="/update" class="solr.UpdateRequestHandler">相互混淆了。
這裏面涉及到:
一、首先這些存儲存在什麼位置:
<dataDir>${solr.data.dir:}</dataDir> 這個更改默認的data位置,通常data是在solr的根目錄下面的core的子目錄的data裏面。
建議若是存在多個磁盤能夠不一樣的core存放在不一樣的磁盤上。
二、具體的寫操做的實現:
<directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"> <!-- These will be used if you are using the solr.HdfsDirectoryFactory, otherwise they will be ignored. If you don't plan on using hdfs, you can safely remove this section. --> <!-- The root directory that collection data should be written to. --> <str name="solr.hdfs.home">${solr.hdfs.home:}</str> <!-- The hadoop configuration files to use for the hdfs client. --> <str name="solr.hdfs.confdir">${solr.hdfs.confdir:}</str> <!-- Enable/Disable the hdfs cache. --> <str name="solr.hdfs.blockcache.enabled">${solr.hdfs.blockcache.enabled:true}</str> <!-- Enable/Disable using one global cache for all SolrCores. The settings used will be from the first HdfsDirectoryFactory created. --> <str name="solr.hdfs.blockcache.global">${solr.hdfs.blockcache.global:true}</str> </directoryFactory>
默認的NRTCachingDirectoryFactory 其實是standardDirectoryFactory的封裝。
在實際運行過程當中,solr會根據系統和JVM的版本進行。
一、在linux、windows、solaris的64位操做系統用的是MMapDirectory中。
二、在32windows下用的是SimpleFSDirectory。
三、NIOFSDirectory :利用NIO優化,避免從相同的文件讀數據須要同步。不能在windows上利用這個,是由於JVM的bug。
在solr的管理界面,能夠看到Directory的具體實現。
在solrconfig.xml中,你能夠重寫默認的Directory的實現,經過以下的更改:
<directoryFactory name="DirectoryFactory"
class="${solr.directoryFactory:solr.MMapDirectoryFactory}"/>
在64位windows上、solaris、和linux上,它經過虛擬內存管理功能能夠得到讀的更好性能。