無綱要模式

無綱要模式是一組 Solr 功能,當一起使用時,可讓使用者透過簡單地為範例資料建立索引,快速建構有效的綱要,而無需手動編輯綱要。

這些 Solr 功能都透過 solrconfig.xml 控制,包括:

  1. 託管綱要:綱要修改是在執行時透過 Solr API 進行,這需要使用支援這些變更的 schemaFactory。如需更多詳細資訊,請參閱綱要工廠設定一節。

  2. 欄位值類別猜測:先前未見過的欄位會通過一連串基於值的剖析器,這些剖析器會猜測欄位值的 Java 類別 - 目前提供 Boolean、Integer、Long、Float、Double 和 Date 的剖析器。

  3. 根據欄位值類別自動新增綱要欄位:先前未見過的欄位會根據欄位值 Java 類別新增至綱要,這些類別會對應至綱要欄位類型 - 請參閱欄位類型定義與屬性

使用無綱要範例

無綱要模式的三個功能已預先設定在 Solr 發行版本中的 _default configset 中。若要使用這些設定啟動 Solr 的範例執行個體,請執行下列命令:

bin/solr start -e schemaless

這會啟動單一 Solr 伺服器,並自動建立一個集合(名為「gettingstarted」),該集合在初始綱要中僅包含三個欄位:id_version__text_

您可以使用 /schema/fields 綱要 API 來確認這一點:curl https://127.0.0.1:8983/solr/gettingstarted/schema/fields 將會輸出:

{
  "responseHeader":{
    "status":0,
    "QTime":1},
  "fields":[{
      "name":"_text_",
      "type":"text_general",
      "multiValued":true,
      "indexed":true,
      "stored":false},
    {
      "name":"_version_",
      "type":"long",
      "indexed":true,
      "stored":true},
    {
      "name":"id",
      "type":"string",
      "multiValued":false,
      "indexed":true,
      "required":true,
      "stored":true,
      "uniqueKey":true}]}

設定無綱要模式

如上所述,有三個設定元素需要到位才能在無綱要模式下使用 Solr。在 Solr 隨附的 _default configset 中,這些元素已設定。但是,如果您想在自己的環境中實作無綱要模式,則應進行以下變更。

啟用託管綱要

Schema Factory 配置章節所述,除非您的配置指定應使用 ClassicIndexSchemaFactory,否則預設會啟用 Managed Schema 支援。

您可以透過加入如下的明確 <schemaFactory/> 來配置 ManagedIndexSchemaFactory(並控制使用的資源檔案,或停用未來的修改),請參閱Schema Factory 配置以取得有關可用選項的更多詳細資訊。

<schemaFactory class="ManagedIndexSchemaFactory">
  <bool name="mutable">true</bool>
  <str name="managedSchemaResourceName">managed-schema.xml</str>
</schemaFactory>

啟用欄位類別猜測

在 Solr 中,UpdateRequestProcessorChain 定義了一系列外掛程式,這些外掛程式會在文件索引之前或索引期間應用於文件。

Solr 的無綱要模式的欄位猜測方面使用特別定義的 UpdateRequestProcessorChain,允許 Solr 猜測欄位類型。您還可以定義要使用的預設欄位類型類別。

