'Elasticsearch boolquery equivalent in lucene Java
Previously, we were using Elasticsearch and the search operations were working fine as expected. We are trying to move to Lucene from Elasticsearch due to some reasons. I'm trying to implement the same using Lucene (9.0.0), but my search operations are not working as expected.
I have to perform search with multiple filters. For example, below search operations
- General keyword based search (HTTP GET method)
- Filter by categories, filter by categories along with keyword (AND operation) (HTTP POST method)
- Filter by models/catalogs, filter by models/catalogs along with keyword (AND operation) (HTTP POST method)
- Above 2 and 3 combined. (HTTP POST method)
The main part I need equivalent in Lucene is below. The following snippet is with Spring Data Elasticsearch. Here oTypes and cIds are of List<Integer> types.
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes))
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds));
QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes))
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds))
.must(QueryBuilders.wildcardQuery(O_NAME_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_PHYSICAL_NAME_ELASTICSEARCH, "*" + keyword + "*"));
My approach of doing the same in Lucene is below (doesn't give proper results).
BooleanQuery.Builder queryBuilder = new BooleanQuery.Builder();
for (Integer oType : oTypes) {
queryBuilder.add(new TermQuery(new Term("oType", String.valueOf(oType))), BooleanClause.Occur.SHOULD);
}
for (Integer cId : cIds) {
queryBuilder.add(new TermQuery(new Term("cId", String.valueOf(cId))), BooleanClause.Occur.SHOULD);
}
queryBuilder.add(new WildcardQuery(new Term("oName", "*" + keyword + "*")),
BooleanClause.Occur.SHOULD);
queryBuilder.add(new WildcardQuery(new Term("oPhysicalName", "*" + keyword + "*")),
BooleanClause.Occur.SHOULD);
e.g. When I select Tables and Views filters in categories and some model/catalog in Model filters, I expect tables and views in that model as my results, but it gives all the results in that model. The results are still the same even when I add keyword along with these filters. I'm not able to understand how should I add filters for multiple values for single field.
a: In case of empty keyword and some filters
Elasticsearch (Spring Data Elasticsearch): Here oTypes and cIds are categories and catalogs filters.
private BoolQueryBuilder getBoolQueryBuilderForEmptyKeyword(List<Integer> oTypes, List<Integer> cIds) {
BoolQueryBuilder boolQueryBuilder;
if (!oTypes.isEmpty() && !cIds.isEmpty()) {
boolQueryBuilder = QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes))
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds));
} else {
if (!cIds.isEmpty()) {
boolQueryBuilder = QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds));
} else {
boolQueryBuilder = QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes));
}
}
return boolQueryBuilder;
}
Trying to do same in Lucene (but not giving correct results):
private BooleanQuery.Builder getBuilderForEmptyKeyword(List<Integer> oTypes, List<Integer> cIds) {
BooleanQuery.Builder finalQueryBuilder = new BooleanQuery.Builder();
BooleanQuery.Builder queryBuilder = new BooleanQuery.Builder();
if (!oTypes.isEmpty() && !cIds.isEmpty()) {
getBuilderForTypesAndCIds(oTypes, cIds, queryBuilder);
} else {
if (!cIds.isEmpty()) {
for (Integer cId : cIds) {
queryBuilder.add(new TermQuery(new Term("cId", String.valueOf(cId))), BooleanClause.Occur.SHOULD);
}
} else {
for (Integer oType : oTypes) {
queryBuilder.add(new TermQuery(new Term("oType", String.valueOf(oType))), BooleanClause.Occur.SHOULD);
}
}
}
finalQueryBuilder.add(queryBuilder.build(), BooleanClause.Occur.MUST);
return finalQueryBuilder;
}
private void getBuilderForTypesAndCIds(List<Integer> oTypes, List<Integer> cIds, BooleanQuery.Builder queryBuilder) {
for (Integer oType : oTypes) {
queryBuilder.add(new TermQuery(new Term("oType", String.valueOf(oType))), BooleanClause.Occur.SHOULD);
}
for (Integer cId : cIds) {
queryBuilder.add(new TermQuery(new Term("cId", String.valueOf(cId))), BooleanClause.Occur.SHOULD);
}
}
b: Non empty keyword along with categories and model filters
private BoolQueryBuilder getBoolQueryBuilderForKeywordModelTypes(String keyword, List<Integer> oTypes,
List<Integer> cIds, List<String> searchFields,
short searchFieldsSize, String[] fieldNames) {
BoolQueryBuilder boolQueryBuilder;
// get search results using object types/catalog ids and apply filter with keyword
// in that list along with fieldNames
if (keyword.length() == 3) {
if (searchFieldsSize == 2 && containsValue(searchFields, O_NAME_ELASTICSEARCH) &&
containsValue(searchFields, O_PHYSICAL_NAME_ELASTICSEARCH)) {
boolQueryBuilder = getBoolAllNamesWildcardQueryBuilder(keyword, oTypes, cIds);
} else if (searchFieldsSize == 1 && containsValue(searchFields, O_NAME_ELASTICSEARCH)) {
boolQueryBuilder = getBoolNameWildcardQueryBuilder(keyword, oTypes, cIds, O_NAME_ELASTICSEARCH);
} else if (searchFieldsSize == 1 && containsValue(searchFields, O_NAME_ELASTICSEARCH)) {
boolQueryBuilder = getBoolNameWildcardQueryBuilder(keyword, oTypes, cIds,
O_PHYSICAL_NAME_ELASTICSEARCH);
} else if (searchFieldsSize == 4) {
boolQueryBuilder = getBoolAllFieldsWildcardQueryBuilder(keyword, oTypes, cIds);
} else {
boolQueryBuilder = getBoolAllNamesWildcardQueryBuilder(keyword, oTypes, cIds);
}
} else {
if (searchFieldsSize == 0) {
boolQueryBuilder = getBoolAllNamesWildcardQueryBuilder(keyword, oTypes, cIds);
} else {
boolQueryBuilder = QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes))
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds))
.filter(QueryBuilders.multiMatchQuery(keyword, fieldNames).fuzziness(Fuzziness.AUTO));
}
}
return boolQueryBuilder;
}
private QueryBuilder getNameQueryBuilder(String keyword, String fieldName) {
return QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery(fieldName, "*" + keyword + "*"));
}
private QueryBuilder getAllNamesQueryBuilder(String keyword) {
return QueryBuilders.boolQuery()
.must(QueryBuilders.wildcardQuery(O_NAME_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_PHYSICAL_NAME_ELASTICSEARCH, "*" + keyword + "*"));
}
private QueryBuilder getAllFieldsQueryBuilder(String keyword) {
return QueryBuilders.boolQuery()
.must(QueryBuilders.wildcardQuery(O_NAME_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_PHYSICAL_NAME_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_DEFINITION_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_COMMENT_ELASTICSEARCH, "*" + keyword + "*"));
}
private BoolQueryBuilder getBoolNameWildcardQueryBuilder(String keyword, List<Integer> oTypes, List<Integer> cIds,
String fieldName) {
return QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes))
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds))
.must(QueryBuilders.wildcardQuery(fieldName, "*" + keyword + "*"));
}
private BoolQueryBuilder getBoolAllNamesWildcardQueryBuilder(String keyword, List<Integer> oTypes,
List<Integer> cIds) {
return QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes))
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds))
.must(QueryBuilders.wildcardQuery(O_NAME_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_PHYSICAL_NAME_ELASTICSEARCH, "*" + keyword + "*"));
}
private BoolQueryBuilder getBoolAllFieldsWildcardQueryBuilder(String keyword, List<Integer> oTypes,
List<Integer> cIds) {
return QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery(O_TYPE_ELASTICSEARCH, oTypes))
.filter(QueryBuilders.termsQuery(C_ID_ELASTICSEARCH, cIds))
.must(QueryBuilders.wildcardQuery(O_NAME_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_PHYSICAL_NAME_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_DEFINITION_ELASTICSEARCH, "*" + keyword + "*"))
.must(QueryBuilders.wildcardQuery(O_COMMENT_ELASTICSEARCH, "*" + keyword + "*"));
}
Can you please guide me how to perform filters with multiple values for single field?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
