我有一组数据和一组要针对该数据运行的搜索过滤器。过滤器遵循 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
andstudent.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 语句才应匹配。