Lucene's 1024 term limit per query is there to protect you from incorrect use. You shouldn't be trying to bypass it.
public class FavoriteProduct
{
public Guid ProductId { get; set; }
public string ProductName { get; set; }
public int[] UserIds { get; set; }
}
public class Products_ByUserFavorites : AbstractIndexCreationTask<FavoriteProduct>
{
public Products_ByUserFavorites()
{
Map = favs => from product in favs
from userId in product.UserIds
select new { product.ProductId, product.ProductName, userId};
}
}
The idea is having an index with fields for the product name and the user id. You query it with the user id first and then the full-text parameter for the product id, to get a performing query. You can use TransformResults/Includes too to get the actual product entity. Updates to product names will have to be performed twice - on products and on FavoriteProduct.
The only real con of this approach is the cost of saving a new favorite or deleting one, which depends on the amount of users you have. Perhaps a patch operation is going to be useful for doing that. The factor to consider is how common such operations are expected to be.
There's probably even a better way of doing that using a similar logic.