顯示具有 SOQL 標籤的文章。 顯示所有文章
顯示具有 SOQL 標籤的文章。 顯示所有文章

2017-12-10

Salesforce SOSL, SOQL, and Tokenization

Salesforce 在登入後的畫面頂端提供了一個搜尋框,提供使用者搜尋各式資訊,例如:Account, Contact, Opportunity, Contract 等。

但由於預設的搜尋行為使用其內部的斷詞系統,因此針對一些專有名詞搜尋時,可能就不那麼盡如人意;例如:當資料為東京都時,可以用東京或完整的東京都搜尋到,但是無法用京都搜尋到該筆資料,或許這在很多時候是好用的,尤其當大家公認東京都跟京都是完全不同的 entity,但有時候當使用者只知道公司部分名稱時,就容易造成困擾。以下是 Salesforce 搜尋框的兩個主要限制:
  • 預設行為為 start with:一如前例,系統搜尋行為會找出以京都為起始字串的資料,如果想找到東京都,搜尋時必須輸入「*京都」。
  • 底層以 morphological tokenization 為基礎的索引:換言之,當專有名詞不常見時,可能因斷詞系統無法正確辨識而找不到。

上述兩個問題在斷詞系統剛從 bigram 轉換為 morphological [1] 時備受批評,但在 2017 年 4 月 [2] 跟 6 月 [3] 有修正得更精細些,例如:「横浜市中区」已經可以使用「中区」找到,關鍵不只是 start-with 的問題,更在於斷詞系統能識別「中区」一詞;然而對於廣大可能的中文專由名詞來說,這樣的解法仍然不夠。

其實英文也不見得就完全沒事,因為有時候在專有名詞欄位,使用者可能只輸入縮寫,甚至是自創的縮寫,這時候 morphological 一樣無法正確辨識並提供搜尋時所需的索引。

想要徹底解決,自己動手寫點程式可能免不了,就 Salesforce 提供的 SOSL 與 SOQL 而言,前者仍然以斷詞系統為基礎 [4],因此只能選用 SOQL 的 like-anywhere 完成,但相對效能上難免吃重些。

