Repository: deepset-ai/haystack

Issue:
FaissDocumentStore + EmbeddingRetriever: Numba TypingError when update_embeddings()
**Describe the bug**
I get the following error, when I try to create a FAISSDocumentStore with embeddings for cosine similarity comparison.

**Error message**
```
---------------------------------------------------------------------------
TypingError                               Traceback (most recent call last)
/var/folders/pk/g5q9c_px2nb425jdd8yn7qk80000gn/T/ipykernel_91523/3425554236.py in <module>
      1 if document_store.get_embedding_count() == 0:
----> 2     document_store.update_embeddings(retriever)
      3     document_store.save('data/haystack/faiss_index')

~/opt/anaconda3/lib/python3.8/site-packages/haystack/document_stores/faiss.py in update_embeddings(self, retriever, index, update_existing_embeddings, filters, batch_size)
    321                 embeddings_to_index = np.array(embeddings, dtype="float32")
    322 
--> 323                 if self.similarity=="cosine": self.normalize_embedding(embeddings_to_index)
    324 
    325                 self.faiss_indexes[index].add(embeddings_to_index)

~/opt/anaconda3/lib/python3.8/site-packages/numba/core/dispatcher.py in _compile_for_args(self, *args, **kws)
    480                 e.patch_message(msg)
    481 
--> 482             error_rewrite(e, 'typing')
    483         except errors.UnsupportedError as e:
    484             # Something unsupported is present in the user code, add help info

~/opt/anaconda3/lib/python3.8/site-packages/numba/core/dispatcher.py in error_rewrite(e, issue_type)
    421                 raise e
    422             else:
--> 423                 raise e.with_traceback(None)
    424 
    425         argtypes = []

TypingError: Failed in nopython mode pipeline (step: nopython frontend)
non-precise type pyobject
During: typing of argument at /Users/roebbert92/opt/anaconda3/lib/python3.8/site-packages/haystack/document_stores/base.py (202)

File "../../opt/anaconda3/lib/python3.8/site-packages/haystack/document_stores/base.py", line 202:
    def normalize_embedding(self, emb: np.ndarray) -> None:
        <source elided>
        # Single vec
        if len(emb.shape) == 1:
        ^ 

This error may have been caused by the following argument(s):
- argument 0: Cannot determine Numba type of <class 'haystack.document_stores.faiss.FAISSDocumentStore'> 

This error may have been caused by the following argument(s):
- argument 0: Cannot determine Numba type of <class 'haystack.document_stores.faiss.FAISSDocumentStore'>
```
 

**Expected behavior**
Updating embeddings with cosine similarity on FAISSDocumentStore works.

**Additional context**
```
from haystack.document_stores import FAISSDocumentStore
from haystack.nodes import EmbeddingRetriever
document_store = FAISSDocumentStore(sql_url='sqlite:///data/haystack/faiss_document_store.db', 
                                        faiss_index_factory_str="Flat", 
                                        similarity="cosine", 
                                        return_embedding=True,
                                        vector_dim=384)
# omitted document_store.write_documents() for brevity
retriever = EmbeddingRetriever(document_store=document_store,
                               embedding_model="sentence-transformers/all-MiniLM-L6-v2",
                               batch_size=8)
document_store.update_embeddings(retriever)
document_store.save('data/haystack/faiss_index')
```

**To Reproduce**
Steps to reproduce the behavior


**System:**
 - OS: macOS Monterey
 - GPU/CPU: 2,3 GHz Quad-Core Intel Core i5 (No GPU)
 - Haystack version (commit or version number): 1.0.0
 - DocumentStore: FaissDocumentStore
 - Reader: ---
 - Retriever: Embedding Retriever



Discussion:
I tried other similarity measures ('l2', 'dot_product') and they worked just fine. 
Please take a look into it.

Numba version: 
```
Name: numba
Version: 0.54.1
Summary: compiling Python code using LLVM
Home-page: https://numba.pydata.org
Author: Anaconda, Inc.
Author-email: numba-users@continuum.io
License: BSD
```
Hi @roebbert92, thanks for raising this issue! Just letting you know that I will have a look at it in the following  days. :)

Resolving patch:
diff --git a/haystack/document_stores/base.py b/haystack/document_stores/base.py
--- a/haystack/document_stores/base.py
+++ b/haystack/document_stores/base.py
@@ -191,22 +191,27 @@ def get_document_by_id(self, id: str, index: Optional[str] = None) -> Optional[D
     def get_document_count(self, filters: Optional[Dict[str, List[str]]] = None, index: Optional[str] = None) -> int:
         pass
 
+    @staticmethod
     @njit#(fastmath=True)
-    def normalize_embedding(self, emb: np.ndarray) -> None:
+    def normalize_embedding(emb: np.ndarray) -> None:
         """
-        Performs L2 normalization of embeddings vector inplace. Input can be a single vector (1D array) or a matrix (2D array).
+        Performs L2 normalization of embeddings vector inplace. Input can be a single vector (1D array) or a matrix
+        (2D array).
         """
         # Might be extended to other normalizations in future
 
         # Single vec
         if len(emb.shape) == 1:
-            norm = np.sqrt(emb.dot(emb)) #faster than np.linalg.norm()
+            norm = np.sqrt(emb.dot(emb))  # faster than np.linalg.norm()
             if norm != 0.0:
                 emb /= norm
         # 2D matrix
         else:
-            norm = np.linalg.norm(emb, axis=1)
-            emb /= norm[:, None]
+            for vec in emb:
+                vec = np.ascontiguousarray(vec)
+                norm = np.sqrt(vec.dot(vec))
+                if norm != 0.0:
+                    vec /= norm
 
     def finalize_raw_score(self, raw_score: float, similarity: Optional[str]) -> float:
         if similarity == "cosine":


Test patch: