|
@@ -28,8 +28,8 @@ import org.elasticsearch.action.search.SearchRequestBuilder;
|
|
|
import org.elasticsearch.action.search.SearchResponse;
|
|
|
import org.elasticsearch.action.search.SearchType;
|
|
|
import org.elasticsearch.common.lucene.search.function.CombineFunction;
|
|
|
-import org.elasticsearch.common.settings.ImmutableSettings;
|
|
|
import org.elasticsearch.common.settings.ImmutableSettings.Builder;
|
|
|
+import org.elasticsearch.common.settings.ImmutableSettings;
|
|
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
|
import org.elasticsearch.index.query.MatchQueryBuilder;
|
|
@@ -38,6 +38,7 @@ import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
|
|
|
import org.elasticsearch.search.SearchHit;
|
|
|
import org.elasticsearch.search.SearchHits;
|
|
|
import org.elasticsearch.search.rescore.RescoreBuilder.QueryRescorer;
|
|
|
+import org.elasticsearch.search.sort.SortOrder;
|
|
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
|
|
import org.junit.Test;
|
|
|
|
|
@@ -83,7 +84,6 @@ public class QueryRescorerTests extends ElasticsearchIntegrationTest {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
@Test
|
|
@@ -193,6 +193,168 @@ public class QueryRescorerTests extends ElasticsearchIntegrationTest {
|
|
|
assertFirstHit(searchResponse, hasId("2"));
|
|
|
assertSecondHit(searchResponse, hasId("6"));
|
|
|
assertThirdHit(searchResponse, hasId("3"));
|
|
|
+
|
|
|
+ // Make sure non-zero from works:
|
|
|
+ searchResponse = client()
|
|
|
+ .prepareSearch()
|
|
|
+ .setQuery(QueryBuilders.matchQuery("field1", "lexington avenue massachusetts").operator(MatchQueryBuilder.Operator.OR))
|
|
|
+ .setFrom(2)
|
|
|
+ .setSize(5)
|
|
|
+ .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
|
|
|
+ .setRescorer(
|
|
|
+ RescoreBuilder.queryRescorer(QueryBuilders.matchPhraseQuery("field1", "lexington avenue massachusetts").slop(3))
|
|
|
+ .setQueryWeight(0.6f).setRescoreQueryWeight(2.0f)).setRescoreWindow(20).execute().actionGet();
|
|
|
+
|
|
|
+ assertThat(searchResponse.getHits().hits().length, equalTo(3));
|
|
|
+ assertHitCount(searchResponse, 9);
|
|
|
+ assertFirstHit(searchResponse, hasId("3"));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Tests a rescore window smaller than number of hits:
|
|
|
+ @Test
|
|
|
+ public void testSmallRescoreWindow() throws Exception {
|
|
|
+ Builder builder = ImmutableSettings.builder();
|
|
|
+ builder.put("index.analysis.analyzer.synonym.tokenizer", "whitespace");
|
|
|
+ builder.putArray("index.analysis.analyzer.synonym.filter", "synonym", "lowercase");
|
|
|
+ builder.put("index.analysis.filter.synonym.type", "synonym");
|
|
|
+ builder.putArray("index.analysis.filter.synonym.synonyms", "ave => ave, avenue", "street => str, street");
|
|
|
+
|
|
|
+ XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties")
|
|
|
+ .startObject("field1").field("type", "string").field("index_analyzer", "whitespace").field("search_analyzer", "synonym")
|
|
|
+ .endObject().endObject().endObject().endObject();
|
|
|
+
|
|
|
+ assertAcked(client().admin().indices().prepareCreate("test").addMapping("type1", mapping).setSettings(builder.put("index.number_of_shards", 1)));
|
|
|
+
|
|
|
+ client().prepareIndex("test", "type1", "1").setSource("field1", "massachusetts avenue boston massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "2").setSource("field1", "lexington avenue boston massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "3").setSource("field1", "boston avenue lexington massachusetts").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "4").setSource("field1", "boston road lexington massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "5").setSource("field1", "lexington street lexington massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "6").setSource("field1", "massachusetts avenue lexington massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "7").setSource("field1", "bosten street san franciso california").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "8").setSource("field1", "hollywood boulevard los angeles california").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "9").setSource("field1", "1st street boston massachussetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "10").setSource("field1", "1st street boston massachusetts").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "11").setSource("field1", "2st street boston massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "12").setSource("field1", "3st street boston massachusetts").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+
|
|
|
+ SearchResponse searchResponse = client()
|
|
|
+ .prepareSearch()
|
|
|
+ .setQuery(QueryBuilders.matchQuery("field1", "massachusetts").operator(MatchQueryBuilder.Operator.OR))
|
|
|
+ .setFrom(0)
|
|
|
+ .setSize(5).execute().actionGet();
|
|
|
+ assertThat(searchResponse.getHits().hits().length, equalTo(5));
|
|
|
+ assertHitCount(searchResponse, 9);
|
|
|
+ assertFirstHit(searchResponse, hasId("1"));
|
|
|
+ assertSecondHit(searchResponse, hasId("6"));
|
|
|
+ assertThirdHit(searchResponse, hasId("2"));
|
|
|
+ assertFourthHit(searchResponse, hasId("3"));
|
|
|
+ assertFifthHit(searchResponse, hasId("4"));
|
|
|
+
|
|
|
+ // Now, rescore only top 2 hits w/ proximity:
|
|
|
+ searchResponse = client()
|
|
|
+ .prepareSearch()
|
|
|
+ .setQuery(QueryBuilders.matchQuery("field1", "massachusetts").operator(MatchQueryBuilder.Operator.OR))
|
|
|
+ .setFrom(0)
|
|
|
+ .setSize(5)
|
|
|
+ .setRescorer(
|
|
|
+ RescoreBuilder.queryRescorer(QueryBuilders.matchPhraseQuery("field1", "lexington avenue massachusetts").slop(3))
|
|
|
+ .setQueryWeight(0.6f).setRescoreQueryWeight(2.0f)).setRescoreWindow(2).execute().actionGet();
|
|
|
+
|
|
|
+ // Only top 2 hits were re-ordered:
|
|
|
+ assertThat(searchResponse.getHits().hits().length, equalTo(5));
|
|
|
+ assertHitCount(searchResponse, 9);
|
|
|
+ assertFirstHit(searchResponse, hasId("6"));
|
|
|
+ assertSecondHit(searchResponse, hasId("1"));
|
|
|
+ assertThirdHit(searchResponse, hasId("2"));
|
|
|
+ assertFourthHit(searchResponse, hasId("3"));
|
|
|
+ assertFifthHit(searchResponse, hasId("4"));
|
|
|
+
|
|
|
+ // Now, rescore only top 3 hits w/ proximity:
|
|
|
+ searchResponse = client()
|
|
|
+ .prepareSearch()
|
|
|
+ .setQuery(QueryBuilders.matchQuery("field1", "massachusetts").operator(MatchQueryBuilder.Operator.OR))
|
|
|
+ .setFrom(0)
|
|
|
+ .setSize(5)
|
|
|
+ .setRescorer(
|
|
|
+ RescoreBuilder.queryRescorer(QueryBuilders.matchPhraseQuery("field1", "lexington avenue massachusetts").slop(3))
|
|
|
+ .setQueryWeight(0.6f).setRescoreQueryWeight(2.0f)).setRescoreWindow(3).execute().actionGet();
|
|
|
+
|
|
|
+ // Only top 3 hits were re-ordered:
|
|
|
+ assertThat(searchResponse.getHits().hits().length, equalTo(5));
|
|
|
+ assertHitCount(searchResponse, 9);
|
|
|
+ assertFirstHit(searchResponse, hasId("2"));
|
|
|
+ assertSecondHit(searchResponse, hasId("6"));
|
|
|
+ assertThirdHit(searchResponse, hasId("1"));
|
|
|
+ assertFourthHit(searchResponse, hasId("3"));
|
|
|
+ assertFifthHit(searchResponse, hasId("4"));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Tests a rescorer that penalizes the scores:
|
|
|
+ @Test
|
|
|
+ public void testRescorerMadeScoresWorse() throws Exception {
|
|
|
+ Builder builder = ImmutableSettings.builder();
|
|
|
+ builder.put("index.analysis.analyzer.synonym.tokenizer", "whitespace");
|
|
|
+ builder.putArray("index.analysis.analyzer.synonym.filter", "synonym", "lowercase");
|
|
|
+ builder.put("index.analysis.filter.synonym.type", "synonym");
|
|
|
+ builder.putArray("index.analysis.filter.synonym.synonyms", "ave => ave, avenue", "street => str, street");
|
|
|
+
|
|
|
+ XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties")
|
|
|
+ .startObject("field1").field("type", "string").field("index_analyzer", "whitespace").field("search_analyzer", "synonym")
|
|
|
+ .endObject().endObject().endObject().endObject();
|
|
|
+
|
|
|
+ assertAcked(client().admin().indices().prepareCreate("test").addMapping("type1", mapping).setSettings(builder.put("index.number_of_shards", 1)));
|
|
|
+
|
|
|
+ client().prepareIndex("test", "type1", "1").setSource("field1", "massachusetts avenue boston massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "2").setSource("field1", "lexington avenue boston massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "3").setSource("field1", "boston avenue lexington massachusetts").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "4").setSource("field1", "boston road lexington massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "5").setSource("field1", "lexington street lexington massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "6").setSource("field1", "massachusetts avenue lexington massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "7").setSource("field1", "bosten street san franciso california").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "8").setSource("field1", "hollywood boulevard los angeles california").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "9").setSource("field1", "1st street boston massachussetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "10").setSource("field1", "1st street boston massachusetts").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "11").setSource("field1", "2st street boston massachusetts").execute().actionGet();
|
|
|
+ client().prepareIndex("test", "type1", "12").setSource("field1", "3st street boston massachusetts").execute().actionGet();
|
|
|
+ client().admin().indices().prepareRefresh("test").execute().actionGet();
|
|
|
+
|
|
|
+ SearchResponse searchResponse = client()
|
|
|
+ .prepareSearch()
|
|
|
+ .setQuery(QueryBuilders.matchQuery("field1", "massachusetts").operator(MatchQueryBuilder.Operator.OR))
|
|
|
+ .setFrom(0)
|
|
|
+ .setSize(5).execute().actionGet();
|
|
|
+ assertThat(searchResponse.getHits().hits().length, equalTo(5));
|
|
|
+ assertHitCount(searchResponse, 9);
|
|
|
+ assertFirstHit(searchResponse, hasId("1"));
|
|
|
+ assertSecondHit(searchResponse, hasId("6"));
|
|
|
+ assertThirdHit(searchResponse, hasId("2"));
|
|
|
+ assertFourthHit(searchResponse, hasId("3"));
|
|
|
+ assertFifthHit(searchResponse, hasId("4"));
|
|
|
+
|
|
|
+ // Now, penalizing rescore (nothing matches the rescore query):
|
|
|
+ searchResponse = client()
|
|
|
+ .prepareSearch()
|
|
|
+ .setQuery(QueryBuilders.matchQuery("field1", "massachusetts").operator(MatchQueryBuilder.Operator.OR))
|
|
|
+ .setFrom(0)
|
|
|
+ .setSize(5)
|
|
|
+ .setRescorer(
|
|
|
+ RescoreBuilder.queryRescorer(QueryBuilders.matchPhraseQuery("field1", "lexington avenue massachusetts").slop(3))
|
|
|
+ .setQueryWeight(1.0f).setRescoreQueryWeight(-1f)).setRescoreWindow(3).execute().actionGet();
|
|
|
+
|
|
|
+ // 6 and 2 got worse, and then hits outside the rescore window were sorted ahead:
|
|
|
+ assertFirstHit(searchResponse, hasId("1"));
|
|
|
+ assertSecondHit(searchResponse, hasId("3"));
|
|
|
+ assertThirdHit(searchResponse, hasId("4"));
|
|
|
+ assertFourthHit(searchResponse, hasId("6"));
|
|
|
+ assertFifthHit(searchResponse, hasId("2"));
|
|
|
}
|
|
|
|
|
|
// Comparator that sorts hits and rescored hits in the same way.
|