Skip to content
This repository was archived by the owner on Aug 22, 2025. It is now read-only.

Commit e92acf9

Browse files
author
Eduardo Alonso
authored
Added 'maxClauses' to boolean search (#338)
1 parent fd5ca1c commit e92acf9

File tree

8 files changed

+164
-13
lines changed

8 files changed

+164
-13
lines changed

CHANGELOG.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# Changelog
22

3-
## 3.0.14.0 (July 03, 2017)
3+
## 3.0.14.1 (upcoming)
44

5-
* Upgrade to Apache Cassandra 3.0.14
5+
* Add 'max_clauses' to boolean query
66

7-
## 3.0.13.1 (upcoming)
7+
## 3.0.14.0 (June 27, 2017)
88

9-
*Upgrade to Apache Lucene 5.5.4
9+
* Upgrade to Apache Lucene 5.5.4
10+
* Upgrade to Apache Cassandra 3.0.14
1011

1112
## 3.0.13.0 (April 17, 2017)
1213

builder/src/main/java/com/stratio/cassandra/lucene/builder/search/condition/BooleanCondition.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ public class BooleanCondition extends Condition<BooleanCondition> {
3939
@JsonProperty("not")
4040
private List<Condition> not;
4141

42+
/** The max boolean query clauses. */
43+
@JsonProperty("max_clauses")
44+
private Integer maxClauses = null;
45+
4246
/**
4347
* Returns this with the specified mandatory conditions.
4448
*
@@ -71,4 +75,16 @@ public BooleanCondition not(Condition... conditions) {
7175
not = add(not, conditions);
7276
return this;
7377
}
78+
79+
80+
/**
81+
* Returns this builder with the specified max booleqna query clauses
82+
*
83+
* @param maxClauses teh booleanQuery allowed max clauses
84+
* @return this builder with the specified conditions
85+
*/
86+
public BooleanCondition maxClauses(Integer maxClauses) {
87+
this.maxClauses = maxClauses;
88+
return this;
89+
}
7490
}

builder/src/test/java/com/stratio/cassandra/lucene/builder/BuilderTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ public void testBooleanConditionFull() {
484484
.should(match("f3", 3), match("f4", 4))
485485
.not(match("f5", 5), match("f6", 6))
486486
.boost(2)
487+
.maxClauses(10)
487488
.build();
488489
String expected = "{\"type\":\"boolean\",\"boost\":2.0," +
489490
"\"must\":[" +
@@ -495,7 +496,7 @@ public void testBooleanConditionFull() {
495496
"],\"not\":[" +
496497
"{\"type\":\"match\",\"field\":\"f5\",\"value\":5}," +
497498
"{\"type\":\"match\",\"field\":\"f6\",\"value\":6}" +
498-
"]}";
499+
"],\"max_clauses\":10}";
499500
assertEquals("boolean is wrong", expected, actual);
500501
}
501502

doc/documentation.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,6 +2446,7 @@ Searches for rows matching boolean combinations of other searches.
24462446
(, must: [(search,)?] )?
24472447
(, should: [(search,)?] )?
24482448
(, not: [(search,)?] )?
2449+
(, max_clauses: <max_clauses>)?
24492450
}
24502451
}');
24512452
@@ -2457,6 +2458,7 @@ where:
24572458
OROR search_n
24582459
- **not**: represents the negation of the disjunction of searches:
24592460
NOT(search_1 OR search_2 OROR search_n)
2461+
- **max_clauses**: this is the clauses limit for this query
24602462
24612463
24622464
**Example 1:** search for rows where name ends with “a” AND food starts

plugin/src/main/java/com/stratio/cassandra/lucene/search/condition/BooleanCondition.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
import static org.apache.lucene.search.BooleanClause.Occur.*;
3131

3232
/**
33-
* A {@link Condition} that matches documents matching boolean combinations of other queries, e.g. {@link
34-
* MatchCondition}s, {@link RangeCondition}s or other {@link BooleanCondition}s.
33+
* A {@link Condition} that matches documents matching boolean combinations of other queries, e.g. {@link MatchCondition}s, {@link RangeCondition}s or other {@link BooleanCondition}s.
3534
*
3635
* @author Andres de la Pena {@literal <adelapena@stratio.com>}
3736
*/
3837
public class BooleanCondition extends Condition {
3938

4039
protected static final Logger logger = LoggerFactory.getLogger(BooleanCondition.class);
40+
static final Integer DEFAULT_MAX_CLAUSES = 1024;
4141

4242
/** The mandatory conditions. */
4343
public final List<Condition> must;
@@ -48,28 +48,36 @@ public class BooleanCondition extends Condition {
4848
/** The mandatory not conditions. */
4949
public final List<Condition> not;
5050

51+
/** The max boolean query clauses. */
52+
final Integer maxClauses;
53+
5154
/**
5255
* Returns a new {@link BooleanCondition} compound by the specified {@link Condition}s.
5356
*
54-
* @param boost The boost for this query clause. Documents matching this clause will (in addition to the normal
55-
* weightings) have their score multiplied by {@code boost}.
57+
* @param boost The boost for this query clause. Documents matching this clause will (in addition to the normal weightings) have their score multiplied by {@code boost}.
5658
* @param must the mandatory conditions
5759
* @param should the optional conditions
5860
* @param not the mandatory not conditions
61+
* @param maxClauses teh booleanQuery allowed max clauses
5962
*/
6063
public BooleanCondition(Float boost,
6164
List<Condition> must,
6265
List<Condition> should,
63-
List<Condition> not) {
66+
List<Condition> not,
67+
Integer maxClauses) {
6468
super(boost);
6569
this.must = must == null ? Collections.EMPTY_LIST : must;
6670
this.should = should == null ? Collections.EMPTY_LIST : should;
6771
this.not = not == null ? Collections.EMPTY_LIST : not;
72+
this.maxClauses = maxClauses == null ? DEFAULT_MAX_CLAUSES : maxClauses;
6873
}
6974

7075
/** {@inheritDoc} */
7176
@Override
72-
public BooleanQuery doQuery(Schema schema) {
77+
public synchronized BooleanQuery doQuery(Schema schema) {
78+
int oldMaxClauses= BooleanQuery.getMaxClauseCount();
79+
BooleanQuery.setMaxClauseCount(maxClauses);
80+
7381
BooleanQuery.Builder builder = new BooleanQuery.Builder();
7482
must.forEach(condition -> builder.add(condition.query(schema), MUST));
7583
should.forEach(condition -> builder.add(condition.query(schema), SHOULD));
@@ -78,7 +86,9 @@ public BooleanQuery doQuery(Schema schema) {
7886
logger.warn("Performing resource-intensive pure negation query {}", this);
7987
builder.add(new MatchAllDocsQuery(), FILTER);
8088
}
81-
return builder.build();
89+
BooleanQuery out=builder.build();
90+
BooleanQuery.setMaxClauseCount(oldMaxClauses);
91+
return out;
8292
}
8393

8494
/** {@inheritDoc} */

plugin/src/main/java/com/stratio/cassandra/lucene/search/condition/builder/BooleanConditionBuilder.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public class BooleanConditionBuilder extends ConditionBuilder<BooleanCondition,
4343
@JsonProperty("not")
4444
protected final List<ConditionBuilder<?, ?>> not = new LinkedList<>();
4545

46+
/** The max boolean query clauses. */
47+
@JsonProperty("max_clauses")
48+
protected Integer maxClauses = null;
49+
4650
/**
4751
* Returns this builder with the specified mandatory conditions.
4852
*
@@ -76,6 +80,17 @@ public BooleanConditionBuilder not(ConditionBuilder<?, ?>... builders) {
7680
return this;
7781
}
7882

83+
/**
84+
* Returns this builder with the specified max booleqna query clauses
85+
*
86+
* @param maxClauses teh booleanQuery allowed max clauses
87+
* @return this builder with the specified conditions
88+
*/
89+
public BooleanConditionBuilder maxClauses(Integer maxClauses) {
90+
this.maxClauses = maxClauses;
91+
return this;
92+
}
93+
7994
/**
8095
* Returns the {@link BooleanCondition} represented by this builder.
8196
*
@@ -86,6 +101,7 @@ public BooleanCondition build() {
86101
return new BooleanCondition(boost,
87102
must.stream().map(ConditionBuilder::build).collect(toList()),
88103
should.stream().map(ConditionBuilder::build).collect(toList()),
89-
not.stream().map(ConditionBuilder::build).collect(toList()));
104+
not.stream().map(ConditionBuilder::build).collect(toList()),
105+
maxClauses);
90106
}
91107
}

plugin/src/test/java/com/stratio/cassandra/lucene/search/condition/BooleanConditionTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import static com.stratio.cassandra.lucene.schema.SchemaBuilders.*;
2424
import static com.stratio.cassandra.lucene.search.SearchBuilders.*;
25+
import static com.stratio.cassandra.lucene.search.condition.BooleanCondition.DEFAULT_MAX_CLAUSES;
2526
import static org.junit.Assert.*;
2627

2728
/**
@@ -55,6 +56,7 @@ public void testBuildDefaults() {
5556
assertEquals("Must is not set", 0, condition.must.size());
5657
assertEquals("Should is not set", 0, condition.should.size());
5758
assertEquals("Not is not set", 0, condition.not.size());
59+
assertEquals("Max Clauses is not set", DEFAULT_MAX_CLAUSES, condition.maxClauses);
5860
}
5961

6062
@Test
@@ -118,4 +120,46 @@ public void testToString() {
118120
condition.toString());
119121
}
120122

123+
@Test
124+
public void testOverMaxClauses() {
125+
Schema schema = schema().mapper("name1", stringMapper())
126+
.mapper("name2", stringMapper())
127+
.mapper("name3", stringMapper())
128+
.mapper("name4", stringMapper())
129+
.mapper("name5", stringMapper())
130+
.mapper("name6", stringMapper()).build();
131+
BooleanCondition condition = bool().maxClauses(5)
132+
.must(match("name1","value1"))
133+
.must(match("name2","value2"))
134+
.must(match("name3","value3"))
135+
.must(match("name4","value4"))
136+
.must(match("name5","value5"))
137+
.must(match("name6","value6")).build();
138+
139+
try {
140+
condition.doQuery(schema);
141+
} catch (org.apache.lucene.search.BooleanQuery.TooManyClauses e) {
142+
assertTrue(true);
143+
return;
144+
}
145+
fail("Creating a booleanQuery with more clauses than limited should throw an Exception");
146+
}
147+
148+
@Test
149+
public void testInMaxClauses() {
150+
Schema schema = schema().mapper("name1", stringMapper())
151+
.mapper("name2", stringMapper())
152+
.mapper("name3", stringMapper())
153+
.mapper("name4", stringMapper())
154+
.mapper("name5", stringMapper())
155+
.mapper("name6", stringMapper()).build();
156+
BooleanCondition condition = bool().maxClauses(10)
157+
.must(match("name1","value1"))
158+
.must(match("name2","value2"))
159+
.must(match("name3","value3"))
160+
.must(match("name4","value4"))
161+
.must(match("name5","value5"))
162+
.must(match("name6","value6")).build();
163+
assertEquals("Query count clauses is wrong", 6, condition.doQuery(schema).clauses().size());
164+
}
121165
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.stratio.cassandra.lucene.testsAT.varia;
2+
3+
import com.stratio.cassandra.lucene.builder.search.condition.BooleanCondition;
4+
import com.stratio.cassandra.lucene.testsAT.BaseIT;
5+
import com.stratio.cassandra.lucene.testsAT.util.CassandraUtils;
6+
import org.junit.AfterClass;
7+
import org.junit.BeforeClass;
8+
import org.junit.Test;
9+
import org.junit.runner.RunWith;
10+
import org.junit.runners.JUnit4;
11+
12+
import java.util.LinkedHashMap;
13+
import java.util.Map;
14+
15+
import static com.stratio.cassandra.lucene.builder.Builder.all;
16+
import static com.stratio.cassandra.lucene.builder.Builder.bool;
17+
import static com.stratio.cassandra.lucene.builder.Builder.range;
18+
19+
/**
20+
* @author Eduardo Alonso {@literal <eduardoalonso@stratio.com>}
21+
*/
22+
@RunWith(JUnit4.class)
23+
public class TestBooleanExtremeClauses extends BaseIT {
24+
25+
private static final int NUM_PARTITIONS = 100;
26+
private static final int NUM_MAX_CLAUSES = 1000;
27+
private static CassandraUtils utils;
28+
29+
@BeforeClass
30+
public static void before() {
31+
utils = CassandraUtils.builder("stateless_search_skinny")
32+
.withPartitionKey("pk")
33+
.withColumn("pk", "int")
34+
.withColumn("rc", "int")
35+
.build()
36+
.createKeyspace()
37+
.createTable()
38+
.createIndex();
39+
for (Integer i = 0; i < NUM_PARTITIONS; i++) {
40+
Map<String, String> data = new LinkedHashMap<>();
41+
data.put("pk", i.toString());
42+
data.put("rc", i.toString());
43+
utils.insert(data);
44+
}
45+
utils.refresh();
46+
}
47+
48+
@AfterClass
49+
public static void after() {
50+
CassandraUtils.dropKeyspaceIfNotNull(utils);
51+
}
52+
53+
@Test
54+
public void testQuery() throws Exception {
55+
BooleanCondition bool= bool().maxClauses(NUM_MAX_CLAUSES + 1);
56+
for (int i=0;i< NUM_MAX_CLAUSES ; i++ ) {
57+
bool.must(range("rc").lower(0).upper(i).includeLower(true).includeUpper(true));
58+
}
59+
utils.query(bool).check(1);
60+
}
61+
}

0 commit comments

Comments
 (0)