LRU Cache Key, Value, Node.Value Real World Interpretation - caching

I understand how in principle an LRU cache works. For example, see here: https://java2blog.com/lru-cache-implementation-java/
However, I am having great difficulty understanding how this is interpreted in a real world setting. For example, if I want to store objects (which have no natural numbering/order), I understand that the value (in the hashmap) is just a pointer to a node in the linked list, but what does the key represent?
Furthermore, what does the node.value represent? I think this the actual object which is being cached. However, how does this correspond to the key in the hashmap?

A typical hashmap has a key and a value, both of arbitrary type. The key is the thing you want to index the structure by, and the value is the thing you want to store and retrieve. Consider a normal hashmap in Java:
Map<UUID, Person> peopleById = new HashMap<>();
You can pass in a UUID to a .get method and get the person associated with that UUID, if it exists.
The LRU caches used in the real world are like that as well:
Map<UUID, Person> cachedPeopleById = new LRUCache<>(10);
The UUID is the key, and the Person is the value.
The reference implementation you linked to doesn't use generics, it only supports int to int, which is the equivalent of Map<Integer, Integer>. The Node class in the reference implementation isn't something that ought to be exposed in public methods. So in that reference implementation, Node should be hidden, and delete(Node) and setHead(Node) should be private, because otherwise they expose implementation details of the cache.
A better implementation would be something more like this (doing this off the top of my head, might have compilation errors, for illustrative purposes only):
public class LRUCache <KeyType, ValueType> implements Map<KeyType, ValueType> {
private static class Node <KeyType, ValueType> {
KeyType key;
ValueType value;
Node prev;
Node next;
public Node(KeyType key, ValueType value){
this.key = key;
this.value = value;
}
}
int capacity;
HashMap<KeyType, Node> map = new HashMap<>();
Node head=null;
Node end=null;
public LRUCache(int capacity) {
this.capacity = capacity;
}
public ValueType get(KeyType key) {
...
}
public set(KeyType key, ValueType value) {
...
}
private void delete(Node<KeyType, ValueType> node) {
...
}
private void setHead(Node<KeyType, ValueType> node) {
...
}

Related

Feature envy, encapsulation, active record, separation of concerns? When its bad?

you all say, object oriented programming is about encapsulation, data hiding. Let's given this example:
class Rectangle
{
private int a,b;
public function __construct(int a, int b)
{
this.a = a;
this.b = b;
}
int public function getA()
{
return a;
}
int public function getB()
{
return b;
}
}
var r = new Rectangle(3, 4);
var area = r.getA() * r.getB();
this is a bad code then, so let's refaktor:
class Rectangle
{
private int a,b;
public function __construct(int a, int b)
{
this.a = a;
this.b = b;
}
int public function getArea()
{
return a*b;
}
}
r = new Rectangle(3, 4);
area = r.getArea();
way better, data hiding is done and getArea is brought where it belongs to.
Ok then, here comes the Active Records:
class Record
{
private int ID;
private string username;
public function __constructor(int ID, string username)
{
this.ID = ID;
this.username = username;
}
int public function getID()
{
return ID;
}
string public function getUsername()
{
return username;
}
}
r = new Record(1, 'test');
dbEngine.save(r);
this is again bad, since all data is public. (altough Doctrine works this way)
But if I do that as Propel did:
class Record
{
private int ID;
private string username;
public function __constructor(int ID, string username)
{
this.ID = ID;
this.username = username;
}
public function save()
{
dbEngine.save([ID, username]);
}
}
r = new Record(1, 'test');
r.save();
this is also said bad, because Active Records are antipattern. Then when it's good or bad? When does an "act" (getArea, save) should be brought inside an object - and when does it act outsidely?
You can inject the dbEngine dependency in for your specific case, but this doesn't address your concern.
In general, what makes your code good is how easy it is to understand, and how close changes in intention are tied to changes in implementation.
The problem with revealing private internals are that you're exposing your inner values that programs which interface with your program may rely on (and make difficult to change later on). A record is basically a struct/dataclass - it represents a collection of values that goes together with some well-defined meaning. Without knowing the rest of the code I can't say if this specific class is like that, but if that's the case it would be okay to just make it a struct (all members public, no methods).
There aren't any catch-all rules that makes code 'good'. It's a continuous process of making mistakes or being inefficient, and analysing what code led or made more likely that problem. Code smells are just the result of lots of trial and error by others, and although very robust in most cases may sometimes be outdated and should be applied in the specific situation when they improve your code.
None of your examples are bad. They are just design choices. Dropping the accessors to a and b in the second example seems a step backwards to me. As to putting implementation dependent save code in the class definition, that would be bad if there were multiple types that all needed to define the save. There you would be better to define a parent class with the save function and then inheriting from that class. However, if it’s just you writing code and there is just that one class it doesn’t matter.
Good that you are thinking about what makes good code. As a general rule, good code is code that works and which you can return to in 6 months and modify easily in the future. If you have a group of developers then of course provide accessors.
Another aspect of good code is having unit tests. If you change something and the unit tests pass you’ve done your job. If someone is using internals they should write a unit test that will signal a change that would break their code.

Datastructure for a log search service?

A few months back, i was asked to design a service which takes a start and end time interval and lists down the number of exceptions/errors grouped by the exception type/code. Basically the intention was to create or use an existing data structure for an efficient search. Here is what I coded.
public class ErrorDetail{
private int code;
private String message;
}
public class ExceptionSearchService
{
private Map<Long, ErrorDetail> s = new TreeMap<Long, ErrorDetail>();
public ArrayList<ErrorDetail> getErrors(long start, long end){
ErrorDetail e1 = find(start, s);
ErrorDetail e2 = find(end, s);
//do an in order traversal between e1 and e2 and add it to an array list and return
}
public void addError(long time, ErrorDetail e){
s.put(time,e);
}
}
I realized that i should not have mentioned a TreeMap, instead should have had my own class like TreeNode but the idea was to have a tree structure and a distributed one because we are talking about thousands of services serving millions of request per minute and generating error.
Could i have used a better data structure in this case ?

How can I use Java 8 streams to sort an ArrayList of objects by a primitive int member?

Here is an example class. I know the simplest thing would be to change the members from primitive type int to object Integer and use stream/lambda/sorted, but there may be reasons to only have a primitive type int such as space.
How could I use the streams API to sort a List<DateRange> by int member startRange?
List<DateRange> listToBeSorted = new ArrayList<DateRange>();
static private class DateRange
{
private int startRange ;
private int endRange ;
public int getStartRange() {
return startRange;
}
public void setStartRange(int startRange) {
this.startRange = startRange;
}
public int getEndRange() {
return endRange;
}
public void setEndRange(int endRange) {
this.endRange = endRange;
}
}
You may do it like so,
List<DateRange> sortedList = listToBeSorted.stream()
.sorted(Comparator.comparingInt(DateRange::getStartRange))
.collect(Collectors.toList());
I know you asked for a way to do it with streams, but if you are OK with sorting the original list in-place, you don't need streams for this. Just use the List.sort method:
listToBeSorted.sort(Comparator.comparingInt(DateRange::getStartRange));

Sort a list of objects based on a parameterized attribute of the object

Assuming that we have an object with the following attributes:
public class MyObject {
private String attr1;
private Integer attr2;
//...
public String getAttr1() {
return this.attr1;
}
public Integer getAttr2() {
return this.attr2;
}
}
One way of sorting a list mylist of this object, based on its attribute attr1 is:
mylist.sort(Comparator.comparing(MyObject::getAttr1));
Is it possible to use this code inside a method in a dynamic way and replace the getAttr1 part with a method that returns the getter of an attribute of the object based on its name? Something like:
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(Comparator.comparing(MyObject::getGetterByAttr(attr)));
}
The MyObject::getGetterByAttr(attr) part does not compile, I wrote it just as an example to explain my idea
I tried to implement a method with the following code new PropertyDescriptor(attr, MyObject.class).getReadMethod().invoke(new MyObject()) but It's still not possible to call a method with a parameter from the comparing method
You could add a method like
public static Function<MyObject,Object> getGetterByAttr(String s) {
switch(s) {
case "attr1": return MyObject::getAttr1;
case "attr2": return MyObject::getAttr2;
}
throw new IllegalArgumentException(s);
}
to your class, but the returned function is not suitable for Comparator.comparing, as it expects a type fulfilling U extends Comparable<? super U> and while each of String and Integer is capable of fulfilling this constraint in an individual invocation, there is no way to declare a generic return type for getGetterByAttr to allow both type and be still compatible with the declaration of comparing.
An alternative would be a factory for complete Comparators.
public static Comparator<MyObject> getComparator(String s) {
switch(s) {
case "attr1": return Comparator.comparing(MyObject::getAttr1);
case "attr2": return Comparator.comparing(MyObject::getAttr2);
}
throw new IllegalArgumentException(s);
}
to be used like
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(getComparator(attr));
}
This has the advantage that it also may support properties whose type is not Comparable and requires a custom Comparator. Also, more efficient comparators for primitive types (e.g. using comparingInt) would be possible.
You may also consider using a Map instead of switch:
private static Map<String,Comparator<MyObject>> COMPARATORS;
static {
Map<String,Comparator<MyObject>> comparators=new HashMap<>();
comparators.put("attr1", Comparator.comparing(MyObject::getAttr1));
comparators.put("attr2", Comparator.comparing(MyObject::getAttr2));
COMPARATORS = Collections.unmodifiableMap(comparators);
}
public static Comparator<MyObject> getComparator(String s) {
Comparator<MyObject> comparator = COMPARATORS.get(s);
if(comparator != null) return comparator;
throw new IllegalArgumentException(s);
}
More dynamic is only possible via Reflection, but this would complicate the code, add a lot of potential error source, with only little benefit, considering that you need only to add one line of source code for adding support for another property in either of the examples above. After all, the set of defined properties gets fixed at compile time.
You could also have a single place where this comparators would be defined:
static enum MyObjectComparator {
ATTR1("attr1", Comparator.comparing(MyObject::getAttr1));
MyObjectComparator(String attrName, Comparator<MyObject> comparator) {
this.comparator = comparator;
this.attrName = attrName;
}
private final Comparator<MyObject> comparator;
private final String attrName;
private static MyObjectComparator[] allValues = MyObjectComparator.values();
public static Comparator<MyObject> findByValue(String value) {
return Arrays.stream(allValues)
.filter(x -> x.attrName.equalsIgnoreCase(value))
.map(x -> x.comparator)
.findAny()
.orElseThrow(RuntimeException::new);
}
}
And your usage would be:
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(MyObjectComparator.findByValue(attr));
}

