Oracle Coherence中文教程二十二:查询缓存中的数据

时间:2022-08-28 07:40:50

查询缓存中的数据

coherence可以进行查询和索引对当前缓存的数据,以满足一个给定的标准。查询和索引可以是简单的,采用筛选打包相干,或者它们可以运行多值属性,例如集合和数组。

本章包含以下各节:

    查询概述
    执行简单查询
    使用查询索引
    执行批量查询
    多值属性执行查询
    使用链式提取
    查询成本和效益评估

22.1查询概述

Coherence提供的能力,搜索缓存条目,以满足一个给定的标准。如果需要的话,可以进行排序的结果集。查询评估已提交读隔离。

应该指出的是查询只适用于当前缓存的数据(和不使用缓存加载器的界面来检索附加数据,可满足查询) 。因此,数据集应被完全加载到高速缓存中,查询的执行之前。在数据集的情况下,融入可用内存过大,有可能限制缓存沿特定的尺寸(例如, ” )的内容和手动之间切换的结构基础上的高速缓存查询和数据库查询该查询。可维护性,这通常是最好的实现高速缓存的数据访问对象( DAO )内。

索引需要能够提取每个分区的高速缓存节点的属性;专用缓存服务器实例的,这意味着应用程序的类必须安装在缓存服务器的类路径(通常) 。

对于本地和复制缓存,查询本地进行评估,对未索引数据。分区缓存,并行执行查询时在群集中,如果有使用索引。连贯性包括基于成本的优化器(CBO ) 。没有索引的属性,需要访问对象的反序列化(虽然其他属性上的索引可以减少必须评估对象的数目)

22.1.1查询概念

是基于概念的查询上ValueExtractor接口。值提取器,用于提取的属性,从给定的查询对象(同样地,索引) 。大多数开发人员只需要ReflectionExtractor此接口的实现。实现使用反射来提取一个值对象的属性,通过指的是一个方法的名称,通常是一个getter方法​​。例如:

ValueExtractor extractor = new ReflectionExtractor("getName");

可用于任何无效参数方法,包括对象的toString ( )方法,如(有用的原型/调试) 。索引可能是传统的字段索引(索引字段的对象)或基于功能的索引(索引虚拟对象的属性) 。例如,如果类领域的存取getFirstNamegetLastName , ,类可能定义一个函数getFullName适连接这些名字,这个功能可能被索引。指标的更多信息,请参阅使用查询索引” 

来查询,包含具有的getName属性的对象的高速缓存中,必须使用过滤器。过滤器有一个单一的方法确定一个给定的对象是否符合标准。

Filter filter = new EqualsFilter(extractor, "Bob Smith");

请注意,过滤器也有便利的构造函数接受一个方法的名称和内部构造一个ReflectionExtractor 

Filter filter = new EqualsFilter("getName", "Bob Smith");

下面的例子显示了一个例程来选择满足一个特定的过滤器的缓存条目:

for (Iterator iter = cache.entrySet(filter).iterator(); iter.hasNext(); )

    {

    Map.Entry entry = (Map.Entry)iter.next();

    Integer key = (Integer)entry.getKey();

    Person person = (Person)entry.getValue();

    System.out.println("key=" + key + " person=" + person);

    }


下面的示例使用一个过滤器来选择和排序缓存条目:

// entrySet(Filter filter, Comparator comparator) 

Iterator iter = cache.entrySet(filter, null).iterator();

额外的空参数指定使用自然顺序的比较对象在缓存中的结果集进行排序。客户端可以显式指定提供一个实现比较的结果集的排序。请注意,分拣场所显着优化,连贯性可以申请限制,如排序,需要整个结果集排序前。

22.2进行简单的查询

22-1演示了如何创建一个简单的查询和使用GreaterEqualsFilter过滤。连贯性包括许多预先内置过滤器位于com.tangosol.util.filter包的。所有预先内置滤波器的完整列表,请参阅Oracle CoherenceJava API参考。

22-1查询缓存过滤器
Filter filter = new GreaterEqualsFilter("getAge", 18);

for (Iterator iter = cache.entrySet(filter).iterator(); iter.hasNext(); )

    {

    Map.Entry entry = (Map.Entry) iter.next();

    Integer key = (Integer) entry.getKey();

    Person person = (Person) entry.getValue();

    System.out.println("key=" + key + " person=" + person);

    }

Coherence提供广泛的过滤器在com.tangosol.util.filter包。

注意事项:
虽然查询可以通过近缓存,执行该查询不使用的前部附近的一个缓存。如果使用近缓存查询的,最好的方法是使用下面的序列:

Set setKeys = cache.key set(filter);

Map mapResult = cache.getAll(setKeys);

22.3使用查询索引

查询索引允许值(或这些值的属性)和相应的键内的相关属性查来提高查询性能。

在本节包括以下主题:

    创建索引
    创建用户定义的索引

22.3.1创建索引

属性查类的addIndex方法是用来创建索引。使用这种方法,任何能够被查询的属性可被编入索引。该方法包括三个参数:

addIndex(ValueExtractor extractor, boolean fOrdered, Comparator comparator)

22-2演示了如何创建一个索引:

22-2的代码示例创建索引

NamedCache cache = CacheFactory.getCache("MyCache");

ValueExtractor extractor = new ReflectionExtractor("getAttribute");

cache.addIndex(extractor, true, null);

fOrdered参数指定是否索引结构排序。排序索引是有用的范围查询,如选择属于两个日期之间的选择所有员工的姓开始以”S“ ”的所有条目。对于平等的查询,无序指数可能会被使用,这在时间和空间方面可能有更好的效率。

比较参数可以提供定制的java.util.Comparator订购索引。

只打算作为缓存实现了一丝的addIndex方法,因此,它可能会忽略缓存索引,如果不支持,或者如果存在所需的索引(或类似的指数) 。据预计,应用程序调用此方法建议即使索引的索引可能存在,只是让申请指数已建议。例如在分布式环境中,每个服务器可能表明相同的一组索引,在启动时,盲目请求的应用程序的另一个服务器是否已经请求了相同的索引这些索引,而不管有没有缺点。

