Based on this article from Ayende i have created the following index definition
public class ProductsSearch : AbstractIndexCreationTask<Product, ProductsSearch.Result>
{
public class Result
{
public string Query { get; set; }
}
public ProductsSearch()
{
Map = products => from product in products
select new
{
Query = new object[]
{
product.Title,
product.Tags.Select(tag => tag.Name),
product.Tags.SelectMany(tag => tag.Aliases, (tag, alias) => alias.Name)
}
};
Index(x => x.Query, FieldIndexing.Analyzed);
}
}
One difference is that i must use a SelectMany statement to get the aliases of a tag.
A tag can have many aliases (i. e. tag: mouse alias:pointing device)
I have no idea why the SelectMany line breaks the index. If i remove it, the index works.
This should work:
Map = products => from product in products
from tag in product.Tags
from alias in tag.Aliases
select new
{
Query = new object[]
{
product.Title,
tag.Name,
alias.Name
}
};
Related
I have a table named SerialNumbers containing some columns in it.
I want to get the data with SNum based on scanned value which has been listed in an Array.
Below is my code:
public class SNController : ApiController
{
[HttpGet]
public HttpResponseMessage AllSN()
{
using (SNDBContext dbContext = new SNDBContext())
{
string[] SNum = { "01070A2", "01070A3", "01070A4" };
var SerialNum = dbContext.SNumbers.Where(x => x.SN == "01070A2")
.Select(p => new { p.Name, p.Status})
.ToList();
return Request.CreateResponse(HttpStatusCode.OK, SerialNum );
}
}
When I try to hardcoded this part var SerialNum = dbContext.SNumbers.Where(x => x.SN == "01070A2"), its working.
How can I solve this issue?
Use Contains method in Where clause.
var SerialNum = dbContext.SNumbers.Where(x => SNum.Contains(x.SN))
.Select(p => new { p.Name, p.Status})
.ToList();
My application has a requirement that is should be able to filter/search for Pairs by the Number of the related Contact.
A Pair always has a reference to a Contact stored, but the number of the contact is not, and will not, be stored in the reference. So I tried to create a custom index for this, because the Pair and Contact are stored in different collections.
A simplified example of the index looks like this.
public class Pairs_Search : AbstractMultiMapIndexCreationTask<Pairs_Search.Result>
{
public class Result
{
public string Id { get; set; }
public string Workspace { get; set; }
public ContactResult Contact { get; set; }
public bool HasContactDetails { get; set; }
}
public class ContactResult
{
public string Id { get; set; }
public string Name { get; set; }
public int Number { get; set; }
}
public Pairs_Search()
{
AddMap<Pair>(pairs => pairs
.Select(p => new
{
p.Id,
p.Workspace,
Contact = new
{
p.Contact.Id,
p.Contact.Name,
Number = 0
},
// Mark this items as WITHOUT contact details.
HasContactDetails = false,
}
)
);
AddMap<Contact>(contacts => contacts
.Select(c => new
{
Id = (string) null,
Workspace = (string) null,
Contact = new
{
c.Id,
Name = c.DisplayName,
c.Number
},
// Mark this items as WITH contact details.
HasContactDetails = true,
}
)
);
Reduce = results => results
// First group by the contact ID. This will
// create a group with 2 or more items. One with the contact
// details, and one or more with pair details.
// They are all marked by a boolean flag 'HasContactDetails'.
.GroupBy(x => x.Contact.Id)
// We are going to enrich each item in the current group, that is
// marked as 'HasContactDetails = false', with the contact number.
// We need that so that we can filter on it later.
.Select(group =>
group
.Select(i => new
{
i.Id,
i.Workspace,
Contact = new
{
i.Contact.Id,
i.Contact.Name,
// Does the current item have the contact details?
Number = i.HasContactDetails
// Yes, in this case we use the previously set contact number.
? i.Contact.Number
// No, find the item with the contact details and grab the number.
: group.Single(x => x.HasContactDetails).Contact.Number
},
// Pass on the flag that indicates wheter or not
// this item has the contact details. We are going
// to need it later.
i.HasContactDetails
}
)
// We don't need the items with the contact details
// anymore, so filter them out.
.Where(x => !x.HasContactDetails)
)
// Flatten all the small lists to one big list.
.SelectMany(x => x);
// Mark the following fields of the result as searchable.
Index(x => x.Contact.Number, FieldIndexing.Search);
}
}
I've setup a full example that reproduces the issues I am having. You can find the example here.
Creating the index works fine. Querying the index works fine also as it properly matched the pair and contact and enriched the index result with the number of the contact. But when I try to use a .Where() or .Search() on the nested Number property it fails to properly filter the result dataset from the index.
The index without any filtering works as you can see in below code example (also available in the full example).
private static async Task ThisOneWorks()
{
using (var session = Store.OpenAsyncSession())
{
var results = await session
.Query<Pairs_Search.Result, Pairs_Search>()
.ToListAsync();
LogResults("ThisOneWorks()", results);
}
// Output:
// ThisOneWorks(): Pair 'Harry Potter' with number '70'
// ThisOneWorks(): Pair 'Harry Potter' with number '70'
// ThisOneWorks(): Pair 'Hermione Granger' with number '71'
// ThisOneWorks(): Pair 'Albus Dumbledore' with number '72'
}
Filtering on a non-nested value also works (also available in the full example). As you can see it filters out the one with a different workspace.
private static async Task ThisOneWithWorkspaceFilterWorks()
{
using (var session = Store.OpenAsyncSession())
{
var results = await session
.Query<Pairs_Search.Result, Pairs_Search>()
.Where(x => x.Workspace == "hogwarts")
.ToListAsync();
LogResults("ThisOneWithWorkspaceFilterWorks()", results);
}
// Output:
// ThisOneWithWorkspaceFilterWorks(): Pair 'Harry Potter' with number '70'
// ThisOneWithWorkspaceFilterWorks(): Pair 'Harry Potter' with number '70'
// ThisOneWithWorkspaceFilterWorks(): Pair 'Hermione Granger' with number '71'
}
When I try to filter/search on the Workspace and Number properties I would expect two results that are related to the contact Harry Potter. But instead I just get an empty dataset back.
private static async Task ThisOneWithWorkspaceAndNumberFilterDoesntWork()
{
using (var session = Store.OpenAsyncSession())
{
var results = await session
.Query<Pairs_Search.Result, Pairs_Search>()
.Where(x => x.Workspace == "hogwarts")
.Where(x => x.Contact.Number == 70)
.ToListAsync();
LogResults("ThisOneWithWorkspaceAndNumberFilterDoesntWork()", results);
}
// Output:
// ThisOneWithWorkspaceAndNumberFilterDoesntWork(): EMPTY RESULTS!
}
Can anyone tell me what I am doing wrong here? Any help would be greatly appreciated!
The way to go about it is to store ContactResult in a different collection,
which is what is called a related document in this case,
and when you create the index then you 'Index the Related Document'
Learn from the demo example in:
https://demo.ravendb.net/demos/csharp/related-documents/index-related-documents
The example is for a basic map index but the principle is the same for Multi-Map.
Remove the public class ContactResult from the index class
and define the index with something like:
select new Result
{
....
Number = LoadDocument<Contact>(Pair.Contact).Number
....
}
I want to use MinHash elastic search plugin in NEST Elasticsearch.net.
How can I use minhash plugin in nest?
Create index with following mapping:
elasticClient.CreateIndex(descriptor => descriptor
.Index("my_index")
.Analysis(
analysis => analysis.Analyzers(bases => bases.Add("minhash_analyzer", new CustomAnalyzer
{
Tokenizer = "standard",
Filter = new[] {"minhash"}
})))
.AddMapping<IndexElement>(
mappingDescriptor =>
mappingDescriptor
.Properties(p => p
.String(s => s.Name(element => element.Message).CopyTo("minhashvalue"))
.Custom(new MiniHashMapping()))));
class MiniHashMapping : BinaryMapping
{
[JsonProperty("minhash_analyzer")]
public string Analyzer { get { return "minhash_analyzer"; } }
public MiniHashMapping()
{
Type = "minhash";
Name = "minhashvalue";
}
}
class IndexElement
{
public string Message { get; set; }
}
Index sample document:
elasticClient.Index(new IndexElement
{
Message = "Fess is Java based full text search server provided as OSS product."
}, descriptor => descriptor.Index("my_index"));
Tell elasticsearch to include fields in response:
var searchResponse = elasticClient.Search<IndexElement>(s => s.Query(q => q.MatchAll()).Fields("*"));
You can get hash value from searchResponse.Hits[..].Fields or searchResponse.FieldSelections.
Hope this helps.
When I add the index below to my raven database a simple query like
return Session.Query<R>().FirstOrDefault(x => x.RId == Id);
Always returns null. Only after forcing Raven to remove my custom index does desired functionality return. Why is this?
The Index with side effects:
public class RByLatestCommentIndex : AbstractIndexCreationTask<R>
{
public RByLatestCommentIndex()
{
SetMap();
}
void SetMap()
{
Map = r => r.Select(x => new
{
Id = x.Id,
TimeStamp = x.Comments.Count() > 0 ? x.Comments.Max(u => u.Created)
: x.Created
}).OrderByDescending(y => y.TimeStamp).Select(r => new { Id = r.Id });
}
}
public class RIdTransformer : AbstractTransformerCreationTask<R>
{
public RIdTransformer()
{
TransformResults = ids => ids.Select(x => LoadDocument<R>(x.Id));
}
}
EDIT:
In response to Ayende Rahien's comment:
There's a query in the DB which would otherwise be used (Auto/R/ByRID) but the index used looks like this, puzzling enough:
from doc in docs.Rs select new { Images_Count__ = doc.Images["Count()"], RId = doc.RId }
What explains this behaviour? And, will I have to add a static index to be able to query R by RId ?
So far I have an index like this:
public class Animals_Search : AbstractMultiMapIndexCreationTask<Animals_Search.Result> {
public class Result {
public object[] Content { get; set; }
}
public Animals_Search() {
AddMap<Dog>(a => from b in a select new Result { Content = new object[] { b.Name, b.Breed} });
AddMap<Cat>(a=> from bin docs select new Result { Content = new object[] { b.Name, b.Breed} });
Index(x => x.Content, FieldIndexing.Analyzed);
}
}
And a query like this:
session.Query<Animals_Search.Result, Animals_Search>()
.Search(a => a.Content, match)
.As<Animal>()
.ToList();
This works if I provide search terms like "Collie" or "Terrier", but not "Coll" or "Terr"
How do I rewrite the query to work something like String.Contains("Terr")?
RavenDB make it hard to do contains query, because for the most part, they aren't needed.
What you probably want is to do a StartsWith, instead.
session.Query<Animals_Search.Result, Animals_Search>()
.Where(a => a.Content.StartsWith(match))
.As<Animal>()
.ToList();