I read How to incorporate multiple fields in QueryParser? but i didn't get it.
At the moment i have a very strange construction like:
parser = New QueryParser("bodytext", analyzer)
parser2 = New QueryParser("title", analyzer)
query = parser.Parse(strSuchbegriff)
query2 = parser.Parse(strSuchbegriff)
What can i do for something like:
parser = New QuerParser ("bodytext" , "title",analyzer)
query =parser.Parse(strSuchbegriff)
so the Parser looks for the searching word in the field "bodytext" an in the field "title".
There are 3 ways to do this.
The first way is to construct a query manually, this is what QueryParser is doing internally. This is the most powerful way to do it, and means that you don't have to parse the user input if you want to prevent access to some of the more exotic features of QueryParser:
IndexReader reader = IndexReader.Open("<lucene dir>");
Searcher searcher = new IndexSearcher(reader);
BooleanQuery booleanQuery = new BooleanQuery();
Query query1 = new TermQuery(new Term("bodytext", "<text>"));
Query query2 = new TermQuery(new Term("title", "<text>"));
booleanQuery.add(query1, BooleanClause.Occur.SHOULD);
booleanQuery.add(query2, BooleanClause.Occur.SHOULD);
// Use BooleanClause.Occur.MUST instead of BooleanClause.Occur.SHOULD
// for AND queries
Hits hits = searcher.Search(booleanQuery);
The second way is to use MultiFieldQueryParser, this behaves like QueryParser, allowing access to all the power that it has, except that it will search over multiple fields.
IndexReader reader = IndexReader.Open("<lucene dir>");
Searcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer();
MultiFieldQueryParser queryParser = new MultiFieldQueryParser(
new string[] {"bodytext", "title"},
analyzer);
Hits hits = searcher.Search(queryParser.parse("<text>"));
The final way is to use the special syntax of QueryParser see here.
IndexReader reader = IndexReader.Open("<lucene dir>");
Searcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer();
QueryParser queryParser = new QueryParser("<default field>", analyzer);
// <default field> is the field that QueryParser will search if you don't
// prefix it with a field.
string special = "bodytext:" + text + " OR title:" + text;
Hits hits = searcher.Search(queryParser.parse(special));
Your other option is to create new field when you index your content called bodytextandtitle, into which you can place the contents of both bodytext and title, then you only have to search one field.
We can not use
BooleanQuery booleanQuery = new BooleanQuery();
We have to use builder
BooleanQuery.Builder finalQuery = new BooleanQuery.Builder();
then we can use finalQuery.build(); to get query
more generic way to do this is
private static TopDocs search(Map filters, IndexSearcher searcher) throws Exception {
StandardAnalyzer analyzer = new StandardAnalyzer();
BooleanQuery.Builder finalQuery = new BooleanQuery.Builder();
for(String attribute : filters.keySet()) {
QueryParser queryParser = new QueryParser(attribute, analyzer);
Query query = queryParser.parse(filters.get(attribute));
finalQuery.add(query, Occur.MUST);
}
TopDocs hits = searcher.search(finalQuery.build(),10);
return hits;
}
Related
I want to search through all fields in the index by lucene, and I learned to do this by writting the code like this:
//Create a parser that searches through all fields
QueryParser queryParser = new QueryParser("*", new StandardAnalyzer());
//Specify the search terms
String queryString = "search terms";
//Create the query to search through all fields
Query query = queryParser.parse(queryString);
//Execute the query and get the results
IndexSearcher searcher = new IndexSearcher(indexReader);
TopDocs results = searcher.search(query, 100);
ScoreDoc[] hits = results.scoreDocs;
//Iterate through the results
for (ScoreDoc hit : hits) {
Document doc = searcher.doc(hit.doc);
//Process the document
}
when I setted first parameter of QueryParser Constructor to "*", like the code above, and I got nothing from the TopDocs(which I had expected to search through all fields of the documents I'd write into the index and returnd all matching documents), the "hits.totalHits" returns 0.
Can anyone tell me what is wrong with my code or how to write code using QueryParser to search through all fields in the index?
Thanks!
I am using Lucene 8.2.0 in Java 11.
I am trying to index a Long value so that I can filter by it using a range query, for example like so: +my_range_field:[1 TO 200]. However, any variant of that, even my_range_field:[* TO *], returns 0 results in this minimal example. As soon as I remove the + from it to make it an OR, I get 2 results.
So I am thinking I must make a mistake in how I index it, but I can't make out what it might be.
From the LongPoint JavaDoc:
An indexed long field for fast range filters. If you also need to store the value, you should add a separate StoredField instance.
Finding all documents within an N-dimensional shape or range at search time is efficient. Multiple values for the same field in one document is allowed.
This is my minimal example:
public static void main(String[] args) {
Directory index = new RAMDirectory();
StandardAnalyzer analyzer = new StandardAnalyzer();
try {
IndexWriter indexWriter = new IndexWriter(index, new IndexWriterConfig(analyzer));
Document document1= new Document();
Document document2= new Document();
document1.add(new LongPoint("my_range_field", 10));
document1.add(new StoredField("my_range_field", 10));
document2.add(new LongPoint("my_range_field", 100));
document2.add(new StoredField("my_range_field", 100));
document1.add(new TextField("my_text_field", "test content 1", Field.Store.YES));
document2.add(new TextField("my_text_field", "test content 2", Field.Store.YES));
indexWriter.deleteAll();
indexWriter.commit();
indexWriter.addDocument(document1);
indexWriter.addDocument(document2);
indexWriter.commit();
indexWriter.close();
QueryParser parser = new QueryParser("text", analyzer);
IndexSearcher indexSearcher = new IndexSearcher(DirectoryReader.open(index));
String luceneQuery = "+my_text_field:test* +my_range_field:[1 TO 200]";
Query query = parser.parse(luceneQuery);
System.out.println(indexSearcher.search(query, 10).totalHits.value);
} catch (IOException e) {
} catch (ParseException e) {
}
}
You need to first use StandardQueryParser, then provide the parser with a PointsConfig map, essentially hinting which fields are to be treated as Points. You'll now get 2 results.
// Change this line to the following
StandardQueryParser parser = new StandardQueryParser(analyzer);
IndexSearcher indexSearcher = new IndexSearcher(DirectoryReader.open(dir));
/* Added code */
PointsConfig longConfig = new PointsConfig(new DecimalFormat(), Long.class);
Map<String, PointsConfig> pointsConfigMap = new HashMap<>();
pointsConfigMap.put("my_range_field", longConfig);
parser.setPointsConfigMap(pointsConfigMap);
/* End of added code */
String luceneQuery = "+my_text_field:test* +my_range_field:[1 TO 200]";
// Change the query to the following
Query query = parser.parse(luceneQuery, "text");
I found the solution to my problem.
I was under the impression that the query parser could just parse any query string correctly. That doesn't seem to be the case.
Using
Query rangeQuery = LongPoint.newRangeQuery("my_range_field", 1L, 11L);
Query searchQuery = new WildcardQuery(new Term("my_text_field", "test*"));
Query build = new BooleanQuery.Builder()
.add(searchQuery, BooleanClause.Occur.MUST)
.add(rangeQuery, BooleanClause.Occur.MUST)
.build();
returned the correct result.
I'm trying to use SpanFirstQuery to match beginning of a field in lucene. But it just doesn't seem to work. here's code i'm using.
Map<String, Analyzer> searchAnalyzers = new HashMap<String, Analyzer>();
searchAnalyzers.put(NAME, new KeywordAnalyzer());
searchAnalyzers.put(ORGANIZATION_NAME, new KeywordAnalyzer());
searchAnalyzers.put(ORGANIZATION_POSITION, new KeywordAnalyzer());
PerFieldAnalyzerWrapper perFieldAnalyzerWrapper = new PerFieldAnalyzerWrapper(new KeywordAnalyzer(), searchAnalyzers);
MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_40, mSearchFields, perFieldAnalyzerWrapper); //mSearchFiels is array of fiels
multiFieldQueryParser.setDefaultOperator(QueryParser.Operator.AND);
Query query = (Utils.isEmpty(queryString)) ? new MatchAllDocsQuery() : multiFieldQueryParser.parse(QueryParser.escape(queryString)); //queryString is text to be searched
Term term = new Term(NAME, queryString);
SpanFirstQuery spanFirstQuery = new SpanFirstQuery(new SpanTermQuery(term), 5);
spanFirstQuery.setBoost(5.0f);
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.add(spanFirstQuery, BooleanClause.Occur.SHOULD);
booleanQuery.add(query, BooleanClause.Occur.MUST);
indexSearcher.search(booleanQuery, 100);
it returns results when only single character is passed in queryString. but doesn't work when i pass string. always totalHits count is 0.
I am using Version.Lucene_29. Using the normal string query method i could do the following:
Directory directory = new FSDirectory(...);
//Start Lucene retrieval.
IndexSearcher iSearch = new IndexSearcher(directory, true);
Analyzer analyzer = new WhitespaceAnalyzer();
QueryParser parser = new QueryParser(Version.LUCENE_29, "content", analyzer);
String str = 'filename:testfile.txt AND filetext:"Singapore food"'
Query query = parser.parse(str);
ScoreDoc[] hits = iSearch.search(query, 1000).scoreDocs;
How do i fire a query using MultiFieldQueryParser in Lucene similar to the string query method?
MultiFieldQueryParser multiParser = new MultiFieldQueryParser(
Version.LUCENE_29, new String[] {"content", "ne"}, analyzer);
str = ???
Query = ????
ScoreDoc[] hits = iSearch.search(query, 1000).scoreDocs;
MultiFieldQueryParser allows you to search for a "WORD" in more then one Fileds with same Analyzer.
e.g.
Query query = MultiFieldQueryParser.parse("development",
new String[]{"title", "subject"},
new SimpleAnalyzer());
it will look for word development in Field : "title" and Field : "subject"
MultiFieldQueryParser is-a QueryParser, MultiFieldQueryParser creates the two Queries into a BooleanClause in this case. So it also supports filename:testfile.txt AND filetext:"Singapore food".
Some of my indexed fields use a Greek analyzer and I want to use an English analyzer for some other fields. My problem is: When searching for results (with a MultiFieldQueryParser currently), how can I use a different analyzer per field, so that a Greek analyzer is used for Greek-indexed fields and an English analyzer is used for English-indexed fields?
Here is the solution I found. Please comment.
transaction.begin();
PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(new StandardAnalyzer(Version.LUCENE_30));
wrapper.addAnalyzer("greekTitle", new GreekAnalyzer(Version.LUCENE_30));
wrapper.addAnalyzer("greekDescription", new GreekAnalyzer(Version.LUCENE_30));
String[] fields = {"greekTitle", "greekDescription", "englishTitle", "englishDescription"};
QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_30, fields, wrapper);
queryParser.setDefaultOperator(QueryParser.AND_OPERATOR);
org.apache.lucene.search.Query query = queryParser.parse(QueryParser.escape(queryString));
javax.persistence.Query persistenceQuery =
fullTextEntityManager.createFullTextQuery(query, Item.class);
#SuppressWarnings("unchecked")
List<Item> result = persistenceQuery.getResultList();
transaction.commit();
return result;
You could build your query parser like this:
Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer(Item.class);
QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_31, fields, analyzer);
which would use the proper analyzer, as defined in the annotations of your Item class:
#Field(name = "greekTitle" analyzer = #Analyzer(impl = GreekAnalyzer.class))
public void getGreekTitle(){
//...
}
#Field(name = "englishTitle" analyzer = #Analyzer(impl = StandardAnalyzer.class))
public void getEnglishTitle(){
//...
}