TinkerPop Frames - storing a Map<String,String> into a vertex properties - dictionary

I'd like to persist a bare Map to vertex properties.
The motivation is that I don't know in advance which properties the map will contain.
And storing one vertex per property doesn't seem effective.
How would I do that?
interface Foo {
#Properties...?
Map<String,String> getProperties();
#Properties
Map<String,String> addProperty();
}
Perhaps through method handlers. How?
And is there any native support?

I've added support for it using the handlers.
See the Windup project.
https://github.com/windup/windup/pull/157
This is how it looks in models.
This one stores the map in the props of given frame's vertex, using a prefix map:
#TypeValue("MapInAdjPropsModelMain")
public interface MapMainModel extends WindupVertexFrame
{
#InProperties(propPrefix = "map") void setMap(Map<String, String> map);
#InProperties(propPrefix = "map") Map<String, String> getMap();
}
And this one stores the map in an adjacent vertex, hence can store multiple maps:
#TypeValue("MapInAdjPropsModelMain")
public interface MapMainModel extends WindupVertexFrame
{
#InAdjacentProperties(edgeLabel = "map")
void setMap(Map<String, String> map);
#InAdjacentProperties(edgeLabel = "map")
Map<String, String> getMap();
#InAdjacentProperties(edgeLabel = "map2")
void setMap2(Map<String, String> map);
#InAdjacentProperties(edgeLabel = "map2")
Map<String, String> getMap2();
}

Related

DynamoDB Mapper "batchLoad()" input

I was just using batchLoad function of dynamoDB. Here, the documentation
of the function says, the input it takes is List<KeyPair>. But when I use a KeyPair object, it throws the error that the argument should be a dynamodb annotated class.
I can use a DynamoDB class, where I set only hashKey and rangeKey attributes of the class and pass them as an argument. But now my use case is the Class(DynamoDB annotated), I am using has #NonNull fields. If I have to pass arguments for this I have to set junk values in them, which is obviously not desirable. Any kind of help/ suggestions ?
Thanks!
Here is the working example.
Summary:-
Model class - should be the key of map
keyPairList - List of key pairs which you would like to retrieve
With model class:-
Map<Class<?>, List<KeyPair>> keyPairForTable = new HashMap<>();
keyPairForTable.put(Movies.class, keyPairList);
Full code:-
public Boolean batchLoadMoviesUsingKeyPair() {
DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(dynamoDBClient);
KeyPair keyPair1 = new KeyPair();
keyPair1.withHashKey(1991);
keyPair1.withRangeKey("Movie with map attribute");
KeyPair keyPair2 = new KeyPair();
keyPair2.withHashKey(2010);
keyPair2.withRangeKey("The Big New Movie 2010");
List<KeyPair> keyPairList = new ArrayList<>();
keyPairList.add(keyPair1);
keyPairList.add(keyPair2);
Map<Class<?>, List<KeyPair>> keyPairForTable = new HashMap<>();
keyPairForTable.put(Movies.class, keyPairList);
Map<String, List<Object>> batchResults = dynamoDBMapper.batchLoad(keyPairForTable);
for (Map.Entry<String, List<Object>> entry : batchResults.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
return true;
}

Create list of map using streams and lambda expressions

for (String varValue : arrayList1) {
Map<String, String> mapInstance = new HashMap<>();
val.put(KEY, VALUE);
val.put(VAR_KEY, varValue);
arrayList2.add(mapInstance);
}
Basically, I want to create a map with two entries and then add each of these maps to a list.
Final list:
{KEY,VALUE} {VAR_KEY,arrayList1.get(0)}
{KEY,VALUE} {VAR_KEY,arrayList1.get(1)}
{KEY,VALUE} {VAR_KEY,arrayList1.get(2)}
...
and so on
It seems you only need a simple map stage.
List<Map<String, String>> list = arrayList1.stream().map(t -> {
Map<String, String> map = new HashMap<>();
map.put("KEY", "VALUE");
map.put("VAR_KEY", t);
return map;
}).collect(Collectors.toList());
What is KEY and VAR_KEY? are they instance variable of some object which you are trying to put in Map from the incoming object.
However, you can try something like this :
Map result =
arrayList1.stream().collect(Collectors.toMap(Class::getKey, c -> c));

Average counts from HashMap using java 8 stream API?

I have a Map of the following type
public class MapUtils {
private Map<String, Integer> queryCounts = new HashMap<>();
public void averageCounters(){
int totalCounts = queryCounts.values().stream().reduce(0, Integer::sum);
queryCounts = queryCounts.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
(Map.Entry::getValue)/totalCounts
));
}
This does not compile and shows error in this line (Map.Entry::getValue)/totalCounts. How do I fix this? Is there a better way to get achieve average over Map using Java 8 API?
EDIT:
Is this a better approach?
queryCounts.entrySet()
.forEach(entry -> queryCounts.put(entry.getKey(),
entry.getValue()/totalCounts));
If you want in-place modification, it's much better to use Map.replaceAll instead of Stream API:
int totalCounts = queryCounts.values().stream()
.collect(Collectors.summingInt(Integer::intValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
However in your case this solution is problematic as division results will be rounded to an int number, thus you almost always will got zeroes in the result. Actually there's the same problem in your code. You probably want to have Map<String, Double> as the resulting type. So you probably need to create a completely new Map:
Map<String, Double> averages = queryCounts.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey,
e -> ((double)e.getValue())/totalCounts));
An alternative would be to have queryCounts declared as Map<String, Double> in the first place. This way you can use replaceAll:
double totalCounts = queryCounts.values().stream()
.collect(Collectors.summingDouble(Double::doubleValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
Finally there's also one more alternative which is the most efficient, but dirty. Your code assumes that original (non-averaged) queryCounts are unnecessary after averageCounters() is called. Thus you can keep queryCounts as Map<String, Integer> (which is more effective than counting to Map<String, Double>), but then change the Map values type like this:
double totalCounts = queryCounts.values().stream()
.collect(Collectors.summingInt(Integer::intValue));
Map<String, Object> map = (Map<String, Object>)queryCounts;
map.replaceAll((k, v) -> ((Integer)v)/totalCounts);
Map<String, Double> averages = (Map<String, Double>)map;
queryCounts = null;
The similar trick is performed in JDK inside the Collectors.groupingBy implementation.

Google Guava - Filter Multiple Inputs on Single Property

I just got into Google Guava and it seems like a powerful tool and I see how you can use Predicates and filter by a specific property. How you can also chain predicates in FluentIterable My question is what's the best way to filter for a single property.
For example, if I have a collection of Cars. How do I filter the Cars.getPaintColor() to give me cars that are in Black, Red, and Yellow? Creating 3 separate predicates and using FluentIterable seems clumsy. Especially in my use, I could want possibly 10+ filters on the same property and I wouldn't want to create 10 Predicates.
Thanks you!
List<String> colorList = (List<String>)filterCriteria.get("Color");
List<String> makeList = (List<String>)filterCriteria.get("Make");
List<String> rimSizeList = (List<String>)filterCriteria.get("RimSize");
Predicate<String> predColor = Predicates.in(ImmutableSet.copyOf(colorList));
Predicate<CarObj> predDirection2 = Predicates.compose(predColor ,[????] );
Predicate<String> predMakeList = Predicates.in(ImmutableSet.copyOf(makeList));
Predicate<CarObj> predMakeList2 = Predicates.compose(predMakeList, [????] );
Predicate<String> predRimSize = Predicates.in(ImmutableSet.copyOf(rimSizeList));
Predicate<CarObj> predRimSize2 = Predicates.compose(predRimSize, [????] );
Collection<CarObj> filtered = FluentIterable.from(mAllCars)
.filter(predDirection2)
.filter(predMakeList2)
.filter(predRimSize2)
.toList();
Since I am using an List, I used copyOf instead of of when creating ImmutableSet.
I am not sure what to put in the second parameter of the compose. I am guessing it is something like this... in the CarObj class.
static Predicate<CarObj> byColor= new Predicate<CarObj>() {
public boolean apply(CarObj input) {
// What do I put here?
}
};
So, to check if a paint color is one of black, read or yellow, you'd want to create a Predicate that checks if a set contains that color:
Predicate<PaintColor> p = Predicates.in(ImmutableSet.of(
PaintColor.RED, PaintColor.BLACK, PaintColor.YELLOW));
You could then compose that with a Function<Car, PaintColor> that returns the paint color property of your class:
Predicate<Car> p2 = Predicates.compose(p, Car.GET_PAINT_COLOR_FUNCTION);
Edit:
By Car.GET_PAINT_COLOR_FUNCTION I just mean something like this:
public static final Function<Car, PaintColor> GET_PAINT_COLOR_FUNCTION =
new Function<Car, PaintColor>() {
#Override public PaintColor apply(Car car) {
return car.getPaintColor();
}
});
As I said in the comments, you can adapt that to your actual types as needed. For example, make it a Function<CarObj, String> instead.
The alternative to composing your extracting Function<Car, PaintColor> with a Predicates.in() as suggested by ColinD is to write your parameterized Predicate<Car>:
public class CarPaintColorPredicate implements Predicate<Car> {
private final PaintColor paintColor;
public CarPaintColorPredicate(PaintColor paintColor) {
this.paintColor = paintColor;
}
#Override
public boolean apply(#Nullable Car input) {
return input != null && input.getPaintColor() == paintColor;
}
}
which you can then use directly:
FluentIterable.from(cars)
.filter(new CarPaintColorPredicate(PaintColor.RED))
.toList();
or combine for multiple colors:
FluentIterable.from(cars)
.filter(Predicates.or(
new CarPaintColorPredicate(PaintColor.RED),
new CarPaintColorPredicate(PaintColor.BLACK)))
.toList();
or even combine with other types of predicates:
FluentIterable.from(cars)
.filter(new CarPaintColorPredicate(PaintColor.RED))
.filter(new CarMakePredicate("Ferrari"))
.toList();
To be complete, the version with the Function<Car, PaintColor> is as follows:
public enum CarPaintColorFunction implements Function<Car, PaintColor> {
INSTANCE;
#Override
public PaintColor apply(#Nullable Car input) {
return input == null ? null : input.getPaintColor();
}
}
The Function simply returns the value of the property, which is then compared to the collection (hopefully a Set) of accepted values through the Predicate composition:
FluentIterable.from(cars)
.filter(Predicates.compose(
Predicates.in(Sets.immutableEnumSet(PaintColor.RED, PaintColor.BLACK)),
CarPaintColorFunction.INSTANCE))
.toList();
All that's really explained in the Functional Explained page in the Guava Wiki.

