一.簡介
Solr的函數可以動態計算每個文檔的值,而不是返回在索引階段對應字段的靜態數值集。函數查詢是一類特殊的查詢,它可以像關鍵詞一樣添加到查詢中,對所有文檔進行匹配並返回它們的函數計算值作為文檔得分。使用函數查詢,函數計算結果將用於修改相關度得分或用於搜索結果的排序。在應用程序層,函數計算的結果可以作為一個動態字段添加到每個文檔。函數也可以嵌套,即一個函數的輸出可以作為另一個函數的輸入,函數允許嵌套任意多層。
二.函數語法
Solr的標准函數語法首先定義一個函數名,后面緊跟一對括號,括號中包括零個、一個或多個輸入參數,參數之間以逗號分隔:
functionName()
functionName(input1)
funtionName(input1,...inputN)
以下內容都可以作為 函數的輸入:
1.常量。例如:100,“Hello world”等
2.字段。例如:fieldName,field(fieldName)
3.另一個函數。例如:functionName(...)
4.替代參數。例如:q={!func}min($f1,$f2)&f1=sqrt(popularity)&f2=1
Solr將文檔中每個輸入參數的類型定義為函數,初看可能會對此感到困惑。絕大多數函數遵循標准的函數語法,但常量函數、字段函數和替代參數是簡化語法的特例。常量函數的語法就是常量值本身;字段函數的語法是字段的名稱,可以選擇性地在函數中包含field命名;替代參數的語法是$parameter,其表示URL請求的查詢字符串參數。除此之外,其它函數都遵循標准的函數語法。
由於函數的所有 輸入可以看成函數本身【即使輸入的是常量函數】,標准的函數語法可以在概念上簡化為functionName(function1,...,functionN)。
假設文檔中的fieldContainingNumber字段包含值-99,則會出現以下情況:
不難看出,每個函數可以容易地將字段函數置換為常量函數或者其他標准函數。雖然每個例子中計算輸入參數的命令和方法不同,但都返回了-99和2之間的最大值。將一個函數輸入作為另一個函數的參數的好處是,以有趣的方式組合函數來實現復雜的計算。
並不是所有的函數都接受相同類型的輸入參數。一些函數將常量值輸入轉變為字符串,另一些函數則將其轉變為整數或者浮點數。假設fieldContainingString賦予hello值,如下所示:
strdist函數基於一種特殊的算法【由第三個參數定義,edit表示文本類型】來計算兩個字符串的相似度。如果在此函數中輸入了錯誤的類型,會出現以下結果:
該函數會自動類型轉換,在此是把數值型轉換為字符串。很多時候這種轉換是不可能的【例如:字符串轉數值】,這種情況下,通常會收到Solr異常提醒。需要明確一點,雖然函數嵌套語法是通用的,但並不是所有的函數都可以組合成功。
Solr的函數通用性使得它們可以在Solr的各種核心功能上使用。函數可以影響相關度,可以過濾結果,可以用於排序,也可以對文檔附加返回的函數值,甚至可以用在分面上。
三.函數的搜索
在Solr中執行典型的關鍵詞搜索時,每個關鍵詞會在倒排文檔中查找一遍,通過計算相關度得分來決定每個文檔與關鍵詞的匹配程度。查詢並不局限於詞項本身,也可以在查詢中插入函數 ,將其視為另一個關鍵詞。如下:
該查詢執行布爾搜索的關鍵詞為United States,France,和President,以及一個返回值為1~100區間值的函數,這個函數用來衡量匹配文檔的新舊程度【文檔越新,返回值越高】。此查詢有如下三個方面需要特別注意:
1.語法_val_:value用來將一個查詢函數【嵌套recip和ord函數】作為一個詞項插入到用戶主查詢語句中。
2.函數查詢默認匹配所有文檔。在上面例子中查詢被限制在包含三個詞項的所有文檔中,函數查詢作為額外的詞項並沒有改變查詢匹配的文檔結果數。
3.一個查詢的相關度評分是查詢中每個詞項相關度得分的總和。上面提到的三個詞項都會得到各自基於tf-idf【詞頻-逆文檔頻率】相似度計算的相關度得分,然而函數查詢的得分是函數自身的取值。
_val_的目的是讓越新的文檔相關度得分越高。具體而言,最新文檔的相關度得分將獲得100的加分,最舊文檔的相關度得分將獲得1的加分,其余文檔根據其新舊程度獲得1~100之間的加分。注意,每個文檔的最后得分會經過規范化處理,因此不會看到實際的1~100分加到每個文檔的最后得分中,只會看到越新的文檔排名提升越多。如果 從查詢中移除函數,Solr的搜索結果排序會發生變化。
在查詢中掛接函數
上面提到的_val_:"functionName(...)"語法,可以像關鍵詞那樣插入到查詢的任何位置。Solr包含一個函數查詢解析器,通過本地參數{!func}functionName(...)進行調用。兩種方式可以實現相同的功能:將函數的值作為一個詞項添加到查詢中,它的相關度得分就是函數本身的值。因此,一下語句是等價的。
通過向查詢添加函數,可以調整與查詢匹配的文檔相關度得分,這個做法似乎很有用。事實上,如果想要通過函數計算來過濾某個適合結果區間以外的結果,函數查詢就不那么有效了。所幸,Solr提供了函數區間查詢解析器來解決此類需求。
frange查詢解析器
如果需要對搜索結果進行過濾,只留下函數計算產生特定值的文檔,可以選擇函數區間解析器。frange過濾器執行一個特定的函數查詢,然后過濾掉函數值落在最低值和最高值范圍之外的文檔。例如:
frange查詢解析器過濾了總價格在10~15區間之外的那些文檔,上限和下限通過本地參數l【最低】和u【最高】來定義。上限和下限是默認的,如果只想匹配包含特定值的文檔,可以將l和u的值設為同一值。另外,上限值和下限值的設置是可選的,沒有強制要求同時設置上下限。如有需要,frange查詢中的本地參數incll【包含下限】和inclu【包含上限】可設置為false,這樣可以過濾出不在區間范圍內的文檔。
四.以字段形式返回函數
所有的函數輸入,包括常量和字段,在函數查詢語法中都可視為函數本身。既然如此,函數和字段最終都會返回一個值,因此在Solr中其他一些地方中用函數替代字段是可行的。
事實上,不僅可以計算每個文檔對應的函數值,也可以將文檔的計算值當作偽字段返回。例如:
搜索結果如下:
Solr搜索結果向字段列表請求增加一個函數,會將一個新的字段添加到文檔中。這並不是存儲在索引中的真實字段,但會像存儲字段一樣返回到文檔。返回到文檔中的偽字段名稱是計算函數值的語法,這非常不好,因此,需要為返回值的偽字段名稱自定義別名。如下:
冒號之前是偽字段的名稱,冒號之后是計算偽字段值額函數。這讓偽字段可以像真實字段一樣返回函數值。事實上,動態計算的偽字段也可以覆蓋一個真實字段。這樣的用例需要在不同用例中的同一個字段上返回不同的值,例如,基於用戶訪問權限清空字段,或為不同地域提供各種版本的內容翻譯來修改字段值。在返回搜索結果之前,函數可以操作任何字段的取值。函數不僅可以修改返回的文檔字段,還可以改變返回文檔的排序。
五.函數排序
函數的排序語法與字段的排序語法的唯一不同之處在於,整個函數語法【引用參數包含全函數語法】取代了字段名稱:
這個請求將根據之前計算的總價格進行排序【升序】,如果價格相同,則按照文檔得分降序排序。
六.Solr的可用函數集
Solr的函數主要分為4類:數據轉換函數、數學函數、相關度函數和布爾函數。
1.數據轉換函數
Solr中最常見的函數是將數據從一種格式轉換成另一種格式的函數。例如:map(x, min, max, target):如果x落在最小值與最大值之間,則使用x替換target的值。
常用數據轉換函數如下:
2.數學函數
3.相關度函數
Solr的相關度得分默認使用DefaultSimilarity類計算。這個類使用了來自搜索索引及查詢術語的多種統計數據,以便識別出與查詢最佳匹配的文檔。Solr的相關度函數可以返回單獨的統計數據供選用。所有關鍵的相關度統計數據都包含在內,例如常見的tf-idf。
例如:
4.距離函數
有時計算兩個值直接的距離很有用,可能是地球上兩個坐標點的地理距離,也有可能是兩個點或者向量的幾何距離,甚至是兩個字符串之間的字符距離。如下:
5.布爾函數
6.自定義函數
對於想執行的某些數據操作,Solr中可能沒有相應的內置函數。別擔心,Solr的用戶自定義函數功能十分簡便。代碼在函數中執行,這意味着可以做很多技術處理,簡單的如內存計算到鏈接外部文件,復雜的如從數據源導入更多信息,甚至執行一段任意代碼等。自定義函數唯一的局限是等待函數計算完成的時間。因為函數代碼在每個匹配文檔中執行,它需要快速執行以便在合理的時間內進行搜索響應。
例如,創建一個多字符串拼接的自定義函數步驟:
1.編寫一個函數類。這個類繼承ValueSource類,保證在搜索索引中的每個文檔都返回一個計算值。
2.編寫ValueSourceParser類,它可以理解自定義函數的語法,並將它解析為步驟1定義的ValueSource函數需要的變量。
3.向Solrconfig.xml文件添加一個XML元素,定義自定義函數的名稱及ValueSourceParser的位置。當自定義函數通過函數名稱調用時,ValueSourceParser類將會解析ValueSource中的輸入。
6.1通過擴展ValueSource實現自定義函數
自定義的連接函數會擴展Solr的ValueSource類。ValueSource通過getValues方法返回一個FuncationValues對象。FunctionValues對象返回Solr索引中自定義函數任意文檔的計算值。Java代碼如下:
就輸入參數而言,ConcatenateFunction類接受兩個ValueSource對象和一個代表定界符的字符串。
6.2通過ValueSourceParser解析函數輸入
在ConcatenateFuncationParser的代碼中,預設了兩個ValueSource輸入【字段、用戶輸入字符串,或者其他函數】和一個可選的字符串分界符。ConcatenateFunctionParser讀取查詢請求中的輸入后,創建ConcatenateFunction對象並導入輸入內容。
6.3自定義函數調用
創建好自定義連接函數所需要的兩個類之后,剩下的工作就是向Solrconfig.xml文件添加一下內容,讓Solr知曉新建的函數。
<valueSourceParser name="concat" class="sia.ch15.ConcatenateFunctionParser" />
調用方式如下: