2010-01-22 63 views
4

我正在爲我的數據庫開發高度專業化的搜索引擎。當用戶提交搜索請求時,引擎將搜索項分割成數組並循環。在循環內部,將根據幾種可能的場景來檢查每個搜索項,以確定它可能的含義。當搜索條件與場景匹配時,會將WHERE條件添加到SQL查詢中。有些術語可以有多種含義,在這種情況下,引擎會建立一系列建議來幫助用戶縮小結果。在同一個循環中執行兩個不同的任務不好嗎?

另外:如果任何人有興趣知道,ambigous術語是通過加上關鍵字前綴。例如,1954年可能是一年或序列號。引擎會向用戶建議這兩種情況,並將搜索字詞修改爲年份:1954年或序列號:1954年。

在同一個循環中構建SQL查詢和精化建議對我而言感覺不知怎麼地錯了,但是將它們分開會增加更多的開銷,因爲我將不得不循環遍歷同一個數組兩次並測試所有相同的場景兩次。什麼是更好的行動方式?

回答

13

我可能會將這兩種行爲分解爲他們自己的功能。那麼你會有

foreach (term in terms) { 
    doThing1(); 
    doThing2(); 
} 

這是很好,乾淨。

1

我不認爲在一個循環中做兩個動作是錯誤的。我甚至會建議做兩個方法,從循環中調用,像:

for (...) { 
    refineSuggestions(..) 
    buildQuery(); 
} 

在另一方面,爲O(n)= O(2N)

所以不要太擔心很多 - 這不是一個表演罪。

+2

只是因爲它仍然爲O(n)不會使它更好。 O(n)= O(100000n)。當你可以做一次的時候,爲什麼要跑兩次? 很明顯,將代碼分離到方法中是一個好主意。 – 2010-01-22 16:07:59

+0

這就是我所建議的。我只是表示,理論上這不是一個表現_issue_,但它肯定不會提供更好的性能(更糟的是) – Bozho 2010-01-22 16:09:53

6

不,這不壞。我會認爲循環兩次會更混亂。

但是,如果任務之間的耦合度足夠高,那麼有些任務可能會被放入函數中。

4

爲了理論的純淨性,我認爲不需要添加多個循環,尤其是考慮到如果您要針對多個場景添加一個循環,您將從O(n) - > O(N *#場景)。另一種解決此問題而不陷入「上帝方法」陷阱的方法是獲得一個運行單個循環並返回匹配數組的方法,另一個方法是運行匹配數組中每個元素的搜索。

+0

但它仍然是O(n)。如果測試本身代價高昂,那麼當然會增加兩個循環的開銷,但不會增加大O的複雜性。 – 2010-01-22 16:19:58

3

使用相同的循環似乎是對我有效的優化,試圖保持兩個任務的代碼獨立,因此如果需要可以更改此優化。

1

我稱之爲代碼氣味,但不是非常糟糕的。我將把循環內部的功能分開,首先放置其中一個,然後在空行之後和/或註釋另一個。

0

你當然可以運行兩個循環。

如果有很多,這是業務邏輯,你也可以創建在第一循環的某種數據結構,然後用它來生成SQL,像

search_objects = [] 
loop through term in terms 
    search_object = {} 
    search_object.string = term 
    // suggestion & rules code 
    search_object.suggestion = suggestion 
    search_object.rule = { 'contains', 'term' } 
    search_objects.push(search_object) 

loop through search_object in search_objects 
    //generate SQL based on search_object.rule 

這至少可以節省你從兩個循環中如果/然後都要做,我認爲在第一個循環之外移動SQL代碼更清潔一點。

1

我會將它看作是觀察者模式的一個實例:每當你循環時引發一個事件,並且儘可能多的觀察者可以訂閱它。當然,將它作爲模式來做是件小事,但相似之處告訴我,執行兩到三次或多少次你想要的動作就好了。

0

如果你在循環中做的事情是相關的,那很好。編寫「每次迭代的內容」然後將其封裝在一個循環中可能是有意義的,因爲這可能是您如何看待它的頭腦。

添加評論,如果時間太長,請考慮拆分它或使用簡單的實用程序方法。

0

我想人們可能會爭辯說,這可能不完全是語言不可知的;它也高度依賴於你想要完成的事情。如果你將多個任務放在一個循環中,使得編譯器不能很容易地將它們並行化爲並行環境,那麼這肯定是一種代碼異味。

3

您的情況符合建造者模式,如果每個操作是相當複雜的那麼它將使你打破了一點東西。如果你所有的邏輯都適用於50行代碼,但是如果你有依賴來管理和複雜的邏輯,那麼你應該使用經過驗證的設計模式來實現問題分離。這可能是這樣的:

var relatedTermsBuilder = new RelatedTermsBuilder(); 
var whereClauseBuilder = new WhereClauseBuilder(); 

var compositeBuilder = new CompositeBuilder() 
    .Add(relatedTermsBuilder) 
    .Add(whereClauseBuilder); 

var parser = new SearchTermParser(compositeBuilder); 
parser.Execute("the search phrase"); 

string[] related = relatedTermsBuilder.Result; 

string whereClause = whereClauseBuilder.Result; 

支持對象看起來像:

public interface ISearchTermBuilder { 
    void Build(string term); 
} 

public class SearchTermParser { 
    private readonly ISearchTermBuilder builder; 

    public SearchTermParser(ISearchTermBuilder builder) { 
     this.builder = builder; 
    } 

    public void Execute(string phrase) { 
     foreach (var term in Parse(phrase)) { 
      builder.Build(term); 
     } 
    } 

    private static IEnumerable<string> Parse(string phrase) { 
     throw new NotImplementedException(); 
    } 
} 
相關問題