分布式缓存的对象查询语言

作者:伊克巴尔汗

NCache 允许您在中间层创建一个可扩展的分布式缓存,这样您就可以减少昂贵的数据库访问并大大提高您的应用程序性能。 它还提高了应用程序的可伸缩性,因为您能够在这个高度可伸缩的缓存中找到常用的数据,而不是无法很好地扩展的单个数据库服务器。

您的应用程序通常使用缓存作为 Hashtable,其中所有内容都基于键存储,您必须拥有此键才能获取项目。 这就像拥有一个关系数据库,您只能使用主键来查找数据。 这在许多情况下都可以正常工作,但在现实生活中的复杂应用程序中,您的应用程序通常需要根据主键以外的属性查找数据。 而且,由于您将大量数据保存在缓存中,因此如果您也可以以这种方式搜索缓存,那将非常有用。 NCache 提供正是这样的设施。

在这篇文章中,我将讨论如何 NCache 对象查询有效。

缓存搜索返回键

NCache 提供对象查询语言 (OQL) 让您搜索缓存。 您必须进行 API 调用并指定基于此 OQL 的搜索,以便从缓存中获取对象集合。 为了查询缓存,您需要在 .NET 应用程序中使用以下内容。

public class Program
{
    public static void Main(string[] args)
    {
        NCache.InitializeCache("myReplicatedCache");
        String query = "SELECT NCacheQuerySample.Business.Product WHERE this.ProductID > 100";
        // Fetch the keys matching this search criteria
        ICollection keys = NCache.Cache.Search(query);
        if (keys.Count > 0)
        {
            IEnumerator ie = keys.GetEnumerator();
            while (ie.MoveNext())
            {
                String key = (String)ie.Current;
                Product prod = (Product)NCache.Cache.Get(key);

                HandleProduct(prod);
                Console.WriteLine("ProductID: {0}", prod.ProductID);
            }
        }
        NCache.Cache.Dispose();
    }
} 

上面的代码搜索缓存并返回一个键集合。 然后,它遍历所有返回的键,并从缓存中单独获取相应的缓存项。 这种方法的好处是查询不会自动返回大量数据,而是只返回键。 然后,客户端应用程序可以确定它想要获取哪些密钥。 这种方法的缺点是,如果您无论如何都要从缓存中获取大部分项目,那么您最终会多次访问缓存。 而且,如果缓存是分布式的,这最终可能会变得昂贵。 如果是这种情况,那么您可以进行搜索,将键和项目一起返回。

缓存搜索返回项

正如您已经看到的,一个简单的 Cache.Search(...) 返回一个键集合。 但是,如果您打算获取与这些键关联的所有或大部分缓存项,则 Cache.Search(...) 不是搜索缓存的一种非常有效的方法。 原因是您将首先拨打电话进行搜索。 然后,您将进行多次调用以获取与每个键关联的项目。 这可能成为非常昂贵的操作。 在这些情况下,最好在一次调用中获取所有键和项目。 下面是这样做的示例。

public class Program
{
    public static void Main(string[] args)
    {
        NCache.InitializeCache("myReplicatedCache");
        String query = "SELECT NCacheQuerySample.Business.Product WHERE this.ProductID > 100";
        // Fetch the keys matching this search criteria
        IDictionary dict = NCache.Cache.SearchEntries(query);
        if (dict.Count > 0)
        {
            IDictionaryEnumerator ide = dict.GetEnumerator();
            while (ide.MoveNext())
            {
                String key = (String)ide.Key;
                Product prod = (Product)ide.Value;
                HandleProduct(prod);
                Console.WriteLine("Key = {0}, ProductID: {1}",
                key, prod.ProductID);
            }
        }
        NCache.Cache.Dispose();
    }
}

上面的代码搜索缓存并返回一个包含键和值的字典。 这样,基于搜索条件的所有数据都可以在一次调用中获取 NCache. 这比从缓存中获取所有数据的效率更高 Cache.Search().

索引可搜索属性

请注意: NCache 要求对所有可搜索的属性进行索引。 这是因为没有索引, NCache 必须遍历整个缓存才能找到用户正在寻找的项目。 而且,这是一项非常昂贵的操作,可能会减慢整个缓存并撤消人们为什么会这样做的主要原因 NCache,即提高其应用程序性能和可扩展性。

NCache 提供自己的索引机制。 您可以识别 .NET 程序集中要索引的对象。 然后,当您将数据添加到 NCache,它会检查您是否正在添加这些对象。 而且,如果您是,那么它使用 .NET 反射从索引属性中提取数据并构建其内部索引。 然后,当您使用 Cache.Search() 或 Cache.SearchEntries() 查询缓存时, NCache 使用这些索引快速找到所需的对象并将它们返回给您。

在开始缓存之前索引对象属性
图 1:在启动缓存之前索引对象属性

请注意,每当您在对象属性上指定索引时,都会增加一点点添加、插入和删除操作的处理时间。 但是,Get 操作不受影响。

查询不同的缓存拓扑

尽管无论您使用何种缓存拓扑,从客户端应用程序的角度来看,搜索行为都是相同的,但搜索的内部结构因拓扑而异。 例如,如果您正在对复制的缓存进行搜索,则您的搜索将完全在您发起此搜索的缓存服务器上进行。 这是因为整个缓存都在那里可用。 以下是在复制缓存中运行查询的方式。

查询在一台服务器上本地运行
图 2:查询在一台服务器上本地运行

但是,如果您具有分区或分区副本缓存拓扑,则并非所有数据都驻留在集群中的单个缓存节点上。 在这种情况下,发起查询的缓存服务器将查询发送到集群中的所有其他服务器,并在本地运行。 然后,该查询在所有服务器中并行运行,其结果从所有节点返回到该原始服务器节点。 该服务器节点然后组合所有结果(执行“联合”)并将它们返回给客户端。 下面是显示所有这些的图表。

查询在所有服务器节点上并行运行
图 3:查询在所有服务器节点上并行运行

您的 .NET 程序集

In NCache,索引是在服务器节点上完成的。 然而, NCache 在客户端使用 .NET Reflection 来提取对象属性的值并将它们发送到服务器。 因此,包含对象定义的 .NET 程序集只需要在应用程序所在的客户端上。 无论您是在 InProc 还是 OutProc 模式下运行,您的程序集都需要位于您的客户端应用程序可以访问它们的目录中。

此外, NCache 还支持 Java 客户端的对象查询语言。

查询语言语法

NCache 支持称为对象查询语言 (OQL) 的类 SQL 语言。 该语言具有以下语法 NCache.

SELECT NCacheQuerySample.Business.Product WHERE this.ProductID > 100;

SELECT NCacheQuerySample.Business.Product WHERE (this.ProductID != 100 AND this.ProductID <= 200);

SELECT NCacheQuerySample.Business.Product WHERE (this.ProductID == 150 OR this.ProductID == 160);

SELECT NCacheQuerySample.Business.Product WHERE this.ProductID IN (1, 4, 7, 10);

SELECT NCacheQuerySample.Business.Product WHERE this.ProductID NOT IN (1, 4, 7, 10);

SELECT NCacheQuerySample.Business.Employee WHERE this.HiringDate > DateTime.now;

SELECT NCacheQuerySample.Business.Employee WHERE this.HiringDate > DateTime ('01/01/2007');

SELECT NCacheQuerySample.Business.Employee WHERE this.Hired = true;

您可以使用 AND 和 OR 以及使用嵌套括号将多个表达式组合在一起。 完整的查询语言语法如下所示。

<Query>                 ::= SELECT <ObjectType> 
                          | SELECT <ObjectType> WHERE <Expression>

<Expression>            ::= <OrExpr>

<OrExpr>                ::= <OrExpr> 'OR' <AndExpr>
                          | <AndExpr>

<AndExpr>               ::= <AndExpr> 'AND' <UnaryExpr>
                          | <UnaryExpr>

<UnaryExpr>             ::= 'NOT'  <CompareExpr>
                          | <CompareExpr>

<CompareExpr>           ::= <Atrrib> '='  <Value>
                          | <Atrrib> '!=' <Value>
                          | <Atrrib> '==' <Value>
                          | <Atrrib> '<>' <Value>
                          | <Atrrib> '<'  <Value>
                          | <Atrrib> '>'  <Value>
                          | <Atrrib> '<=' <Value>
                          | <Atrrib> '>=' <Value>
                          | <Atrrib> 'IN' <InList>
                          | <Atrrib> 'NOT' 'IN' <InList>
                          | '(' <Expression> ')'

<Atrrib>		::= <ObjectValue>                                                    

<Value>                 ::= '-' <NumLiteral> 
                          | <NumLiteral> 
                          | <StrLiteral>
                          | 'true'
                          | 'false'
                          | <Date>

<Date>                  ::= 'DateTime' '.' 'now'
                          | 'DateTime' '(' StringLiteral ')'

<StrLiteral>		::= StringLiteral
			  | 'null'  

<NumLiteral>            ::= IntegerLiteral 
                          | RealLiteral

<ObjectType>            ::= '*' 
                          | <Property>

<Property>		::= <Property> '.' Identifier
			  | Identifier

<ObjectValue>           ::= Keyword '.' Identifier              

<InList>                ::= '(' <ListType> ')'

<ListType>              ::= <NumLiteralList>
                          | <StrLiteralList>
                          | <DateList>

<NumLiteralList>        ::=  <NumLiteral> ',' <NumLiteralList>
                          | <NumLiteral>

<StrLiteralList>        ::= <StrLiteral> ',' <StrLiteralList>
                          | <StrLiteral>

<DateList>              ::= <Date> ',' <DateList>
                          | <Date> 

结论

如您所见, NCache 使得查询分布式缓存变得非常简单。 这是一项强大的功能,可让您以更有意义的方式使用缓存并更轻松地在其中查找内容。 看看这个。


作者: 伊克巴尔·汗为 Alachisoft ,一家领先的软件公司,提供 .NET 和 Java 分布式缓存、O/R 映射和 SharePoint 存储优化解决方案。 你可以联系他 伊克巴尔@alachisoft .

联系我们

联系电话
©版权所有 Alachisoft 2002 - 版权所有。 NCache 是 Diyatech Corp. 的注册商标。