Lucene.Net IndexSearcher not working with BooleanQuery - lucene.net

I have the following code snippet:
QueryParser parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_29, new string[] { Field1, Field2, Field3 }, _analyzer);
parser.SetDefaultOperator(QueryParser.Operator.AND);
Query queryOrig= parser.Parse(queryString);
var query = new BooleanQuery();
query.Add(queryOrig, BooleanClause.Occur.MUST);
if (itemId.HasValue)
query.Add(new TermQuery(new Term("Field3", NumericUtils.IntToPrefixCoded(itemId.Value))), BooleanClause.Occur.MUST);
Hits hits;
if (sortField != null)
{
var sort = new Sort(new SortField(sortField, isDescending));
hits = Searcher.Search(query, null, sort);
}
else
hits = Searcher.Search(query);
This piece of code is always returning 0 hits no matter what.
If I do a direct search using the queryOrig without the boolean, it works fine.
I'm quite sure the data is correct.
Thanks,
Leonardo

Well.. It was a data problem! :D
The lucene works just fine.
Thanks,
Leo!

Related

Query without condition in MongoDB + C#

I'm trying to use the collection.FindAndModify and give it a IMongoQuery which selects all the documents. But I can not find how to create a query without any conditions!
Can anyone tell me how to do this? I'm using MongoDB C# Driver v1.8.3.
Here's my code:
var query = ???;
var sortBy = SortBy.Ascending(new string[] { "last_update" });
var update = Update<Entity>.Set(e => e.last_update, DateTime.Now);
var fields = Fields.Include(new string[] { "counter", "_id" });
var m = collection.FindAndModify(query, sortBy, update, fields, false, false);
I wonder what should I write in place of ??? to select all the documents!?
Use an empty QueryDocument:
var query = new QueryDocument();
But keep in mind that FindAndModify will only modify the first matching document.

mongodb query for or operator

As in ravendb Or operation are not available we have a query in ravendb. iwant the expression to be written in mongodb query using Query.Or
var customerIdExpression = string.Format("CustomerId:({0})", string.Join(" OR "item.CustomerId));
I knocked together a test app that is my interpretation of what you are looking for:
var item = new {CustomerId = "123"};
var item2 = new { CustomerId = "123" };
var query1 = new QueryDocument("CustomerId", item.CustomerId);
var query2 = new QueryDocument("CustomerId", item2.CustomerId);
var logicalOrBetweenSubQueries = Query.Or(query1,query2);
If this is what your looking for I can't but think there might be a better way to achieve set membership semantics. Something like this might be useful:
var membership = Query.In("CustomerId", new[] { BsonValue.Create(item.CustomerId), BsonValue.Create(item2.CustomerId)});
All predicated on my understanding of your problem.
Hope this helps
p.s. some links
http://docs.mongodb.org/manual/reference/operator/or/
http://docs.mongodb.org/manual/reference/operator/in/

MongoDB query in C#

I'd like to get certain documents that match a specific clause, but don't know how to achieve that WHERE effect in relational databases. I have a simple database with words and their translations (objects with 2 fields) and use this code
var words = database.GetCollection<Word>("Dictionary")
to get them. But this gets the whole collection. What if there were thousands of records in the collection? How to get just the records I want?
Use regular expressions matching as below. The 'i' shows case insensitivity.
var collections = mongoDatabase.GetCollection("Abcd");
var queryA = Query.And(
Query.Matches("strName", new BsonRegularExpression("ABCD", "i")),
Query.Matches("strVal", new BsonRegularExpression("4121", "i")));
var queryB = Query.Or(
Query.Matches("strName", new BsonRegularExpression("ABCD","i")),
Query.Matches("strVal", new BsonRegularExpression("33156", "i")));
var getA = collections.Find(queryA);
var getB = collections.Find(queryB);
For Using 'And' or 'Or' in your query, if you want to search over multiple fields.
This assumes you have a class called Word that is modled like you collection.
MongoServer _server = new MongoClient(connectionString).GetServer();
MongoDatabase _database = _server.GetDatabase(database);
MongoCollection _collection = _database.GetCollection(collection);
var results = _collection.FindAs<Word>(Query.EQ("MyField","WordToFind"));

Lucene.Net BooleanClause issue

I'm having an issue with Lucene.Net and a BooleanQuery. This is my code:
BooleanQuery query = new BooleanQuery();
String[] types = searchTypes.Split(',');
foreach (string t in types)
query.Add(new TermQuery(new Term("document type", t.ToLower())), BooleanClause.Occur.SHOULD);
This should basically be an OR statement going through documents that have a certain type, which works on its own. However, I also have this query:
Query documentTitleQuery = new WildcardQuery(new Term("title", "*" + documentTitle.ToLower() + "*"));
query.Add(documentTitleQuery, BooleanClause.Occur.MUST);
Which searches for words in a title. Both of these queries work find on their own. When they are used together, it seems Lucene is treating the documentTitleQuery as an OR. So both queries together should return documents of a specific type AND contain specific words in the title, but it is returning all types that have specific words in the title.
Use one more layer of Boolean query to group both:
BooleanQuery topQuery = new BooleanQuery();
...
BooleanQuery query1 = new BooleanQuery();
...
BooleanQuery query2 = new BooleanQuery();
...
topQuery.add(query1, BooleanClause.Occur.MUST);
topQuery.add(query2, BooleanClause.Occur.MUST);

Lucene.NET "OR"

How do I do an "OR" in Lucene.NET. Basically what I have is an array of IDs and I want to return any records where a particular field contains any of the values. I previously was doing this with just one value, but now I want to convert the following code so that MetaDataID is an array of possible values instead of one single value.
if (MetaDataID.Length > 0)
completeQuery.Add(new QueryParser("MetaData", new StandardAnalyzer()).Parse(MetaDataID), BooleanClause.Occur.MUST);
When combining Lucene queries where you want any index record that contains any one of multiple possible values with additional criteria that must also be met, create multiple boolean query objects.
For the first group of "OR" conditions:
BooleanQuery booleanQueryInner = new BooleanQuery();
Query query1 = new TermQuery(new Term("id", "<id 1>"));
Query query2 = new TermQuery(new Term("id", "<id 2>"));
Query query3 = new TermQuery(new Term("id", "<id 3>"));
Query query4 = new TermQuery(new Term("id", "<id 4>"));
booleanQueryInner.add(query1, BooleanClause.Occur.SHOULD);
booleanQueryInner.add(query2, BooleanClause.Occur.SHOULD);
booleanQueryInner.add(query3, BooleanClause.Occur.SHOULD);
booleanQueryInner.add(query4, BooleanClause.Occur.SHOULD);
Now combine with other conditions in query
BooleanQuery booleanQueryOuter = new BooleanQuery();
booleanQueryOuter.add(booleanQueryInner, BooleanClause.Occur.MUST);
booleanQueryOuter.add(boolenaQueryOtherConditions, BooleanClause.Occur.MUST);
Now index records will only be returned if they meet one of the conditions in the inner "OR" group and also meet the conditions in the "other conditions" query.
You need to use BooleanClause.Occur.SHOULD instead of BooleanClause.Occur.MUST
e.g.:
BooleanQuery booleanQuery = new BooleanQuery();
Query query1 = new TermQuery(new Term("id", "<id 1>"));
Query query2 = new TermQuery(new Term("id", "<id 2>"));
booleanQuery.add(query1, BooleanClause.Occur.SHOULD);
booleanQuery.add(query2, BooleanClause.Occur.SHOULD);
When you really want to parse your query, you just need to choose the correct Analyzer and format for your query.
The StandardAnalyzer is not a good choice when you are indexing anything but english full text, especially not in your case! It filters out numbers!
The shortest solution in you case is to create an analyzer that tokenizes at a separator and combine your object into a string.
Example:
Create a Tokenizer that splits at typical seperators and an Analyzer that uses it
using System.IO;
using System.Linq;
using Lucene.Net.Analysis;
namespace Project.Analysis
{
public class TermTokenizer : LetterTokenizer
{
// some static separators
private static readonly char[] NONTOKEN_CHARS = new char[] { ',', ';', ' ', '\n', '\t' };
protected override bool IsTokenChar(char c)
{
return !NONTOKEN_CHARS .Contains(c);
}
}
public class LowerCaseTermAnalyzer : Analyzer
{
public override TokenStream TokenStream(string fieldName, TextReader reader)
{
return new LowerCaseFilter(new TermTokenizer(reader));
}
}
}
Use the new analyzer in your parser
(You need to include System.Linq)
if (MetaDataID.Length > 0)
{
// the search term will look like this: "1;5;7"
string searchTerm = string.Join(";", MetaDataID);
// the query parser uses the new Analyzer
QueryParser parser = new QueryParser("MetaData",new LowerCaseTermAnalyzer());
// the parsed search term (only used internally) will look like this:
// "MetaData:1 MetaData:5 MetaData:7", which is essentially what you want to achieve
completeQuery.Add(new parser.Parse(MetaDataID), BooleanClause.Occur.MUST);
}
Be careful when using BooleanQuery for retrieving documents by id, because it has a limit of maximum boolean clauses.
The basic "OR" clause in Lucene is performed like this, assuming that your searchable field is named "id":
"id:1 id:2 id:3 id:4"
Instead of an "AND" query:
"+id:1 +id:2 +id:3 + id:4"
Using the standard QueryParser and a StringBuilder should do the magic for you.