user_app_id=self._userDataObject,
            searches=[
                resources_pb2.Search(
                    query=resources_pb2.Query(
                        ranks=[
                            resources_pb2.Rank(
                                annotation=resources_pb2.Annotation(
                                    data=resources_pb2.Data(
                                        text=resources_pb2.Text(raw=query),
                                    )
                                )
                            )
                        ]
                    )
                )
            ],
            pagination=service_pb2.Pagination(page=1, per_page=k),
        )
        # Add filter by metadata if provided.
        if filter is not None:
            search_metadata = Struct()
            search_metadata.update(filter)
            f = req.searches[0].query.filters.add()
            f.annotation.data.metadata.update(search_metadata)
        post_annotations_searches_response = self._stub.PostAnnotationsSearches(req)
        # Check if search was successful
        if post_annotations_searches_response.status.code != status_code_pb2.SUCCESS:
            raise Exception(
                "Post searches failed, status: "
                + post_annotations_searches_response.status.description
            )
        # Retrieve hits
        hits = post_annotations_searches_response.hits
        executor = ThreadPoolExecutor(max_workers=10)
        def hit_to_document(hit: resources_pb2.Hit) -> Tuple[Document, float]:
            metadata = json_format.MessageToDict(hit.input.data.metadata)
            h = {"Authorization": f"Key {self._auth.pat}"}
            request = requests.get(hit.input.data.text.url, headers=h)
            # override encoding by real educated guess as provided by chardet
            request.encoding = request.apparent_encoding
            requested_text = request.text
            logger.debug(
                f"\tScore {hit.score:.2f} for annotation: {hit.annotation.id}\