package org.nlpcn.es4sql;
import com.google.common.collect.ImmutableMap;
import org.elasticsearch.plugin.nlpcn.ElasticJoinExecutor;
import org.elasticsearch.plugin.nlpcn.HashJoinElasticExecutor;
import org.elasticsearch.search.SearchHit;
import org.junit.Test;
import org.junit.Assert;
import org.nlpcn.es4sql.exception.SqlParseException;
import org.nlpcn.es4sql.query.join.HashJoinElasticRequestBuilder;
import org.nlpcn.es4sql.query.SqlElasticRequestBuilder;
import java.io.IOException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.nlpcn.es4sql.TestsConstants.TEST_INDEX;
/**
* Created by Eliran on 22/8/2015.
*/
public class JoinTests {
@Test
public void joinParseCheckSelectedFieldsSplitHASH() throws SqlParseException, SQLFeatureNotSupportedException, IOException {
joinParseCheckSelectedFieldsSplit(false);
}
@Test
public void joinParseCheckSelectedFieldsSplitNL() throws SqlParseException, SQLFeatureNotSupportedException, IOException {
joinParseCheckSelectedFieldsSplit(true);
}
private void joinParseCheckSelectedFieldsSplit(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = "SELECT a.firstname ,a.lastname , a.gender ,d.dog_name FROM elasticsearch-sql_test_index/people a " +
" JOIN elasticsearch-sql_test_index/dog d on d.holdersName = a.firstname " +
" WHERE " +
" (a.age > 10 OR a.balance > 2000)" +
" AND d.age > 1";
if(useNestedLoops) query = query.replace("SELECT","SELECT /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(2, hits.length);
Map<String,Object> oneMatch = ImmutableMap.of("a.firstname", (Object) "Daenerys", "a.lastname", "Targaryen",
"a.gender", "M", "d.dog_name", "rex");
Map<String,Object> secondMatch = ImmutableMap.of("a.firstname", (Object) "Hattie", "a.lastname", "Bond",
"a.gender", "M", "d.dog_name", "snoopy");
Assert.assertTrue(hitsContains(hits, oneMatch));
Assert.assertTrue(hitsContains(hits,secondMatch));
}
@Test
public void joinParseWithHintsCheckSelectedFieldsSplitHASH() throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = "SELECT /*! HASH_WITH_TERMS_FILTER*/ a.firstname ,a.lastname , a.gender ,d.dog_name FROM elasticsearch-sql_test_index/people a " +
" JOIN elasticsearch-sql_test_index/dog d on d.holdersName = a.firstname " +
" WHERE " +
" (a.age > 10 OR a.balance > 2000)" +
" AND d.age > 1";
String explainedQuery = hashJoinRunAndExplain(query);
boolean containTerms = explainedQuery.replaceAll("\\s+","").contains("\"terms\":{\"holdersName\":[");
List<String> holdersName = Arrays.asList("daenerys","nanette","virginia","aurelia","mcgee","hattie","elinor","burton");
for(String holderName : holdersName){
Assert.assertTrue("should contain:" + holderName , explainedQuery.contains(holderName));
}
Assert.assertTrue(containTerms);
}
@Test
public void joinWithNoWhereButWithConditionHash() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithNoWhereButWithCondition(false);
}
@Test
public void joinWithNoWhereButWithConditionNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithNoWhereButWithCondition(true);
}
private void joinWithNoWhereButWithCondition(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.gender , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h " +
"on h.hname = c.house ",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
Map<String,Object> someMatch = ImmutableMap.of("c.gender", (Object) "F", "h.hname", "Targaryen",
"h.words", "fireAndBlood");
Assert.assertTrue(hitsContains(hits, someMatch));
}
@Test
public void joinWithStarASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithStar(false);
}
private void joinWithStar(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select * from %s/gotCharacters c " +
"JOIN %s/gotHouses h " +
"on h.hname = c.house ",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
String house = hits[0].sourceAsMap().get("c.house").toString();
boolean someHouse = house.equals("Targaryen") || house.equals( "Stark") || house.equals("Lannister");
Assert.assertTrue(someHouse );;
String houseName = hits[0].sourceAsMap().get("h.hname").toString();
Assert.assertEquals(house,houseName);
}
@Test
public void joinNoConditionButWithWhereHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinNoConditionButWithWhere(false);
}
@Test
public void joinNoConditionButWithWhereNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinNoConditionButWithWhere(true);
}
private void joinNoConditionButWithWhere(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.gender , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h " +
"where c.name.firstname='Daenerys'",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(3, hits.length);
}
@Test
public void joinNoConditionAndNoWhereHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinNoConditionAndNoWhere(false);
}
@Test
public void joinNoConditionAndNoWhereNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinNoConditionAndNoWhere(true);
}
private void joinNoConditionAndNoWhere(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h ",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(12, hits.length);
}
@Test
public void joinNoConditionAndNoWhereWithTotalLimitHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinNoConditionAndNoWhereWithTotalLimit(false);
}
@Test
public void joinNoConditionAndNoWhereWithTotalLimitNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinNoConditionAndNoWhereWithTotalLimit(true);
}
private void joinNoConditionAndNoWhereWithTotalLimit(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h LIMIT 10",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(10, hits.length);
}
@Test
public void joinWithNestedFieldsOnReturnHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithNestedFieldsOnReturn(false);
}
@Test
public void joinWithNestedFieldsOnReturnNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithNestedFieldsOnReturn(true);
}
private void joinWithNestedFieldsOnReturn(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h " +
"on h.hname = c.house " +
"where c.name.firstname='Daenerys'", TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(1, hits.length);
//use flatten?
Map<String,Object> someMatch = ImmutableMap.of("c.name.firstname", (Object) "Daenerys", "c.parents.father", "Aerys", "h.hname", "Targaryen",
"h.words", "fireAndBlood");
Assert.assertTrue(hitsContains(hits, someMatch));
}
@Test
public void joinWithAllAliasOnReturnHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithAllAliasOnReturn(false);
}
@Test
public void joinWithAllAliasOnReturnNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithAllAliasOnReturn(true);
}
private void joinWithAllAliasOnReturn(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.name.firstname name,c.parents.father father, h.hname house from %s/gotCharacters c " +
"JOIN %s/gotHouses h " +
"on h.hname = c.house " +
"where c.name.firstname='Daenerys'", TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(1, hits.length);
Map<String,Object> someMatch = ImmutableMap.of("name", (Object) "Daenerys", "father", "Aerys", "house", "Targaryen");
Assert.assertTrue(hitsContains(hits, someMatch));
}
@Test
public void joinWithSomeAliasOnReturnHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithSomeAliasOnReturn(false);
}
@Test
public void joinWithSomeAliasOnReturnNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithSomeAliasOnReturn(true);
}
private void joinWithSomeAliasOnReturn(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.name.firstname ,c.parents.father father, h.hname house from %s/gotCharacters c " +
"JOIN %s/gotHouses h " +
"on h.hname = c.house " +
"where c.name.firstname='Daenerys'", TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(1, hits.length);
Map<String,Object> someMatch = ImmutableMap.of("c.name.firstname", (Object) "Daenerys", "father", "Aerys", "house", "Targaryen");
Assert.assertTrue(hitsContains(hits, someMatch));
}
@Test
public void joinWithNestedFieldsOnComparisonAndOnReturnHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithNestedFieldsOnComparisonAndOnReturn(false);
}
@Test
public void joinWithNestedFieldsOnComparisonAndOnReturnNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithNestedFieldsOnComparisonAndOnReturn(true);
}
private void joinWithNestedFieldsOnComparisonAndOnReturn(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h " +
"on h.hname = c.name.lastname " +
"where c.name.firstname='Daenerys'", TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(1, hits.length);
Map<String,Object> someMatch = ImmutableMap.of("c.name.firstname", (Object) "Daenerys", "c.parents.father", "Aerys", "h.hname", "Targaryen",
"h.words", "fireAndBlood");
Assert.assertTrue(hitsContains(hits, someMatch));
}
@Test
public void testLeftJoinHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
testLeftJoin(false);
}
@Test
public void testLeftJoinNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
testLeftJoin(true);
}
private void testLeftJoin(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select c.name.firstname, f.name.firstname,f.name.lastname from %s/gotCharacters c " +
"LEFT JOIN %s/gotCharacters f " +
"on f.name.firstname = c.parents.father "
, TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
Map<String,Object> oneMatch = new HashMap<>();
oneMatch.put("c.name.firstname", "Daenerys");
oneMatch.put("f.name.firstname",null);
oneMatch.put("f.name.lastname",null);
Assert.assertTrue(hitsContains(hits, oneMatch));
Map<String,Object> secondMatch = ImmutableMap.of("c.name.firstname", (Object) "Brandon",
"f.name.firstname", "Eddard", "f.name.lastname", "Stark");
Assert.assertTrue(hitsContains(hits, secondMatch));
}
@Test
public void hintLimits_firstLimitSecondNullHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstLimitSecondNull(false);
}
@Test
public void hintLimits_firstLimitSecondNullNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstLimitSecondNull(true);
}
private void hintLimits_firstLimitSecondNull(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select /*! JOIN_TABLES_LIMIT(2,null) */ c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h ",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(6, hits.length);
}
@Test
public void hintLimits_firstLimitSecondLimitHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstLimitSecondLimit(false);
}
@Test
public void hintLimits_firstLimitSecondLimitNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstLimitSecondLimit(true);
}
private void hintLimits_firstLimitSecondLimit(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select /*! JOIN_TABLES_LIMIT(2,2) */ c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h ",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
}
@Test
public void hintLimits_firstLimitSecondLimitOnlyOneNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstLimitSecondLimitOnlyOne(true);
}
@Test
public void hintLimits_firstLimitSecondLimitOnlyOneHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstLimitSecondLimitOnlyOne(false);
}
private void hintLimits_firstLimitSecondLimitOnlyOne(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select /*! JOIN_TABLES_LIMIT(3,1) */ c.name.firstname,c.parents.father , h.hname,h.words from %s/gotHouses h " +
"JOIN %s/gotCharacters c ON c.name.lastname = h.hname ",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
if(useNestedLoops) Assert.assertEquals(3, hits.length);
else Assert.assertEquals(1, hits.length);
}
@Test
public void hintLimits_firstNullSecondLimitHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstNullSecondLimit(false);
}
@Test
public void hintLimits_firstNullSecondLimitNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
hintLimits_firstNullSecondLimit(true);
}
private void hintLimits_firstNullSecondLimit(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select /*! JOIN_TABLES_LIMIT(null,2) */ c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h ",TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(8, hits.length);
}
@Test
public void testLeftJoinWithLimitHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
testLeftJoinWithLimit(false);
}
@Test
public void testLeftJoinWithLimitNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
testLeftJoinWithLimit(true);
}
private void testLeftJoinWithLimit(boolean useNestedLoops) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
String query = String.format("select /*! JOIN_TABLES_LIMIT(3,null) */ c.name.firstname, f.name.firstname,f.name.lastname from %s/gotCharacters c " +
"LEFT JOIN %s/gotCharacters f " +
"on f.name.firstname = c.parents.father"
, TEST_INDEX,TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(3, hits.length);
}
@Test
public void hintMultiSearchCanRunFewTimesNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select /*! USE_NL*/ /*! NL_MULTISEARCH_SIZE(2)*/ c.name.firstname,c.parents.father , h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h ",TEST_INDEX,TEST_INDEX);
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(12, hits.length);
}
@Test
public void joinWithGeoIntersectNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select p1.description,p2.description from %s/location p1 " +
"JOIN %s/location2 p2 " +
"ON GEO_INTERSECTS(p2.place,p1.place)",TEST_INDEX,TEST_INDEX);
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(2, hits.length);
Assert.assertEquals("squareRelated", hits[0].getSource().get("p2.description"));
Assert.assertEquals("squareRelated",hits[1].getSource().get("p2.description"));
}
@Test
public void joinWithInQuery() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select c.gender ,c.name.firstname, h.hname,h.words from %s/gotCharacters c " +
"JOIN %s/gotHouses h on h.hname = c.house" +
" where c.name.firstname in (select holdersName from %s/dog)", TEST_INDEX, TEST_INDEX, TEST_INDEX);
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(1, hits.length);
Assert.assertEquals("Daenerys", hits[0].getSource().get("c.name.firstname"));
}
@Test
public void joinWithOrHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithOr(false);
}
@Test
public void joinWithOrNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithOr(true);
}
private void joinWithOr(boolean useNestedLoops) throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select d.dog_name , c.name.firstname from %s/gotCharacters c " +
"JOIN %s/dog d on d.holdersName = c.name.firstname" +
" OR d.age = c.name.ofHisName"
, TEST_INDEX, TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(2, hits.length);
Map<String,Object> oneMatch = ImmutableMap.of("c.name.firstname", (Object) "Daenerys", "d.dog_name", "rex");
Map<String,Object> secondMatch = ImmutableMap.of("c.name.firstname", (Object) "Brandon", "d.dog_name", "snoopy");
Assert.assertTrue("hits contains daenerys",hitsContains(hits, oneMatch));
Assert.assertTrue("hits contains brandon",hitsContains(hits, secondMatch));
}
@Test
public void joinWithOrWithTermsFilterOpt() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select /*! HASH_WITH_TERMS_FILTER*/ d.dog_name , c.name.firstname from %s/gotCharacters c " +
"JOIN %s/dog d on d.holdersName = c.name.firstname" +
" OR d.age = c.name.ofHisName"
, TEST_INDEX, TEST_INDEX);
String explainedQuery = hashJoinRunAndExplain(query);
boolean containsHoldersNamesTerms = explainedQuery.replaceAll("\\s+","").contains("\"terms\":{\"holdersName\":");
Assert.assertTrue(containsHoldersNamesTerms);
List<String> holdersName = Arrays.asList("daenerys","brandon","eddard","jaime");
for(String holderName : holdersName){
Assert.assertTrue("should contain:" + holderName , explainedQuery.contains(holderName));
}
boolean containsAgesTerms = explainedQuery.replaceAll("\\s+","").contains("\"terms\":{\"age\":");
Assert.assertTrue(containsAgesTerms);
}
@Test
public void joinWithOrderbyFirstTableHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithOrderFirstTable(false);
}
@Test
public void joinWithOrderbyFirstTableNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithOrderFirstTable(true);
}
private void joinWithOrderFirstTable(boolean useNestedLoops) throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select c.name.firstname , d.words from %s/gotCharacters c " +
"JOIN %s/gotHouses d on d.hname = c.house " +
"order by c.name.firstname"
, TEST_INDEX, TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
Assert.assertEquals("Brandon",hits[0].sourceAsMap().get("c.name.firstname"));
Assert.assertEquals("Daenerys",hits[1].sourceAsMap().get("c.name.firstname"));
Assert.assertEquals("Eddard",hits[2].sourceAsMap().get("c.name.firstname"));
Assert.assertEquals("Jaime",hits[3].sourceAsMap().get("c.name.firstname"));
}
@Test
public void joinWithAllFromSecondTableHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithAllFromSecondTable(false);
}
@Test
public void joinWithAllFromSecondTableNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithAllFromSecondTable(true);
}
private void joinWithAllFromSecondTable(boolean useNestedLoops) throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select c.name.firstname , d.* from %s/gotCharacters c " +
"JOIN %s/gotHouses d on d.hname = c.house "
, TEST_INDEX, TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
Assert.assertEquals(5,hits[0].sourceAsMap().size());
}
@Test
public void joinWithAllFromFirstTableHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithAllFromFirstTable(false);
}
@Test
public void joinWithAllFromFirstTableNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
joinWithAllFromFirstTable(true);
}
private void joinWithAllFromFirstTable(boolean useNestedLoops) throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select d.* , c.name.firstname from %s/gotHouses d " +
"JOIN %s/gotCharacters c on c.house = d.hname "
, TEST_INDEX, TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
Assert.assertEquals(5,hits[0].sourceAsMap().size());
}
@Test
public void leftJoinWithAllFromSecondTableHASH() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
leftJoinWithAllFromSecondTable(false);
}
@Test
public void leftJoinWithAllFromSecondTableNL() throws SQLFeatureNotSupportedException, IOException, SqlParseException {
leftJoinWithAllFromSecondTable(true);
}
private void leftJoinWithAllFromSecondTable(boolean useNestedLoops) throws SQLFeatureNotSupportedException, IOException, SqlParseException {
String query = String.format("select c.name.firstname , d.* from %s/gotCharacters c " +
"LEFT JOIN %s/gotHouses d on d.name = c.house " +
"where d.sigil <> 'direwolf'"
, TEST_INDEX, TEST_INDEX);
if(useNestedLoops) query = query.replace("select","select /*! USE_NL*/ ");
SearchHit[] hits = joinAndGetHits(query);
Assert.assertEquals(4, hits.length);
for (SearchHit hit : hits) {
if(hit.getId().endsWith("0")){
Assert.assertEquals(1,hit.sourceAsMap().size());
}
else {
Assert.assertEquals(5,hit.sourceAsMap().size());
}
}
}
private String hashJoinRunAndExplain(String query) throws IOException, SqlParseException, SQLFeatureNotSupportedException {
SearchDao searchDao = MainTestSuite.getSearchDao();
HashJoinElasticRequestBuilder explain = (HashJoinElasticRequestBuilder) searchDao.explain(query).explain();
HashJoinElasticExecutor executor = new HashJoinElasticExecutor(searchDao.getClient(), explain);
executor.run();
return explain.explain();
}
private SearchHit[] joinAndGetHits(String query) throws SqlParseException, SQLFeatureNotSupportedException, IOException {
SearchDao searchDao = MainTestSuite.getSearchDao();
SqlElasticRequestBuilder explain = searchDao.explain(query).explain();
ElasticJoinExecutor executor = ElasticJoinExecutor.createJoinExecutor(searchDao.getClient(),explain);
executor.run();
return executor.getHits().getHits();
}
private boolean hitsContains(SearchHit[] hits, Map<String, Object> matchMap) {
for(SearchHit hit : hits){
Map<String, Object> hitMap = hit.sourceAsMap();
boolean matchedHit = true;
for(Map.Entry<String,Object> entry: hitMap.entrySet()){
if(!matchMap.containsKey(entry.getKey())) {
matchedHit = false;
break;
}
if(!equalsWithNullCheck(matchMap.get(entry.getKey()), entry.getValue())){
matchedHit = false;
break;
}
}
if(matchedHit) return true;
}
return false;
}
private boolean equalsWithNullCheck(Object one, Object other) {
if(one == null) return other == null;
return one.equals(other);
}
}