diff --git a/include/opendht/indexation/pht.h b/include/opendht/indexation/pht.h
index 5e91ac9cdb35628e2cc38d23b4d97993724140da..45e7d9cc8098bf4c8f9e95e9555551328fd4d71c 100644
--- a/include/opendht/indexation/pht.h
+++ b/include/opendht/indexation/pht.h
@@ -15,6 +15,15 @@
 namespace dht {
 namespace indexation {
 
+/*!
+ * @class   Prefix
+ * @brief   A blob structure which prefixes a Key in the PHT.
+ * @details
+ * Since the PHT structure is a "trie", every node in this structure have a
+ * label which is defined by the path from the root of the trie to the node. If
+ * the node in question is a leaf, *the label is a prefix of all the keys
+ * contained in the leaf*.
+ */
 struct Prefix {
     Prefix() {}
     Prefix(InfoHash h) : size_(h.size() * 8), content_(h.begin(), h.end()) {}
@@ -32,6 +41,12 @@ struct Prefix {
             len += size_;
         return Prefix(*this, len);
     }
+
+    /**
+     * This methods gets the prefix of its sibling in the PHT structure.
+     *
+     * @return The prefix of this sibling.
+     */
     Prefix getSibling() const {
        Prefix copy = *this;
        if (size_) {
@@ -59,6 +74,30 @@ struct Prefix {
         return ss.str();
     }
 
+    static inline unsigned commonBits(const Prefix& p1, const Prefix& p2) {
+        unsigned i, j;
+        uint8_t x;
+        auto longest_prefix_size = std::min(p1.size_, p2.size_);
+
+        for (i = 0; i < longest_prefix_size; i++) {
+            if (p1.content_.data()[i] != p2.content_.data()[i])
+                break;
+        }
+
+        if (i == longest_prefix_size)
+            return 8*longest_prefix_size;
+
+        x = p1.content_.data()[i] ^ p2.content_.data()[i];
+
+        j = 0;
+        while ((x & 0x80) == 0) {
+            x <<= 1;
+            j++;
+        }
+
+        return 8 * i + j;
+    }
+
     size_t size_ {0};
     Blob content_ {};
 };
@@ -111,7 +150,7 @@ public:
     /**
      * Lookup a key for a value.
      */
-    void lookup(Key k, LookupCallback cb = {}, Dht::DoneCallbackSimple doneCb = {});
+    void lookup(Key k, LookupCallback cb = {}, Dht::DoneCallbackSimple doneCb = {}, bool exact_match = true);
     /**
      * Adds an entry into the index.
      */
@@ -135,10 +174,10 @@ private:
      * Performs a step in the lookup operation. Each steps are performed
      * asynchronously.
      */
-    void lookupStep(Prefix k, std::shared_ptr<int> lo,
-                       std::shared_ptr<int> hi,
-                       std::shared_ptr<std::vector<std::shared_ptr<Value>>> vals,
-                       LookupCallback cb, Dht::DoneCallbackSimple done_cb);
+    void lookupStep(Prefix k, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
+            std::shared_ptr<std::vector<std::shared_ptr<Value>>> vals,
+            LookupCallback cb, Dht::DoneCallbackSimple done_cb,
+            std::shared_ptr<unsigned> max_common_prefix_len);
 
     /**
      * Updates the canary token on the node responsible for the specified
diff --git a/src/indexation/pht.cpp b/src/indexation/pht.cpp
index 07442a6781ac72cb7e5a70aba515c5ecd88c8df1..1b2e2636a95a6311487d780621213f22742ffedf 100644
--- a/src/indexation/pht.cpp
+++ b/src/indexation/pht.cpp
@@ -4,10 +4,12 @@
 namespace dht {
 namespace indexation {
 
-void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo,
-                       std::shared_ptr<int> hi,
-                       std::shared_ptr<std::vector<std::shared_ptr<Value>>> vals,
-                       LookupCallback cb, Dht::DoneCallbackSimple done_cb)
+const ValueType IndexEntry::TYPE = ValueType::USER_DATA;
+
+void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
+        std::shared_ptr<std::vector<std::shared_ptr<Value>>> vals,
+        LookupCallback cb, Dht::DoneCallbackSimple done_cb,
+        std::shared_ptr<unsigned> max_common_prefix_len)
 {
     struct node_lookup_result {
         bool done {false};
@@ -28,7 +30,7 @@ void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo,
         } else {
             // internal node
             *lo = mid+1;
-            lookupStep(p, lo, hi, vals, cb, done_cb);
+            lookupStep(p, lo, hi, vals, cb, done_cb, max_common_prefix_len);
         }
     };
     if (*lo <= *hi) {
@@ -42,8 +44,27 @@ void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo,
             else {
                 IndexEntry entry;
                 entry.unpackValue(*value);
-                if (entry.prefix == p.content_)
+
+                auto add_value = [&](bool better = true) {
                     vals->emplace_back(std::make_shared<Value>(entry.value));
+                    if (better and max_common_prefix_len)
+                        *max_common_prefix_len = Prefix::commonBits(p, vals->front()->first);
+                };
+                if (max_common_prefix_len) {
+                    if (vals->empty()) {
+                        add_value();
+                    } else {
+                        auto common_bits = Prefix::commonBits(vals->front()->first, p.getPrefix(mid));
+                        if (common_bits == *max_common_prefix_len)
+                            add_value(false);
+                        else if (common_bits > *max_common_prefix_len) {
+                            vals->clear();
+                            add_value();
+                        }
+                    }
+                }
+                else if (entry.prefix == p.content_)
+                    add_value(false);
             }
             return true;
         };
@@ -59,7 +80,7 @@ void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo,
                         if (not first_res->is_pht) {
                             // Not a PHT node.
                             *hi = mid-1;
-                            lookupStep(p, lo, hi, vals, cb, done_cb);
+                            lookupStep(p, lo, hi, vals, cb, done_cb, max_common_prefix_len);
                         } else {
                             first_res->done = true;
                             if (second_res->done)
@@ -88,12 +109,13 @@ void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo,
     }
 }
 
-void Pht::lookup(Key k, Pht::LookupCallback cb, Dht::DoneCallbackSimple done_cb) {
+void Pht::lookup(Key k, Pht::LookupCallback cb, Dht::DoneCallbackSimple done_cb, bool exact_match) {
     auto values = std::make_shared<std::vector<std::shared_ptr<Value>>>();
     auto prefix = linearize(k);
     auto lo = std::make_shared<int>(0);
     auto hi = std::make_shared<int>(prefix.size_);
-    lookupStep(prefix, lo, hi, values, cb, done_cb);
+    std::shared_ptr<unsigned> max_common_prefix_len = not exact_match ? std::make_shared<unsigned>(0) : nullptr;
+    lookupStep(prefix, lo, hi, values, cb, done_cb, max_common_prefix_len);
 }
 
 void Pht::updateCanary(Prefix p) {
@@ -145,7 +167,7 @@ void Pht::insert(Key k, Value v, Dht::DoneCallbackSimple done_cb) {
                 updateCanary(*final_prefix);
                 dht_->put(final_prefix->hash(), std::move(entry), done_cb);
             }
-        }
+        }, nullptr
     );
 }