请注意,查询连贯性,如果有必要,可以结合,连贯性包括基于成本的优化器(CBO )优先使用索引。要充分利用索引,查询必须使用榨汁机是相等的( (的Object.equals ()) ,在查询中使用的一个。

应用索引​​的列表可以通过使用JMX 。从StorageManagerMBean检索使用JMX与连贯性的更多信息,请参阅Oracle Coherence的管理指南。

22.3.2创建用户定义的索引

应用程序可以选择创建用户定义的指标来控制哪些条目添加到索引。用户定义的索引,通常用于降低维护一个索引所需要的内存和处理开销。要创建一个用户定义的索引,应用程序必须实现的MapIndex的接口和IndexAwareExtractor接口。本节还介绍ConditionalIndexConditionalExtractor类提供的接口的实现创造条件指数使用相关的过滤器,以评估是否应该索引条目。

22.3.2.1实现MapIndex接口


MapIndex接口是用来存储在索引的地图(或这些值的属性)中的索引的地图对应的键关联的值。应用程序实现此接口,以提供一个自定义的索引。

下面的例子实现定义的索引与非空值只添加条目。有一个缓存大量的条目,只有一小部分的情况下,这将是有益的,有意义的,非空值。

public class CustomMapIndex implements MapIndex

   {

   public void insert(Map.Entry entry)

       {

       if (entry.getValue()!= null)

           {

           ...

           }

       }

   ...

   }

另外,在上述的例子中,该表项的值是否为空在提取前进行检查,但它可以被完成后。如果该表项的值是空值,则没有被插入到索引。为的更新MapIndex方法,类似的检查还需要为空。的其余部分的MapIndex方法必须适当地实施。

22.3.2.2实现IndexAwareExtractor的接口

IndexAwareExtractor接口的扩展接口,支持创建和销毁一个MapIndex索引ValueExtractor 。此接口的实例是拟用于与属性查API支持创建自定义索引。下面的例子演示了如何实现这个接口和是上面创建的的例子CustomMapIndex类的:

public class CustomIndexAwareExtractor

        implements IndexAwareExtractor, ExternalizableLite, PortableObject

    {

    public CustomIndexAwareExtractor(ValueExtractor extractor)

        {

        m_extractor = extractor;

        }

 

    public MapIndex createIndex(boolean fOrdered, Comparator comparator,

            Map mapIndex)

        {

        ValueExtractor extractor = m_extractor;

        MapIndex       index     = (MapIndex) mapIndex.get(extractor);

 

        if (index != null)

            {

            throw new IllegalArgumentException(

                    "Repetitive addIndex call for " + this);

            }

 

        index = new CustomMapIndex(extractor, fOrdered, comparator);

        mapIndex.put(extractor, index);

        return index;

        }

 

    public MapIndex destroyIndex(Map mapIndex)

        {

        return (MapIndex) mapIndex.remove(m_extractor);

        }

    ...

}

另外,在上述的例子中,基础提取实际使用来创建索引,并最终提取从高速缓存中条目的值。同时保留现有的属性查接口,用于管理IndexAwareExtractor实现创建和销毁一个自定义MapIndex实现。

通过IndexAwareExtractor到的QueryMap.addIndex和的QueryMap.removeIndex调用。连贯性,反过来,调用CreateIndexdestroyIndex的上IndexAwareExtractor 。另外请注意,它是责任,维持IndexAwareExtractor的地图被传递到CreateIndexdestroyIndex的的提取指数协会。

22.3.2.3使用条件指数

条件指数是一个自定义的索引实现如上所述的MapIndexIndexAwareExtractor接口,并使用相关的过滤器,以评估是否应该索引条目。提取条目的值添加到索引中,如果过滤器的值为true 。实现的类:分别为ConditionalIndex ConditionalExtractor 

创建ConditionalIndexConditionalExtractor 。该过滤器和抽取器用于由ConditionalIndex的上ConditionalExtractor设置, ,和通过给的ConditionalIndex构造在QueryMap.addIndex通话。

ConditionalExtractor是仅用于建立ConditionalIndex的一个实施IndexAwareExtractor 。底层ValueExtractor用于创建索引期间值提取是与在给定的索引图的创建ConditionalIndex的提取。使用ConditionalExtractor不支持提取值。例如:

ValueExtractor extractor = new ReflectionExtractor("getLastName");

Filter filter = new NotEqualsFilter("getId", null);

ValueExtractor condExtractor = new ConditionalExtractor(filter, extractor, true);

 

// add the conditional index which should only contain the last name values for the

// entries with non-null Ids

cache.addIndex(condExtractor, true, null);

22.4执行批处理查询

为了保存存储器上的客户机发出一个查询,有各种不同的技术,可以分批检索查询结果。

使用按键形式的查询 合并使用getAll方法( ) 减少了内存的消耗,因为整个项目组同时在客户端上没有反序列化。它还利用近缓存。例如:

22-3使用一键设置查询格式

// key set(Filter filter)

Set setKeys = cache.key set(filter);

Set setPageKeys = new HashSet();

int PAGE_SIZE = 100;

for (Iterator iter = setKeys.iterator(); iter.hasNext();)

    {

    setPageKeys.add(iter.next());

    if (setKeyPage.size() == PAGE_SIZE || !iter.hasNext())

        {

        // get a block of values

        Map mapResult = cache.getAll(setPageKeys);

        // process the block

        // ...

        setPageKeys.clear();

        }

    }

可用于甲LimitFilter的限制发送到客户端的数据量,并且还提供寻呼。例22-4演示使用LimitFilter 

22-4使用限制滤波器

int pageSize = 25;

Filter filter = new GreaterEqualsFilter("getAge", 18);

// get entries 1-25

Filter limitFilter = new LimitFilter(filter, pageSize);

Set entries = cache.entrySet(limitFilter);

// get entries 26-50

limitFilter.nextPage();

entries = cache.entrySet(limitFilter);

当使用一个分布式/分区的高速缓存,查询可以有针对性地使用PartitionedFilter分区和缓存服务器。配料为每个查询请求对象到一个单一的缓存服务器,从而减少必须响应请求的服务器的数量和最有效地使用网络的查询结果,这是最有效的方式。

注意事项:
使用PartitionedFilter是有限的集群成员,它不能被使用的连贯*扩展客户端。相干*扩展的客户端可以使用上述两种技术,或由一个连贯*扩展客户端,这些查询可以作为远程地调用和执行实施。

要执行一个查询逐个分区:

DistributedCacheService service =

   (DistributedCacheService) cache.getCacheService();

int cPartitions = service.getPartitionCount();

 

PartitionSet parts = new PartitionSet(cPartitions);

for (int iPartition = 0; iPartition < cPartitions; iPartition++)

    {

    parts.add(iPartition);

    Filter filterPart = new PartitionedFilter(filter, parts);

    Set setEntriesPart = cache.entrySet(filterPart);

 

    // process the entries ...

    parts.remove(iPartition);

    }

查询也可以在服务器上执行的服务器的基础:

DistributedCacheService service =

   (DistributedCacheService) cache.getCacheService();

int cPartitions = service.getPartitionCount();

 

PartitionSet partsProcessed = new PartitionSet(cPartitions);

for (Iterator iter = service.getStorageEnabledMembers().iterator();

        iter.hasNext();)

    {

    Member member = (Member) iter.next();

    PartitionSet partsMember = service.getOwnedPartitions(member);

 

    // due to a redistribution some partitions may have been processed

    partsMember.remove(partsProcessed);

    Filter filterPart = new PartitionedFilter(filter, partsMember);

    Set setEntriesPart = cache.entrySet(filterPart);

 

    // process the entries ...

    partsProcessed.add(partsMember);

    }

 

// due to a possible redistribution, some partitions may have been skipped

if (!partsProcessed.isFull())

    {

    partsProcessed.invert();

    Filter filter = new PartitionedFilter(filter, partsProcessed);

 

    // process the remaining entries ...

    }

22.5执行查询多值属性

Coherence支持多值属性,包括集合和数组的索引和查询。当一个对象被索引,一致性验证,如果它是一个多值的类型,然后建立索引的集合,而不是一个单。的ContainsAllFilter ,用于查询ContainsAnyFilterContainsFilter对这些藏品。

示例22-5多值属性查询

Set searchTerms = new HashSet();

searchTerms.add("java");

searchTerms.add("clustering");

searchTerms.add("books");

// The cache contains instances of a class "Document" which has a method

// "getWords" which returns a Collection<String> containing the set of

// words that appear in the document.

Filter filter = new ContainsAllFilter("getWords", searchTerms);

Set entrySet = cache.entrySet(filter);

// iterate through the search results

// ...

22.6使用链式提取

允许链接ChainedExtractor实现零参数(存取)方法调用。例22-6中,首先提取使用反射来调用每个缓存的Person对象的getName ( ) ,然后使用反射调用返回的字符串的长度( ) 。

22-6链调用方法
ValueExtractor extractor = new ChainedExtractor("getName.length");

该提取可以通过查询,让查询(例如)选择所有的人不超过10个字母的名字。方法调用可以链接下去,例如getName.trim.length中。

22.7评估查询成本和有效性

本节提供了用于创建查询解释计划记录和查询跟踪记录,以便查询,分别查看每个过滤器之估计成本及实际效益。记录用于评估连贯性是如何运行的查询和查询,以确定为什么表现不佳或如何可以对其进行修改,以便更好地执行。又见StorageManagerMBeanOracle Coherence的管理指南的详细信息,查看基于查询的统计参考。

在本节包括以下主题:

    创建查询记录
    口译查询记录
    运行记录查询示例

22.7.1创建查询记录

com.tangosol.util.aggregator.QueryRecorder类产生一个解释或跟踪记录,对于一个给定的过滤器。类是实施一个平行的聚合,能够查询所有集群中的节点和聚集的结果。类支持两种记录类型:解释记录显示查询中的过滤器的估计成本,并跟踪记录显示查询中的每个过滤器的实际效益。

要创建一个查询记录,创建一个新的QueryRecorder实例指定一个记录类型参数。包括总的方法作为参数进行测试实例和过滤器。下面的示例创建一个解释记录:

NamedCache cache = CacheFactory.getCache("mycache");

cache.addIndex(new ReflectionExtractor("getAge"), true, null);

AllFilter filter = new AllFilter(new Filter[]

   {

    new OrFilter(

       new EqualsFilter(new ReflectionExtractor("getAge"), 16),

       new EqualsFilter(new ReflectionExtractor("getAge"), 19)),

    new EqualsFilter(new ReflectionExtractor("getLastName"), "Smith"),

    new EqualsFilter(new ReflectionExtractor("getFirstName"), "Bob"),

    });

 

QueryRecorder agent = new QueryRecorder(RecordType.EXPLAIN);

Object resultsExplain = cache.aggregate(filter, agent);

 

System.out.println("\n" + resultsExplain + "\n");

要创建一个跟踪记录,变更记录类型参数跟踪:

QueryRecorder agent = new QueryRecorder(RecordType.TRACE);

22.7.2解释查询记录

查询记录用于评估的过滤器和索引查询。解释计划记录用于评估的估计成本与应用过滤。跟踪记录用于评估如何有效的过滤器是减少一键设置。

本节提供了一个示例解释计划记录和一个样本跟踪记录,并讨论如何阅读和解释的记录。记录是基于一个示例查询1500个项目分别位于4个存储功能节点的集群。查询由一个过滤器,发现任何人,要么是16岁或19的第一个名字鲍勃和姓史密斯。最后,添加和索引getAge 。要运行完整的示例,请参阅运行记录查询示例” 

NamedCache cache = CacheFactory.getCache("mycache");

cache.addIndex(new ReflectionExtractor("getAge"), true, null);

AllFilter filter = new AllFilter(new Filter[]

   {

    new OrFilter(

       new EqualsFilter(new ReflectionExtractor("getAge"), 16),

       new EqualsFilter(new ReflectionExtractor("getAge"), 19)),

    new EqualsFilter(new ReflectionExtractor("getLastName"), "Smith"),

    new EqualsFilter(new ReflectionExtractor("getFirstName"), "Bob"),

    });

22.7.2.1查询的解释计划记录

解释记录的查询提供的估计成本评估一个过滤器作为查询操作的一部分。的成本考虑到是否一个索引可以使用一个过滤器。成本评估是用来执行查询时,在过滤器的应用来决定顺序。过滤器使用索引以最低的成本,并首次得到应用。

22-7显示了一个典型的查询解释计划记录。该记录包括解释素色表格可用于评价在查询中的每一个过滤器和一个索引查找表,该表列出了由过滤器,可用于每个索引。列的说明如下:

    Name  - 此列显示查询中的每个过滤器的名称。复合过滤器内的复合过滤器的过滤器的信息。

    Index  - 此列显示与否的指标可以用给定的过滤器。如果发现索引,索引查找表上显示的数字对应的索引号。在该示例中,有序的简单的map index0) getAge ( )找到的。

    Cost  - 此列显示应用过滤器,估计所需费用。可以使用,如果有一个索引的成本被给定为。应用索引​​的操作使用,因为只需要一个单一的访问的索引内容1的值。在这个例子中,有4个存储功能的集群成员,并因此成本体现在所有四个成员访问索引。如果不存在索引,计算成本作为EVAL_COST * number 键。EVAL_COST值是一个恒定值,为1000。这是为了显示做了充分的扫描,以减少使用的过滤器的密钥集的相对成本。在这个例子中,有1500高速缓存条目的需要进行评估。查询索引条目总是相比,价格相对低廉的非索引项,但不一定能保证有效性。

