【发布时间】:2013-10-23 17:38:19
【问题描述】:
我有一组数据和一组要针对这些数据运行的搜索过滤器。过滤器遵循 LDAP 搜索过滤器格式并被解析为表达式树。数据一次读取一项,并通过所有过滤器进行处理。中间匹配结果存储在树的每个叶节点中,直到处理完所有数据。然后通过遍历树并将逻辑运算符应用于每个叶子节点的中间结果来获得最终结果。例如,如果我有过滤器(&(a=b)(c=d)),那么我的树将如下所示:
root = "&"
left = "a=b"
right = "c=d"
所以如果a=b 和c=d 则左右子节点都是匹配的,因此过滤器是匹配的。
数据是不同类型对象的集合,每个对象都有自己的字段。例如,假设集合代表学校的一个班级:
class { name = "math" room = "12A" }
teacher { name = "John" age = "35" }
student { name = "Billy" age = "6" grade = "A" }
student { name = "Jane" age = "7" grade = "B" }
所以过滤器可能看起来像 (&(teacher.name=John)(student.age>6)(student.grade=A)) 并被解析为:
root = "&"
left = "teacher.name=John"
right = "&"
left = "student.age>6"
right = "student.grade=A"
我针对它运行class 对象;无匹配。我针对它运行teacher 对象; root.left 是匹配项。我针对它运行第一个 student 节点; root.right.right 是匹配项。我针对它运行第二个student 节点; root.right.left 是匹配项。然后我遍历树并确定所有节点都匹配,因此最终结果是匹配。
问题是中间匹配需要基于共性进行约束:student.age 和 student.grade 过滤器需要以某种方式绑定在一起,以便仅当它们匹配同一个对象时才存储中间匹配。我这辈子都不知道该怎么做。
我的过滤器节点抽象基类:
class FilterNode
{
public:
virtual void Evaluate(string ObjectName, map<string, string> Attributes) = 0;
virtual bool IsMatch() = 0;
};
我有一个LogicalFilterNode 类来处理逻辑AND、OR 和NOT 操作;它的实现非常简单:
void LogicalFilterNode::Evaluate(string ObjectName, map<string, string> Attributes)
{
m_Left->Evaluate(ObjectName, Attributes);
m_Right->Evaluate(ObjectName, Attributes);
}
bool LogicalFilterNode::IsMatch()
{
switch(m_Operator)
{
case AND:
return m_Left->IsMatch() && m_Right->IsMatch();
case OR:
return m_Left->IsMatch() || m_Right->IsMatch();
case NOT:
return !m_Left->IsMatch();
}
return false;
}
然后我有一个处理叶节点的ComparisonFilterNode 类:
void ComparisonFilterNode::Evaluate(string ObjectName, map<string, string> Attributes)
{
if(ObjectName == m_ObjectName) // e.g. "teacher", "student", etc.
{
foreach(string_pair Attribute in Attributes)
{
Evaluate(Attribute.Name, Attribute.Value);
}
}
}
void ComparisonFilterNode::Evaluate(string AttributeName, string AttributeValue)
{
if(AttributeName == m_AttributeName) // e.g. "age", "grade", etc.
{
if(Compare(AttributeValue, m_AttributeValue) // e.g. "6", "A", etc.
{
m_IsMatch = true;
}
}
}
bool ComparisonFilterNode::IsMatch() { return m_IsMatch; }
如何使用:
FilterNode* Root = Parse(...);
foreach(Object item in Data)
{
Root->Evaluate(item.Name, item.Attributes);
}
bool Match = Root->IsMatch();
基本上我需要的是子级具有相同对象名称的 AND 语句,只有当子级与同一对象匹配时,AND 语句才应匹配。
【问题讨论】:
-
到目前为止,我只阅读了“问题是中间匹配需要根据共性进行限制”,但在我看来,您并没有按照您所说的句子 #3 , “数据一次读取一项并通过所有过滤器进行处理”。就这样做吧!您想测试集合的每个元素,对吗?在这种情况下,您不希望或不需要在元素之间保留任何状态!您需要一个最外层的循环,该循环遍历集合中的每个项目,将整个表达式树应用于每个项目,并得到一个是或否的答案来说明是否保留该项目。
-
没有。过滤器可以包含多种元素的表达式。我一次只读取一个元素,可以是
teacher或student。像teacher.name=John AND student.grade=A这样的过滤器永远不会匹配单个元素。 -
如果过滤器可以包含多种元素的表达式,那么我不明白你在做什么。例如。你怎么知道什么老师对应什么孩子? “过滤”通常意味着“选择项目的子集”,其中每个项目都独立于其他项目来考虑。
-
教师和学生是一个不好的例子,因为实际的数据元素彼此不相关。不同类型零件的库存将是一个更好的例子。过滤器可能也是错误的词。我想确定数据集中是否存在一组符合条件的元素。
-
啊,我想我明白你现在想要做什么了。我会将我的建议放在答案中。
标签: algorithm expression-trees evaluation