I am trying to perform a vector search on a collection and map the results into a custom object that contains only some of the properties in the collection along with the vector score. I have managed to do this with the below code but it feels untidy and I am wondering if this can all be done as a projection. It also doesn't allow me to map properties from the collection class into the custom object unless their names match.
Here is my example:
I have a collection for my Accommodation class which contains the vector. I need to do a vector search and then map the results into a list of AccommodationRecommendation.
The classes:
class Accommodation
{
Guid Id { get; set; }
string Name { get; set; }
string Description { get; set; }
string double[] { get; set; }
List<AccommodationImage> AccommodationImages { get; set; }
}
class AccommodationImage
{
string Url{ get; set; }
}
class AccommodationRecommendation
{
HotelSlim Hotel { get; set; }
double Score { get; set; }
}
class AccommodationLite
{
Guid Id { get; set; }
string Name { get; set; }
string ImagerUrl { get; set; }
}
This is my work so far. Note how i have to retrieve all of the images and then filter down to just one.
private async Task<List<AccommodationRecommendation>> VectorSearchInternal(
System.Linq.Expressions.Expression<Func<Accommodation, object?>> field,
double[] baseVector,
int count,
string indexName)
{
var output = new List<AccommodationRecommendation>();
var options = new VectorSearchOptions<Accommodation>()
{
IndexName = indexName,
NumberOfCandidates = 10000
};
var projectionDefinition = Builders<Accommodation>.Projection
.Include(a => a.Id)
.Include(a => a.Name)
.Include(a => a.AccommodationImages)
.Meta("score", "vectorSearchScore");
var results = await Collection.Aggregate()
.VectorSearch(field, baseVector, count + 1, options)
.Project(projectionDefinition)
.ToListAsync<BsonDocument>();
foreach (var result in results)
{
var accom = BsonSerializer.Deserialize<AccommodationLite>(result);
var images = result["AccommodationImages"].AsBsonArray;
if (images != null && images.Any())
{
var image = BsonSerializer.Deserialize<Image>(images[0].AsBsonDocument);
accom.ImageUrl = image.Url;
}
output.Add(new AccommodationRecommendation
{
RecommendedAccommodation = accom,
Score = result["score"].AsDouble * 100
});
}
return output;
}