Using HQL to query on a Map's Values

Let's say I have a map (call it myClass.mapElem<Object, Object>) like so:
Key Val
A X
B Y
C X
I want to write HQL that can query the Values such that I can get back all instances of myClass where mapElem's value is 'X' (where 'X' is a fully populated object-- I just don't want to go through each element and say x.e1 = mapElem.e1 and x.e2=... etc). I know I can do this for the keys by using where ? in index(myClass.mapElem), I just need the corresponding statement for querying the values!
Thanks in advance...
ETA: Not sure if the syntax makes a difference, but the way I am actually querying this is like so:
select myClass.something from myClass mc join myClass.mapElem me where...
You should use elements(). I tried simulating your example with the following class
#Entity
#Table(name="Dummy")
public class TestClass {
private Integer id;
private Map<String, String> myMap;
#Id
#Column(name="DummyId")
#GeneratedValue(generator="native")
#GenericGenerator(name="native", strategy = "native")
public Integer getId() {
return id;
}
#ElementCollection
public Map<String, String> getMyMap() {
return myMap;
}
public void setId(Integer id) {
this.id = id;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
}
And persisted a few instances, which constain maps of a similar structure to what you have in your example. (using < String, String > since the values in your example are strings)
The following query gives me all instances of TestClass, where the map contains a specific value
SELECT DISTINCT myClass
FROM TestClass myClass JOIN myClass.myMap myMap
WHERE ? in elements(myMap)
In my particular case, I ended up having to use an SQL query. Not ideal, but it worked.

Resources