2010-01-22 62 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(); 
    } 
} 
相关问题