22-7中所示shows that the equal filter for getAge() has a low cost ,因为它有一个相关的索引,将适用于前getLastName ()和getFirstName ( ) 。 getAge ( )滤波器,然而,虽然价格低廉,可能不会是非常有效的,如果所有项目1619 ,只有少数条目匹配鲍勃和史密斯。在这种情况下,更有效的是添加一个索引以getLastName ( )和getFirstName ( ) 。此外,与创建索引的成本(主要是内存消耗)是浪费,如果该指数做一个贫穷的减少关键工作。

22-7示例查询的解释计划记录

Explain Plan

Name                                  Index        Cost      

==================================================================================

com.tangosol.util.filter.AllFilter  | ----       | 0         

  com.tangosol.util.filter.OrFilter | ----       | 0         

    EqualsFilter(.getAge(), 16)     | 0          | 4         

    EqualsFilter(.getAge(), 19)     | 0          | 4         

  EqualsFilter(.getLastName(), Smit | 1          | 1500000   

  EqualsFilter(.getFirstName(), Bob | 2          | 1500000   

 

 

Index Lookups

Index  Description                               Extractor             Ordered   

==================================================================================

0      SimpleMapIndex: Extractor=.getAge(), Ord  .getAge()             true

1      No index found                            .getLastName()        false

2      No index found                            .getFirstName()       false

22.7.2.2查询跟踪记录

跟踪记录的查询提供评估过滤器时的实际成本作为查询操作的一部分。的成本考虑到是否一个索引可以使用一个过滤器。查询被实际执行,并示出每一个过滤器,以减少密钥集的有效性。

示例22-8显示了一个典型的查询跟踪记录。该记录包括一个跟踪表,该表显示在查询中的每个过滤器的有效性指数查找表,该表列出了由过滤器,可用于每个索引。列的说明如下:

    Name  - 此列显示查询中的每个过滤器的名称。复合过滤器内的复合过滤器的过滤器的信息。

    Index  - 此列显示与否的指标可以用给定的过滤器。如果发现索引,索引查找表上显示的数字对应的索引号。在该示例中,有序的简单的地图索引(0) getAge ( )找到的。

    Effectiveness  - 此列显示一键设定每个过滤器的结果实际上是减少的金额。的值被给定为prefilter_key_set_size | postfilter_key_set_size也以百分比表示。的prefilter_key_set_size值表示评估前的过滤器或应用索引​​键集的大小。该postfilter_key_set_size值表示的剩余的密钥集进行评估后,过滤器或应用索引​​的大小。对于复合过滤器条目,该值是其包含的过滤器的整体业绩。一旦一个密钥集的大小可以不再基于索引的减少,由此产生的密钥集反序列化的,任何非索引过滤器。

    Duration  - 此列显示评估过滤器或应用索引​​花费的毫秒数。值为0表明,注册的时间是报告阈值以下。在这个例子中, 63毫秒的结果反序列化仅在第一的过滤getLastName ( )产生的密钥集。

22-8显示了约63毫秒减少1500项,找到100个条目的第一个名字,姓史密斯,鲍勃和1619岁的纪录。 1500个条目的密钥集最初是使用getAge ()指数在降低到300 。由此产生的300项(因为他们无法进一步降低使用索引) ,然后反序列化,减少到150项基于getLastName ( ) ,然后降低到100的使用getFirstName ( ) 。这个例子显示了getAge ()上的索引是非常值得的资源,因为它是能够有效地减少按键设置1200个条目。指数对getLastName getFirstName提高整个查询的性能,但可能不值得创建索引所需的额外资源。

示例22-8示例查询跟踪记录

Trace

Name                                  Index        Effectiveness          Duration  

==================================================================================

com.tangosol.util.filter.AllFilter  | ----       | 1500|300(80%)        | 0         

  com.tangosol.util.filter.OrFilter | ----       | 1500|300(80%)        | 0         

    EqualsFilter(.getAge(), 16)     | 0          | 1500|150(90%)        | 0         

    EqualsFilter(.getAge(), 19)     | 0          | 1350|150(88%)        | 0         

  EqualsFilter(.getLastName(), Smit | 1          | 300|300(0%)          | 0         

  EqualsFilter(.getFirstName(), Bob | 2          | 300|300(0%)          | 0         

com.tangosol.util.filter.AllFilter  | ----       | 300|100(66%)         | 63        

  EqualsFilter(.getLastName(), Smit | ----       | 300|150(50%)         | 63        

  EqualsFilter(.getFirstName(), Bob | ----       | 150|100(33%)         | 0         

 

 

Index Lookups

Index  Description                               Extractor             Ordered   

==================================================================================

0      SimpleMapIndex: Extractor=.getAge(), Ord  .getAge()             true

1      No index found                            .getLastName()        false

2      No index found                            .getFirstName()       false

22.7.3运行记录查询示例


下面的例子是一个简单的类,演示如何创建查询记录。类加载一个分布式缓存(mycache中)与1500 Person对象,在属性上创建索引,执行查询,并创建一个解释计划记录查询和查询类退出前发出的跟踪记录到控制台。

22-9记录查询的例子

import com.tangosol.net.CacheFactory;

import com.tangosol.net.NamedCache;

import com.tangosol.util.Filter;

import com.tangosol.util.aggregator.QueryRecorder;

import static com.tangosol.util.aggregator.QueryRecorder.RecordType;

import com.tangosol.util.extractor.ReflectionExtractor;

import com.tangosol.util.filter.AllFilter;

import com.tangosol.util.filter.EqualsFilter;

import com.tangosol.util.filter.OrFilter;

import java.io.Serializable;

import java.util.Properties;

 

public class QueryRecordExanple

   {

   public static void main(String[] args) {

   

      testExplain();

      testTrace();

   }

   

   public static void testExplain()

   {

      NamedCache cache = CacheFactory.getCache("mycache");

      cache.addIndex(new ReflectionExtractor("getAge"), true, null);

      PopulateCache(cache);

        

      AllFilter filter = new AllFilter(new Filter[]

      {

         new OrFilter(

            new EqualsFilter(new ReflectionExtractor("getAge"), 16),

            new EqualsFilter(new ReflectionExtractor("getAge"), 19)),

         new EqualsFilter(new ReflectionExtractor("getLastName"), "Smith"),

         new EqualsFilter(new ReflectionExtractor("getFirstName"), "Bob"),

      });

 

      QueryRecorder agent = new QueryRecorder(RecordType.EXPLAIN);

      Object resultsExplain = cache.aggregate(filter, agent);

      System.out.println("\nExplain Plan=\n" + resultsExplain + "\n");

   } 

   public static void testTrace()

   {

      NamedCache cache = CacheFactory.getCache("hello-example");

      cache.addIndex(new ReflectionExtractor("getAge"), true, null);

      PopulateCache(cache);

        

      AllFilter filter = new AllFilter(new Filter[]

      {

         new OrFilter(

            new EqualsFilter(new ReflectionExtractor("getAge"), 16),

            new EqualsFilter(new ReflectionExtractor("getAge"), 19)),

         new EqualsFilter(new ReflectionExtractor("getLastName"), "Smith"),

         new EqualsFilter(new ReflectionExtractor("getFirstName"), "Bob"),

      });

      QueryRecorder agent = new QueryRecorder(RecordType.TRACE);

      Object resultsExplain = cache.aggregate(filter, agent);

      System.out.println("\nTrace =\n" + resultsExplain + "\n");

   }

    

   private static void PopulateCache(NamedCache cache)

      {

         for (int i = 0; i < 1500; ++i)

            {

               Person person = new Person(i % 3 == 0 ? "Joe" : "Bob",

                  i % 2 == 0 ? "Smith" : "Jones", 15 + i % 10);

               cache.put("key" + i, person);

            }

      } 

 

   public static class Person implements Serializable

      {

      public Person(String sFirstName, String sLastName, int nAge)

         {

            m_sFirstName = sFirstName;

            m_sLastName = sLastName;

            m_nAge = nAge;

         }

 

      public String getFirstName()

         {

            return m_sFirstName;

         }

 

      public String getLastName()

         {

            return m_sLastName;

         }

       public int getAge()

         {

            return m_nAge;

         }

      public String toString()

         {

            return "Person( " +m_sFirstName + " " + m_sLastName + " : " + 

               m_nAge + ")";

         }

      private String m_sFirstName;

      private String m_sLastName;

      private int m_nAge;

   } 

}