Firestore Search Engine
This is a powerful and flexible search engine server for Firestore. This package allows developers to quickly and efficiently add search capability to their Firestore-based applications.
It's Node.js package, so you can use it in your Cloud Functions or any other Node.js environment. It's also compatible with TypeScript.
This package is not intended for front-end usage!
Firestore Search Engine Package
This is a powerful and flexible search engine server for Firestore. This package allows developers to quickly and efficiently add search capability to their Firestore-based applications.
Key Features
- Out-of-the-box Firestore configuration support
- Full-text searching of Firestore documents
- Search by any keypath in the document
- Support only string search
- Full wrapped for express/onCall/onRequest functions
- Built-in Firestore Triggers onCreate/onUpdate/onDelete for automated features
- Use Vector query from firestore vector embeded for better performances
- Use sentence_transformers model
- Use FastEmbeded for interact with model
Warning: add the model is injected in /src/cache for the first call is download.
You need to generate cache in emulator before deploying
GCP not Allow container to write in functions folder
Also you can fork the repo and re-build with another path in /tmp if you have minInstances deployed and you not need cold start and scaling.
For cloud functions implementation on prod it's recommended to create a separated repository and a new firebase init with only this function and the model in src/cache folder in the same firebase project. This is because the model is large(80+Mb) and can cause deployment issues and cost if it is included in the main repository.
Also upgrade memory of cloud functions from 256MB to 512MB or 1GB for better performances and avoid out of memory errors.
When you know how it work you take only 5 minutes for implement new indexed field for a document and build endpoint for search it
for the moment express is recommended for build only on search functions and provide all your routes behind
but onCall and onRequest impl worked too
Installation
npm install firestore-search-engine
Usage
Start by importing all the required modules from the package:
import { FirestoreSearchEngine } from "firestore-search-engine";
const { FirestoreSearchEngine } = require("firestore-search-engine");
Then, create an instance of the FirestoreSearchEngine:
export const searchEngineUserName = new FirestoreSearchEngine(firestore(), {
collection: "YourCollectionName",
wordMaxLength: 100,
wordMinLength: 3,
distanceThreshold: 0.155 ,
});
Manual indexing
Call a searchEngine.indexes for index your document at the same time of you create it:
const updateName = "YourFieldValue";
const documentId = "YourDocumentId";
const myDocumentRef = firestore()
.collection("YourCollectionName")
.doc(documentId);
await myDocumentRef.set(
{ name: updateName, docId: documentId },
{ merge: true }
);
await searchEngineUserName.indexes({
inputField: updateName,
returnedFields: {
indexedDocumentPath: myDocumentRef.path,
name: updateName,
docId: documentId,
},
});
IMPORTANT
Before the search use you need to create indexes the search functions throw in http 400 with error.code = 9 and details including the custom command to deploy the normalized index field :
Install gcloud
Configure gcloud
Or in your GCP console open cloud shell
{
"code": 9,
"details": "Missing vector index configuration. Please create the required index with the following gcloud command:
gcloud firestore indexes composite create --collection-group=<YourCollectionConfig> --query-scope=COLLECTION_GROUP --field-config=field-path=vectors,vector-config='{"dimension":384,"flat": {}}'",
"metadata": {
...
}
}
"indexes": [
{
"collectionGroup": "<YourCollectionConfig>",
"queryScope": "COLLECTION_GROUP",
"fields": [
{
"fieldPath": "vectors",
"vectorConfig": {
"dimension": 384,
"flat": {}
}
}
]
}
],
Finally, execute the search operation:
const results = await searchEngineUserName.search({
fieldValue: inputField,
distanceThreshold: 0.155 ,
limit: 10 ,
});
The results object will hold the documents that matched your search term.
Example
Below is a complete usage example of the Firestore Search Engine Package:
express wrapper
import { FirestoreSearchEngine } from "firestore-search-engine";
const app = express();
searchEngineUserName.expressWrapper(app, "/search/user/name", {
distanceThreshold: 0.155 ,
limit: 10 ,
});
onRequest wrapper
import { FirestoreSearchEngine } from "firestore-search-engine";
export const searchUserName = onRequest(
{ region: "europe-west3" },
searchEngineUserName.onRequestWrapped({
distanceThreshold: 0.155 ,
limit: 10 ,
})
);
onCall wrapped
import { FirestoreSearchEngine } from "firestore-search-engine";
const authCallback = (auth: CallableRequest["auth"]) => {
if (auth && auth.uid) return true;
return false;
};
export const onCallSearchWrapped = onCall(
{ region: "europe-west3" },
searchEngineUserName.onCallWrapped(authCallback, {
distanceThreshold: 0.155 ,
limit: 10 ,
})
);
httpsCallable(searchUserName)({ searchValue: inputValue });
Automatic Indexing from Firestore Triggers
The package provide 3 functions to index your document automatically when you create / update / delete it, you can use it like this
onWrite wrapper
export const firestoreWriter = searchEngineUserName.onDocumentWriteWrapper(
onDocumentCreated,
{ indexedKey: "test", returnedKey: ["other", "setAt"] },
"test/{testId}",
{ wordMaxLength: 25 },
{ region: "europe-west3" }
);
onUpdate wrapper
export const firestoreUpdated = searchEngineUserName.onDocumentUpdateWrapper(
onDocumentUpdated,
{ indexedKey: "test", returnedKey: ["other", "setAt"] },
"test/{testId}",
{ wordMinLength: 3 },
{ region: "europe-west3" }
);
onDelete wraper
export const firestoreDeleted = searchEngineUserName.onDocumentDeletedWrapper(
onDocumentDeleted,
"test/{testId}",
{ region: "europe-west3" }
);
Why Firestore Search Engine ?
Firestore is a powerful, serverless solution provided by Google Cloud Platform for your data storage needs. Yet it does not come with a full-text search feature. Firestore Search Engine package gives you the ability to provide your application with a powerful search feature without significant coding effort. With its easy configuration and extensive documentation, the Firestore Search Engine package is a great choice for empowering your Firestore-based applications with full-text search capabilities.
Please read our documentation carefully to understand how to best utilise Firestore Search Engine in your project and feel free to raise any issues or feature requests.
Next Steps
- Fix types for cjs types
- Add support of GPU (cuda)
- Add metrics in stress test in GCP
- Rewrite handler in Go and start build-in Firestore extenssion from fields configurations
- Use onnxruntime directly without dependency (fastembeded)