Repository: docarray/docarray

Issue:
fix(hashing): ignore casting to float
Fixes #83 

```python
>>> x = Document(text="float test 2.56")
>>> x.get_vocabulary()
Counter({'float': 1, 'test': 1, '2': 1, '56': 1})
```


Discussion:
# [Codecov](https://codecov.io/gh/jina-ai/docarray/pull/84?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai) Report
> Merging [#84](https://codecov.io/gh/jina-ai/docarray/pull/84?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai) (645b1df) into [main](https://codecov.io/gh/jina-ai/docarray/commit/1ed4ddd57163b22c570482168fe274e550553b2d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai) (1ed4ddd) will **decrease** coverage by `0.01%`.
> The diff coverage is `66.66%`.

[![Impacted file tree graph](https://codecov.io/gh/jina-ai/docarray/pull/84/graphs/tree.svg?width=650&height=150&src=pr&token=9WGcGyyqtI&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai)](https://codecov.io/gh/jina-ai/docarray/pull/84?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai)

```diff
@@            Coverage Diff             @@
##             main      #84      +/-   ##
==========================================
- Coverage   82.98%   82.97%   -0.02%     
==========================================
  Files          87       87              
  Lines        3814     3811       -3     
==========================================
- Hits         3165     3162       -3     
  Misses        649      649              
```

| Flag | Coverage Δ | |
|---|---|---|
| docarray | `82.97% <66.66%> (-0.02%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/jina-ai/docarray/pull/84?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai) | Coverage Δ | |
|---|---|---|
| [docarray/document/mixins/featurehash.py](https://codecov.io/gh/jina-ai/docarray/pull/84/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai#diff-ZG9jYXJyYXkvZG9jdW1lbnQvbWl4aW5zL2ZlYXR1cmVoYXNoLnB5) | `87.75% <66.66%> (-0.71%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/jina-ai/docarray/pull/84?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/jina-ai/docarray/pull/84?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai). Last update [1ed4ddd...645b1df](https://codecov.io/gh/jina-ai/docarray/pull/84?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jina-ai).


Resolving patch:
diff --git a/docarray/document/mixins/featurehash.py b/docarray/document/mixins/featurehash.py
--- a/docarray/document/mixins/featurehash.py
+++ b/docarray/document/mixins/featurehash.py
@@ -64,22 +64,24 @@ def _hash_column(col_name, col_val, n_dim, max_value, idxs, data, table):
 
 
 def _any_hash(v):
-    try:
-        return int(v)  # parse int parameter
-    except ValueError:
+    if not v:
+        # ignore it when the parameter is empty
+        return 0
+    elif isinstance(v, (tuple, dict, list, str)):
+        if isinstance(v, str):
+            v = v.strip()
+            if v.lower() in {'true', 'yes'}:  # parse boolean parameter
+                return 1
+            if v.lower() in {'false', 'no'}:
+                return 0
+        else:
+            v = json.dumps(v, sort_keys=True)
+        return int(hashlib.md5(str(v).encode('utf-8')).hexdigest(), base=16)
+    else:
         try:
-            return float(v)  # parse float parameter
+            return int(v)  # parse int parameter
         except ValueError:
-            if not v:
-                # ignore it when the parameter is empty
-                return 0
-            if isinstance(v, str):
-                v = v.strip()
-                if v.lower() in {'true', 'yes'}:  # parse boolean parameter
-                    return 1
-                if v.lower() in {'false', 'no'}:
-                    return 0
-            if isinstance(v, (tuple, dict, list)):
-                v = json.dumps(v, sort_keys=True)
-
-    return int(hashlib.md5(str(v).encode('utf-8')).hexdigest(), base=16)
+            try:
+                return float(v)  # parse float parameter
+            except ValueError:
+                return 0  # unable to hash


Test patch:
diff --git a/tests/unit/document/test_feature_hashing.py b/tests/unit/document/test_feature_hashing.py
--- a/tests/unit/document/test_feature_hashing.py
+++ b/tests/unit/document/test_feature_hashing.py
@@ -8,10 +8,17 @@
 @pytest.mark.parametrize('sparse', [True, False])
 @pytest.mark.parametrize('metric', ['jaccard', 'cosine'])
 def test_feature_hashing(n_dim, sparse, metric):
-    da = DocumentArray.empty(3)
-    da.texts = ['hello world', 'world, bye', 'hello bye']
+    da = DocumentArray.empty(6)
+    da.texts = [
+        'hello world',
+        'world, bye',
+        'hello bye',
+        'infinity test',
+        'nan test',
+        '2.3 test',
+    ]
     da.apply(lambda d: d.embed_feature_hashing(n_dim=n_dim, sparse=sparse))
-    assert da.embeddings.shape == (3, n_dim)
+    assert da.embeddings.shape == (6, n_dim)
     da.embeddings = to_numpy_array(da.embeddings)
     da.match(da, metric=metric, use_scipy=True)
     result = da['@m', ('id', f'scores__{metric}__value')]