首先,您應該按照以下方式定義它(請參閱下面的 javadoc 連結以取得更新處理器工廠的相關文件):

  <updateProcessor class="solr.UUIDUpdateProcessorFactory" name="uuid"/>
  <updateProcessor class="solr.RemoveBlankFieldUpdateProcessorFactory" name="remove-blank"/>
  <updateProcessor class="solr.FieldNameMutatingUpdateProcessorFactory" name="field-name-mutating"> (1)
    <str name="pattern">[^\w-\.]</str>
    <str name="replacement">_</str>
  </updateProcessor>
  <updateProcessor class="solr.ParseBooleanFieldUpdateProcessorFactory" name="parse-boolean"/> (2)
  <updateProcessor class="solr.ParseLongFieldUpdateProcessorFactory" name="parse-long"/>
  <updateProcessor class="solr.ParseDoubleFieldUpdateProcessorFactory" name="parse-double"/>
  <updateProcessor class="solr.ParseDateFieldUpdateProcessorFactory" name="parse-date">
    <arr name="format">
      <str>yyyy-MM-dd['T'[HH:mm[:ss[.SSS]]]z</str>
      <str>yyyy-MM-dd['T'[HH:mm[:ss[,SSS]]]z</str>
      <str>yyyy-MM-dd HH:mm[:ss[.SSS]]]z</str>
      <str>yyyy-MM-dd HH:mm[:ss[,SSS]]]z</str>
      <str>[EEE, ]dd MMM yyyy HH:mm[:ss] z</str>
      <str>EEEE, dd-MMM-yy HH:mm:ss z</str>
      <str>EEE MMM ppd HH:mm:ss [z ]yyyy</str>
    </arr>
  </updateProcessor>
  <updateProcessor class="solr.AddSchemaFieldsUpdateProcessorFactory" name="add-schema-fields"> (3)
    <lst name="typeMapping">
      <str name="valueClass">java.lang.String</str> (4)
      <str name="fieldType">text_general</str>
      <lst name="copyField"> (5)
        <str name="dest">*_str</str>
        <int name="maxChars">256</int>
      </lst>
      <!-- Use as default mapping instead of defaultFieldType -->
      <bool name="default">true</bool>
    </lst>
    <lst name="typeMapping">
      <str name="valueClass">java.lang.Boolean</str>
      <str name="fieldType">booleans</str>
    </lst>
    <lst name="typeMapping">
      <str name="valueClass">java.util.Date</str>
      <str name="fieldType">pdates</str>
    </lst>
    <lst name="typeMapping">
      <str name="valueClass">java.lang.Long</str> (6)
      <str name="valueClass">java.lang.Integer</str>
      <str name="fieldType">plongs</str>
    </lst>
    <lst name="typeMapping">
      <str name="valueClass">java.lang.Number</str>
      <str name="fieldType">pdoubles</str>
    </lst>
  </updateProcessor>

  <!-- The update.autoCreateFields property can be turned to false to disable schemaless mode -->
  <updateRequestProcessorChain name="add-unknown-fields-to-the-schema" default="${update.autoCreateFields:true}"
           processor="uuid,remove-blank,field-name-mutating,parse-boolean,parse-long,parse-double,parse-date,add-schema-fields"> (7)
    <processor class="solr.LogUpdateProcessorFactory"/>
    <processor class="solr.DistributedUpdateProcessorFactory"/>
    <processor class="solr.RunUpdateProcessorFactory"/>
  </updateRequestProcessorChain>

此鏈中定義了許多內容。讓我們逐步了解其中一些。

1 首先,我們使用 FieldNameMutatingUpdateProcessorFactory 將所有欄位名稱轉換為小寫。請注意,此處和每個後續的 <processor> 元素都包含一個 name。這些名稱將用於本範例結尾的最終鏈定義中。
2 接下來,我們新增數個更新請求處理器來解析不同的欄位類型。請注意,ParseDateFieldUpdateProcessorFactory 包含一個長列表,其中列出了可能會被解析為有效 Solr 日期的可能日期格式。如果您有自訂日期,您可以將其新增至此列表(請參閱下面的 Javadocs 連結以取得如何操作的資訊)。
3 一旦欄位被解析,我們會定義將分配給這些欄位的欄位類型。您可以修改任何您想要變更的類型。
4 在此定義中,如果解析步驟判定欄位中的傳入資料是字串,我們會將其放入 Solr 中,其欄位類型為 text_general。此欄位類型預設允許 Solr 查詢此欄位。
5 在我們新增 text_general 欄位後,我們還定義了一個複製欄位規則,將所有資料從新的 text_general 欄位複製到名稱相同且後綴為 _str 的欄位。這是由 Solr 的動態欄位功能完成的。透過以此方式將複製欄位規則的目標定義為動態欄位,您可以控制綱要中使用的欄位類型。預設選項允許 Solr 在這些欄位上進行刻面、醒目提示和排序。
6 這是另一個對應規則的範例。在此案例中,我們定義當 LongInteger 欄位解析器識別出一個欄位時,它們都應將其欄位對應至 plongs 欄位類型。
7 最後,我們新增一個鏈定義來呼叫外掛程式列表。這些外掛程式會依照我們定義時給予它們的名稱來呼叫。我們還可以將其他處理器新增至鏈中,如此處所示。請注意,我們也給予整個鏈一個 name(「add-unknown-fields-to-the-schema」)。我們將在下一節中使用此名稱來指定我們的更新請求處理程式應使用此鏈定義。
此鏈定義會為字串欄位建立許多複製欄位規則,以便從對應的文字欄位建立。如果您的資料導致您最終產生大量複製欄位規則,則索引編製可能會顯著變慢,而且您的索引大小會更大。為了控制這些問題,建議您檢閱已建立的複製欄位規則,並移除任何您不需要用於刻面、排序、醒目提示等的規則。

如果您對此鏈中使用的類別有興趣,以下連結提供了上述提到的更新處理器工廠的 Javadocs

設定預設 UpdateRequestProcessorChain

定義 UpdateRequestProcessorChain 後,您必須指示您的 UpdateRequestHandlers 在處理索引更新時使用它(即新增、移除、取代文件)。

有兩種方法可以做到這一點。上面顯示的更新鏈具有一個 default=true 屬性,該屬性會將其用於任何更新處理程式。

另一種更明確的方法是使用 InitParams 來設定所有 /update 請求處理程式的預設值

<initParams path="/update/**">
  <lst name="defaults">
    <str name="update.chain">add-unknown-fields-to-the-schema</str>
  </lst>
</initParams>
完成所有這些變更後,應重新啟動 Solr 或重新載入核心。

停用自動欄位猜測

可以使用 update.autoCreateFields 屬性停用自動欄位建立。若要執行此操作,您可以使用 bin/solr config 與類似如下的命令:

bin/solr config -c mycollection -p 8983 --action set-user-property --property update.autoCreateFields --value false

索引文件的範例

啟用無綱要模式後(無論您是手動配置還是使用 _default configset),將會索引包含未在您的綱要中定義的欄位的文件,並使用自動新增至綱要的猜測欄位類型。

例如,新增 CSV 文件將導致新增未知的欄位,並根據值來設定 fieldTypes

curl "https://127.0.0.1:8983/solr/gettingstarted/update?commit=true&wt=xml" -H "Content-type:application/csv" -d '
id,Artist,Album,Released,Rating,FromDistributor,Sold
44C,Old Shews,Mead for Walking,1988-08-13,0.01,14,0'

輸出指出成功

<response>
  <lst name="responseHeader"><int name="status">0</int><int name="QTime">106</int></lst>
</response>

現在綱要中的欄位(來自 curl https://127.0.0.1:8983/solr/gettingstarted/schema/fields 的輸出)

{
  "responseHeader":{
    "status":0,
    "QTime":2},
  "fields":[{
      "name":"Album",
      "type":"text_general"},
    {
      "name":"Artist",
      "type":"text_general"},
    {
      "name":"FromDistributor",
      "type":"plongs"},
    {
      "name":"Rating",
      "type":"pdoubles"},
    {
      "name":"Released",
      "type":"pdates"},
    {
      "name":"Sold",
      "type":"plongs"},
    {
      "name":"_root_", ...},
    {
      "name":"_text_", ...},
    {
      "name":"_version_", ...},
    {
      "name":"id", ...}
]}

此外,文字欄位的字串版本會被索引,並使用 copyFields 到 *_str 動態欄位:(來自 curl https://127.0.0.1:8983/solr/gettingstarted/schema/copyfields 的輸出)

{
  "responseHeader":{
    "status":0,
    "QTime":0},
  "copyFields":[{
      "source":"Artist",
      "dest":"Artist_str",
      "maxChars":256},
    {
      "source":"Album",
      "dest":"Album_str",
      "maxChars":256}]}
您仍然可以明確指定

即使您想要對大多數欄位使用無綱要模式,您仍然可以使用 Schema API 在您索引使用它們的文件之前,預先建立一些具有明確類型的欄位。

在內部,Schema API 和 Schemaless Update Processors 都使用相同的 Managed Schema 功能。

此外,如果您不需要文字欄位的 *_str 版本,您可以直接從自動產生的綱要中移除 copyField 定義,而且由於原始欄位現在已定義,因此不會重新新增。

一旦欄位被新增至綱要,其欄位類型就會被固定。因此,新增具有與先前猜測的欄位類型衝突的欄位值的文件將會失敗。例如,在新增上述文件後,「Sold」欄位的 fieldType 為 plongs,但下面的文件在此欄位中具有非整數的小數值

curl "https://127.0.0.1:8983/solr/gettingstarted/update?commit=true&wt=xml" -H "Content-type:application/csv" -d '
id,Description,Sold
19F,Cassettes by the pound,4.93'

此文件將會失敗,如以下輸出所示

<response>
  <lst name="responseHeader">
    <int name="status">400</int>
    <int name="QTime">7</int>
  </lst>
  <lst name="error">
    <str name="msg">ERROR: [doc=19F] Error adding field 'Sold'='4.93' msg=For input string: "4.93"</str>
    <int name="code">400</int>
  </lst>
</response>