Implementation of an ArrayWritable for a custom Hadoop type

How do I define an ArrayWritable for a custom Hadoop type ? I am trying to implement an inverted index in Hadoop, with custom Hadoop types to store the data
I have an Individual Posting class which stores the term frequency, document id and list of byte offsets for the term in the document.
I have a Posting class which has a document frequency (number of documents the term appears in) and list of Individual Postings
I have defined a LongArrayWritable extending the ArrayWritable class for the list of byte offsets in IndividualPostings
When i defined a custom ArrayWritable for IndividualPosting I encountered some problems after local deployment (using Karmasphere, Eclipse).
All the IndividualPosting instances in the list in Posting class would be the same, even though I get different values in the Reduce method
From the documentation of ArrayWritable:
A Writable for arrays containing instances of a class. The elements of this writable must all be instances of the same class. If this writable will be the input for a Reducer, you will need to create a subclass that sets the value to be of the proper type. For example: public class IntArrayWritable extends ArrayWritable { public IntArrayWritable() { super(IntWritable.class); } }
You've already cited doing this with a WritableComparable type defined by Hadoop. Here's what I assume your implementation looks like for LongWritable:
public static class LongArrayWritable extends ArrayWritable
{
public LongArrayWritable() {
super(LongWritable.class);
}
public LongArrayWritable(LongWritable[] values) {
super(LongWritable.class, values);
}
}
You should be able to do this with any type that implements WritableComparable, as given by the documentation. Using their example:
public class MyWritableComparable implements
WritableComparable<MyWritableComparable> {
// Some data
private int counter;
private long timestamp;
public void write(DataOutput out) throws IOException {
out.writeInt(counter);
out.writeLong(timestamp);
}
public void readFields(DataInput in) throws IOException {
counter = in.readInt();
timestamp = in.readLong();
}
public int compareTo(MyWritableComparable other) {
int thisValue = this.counter;
int thatValue = other.counter;
return (thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1));
}
}
And that should be that. This assumes you're using revision 0.20.2 or 0.21.0 of the Hadoop API.

Resources