如何通过IMap<String,Set<MyObject>>中的对象属性查询?
How to query by object attributes from IMap<String,Set<MyObject>>?
Hazelcast docs 解释了当我们有 IMap<String,Object>
时如何做到这一点,但没有说明当映射值是一个集合时的情况。
我看到两个选项:
- 将
Set<Object>
包装成包装器类型,从而能够返回 Set
,然后需要在本地进行过滤;
- 实施 ValueExtractor,但不太确定,因为到目前为止还没有使用它。
编辑:实施最终与 mikhail-baksheev 建议的相似。请注意 CollectionExtractor
使用 ifblock 来决定应收集 MyObject
中的哪个字段。有没有更漂亮(但仍然有效)的解决方案?
public class CollectionExtractor extends ValueExtractor<Set<MyObject>, String> {
@Override
public void extract(
final Set<MyObject> target,
final String argument,
final ValueCollector collector ) {
if ( argument.equals( "field_1" ) ) {
for ( final MyObject o : target ) {
collector.addObject( o.getField_1() );
}
} else if ( argument.equals( "field_2" ) ) {
for ( final MyObject o : target ) {
collector.addObject( o.getField_2() );
}
}
}
}
@Getter
public class MyObject implements Serializable {
private String field_1;
private String field_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" ) ) );
现在可以使用方括号查询指定属性的数据:
objectsMap.values( Predicates.and( Predicates.equal( "parameter[type]", "user" ), Predicates.equal( "parameter[firstName]", "Joe" ) ) );
方括号中的值是一个custom argument,这个值将作为第二个参数传递给值提取器的extract
方法,可用于查找所需的属性。
编辑:如果您有特殊类型的对象在集合中定义的字段,例如MyObject
class 从您的示例中,您可以为 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() );
}
}
}
Edit:您也可以使用 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 有更方便的方法来搜索地图值集合,但我没有在文档中找到它
Hazelcast docs 解释了当我们有 IMap<String,Object>
时如何做到这一点,但没有说明当映射值是一个集合时的情况。
我看到两个选项:
- 将
Set<Object>
包装成包装器类型,从而能够返回Set
,然后需要在本地进行过滤; - 实施 ValueExtractor,但不太确定,因为到目前为止还没有使用它。
编辑:实施最终与 mikhail-baksheev 建议的相似。请注意 CollectionExtractor
使用 ifblock 来决定应收集 MyObject
中的哪个字段。有没有更漂亮(但仍然有效)的解决方案?
public class CollectionExtractor extends ValueExtractor<Set<MyObject>, String> {
@Override
public void extract(
final Set<MyObject> target,
final String argument,
final ValueCollector collector ) {
if ( argument.equals( "field_1" ) ) {
for ( final MyObject o : target ) {
collector.addObject( o.getField_1() );
}
} else if ( argument.equals( "field_2" ) ) {
for ( final MyObject o : target ) {
collector.addObject( o.getField_2() );
}
}
}
}
@Getter
public class MyObject implements Serializable {
private String field_1;
private String field_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" ) ) );
现在可以使用方括号查询指定属性的数据:
objectsMap.values( Predicates.and( Predicates.equal( "parameter[type]", "user" ), Predicates.equal( "parameter[firstName]", "Joe" ) ) );
方括号中的值是一个custom argument,这个值将作为第二个参数传递给值提取器的extract
方法,可用于查找所需的属性。
编辑:如果您有特殊类型的对象在集合中定义的字段,例如MyObject
class 从您的示例中,您可以为 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() );
}
}
}
Edit:您也可以使用 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 有更方便的方法来搜索地图值集合,但我没有在文档中找到它