see also:
[1] Salesforce Release Notes (Winter'15): Users Searching in Chinese, Japanese, Korean, and Thai Find Optimized Results
[2] Salesforce Community Known Issues: New morphology tokenization for Japanese characters after new search framework can cause unexpected morphological tokenization result
[3] Salesforce Community Known Issues: Chinese - Morphology tokenization improvement for mainly proper name noun
[4] Force.com SOQL and SOSL Reference: Introduction to SOQL and SOSL
[5] Salesforce Community Known Issue: Wrong results for Japanese OR search for file content
[6] ROSETTE.com: Why Tokenization Matters

2017-09-21

Salesforce: More about SOQL

上一篇整理了 Salesforce 中各式 object relationships 與相關 SOQL patterns;這邊想多聊一些 SOQL 撰寫時要注意的小地方。

Lazy Fetch

SOQL 算是把 lazy fetch 發揮得淋漓盡致;首先,它不像 SQL,SOQL 中並不提供 SELECT * 的語句,所有需要的 fields 除了 ID 都必須完整列舉。其次,即使只 SELECT 一個 field,回傳型別仍為 List<T> where T extends sObject,以下面這個針對 Account 物件搜尋的 SOQL 為例:
SELECT Name FROM Account
回傳的型別是 List<Account> 而不是 List<String>。

Query from One-side
如同操作 relational database,Salesforce 也提供了一些介面方便使用 SOQL 查詢系統中的資料,無論是 Workbench 或 Eclipse 中的 schema view,都會將結果以表格 (tabular) 的方式呈現。這跟 SOQL 以 object-oriented 的操作思維有些衝突,尤其是針對 one-to-many relationships 查詢時。以下是從 one-side 出發使用 outer JOIN 後在 Workbench 中得到的錯誤訊息。
看來 Salesforce 在這塊並不像 report 介面提供表格中再展開子表的能力,直接給了 parent relationships queries are disabled 的錯誤訊息。

2017-09-19

Salesforce Object Relationships

Salesforce 中有關 objects relationships 對新手往往是比較難懂的,主要原因包括:
  1. Object modeling 時採用的 schema builder 看似 ER model,但實際使用 SOQL 操作時,卻是以物件導向的觀點。
  2. SOQL 沒有 JOIN,只能透過 relationship traversal with path expression 完成各式的 implicit JOIN。
  3. Object 中記錄 relationship 的 field naming,有獨特的 convention,有時使用 __c,有時卻要使用 __r。
  4. Relationship 的 cardinality 固定為 one-to-many;使用 SOQL traverse relationship 時,從 one side 或 many side 出發會需要截然不同的 SOQL statement patterns。
另外還有幾點對撰寫 SOQL 關係不大,但也容易造成困擾:
  1. 設定 relationships 可能分為兩類:lookup 與 master-detail (a.k.a. MD)。
  2. 以物件導向的角度,上述分別是 aggregation 與 composition;前者是 whole-part 的關係,後者有一致的生命週期。
  3. 文件中的 parent 與 child,並非專屬於 master-detail relationship,純粹分別用於 relationship 中的 one side 與 many side。
[1] 是目前看過的參考資料中,最為完整的一篇,建議可以從這篇開始入門;相對其他文件,此處的名詞定義叫為明確,範例也相對清楚。這邊特別說明了如果 SOQL 以 one side (parent) 作為起點時,需使用 nested SELECT:
  • Both relationships are defined from the many-to-1 side, namely from a child to a parent. Note that we have utilized a NESTED select to obtain the records of related children from the parent. This kind of expression is very powerful in obtaining related records traversing from the 1 side in a 1-m relationship.
  • It is a useful pattern to obtain related information on a parent and all its children via traversing path expressions with relationship fields.
另外,當 SOQL 以 one side 出發並使用 nested SELECT 時,回傳結果的數量並非 Cartesian product,而是以 nested object 的方式呈現,意即每一筆 parent object 中含有多筆 child objects。

下表整理了 SOQL 針對不同 side 作為起點,如何透過 relationship traversal 達到各式 JOIN 的 patterns:
Outermost FROM Clause
One Side Many Side
Inner JOIN 在 WHERE clause 中使用 nested SELECT
SELECT Name
FROM Position_c
WHERE Id IN (SELECT Position__c FROM Job_Application__c)
在 WHERE clause 中直接取用 relationship
SELECT Name,Position__r.Name,
FROM Job_Application__c
WHERE Position__r.Department__c = ‘Sales’
Outer JOIN 在 SELECT clause 中使用 nested SELECT
SELECT Name, (SELECT Name FROM Job_Applications__r)
FROM Position__c
在 SELECT clause 中直接取用 relationship
SELECT Name, Position__r.Department__c
FROM Job_Application__c
ps. 上述 SOQL 中,只有在取用 relevant object 的欄位時才需要使用 __r notation,若只需該物件 id,則用 __c 即可。

[2] 說明了定義 relationship 時的命名原則:
  • 在 parent object 中定義 relationship 時:名稱須 unique to the parent,並且使用複數形的 child object name 命名。
  • 在 child object 中定義 relationship 時:名稱須 unique to the child,並且使用單數形的 parent object name 命名。
[3] 提供了一個從 child object (Daughter) 定義 lookup relationship 的範例
  • 按前述第 (2) 項原則,relationship filed 的命名應使用單數的 parent object name,此處命名為 Mother_of_Child (應可簡化為 Mother)。
  • Child Relationship Name 則以 child object 為主,命名為 Daughters。
    => Lookup relationship 中才談 Child Relationship Name,master-detail relationship 無此欄位。
  • 從 child object 為起點實作 outer JOIN:SELECT Id, FirstName__c, Mother_of_Child__r.FirstName__c FROM Daughter__c WHERE Mother_of_Child__r.LastName__c LIKE 'C%'
  • 從 parent object 為起點實作 outer JOIN:SELECT LastName__c, (SELECT LastName__c FROM Daughters__r) FROM Mother__c
see also:
[1] A Deeper Look at SOQL and Relationship Queries on Force.com
[2] Understanding Relationship Names
[3] Understanding Relationship Names, Custom Objects, and Custom Fields