Below is the code I'm using to build the query. The query works with only town criteria. As soon as Style criteria is added, the search returns no results (see the comment "styles" below).
Code:
FullTextSession fullTextSession = Factory.getFullTextSession();
BooleanQuery query = new BooleanQuery();
// bathrooms
query.add(new RangeQuery(new Term("bathrooms", Utility.zeroPad(searchCriteria.getBathrooms(), 2)), new Term("bathrooms", "999"), true), Occur.MUST);
// bedrooms
query.add(new RangeQuery(new Term("bedrooms", Utility.zeroPad(searchCriteria.getBedrooms(), 2)), new Term("bedrooms", "999"), true), Occur.MUST);
// price
if (searchCriteria.getMinPrice() > 0 || searchCriteria.getMaxPrice() > 0)
query.add(new RangeQuery(new Term("listPrice", Utility.zeroPad(searchCriteria.getMinPrice(), 9)), new Term("listPrice", Utility.zeroPad(searchCriteria.getMaxPrice() > 0 ? searchCriteria.getMaxPrice() : 999999999, 9)), true), Occur.MUST);
// map search
if (searchCriteria.getArea() != null) {
LatLngBridge converter = new LatLngBridge();
BooleanQuery subQuery = new BooleanQuery();
subQuery.add(new RangeQuery(new Term("latitude", converter.objectToString(searchCriteria.getArea().getSouthWest().getLatitude())), new Term("latitude", converter.objectToString(searchCriteria.getArea().getNorthEast().getLatitude())), true), Occur.MUST);
subQuery.add(new RangeQuery(new Term("longitude", converter.objectToString(searchCriteria.getArea().getSouthWest().getLongitude())), new Term("longitude", converter.objectToString(searchCriteria.getArea().getNorthEast().getLongitude())), true), Occur.MUST);
query.add(subQuery, Occur.MUST);
// towns and regions
} else if (searchCriteria.getTowns().size() > 0) {
BooleanQuery subQuery = new BooleanQuery();
for (Town town : searchCriteria.getTowns()) {
BooleanQuery townQuery = new BooleanQuery();
townQuery.add(new TermQuery(new Term("town.name", town.getName().toLowerCase())), Occur.MUST);
townQuery.add(new TermQuery(new Term("town.state", town.getState().toLowerCase())), Occur.MUST);
subQuery.add(townQuery, Occur.SHOULD);
}
query.add(subQuery, Occur.MUST);
}
// zip code
if (!Utility.isEmpty(searchCriteria.getZipCode()))
query.add(new TermQuery(new Term("zipCode", searchCriteria.getZipCode())), Occur.MUST);
// styles
if (searchCriteria.getStyles().size() > 0) {
BooleanQuery subQuery = new BooleanQuery();
for (Style style : searchCriteria.getStyles()) {
subQuery.add(new TermQuery(new Term("style.name", "\"" + style.getName().toLowerCase() + "\"")), Occur.SHOULD);
}
query.add(subQuery, Occur.MUST);
}
// type
if (searchCriteria.getTypes().size() > 0) {
BooleanQuery subQuery = new BooleanQuery();
for (ListingType type : searchCriteria.getTypes()) {
subQuery.add(new TermQuery(new Term("type", type.name().toLowerCase())), Occur.SHOULD);
}
query.add(subQuery, Occur.MUST);
}
// garage
if (searchCriteria.getHasGarage())
query.add(new TermQuery(new Term("hasGarage", "true")), Occur.MUST);
// basement
if (searchCriteria.getHasBasement())
query.add(new TermQuery(new Term("hasBasement", "true")), Occur.MUST);
// description
if (!Utility.isEmpty(searchCriteria.getDescription())) {
try {
query.add(MultiFieldQueryParser.parse(new String [] { searchCriteria.getDescription(), searchCriteria.getDescription() }, new String [] { "description", "features.values.value" }, new StandardAnalyzer()), Occur.MUST);
} catch (ParseException ex) {
ApplicationLog.warning("Error parsing description: " + searchCriteria.getDescription());
}
}
// features
if (searchCriteria.getFeatures().size() > 0) {
BooleanQuery subQuery = new BooleanQuery();
for (FeatureValue feature : searchCriteria.getFeatures()) {
subQuery.add(new TermQuery(new Term("featureValueId", Integer.toString(feature.getId()))), Occur.MUST);
}
query.add(subQuery, Occur.MUST);
}
// status
query.add(new TermQuery(new Term("status", ListingStatus.Withdrawn.name())), Occur.MUST_NOT);
FullTextQuery searchQuery = fullTextSession.createFullTextQuery(query, Listing.class);
// set up the transformer
searchQuery.setResultTransformer(new ListingTransformer());
// set projection, this will allow all listing info on search pages to be pulled from lucene
// this means no database hit is necessary!
searchQuery.setProjection("basement", "garage", "latitude", "longitude", "mlsNumber", "town.state", "town.name", "streetName", "streetNumber", "style.name", "type", "yearBuilt", "features.values.featureValueID", "description", "photoCount", "listPrice", "bedrooms", "bathrooms");
return searchQuery;