From 81a581f8e3fd373fee3d066db0b6e15dc30f6f01 Mon Sep 17 00:00:00 2001 From: Stephane Gamard Date: Fri, 25 Jul 2014 09:50:13 +0200 Subject: [PATCH] SONAR-5464 - Changed text query parser for "Human readable" queries --- .../sonar/server/rule/index/RuleIndex.java | 40 +++++--- .../rule/index/RuleIndexMediumTest.java | 95 +++++++++++-------- 2 files changed, 84 insertions(+), 51 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java index 6ce3e100b32..ae6bf7a2154 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java @@ -25,9 +25,15 @@ import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.index.query.*; +import org.elasticsearch.index.query.BoolFilterBuilder; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; +import org.elasticsearch.index.query.MatchQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.SimpleQueryStringBuilder; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.terms.Terms; @@ -43,11 +49,22 @@ import org.sonar.core.profiling.StopWatch; import org.sonar.core.rule.RuleDto; import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer; import org.sonar.server.rule.Rule; -import org.sonar.server.search.*; +import org.sonar.server.search.BaseIndex; +import org.sonar.server.search.ESNode; +import org.sonar.server.search.IndexDefinition; +import org.sonar.server.search.IndexField; +import org.sonar.server.search.QueryOptions; +import org.sonar.server.search.Result; import javax.annotation.CheckForNull; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import static com.google.common.collect.Lists.newArrayList; @@ -166,16 +183,11 @@ public class RuleIndex extends BaseIndex { String queryString = query.getQueryText(); // Human readable type of querying - qb.should(QueryBuilders.queryString(query.getQueryText()) - .field(RuleNormalizer.RuleField.NAME.field() + "." + IndexField.SEARCH_WORDS_SUFFIX, 20f) - .field(RuleNormalizer.RuleField.HTML_DESCRIPTION.field() + "." + IndexField.SEARCH_WORDS_SUFFIX, 3f) - .enablePositionIncrements(true) - .defaultOperator(QueryStringQueryBuilder.Operator.AND) - .fuzziness(Fuzziness.ONE) - .autoGeneratePhraseQueries(true) - .lenient(false) - .useDisMax(true) - .boost(20f)); + qb.should(QueryBuilders.simpleQueryString(query.getQueryText()) + .field(RuleNormalizer.RuleField.NAME.field() + "." + IndexField.SEARCH_WORDS_SUFFIX, 20f) + .field(RuleNormalizer.RuleField.HTML_DESCRIPTION.field() + "." + IndexField.SEARCH_WORDS_SUFFIX, 3f) + .defaultOperator(SimpleQueryStringBuilder.Operator.AND) + ).boost(20f); // Match and partial Match queries qb.should(this.termQuery(RuleNormalizer.RuleField.KEY, queryString, 15f)); diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexMediumTest.java index 8d763d52e3e..3b7fdb0ed29 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexMediumTest.java @@ -50,8 +50,12 @@ import org.sonar.server.search.Result; import org.sonar.server.tester.ServerTester; import javax.annotation.Nullable; - -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; @@ -609,7 +613,7 @@ public class RuleIndexMediumTest { // 4. get all active rules on profile result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto2.getKey()), + .setQProfileKey(qualityProfileDto2.getKey()), new QueryOptions()); assertThat(result.getHits()).hasSize(1); assertThat(result.getHits().get(0).name()).isEqualTo(rule1.getName()); @@ -646,7 +650,7 @@ public class RuleIndexMediumTest { ActiveRuleDto.createFor(qualityProfileDto2, rule3) .setSeverity("BLOCKER") .setInheritance(ActiveRule.Inheritance.INHERITED.name()) - ); + ); dbSession.commit(); @@ -668,77 +672,77 @@ public class RuleIndexMediumTest { // 3. get Inherited Rules on profile1 result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto1.getKey()) - .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.INHERITED.name())), + .setQProfileKey(qualityProfileDto1.getKey()) + .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.INHERITED.name())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(0); // 4. get Inherited Rules on profile2 result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto2.getKey()) - .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.INHERITED.name())), + .setQProfileKey(qualityProfileDto2.getKey()) + .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.INHERITED.name())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(2); // 5. get Overridden Rules on profile1 result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto1.getKey()) - .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.OVERRIDES.name())), + .setQProfileKey(qualityProfileDto1.getKey()) + .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.OVERRIDES.name())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(0); // 6. get Overridden Rules on profile2 result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto2.getKey()) - .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.OVERRIDES.name())), + .setQProfileKey(qualityProfileDto2.getKey()) + .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.OVERRIDES.name())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(1); // 7. get Inherited AND Overridden Rules on profile1 result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto1.getKey()) - .setInheritance(ImmutableSet.of( - ActiveRule.Inheritance.INHERITED.name(), ActiveRule.Inheritance.OVERRIDES.name())), + .setQProfileKey(qualityProfileDto1.getKey()) + .setInheritance(ImmutableSet.of( + ActiveRule.Inheritance.INHERITED.name(), ActiveRule.Inheritance.OVERRIDES.name())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(0); // 8. get Inherited AND Overridden Rules on profile2 result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto2.getKey()) - .setInheritance(ImmutableSet.of( - ActiveRule.Inheritance.INHERITED.name(), ActiveRule.Inheritance.OVERRIDES.name())), + .setQProfileKey(qualityProfileDto2.getKey()) + .setInheritance(ImmutableSet.of( + ActiveRule.Inheritance.INHERITED.name(), ActiveRule.Inheritance.OVERRIDES.name())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(3); // 9. get rules active on profile1 with active severity BLOCKER result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto1.getKey()) - .setActiveSeverities(ImmutableSet.of( - Severity.BLOCKER.toString())), + .setQProfileKey(qualityProfileDto1.getKey()) + .setActiveSeverities(ImmutableSet.of( + Severity.BLOCKER.toString())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(3); // 10. get rules active on profile2 with active severity MINOR, then BLOCKER + MINOR result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto2.getKey()) - .setActiveSeverities(ImmutableSet.of( - Severity.MINOR.toString())), + .setQProfileKey(qualityProfileDto2.getKey()) + .setActiveSeverities(ImmutableSet.of( + Severity.MINOR.toString())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(1); result = index.search(new RuleQuery().setActivation(true) - .setQProfileKey(qualityProfileDto2.getKey()) - .setActiveSeverities(ImmutableSet.of( - Severity.BLOCKER.toString(), Severity.MINOR.toString())), + .setQProfileKey(qualityProfileDto2.getKey()) + .setActiveSeverities(ImmutableSet.of( + Severity.BLOCKER.toString(), Severity.MINOR.toString())), new QueryOptions() - ); + ); assertThat(result.getHits()).hasSize(3); } @@ -951,7 +955,24 @@ public class RuleIndexMediumTest { assertThat(index.search(availableSinceNowQuery, new QueryOptions()).getHits()).hasSize(0); } - private static List ruleKeys(List rules){ + @Test + public void search_protected_chars() throws InterruptedException { + String nameWithProtectedChars = "ja#va&sc\"r:ipt"; + + RuleDto ruleDto = RuleTesting.newXooX1().setName(nameWithProtectedChars); + dao.insert(dbSession, ruleDto); + dbSession.commit(); + + Rule rule = index.getByKey(RuleTesting.XOO_X1); + assertThat(rule.name()).isEqualTo(nameWithProtectedChars); + + RuleQuery protectedCharsQuery = new RuleQuery().setQueryText(nameWithProtectedChars); + List results = index.search(protectedCharsQuery, new QueryOptions()).getHits(); + assertThat(results).hasSize(1); + assertThat(results.get(0).key()).isEqualTo(RuleTesting.XOO_X1); + } + + private static List ruleKeys(List rules) { return newArrayList(Iterables.transform(rules, new Function() { @Override public String apply(@Nullable Rule input) { -- 2.39.5