データのコレクションと、そのデータに対して実行したい検索フィルターのコレクションがあります。フィルターは LDAP 検索フィルター形式に従い、式ツリーに解析されます。データは一度に 1 項目ずつ読み取られ、すべてのフィルターを介して処理されます。中間一致結果は、すべてのデータが処理されるまで、ツリーの各リーフ ノードに格納されます。次に、ツリーをトラバースし、論理演算子を各リーフ ノードの中間結果に適用することによって、最終結果が取得されます。たとえば、フィルターがある(&(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
一致です。それに対して2 番目の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 ステートメントは、子が同じオブジェクトに一致する場合にのみ一致する必要があります。