如何通过IMap <string,set <myobject>&gt;?按对象属性进行查询

时间:2017-07-18 19:56:21

标签: java hazelcast hazelcast-imap

Hazelcast docs解释了当我们有Sys.setenv(http_proxy="http://corp.com:8080") 时如何执行此操作,但没有关于地图值是集合时的情况。

我看到两个选项:

  • IMap<String,Object>包装成包装器类型,从而返回Set<Object>,然后需要在本地过滤;
  • 实施ValueExtractor,但并不完全确定,因为到目前为止还没有使用它。

编辑:实施最终与mikhail-baksheev建议的类似。请注意,Set使用ifblock来决定应收集CollectionExtractor中的哪个字段。对此有没有更漂亮(但仍然有效)的解决方案?

MyObject

1 个答案:

答案 0 :(得分:2)

例如,您要查询一些定义为参数集Set<Parameter>的对象:

public class Parameter {
    private String name;
    private Object value;

    public Parameter( String name, Object value ) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public Object getValue() {
        return value;
    }
}

首先,为Parameters实现ValueExtarcator:

public class ParameterExtractor extends ValueExtractor<Set<Parameter>, String> {
   @Override
   public void extract( Set<Parameter> parameters, String parameterName, ValueCollector collector ) {
      for ( Parameter p : parameters ) {
          if ( parameterName.equals( p.getName() ) ) {
              collector.addObject( p.getValue() );
          }
      }
   }
}

接下来,将ValueExtractor添加到自定义属性parameter的地图配置中:

Config config = new Config( "my-instance" );
MapConfig mapConfig = new MapConfig( "map" );
mapConfig.addMapAttributeConfig( new MapAttributeConfig( "parameter", ParameterExtractor.class.getName() ) );
config.addMapConfig( mapConfig );

在地图中添加一些数据:

HazelcastInstance hzInstance = Hazelcast.getOrCreateHazelcastInstance( config );
IMap<String, Set<Parameter>> objectsMap = hzInstance.getMap( "map" );
objectsMap.put( "user1", ImmutableSet.of(
                new Parameter( "type", "user" ),
                new Parameter( "firstName", "Joe" ) ) );

现在,您可以使用方括号来查询具有指定Property的数据:

objectsMap.values( Predicates.and( Predicates.equal( "parameter[type]", "user" ), Predicates.equal( "parameter[firstName]", "Joe" ) ) );

方括号中的值为custom argument,此值将作为第二个参数传递给值提取器的extract方法,并可用于查找所需的属性。

修改:如果您在具有已定义字段的集合中有特殊类型,例如您的示例中的MyObject类,您可以为MyObject的每个字段实现ValueExtractor,而不是使用自定义属性来查找所需的字段:

public class Field_1Extractor extends ValueExtractor<Set<MyObject>, String> {
    @Override
    public void extract(
            final Set<MyObject> target,
            final String argument,
            final ValueCollector collector ) {

            for ( final MyObject o : target ) {
                collector.addObject( o.getField_1() );
            }
    }
}

编辑:您还可以使用ValueExtractor查找包含值集合中的特定元素的条目。例如,“any”谓词的提取器:list[any] == some value

public class ListValueExtractor extends ValueExtractor<List<String>, String> implements Serializable {

    @Override
    public void extract( List<String> listValues, String argument, ValueCollector collector ) {
        if ( "any".equals( argument ) ) {
            for ( String v : listValues ) {
                collector.addObject( v );
            }
        }
    }
}

使用:

public class Main {

    public static void main( String[] args ) {
        Config cfg = new Config();
        MapConfig mapConfig = new MapConfig( "things" );
        mapConfig.addMapAttributeConfig( new MapAttributeConfig( "list", ListValueExtractor.class.getName() ) );//register extractor for 'list'
        cfg.addMapConfig( mapConfig );
        HazelcastInstance instance = Hazelcast.newHazelcastInstance( cfg );
        IMap<String, List<String>> mapThings = instance.getMap( "things" );

        mapThings.put( "Joe", new ArrayList<String>() {{
            add( "apple" );
            add( "box" );
            add( "laptop" );
        }} );

        mapThings.put( "Denis", new ArrayList<String>() {{
            add( "apple" );
            add( "pencil" );
            add( "jacket" );
        }} );
        EntryObject e = new PredicateBuilder().getEntryObject();
        Predicate withApple = Predicates.equal( "list[any]", "apple" );
        Predicate withLaptop = Predicates.equal( "list[any]", "laptop" );

        List<String> usersWithApple = mapThings.entrySet( withApple ).stream().map( Map.Entry::getKey ).collect( Collectors.toList() );
        List<String> usersWithLaptop = mapThings.entrySet( withLaptop ).stream().map( Map.Entry::getKey ).collect( Collectors.toList() );

        System.out.println( usersWithApple ); // [Joe, Denis]
        System.out.println( usersWithLaptop ); // [Joe]
    }
}

也许hazelcast有更方便的方式来搜索地图值集合,但我没有在文档中找到它