Skip to content

Handle duplicated keys for the user #9

Closed

Description

@lemire

Currently the user is responsible to ensure that there are no duplicated keys. We should handle this for the user (it is relatively easy to do efficiently, without even sorting).

Activity

  1. thomasmueller commented on Dec 20, 2019

    @thomasmueller
    Contributor

    Yes it would be nice. What algorithm would you use? I'm afraid I'm not aware of a very efficient one...

  2. lemire commented on Dec 20, 2019

    @lemire
    MemberAuthor

    Try to construct the filter once (optimistically). The duplicated keys will be in the unmatched keys, just visit these keys.

  3. emidoots commented on Feb 1, 2021

    @emidoots

    Hi! I've been trying to understand the implications of duplicated keys.. apologies if this is a naive question, but does this situation not just imply the key was already previously added to the set, and thus 'there is no work to be done' in order to add that key to the set for future testing of "is-key-in-set"?

  4. lemire commented on Feb 1, 2021

    @lemire
    MemberAuthor

    @slimsag You construct a filter from a set of keys. It is assumed in the construction that the keys are distinct. If two keys are the same, then the construction will always fail because the algorithm won't manage to add both of them.

  5. prataprc commented on Aug 27, 2021

    @prataprc
    Contributor

    Try to construct the filter once (optimistically). The duplicated keys will be in the unmatched keys, just visit these keys.

    In the rust implementation of Xor8 and Fuse8 I am adding the following API.

    pub fn insert<K: ?Sized + Hash>(&mut self, key: &K) {
        ...
    }
    
    pub fn populate<K: Hash>(&mut self, keys: &[K]) {
        ...
    }

    So it would be really nice to handle duplicate keys for the user, since we are computing the 64-bit hash digest for each key. But I don't fully understand how to do this without using sort algorithm. Would be helpful if I can get some reference on that ..

  6. lemire commented on Aug 27, 2021

    @lemire
    MemberAuthor

    @prataprc

    I totally agree that we need to fix this. I just never got around to doing it.

    (So I am not dismissing your concerns, at all.)

    But I don't fully understand how to do this without using sort algorithm. Would be helpful if I can get some reference on that ..

    If the construction succeeds, then you know that there were no duplicated keys. So there is no need to do any work.

    If the construction fails, and only then, do you need to handle the duplicate keys. There should be no need to sort because the failed construction should have left you with unmatched keys... and that number should be small... And, e.g., if x and y are equal then both x and y should be unmatched at the end.

    You can try it out by simulating a case where you have two identifical keys... you will see what happens after the first failure...

  7. lemire commented on Aug 27, 2021

    @lemire
    MemberAuthor

    @prataprc If I am not providing details is because I don't know how to do it because I never spent time on it. I am just reasoning from a high level.

  8. lemire commented on Sep 6, 2021

    @lemire
    MemberAuthor

    I have a fix in the Go version at FastFilter/xorfilter#22

    I'll port it here, but @prataprc would you be so kind to check whether it meets your need?

  9. prataprc commented on Sep 6, 2021

    @prataprc
    Contributor

    Ported this patch to rust-fuse8

    I have tried to measure the performance improvements for the following APIs.

    populate() - accepts an array of keys, for each key compute the hash digest,
    and insert the digest into BTreeMap for deduplication.

    populate_keys() - accepts an array of u64 digests, and insert each digest into
    BTreeMap for deduplication.

    build_keys() - accepts an array of u64 digests, that are expected to be unique
    so there is no overhead of computing the hash and inserting the hash into
    BTreeMap. This can be considered as the reference performance of Fuse8 filter.

    Before the patch,

    build_keys      - 0.577 seconds # Fuse8 filter
    populate_keys   - 1.610 seconds # Fuse8 filter + BTreeMap insert
    populate        - 6.244 seconds # Fuse8 filter + Hash-compute + BTreeMap insert
    

    After the patch

    build_keys      - 0.555 seconds # Fuse8 filter
    populate_keys   - 0.570 seconds # Fuse8 filter
    populate        - 0.720 seconds # Fuse8 filter + Hash-compute
    

    These numbers were for building 10 Million keys, and the machine used was
    1st gen thread-ripper.

  10. lemire commented on Sep 6, 2021

    @lemire
    MemberAuthor

    So I take it that you are happy with this solution. :-)

  11. lemire commented on Sep 7, 2021

    @lemire
    MemberAuthor

    We now support a small number of duplicates. If there are too many duplicates, the user will get a reported failure but this should not happen if the hash values are fair and good.

  12. lemire commented on Sep 7, 2021

    @lemire
    MemberAuthor

    Closing for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions