package org.apache.rya.joinselect.mr;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */



import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.INPUTPATH;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.INSTANCE;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.OUTPUTPATH;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.PASSWORD;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.PROSPECTS_OUTPUTPATH;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.PROSPECTS_TABLE;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.SELECTIVITY_TABLE;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.SPO_OUTPUTPATH;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.SPO_TABLE;
import static org.apache.rya.joinselect.mr.utils.JoinSelectConstants.USERNAME;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.rya.accumulo.AccumuloRdfConfiguration;
import org.apache.rya.api.RdfCloudTripleStoreConstants.TABLE_LAYOUT;
import org.apache.rya.api.domain.RyaStatement;
import org.apache.rya.api.domain.RyaType;
import org.apache.rya.api.domain.RyaIRI;
import org.apache.rya.api.resolver.RyaTripleContext;
import org.apache.rya.api.resolver.triple.TripleRow;
import org.apache.rya.joinselect.mr.JoinSelectAggregate.JoinReducer;
import org.apache.rya.joinselect.mr.JoinSelectAggregate.JoinSelectAggregateMapper;
import org.apache.rya.joinselect.mr.JoinSelectAggregate.JoinSelectGroupComparator;
import org.apache.rya.joinselect.mr.JoinSelectAggregate.JoinSelectPartitioner;
import org.apache.rya.joinselect.mr.JoinSelectAggregate.JoinSelectSortComparator;
import org.apache.rya.joinselect.mr.JoinSelectProspectOutput.CardinalityMapper;
import org.apache.rya.joinselect.mr.JoinSelectSpoTableOutput.JoinSelectMapper;
import org.apache.rya.joinselect.mr.JoinSelectStatisticsSum.CardinalityIdentityCombiner;
import org.apache.rya.joinselect.mr.JoinSelectStatisticsSum.CardinalityIdentityMapper;
import org.apache.rya.joinselect.mr.JoinSelectStatisticsSum.CardinalityIdentityReducer;
import org.apache.rya.joinselect.mr.utils.CardList;
import org.apache.rya.joinselect.mr.utils.CompositeType;
import org.apache.rya.joinselect.mr.utils.JoinSelectStatsUtil;
import org.apache.rya.joinselect.mr.utils.TripleCard;
import org.apache.rya.joinselect.mr.utils.TripleEntry;

import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
import org.apache.accumulo.core.client.BatchWriter;
import org.apache.accumulo.core.client.BatchWriterConfig;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.Scanner;
import org.apache.accumulo.core.client.TableExistsException;
import org.apache.accumulo.core.client.TableNotFoundException;
import org.apache.accumulo.core.client.mapreduce.AccumuloInputFormat;
import org.apache.accumulo.core.client.mapreduce.AccumuloOutputFormat;
import org.apache.accumulo.core.client.mock.MockInstance;
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Mutation;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.MRJobConfig;
import org.apache.hadoop.mapreduce.lib.input.MultipleInputs;
import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class JoinSelectStatisticsTest {
    
    private static final String PREFIX = JoinSelectStatisticsTest.class.getSimpleName();
  
    private static final String DELIM = "\u0000";
    private static final String iri = "uri:";
    private List<String> cardList = Arrays.asList("subject", "predicate", "object");
    private List<String> aggCardList = Arrays.asList("subjectobject", "subjectpredicate", "subjectsubject", "predicateobject", "predicatepredicate", "predicatesubject");
    private static File SPOOUT;
    private static File PROSPECTSOUT;
    private static File tempDir;
    private Connector c;
    private RyaTripleContext ryaContext;
    private static final String INSTANCE_NAME = "mapreduce_instance";
    
    private static class JoinSelectTester1 extends Configured implements Tool {

       
        
        @Override
        public int run(String[] args) throws Exception {

            Configuration conf = getConf();
            
            String inTable = conf.get(SPO_TABLE);
            String outPath = conf.get(SPO_OUTPUTPATH);
           
            
            assert inTable != null && outPath != null;

            Job job = new Job(conf, this.getClass().getSimpleName() + "_" + System.currentTimeMillis());
            job.setJarByClass(this.getClass());
            conf.setBoolean(MRJobConfig.MAPREDUCE_JOB_USER_CLASSPATH_FIRST, true);
            
            initTabToSeqFileJob(job, inTable, outPath);
            job.setMapperClass(JoinSelectMapper.class);
            job.setNumReduceTasks(0);
            job.waitForCompletion(true);
           
            return job.isSuccessful() ? 0 : 1;
        }
    }

    private static class JoinSelectTester2 extends Configured implements Tool {

        
        
        @Override
        public int run(String[] args) throws Exception {

            Configuration conf = getConf();
            
            String inTable = conf.get(PROSPECTS_TABLE);
            System.out.println("Table is " + inTable);
            String outPath = conf.get(PROSPECTS_OUTPUTPATH);
           
            
            assert inTable != null && outPath != null;

            Job job = new Job(conf, this.getClass().getSimpleName() + "_" + System.currentTimeMillis());
            job.setJarByClass(this.getClass());
            conf.setBoolean(MRJobConfig.MAPREDUCE_JOB_USER_CLASSPATH_FIRST, true);
            
            initTabToSeqFileJob(job, inTable, outPath);
            job.setMapperClass(CardinalityMapper.class);
            job.setNumReduceTasks(0);
            job.waitForCompletion(true);
           
            return job.isSuccessful() ? 0 : 1;          
        }
    }
    
    
 private static class JoinSelectTester4 extends Configured implements Tool {

        
        
        @Override
        public int run(String[] args) throws Exception {

            Configuration conf = getConf();
            String outpath = conf.get(OUTPUTPATH);
    
            Job job = new Job(conf, this.getClass().getSimpleName() + "_" + System.currentTimeMillis());
            job.setJarByClass(this.getClass());
            conf.setBoolean(MRJobConfig.MAPREDUCE_JOB_USER_CLASSPATH_FIRST, true);
            
            MultipleInputs.addInputPath(job, new Path(PROSPECTSOUT.getAbsolutePath()), 
                    SequenceFileInputFormat.class, JoinSelectAggregateMapper.class);
            MultipleInputs.addInputPath(job,new Path(SPOOUT.getAbsolutePath()) , 
                    SequenceFileInputFormat.class, JoinSelectAggregateMapper.class);
            job.setMapOutputKeyClass(CompositeType.class);
            job.setMapOutputValueClass(TripleCard.class);

            tempDir = new File(File.createTempFile(outpath, "txt").getParentFile(), System.currentTimeMillis() + "");
            SequenceFileOutputFormat.setOutputPath(job, new Path(tempDir.getAbsolutePath()));
            job.setOutputFormatClass(SequenceFileOutputFormat.class);
            job.setOutputKeyClass(TripleEntry.class);
            job.setOutputValueClass(CardList.class);


            job.setSortComparatorClass(JoinSelectSortComparator.class);
            job.setGroupingComparatorClass(JoinSelectGroupComparator.class);
            job.setPartitionerClass(JoinSelectPartitioner.class);
            job.setReducerClass(JoinReducer.class);
            job.setNumReduceTasks(32);
            job.waitForCompletion(true);
            
            return job.isSuccessful() ? 0 : 1;          
        }
     }
    
    
    
    private static class JoinSelectTester3 extends Configured implements Tool {

        
        
        @Override
        public int run(String[] args) throws Exception {
            
            Configuration conf = getConfig();
            
            String outTable = conf.get(SELECTIVITY_TABLE);
            String inPath = conf.get(INPUTPATH);
            
             
            assert outTable != null && inPath != null;

            Job job = new Job(getConf(), this.getClass().getSimpleName() + "_" + System.currentTimeMillis());
            job.setJarByClass(this.getClass());
            initSumMRJob(job, inPath, outTable);

            job.setMapperClass(CardinalityIdentityMapper.class);
            job.setCombinerClass(CardinalityIdentityCombiner.class);
            job.setReducerClass(CardinalityIdentityReducer.class);
            job.setNumReduceTasks(32);
            job.waitForCompletion(true);
            
           return job.isSuccessful() ? 0 : 1;
           
        }
        
       

    }
    
   
    
    
    
    
    
    public class JoinSelectTestDriver extends Configured implements Tool {
        
        Configuration conf = getConfig();

        @Override
        public int run(String[] args) throws Exception {
            
            int res0 = ToolRunner.run(conf, new JoinSelectTester1(), args);
            int res1 = 1;
            int res2 = 1;
            int res3 = 1;
            
            
           
            if(res0 == 0) {
                res1 = ToolRunner.run(conf, new JoinSelectTester2(), args);
            }
            if(res1 == 0) {
                res2 = ToolRunner.run(conf, new JoinSelectTester4(), args);
            }
            if(res2 == 0) {
                res3 = ToolRunner.run(conf, new JoinSelectTester3(), args);
            }
            
            return res3;
        }

    }
    
    
    
    
    private static Configuration getConfig() {
        
        Configuration conf = new Configuration();
        conf.set("fs.default.name", "file:///");
        conf.set("mapreduce.framework.name", "local");
        conf.set("spo.table", "rya_spo");
        conf.set("prospects.table", "rya_prospects");
        conf.set("selectivity.table", "rya_selectivity");
        conf.set("auths", "");
        conf.set("instance",INSTANCE_NAME);
        conf.set("username","root");
        conf.set("password", "");
        conf.set("inputpath","temp");
        conf.set("outputpath","temp");
        conf.set("prospects.outputpath","prospects");
        conf.set("spo.outputpath", "spo");
        
        
        return conf;
        
    }
    
    
   
    
    
    
    
    
    
    
    public static void initTabToSeqFileJob(Job job, String intable, String outpath) throws AccumuloSecurityException, IOException {
        
        Configuration conf = job.getConfiguration();
       
        String username = conf.get(USERNAME);
        System.out.println("Username is " + username);
        String password = conf.get(PASSWORD);
        String instance = conf.get(INSTANCE);
        System.out.println("Instance is " + instance);
        
       
        AccumuloInputFormat.setMockInstance(job, instance);
        AccumuloInputFormat.setConnectorInfo(job, username, new PasswordToken(password));
        AccumuloInputFormat.setInputTableName(job, intable);
        
        job.setInputFormatClass(AccumuloInputFormat.class);
        job.setMapOutputKeyClass(CompositeType.class);
        job.setMapOutputValueClass(TripleCard.class);

        System.out.println("Outpath is " + outpath);
        
        // OUTPUT
        if(outpath.equals("spo")) {
            SPOOUT = new File(File.createTempFile(outpath, "txt").getParentFile(), System.currentTimeMillis() + "spo");
            SequenceFileOutputFormat.setOutputPath(job, new Path(SPOOUT.getAbsolutePath()));
        } else {
            PROSPECTSOUT = new File(File.createTempFile(outpath, "txt").getParentFile(), System.currentTimeMillis() + "prospects");
            SequenceFileOutputFormat.setOutputPath(job, new Path(PROSPECTSOUT.getAbsolutePath()));
        }
        job.setOutputFormatClass(SequenceFileOutputFormat.class);
        job.setOutputKeyClass(CompositeType.class);
        job.setOutputValueClass(TripleCard.class);
    
     }
    
    public static void initSumMRJob(Job job, String inputPath, String outtable) throws AccumuloSecurityException, IOException {
      
        Configuration conf = job.getConfiguration();
        
        String username = conf.get(USERNAME);
        String password = conf.get(PASSWORD);
        String instance = conf.get(INSTANCE);
       
        

        AccumuloOutputFormat.setConnectorInfo(job, username, new PasswordToken(password));
        AccumuloOutputFormat.setMockInstance(job, instance);
        AccumuloOutputFormat.setDefaultTableName(job, outtable);

        
        SequenceFileInputFormat.addInputPath(job, new Path(tempDir.getAbsolutePath()));
        job.setInputFormatClass(SequenceFileInputFormat.class);
        job.setMapOutputKeyClass(TripleEntry.class);
        job.setMapOutputValueClass(CardList.class);

       
        job.setOutputFormatClass(AccumuloOutputFormat.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Mutation.class);
         
      
    }
    
    
    
   
    
    @Before
    public void init() throws AccumuloException, AccumuloSecurityException, TableExistsException, TableNotFoundException {
      
        MockInstance mockInstance = new MockInstance(INSTANCE_NAME);
        c = mockInstance.getConnector("root", new PasswordToken(""));
        
        if (c.tableOperations().exists("rya_prospects")) {
            c.tableOperations().delete("rya_prospects");
        } 
        if (c.tableOperations().exists("rya_selectivity")) {
            c.tableOperations().delete("rya_selectivity");
        }
        if (c.tableOperations().exists("rya_spo")) {
            c.tableOperations().delete("rya_spo");
        } 
        
        
        c.tableOperations().create("rya_spo");
        c.tableOperations().create("rya_prospects");
        c.tableOperations().create("rya_selectivity");
        ryaContext = RyaTripleContext.getInstance(new AccumuloRdfConfiguration(getConfig()));
    }
    
    
    
    
    
    
    
    

    @Test
    public void testMap1() throws Exception {
        init();
        
        System.out.println("*****************************Test1**************************** ");
        
        BatchWriter bw_table1 = c.createBatchWriter("rya_spo", new BatchWriterConfig());
        for (int i = 1; i < 3; i++) {

            RyaStatement rs = new RyaStatement(new RyaIRI(iri + i), new RyaIRI(iri + 5), new RyaType(iri + (i + 2)));
            Map<TABLE_LAYOUT, TripleRow> tripleRowMap = ryaContext.serializeTriple(rs);
            TripleRow tripleRow = tripleRowMap.get(TABLE_LAYOUT.SPO);
            Mutation m = JoinSelectStatsUtil.createMutation(tripleRow);
            bw_table1.addMutation(m);
            

        }
        bw_table1.close();

        BatchWriter bw_table2 = c.createBatchWriter("rya_prospects", new BatchWriterConfig());
        for (int i = 1; i < 6; i++) {

            int j = 1;
            
            for (String s : cardList) {
                Mutation m = new Mutation(new Text(s + DELIM + iri + i + DELIM + i));
                m.put(new Text(), new Text(), new Value(new IntWritable(i + j).toString().getBytes()));
                bw_table2.addMutation(m);
                j++;
            }

        }
        bw_table2.close();
        
        
        
        

        Assert.assertEquals(0, ToolRunner.run(new JoinSelectTestDriver(), new String[]{""}));     
        Scanner scan = c.createScanner("rya_selectivity", new Authorizations());
        scan.setRange(new Range());

        for (Map.Entry<Key, Value> entry : scan) {
            System.out.println("Key row string is " + entry.getKey().getRow().toString());
            System.out.println("Join type is " + entry.getKey().getColumnFamily().toString());
            System.out.println("Value is " + entry.getKey().getColumnQualifier().toString());
        }

        Scanner scan1 = c.createScanner("rya_selectivity" , new Authorizations());
        scan1.setRange(Range.prefix("predicate" +DELIM + iri + 5));
        int i = 5;
        
        for (Map.Entry<Key, Value> entry : scan1) {
            
            int val1 = 5 + 2*i;
            int val2 = 5 + 2*(i-1);
            int val = Integer.parseInt(entry.getKey().getColumnQualifier().toString());
            
            if(i < 3) {
                Assert.assertTrue( val == val1);
            }
            if(i >= 3  && i < 6) {
                Assert.assertTrue(val == val2);
            }
            i--;
        }
        Assert.assertTrue(i == -1);
        
        
        
        Scanner scan2 = c.createScanner("rya_selectivity" , new Authorizations());
        scan2.setRange(Range.prefix("object" +DELIM + iri + 3));
        int j = 5;
        
        for (Map.Entry<Key, Value> entry : scan2) {
            
            int val1 = 5 + (j-2);
            int val2 = 2+j;
            int val = Integer.parseInt(entry.getKey().getColumnQualifier().toString());
            
            if(j < 3) {
                Assert.assertTrue( val == val2);
            }
            if(j >= 3  && j < 6) {
                Assert.assertTrue(val == val1);
            }
            j--;
        }
        Assert.assertTrue(j == -1);
        
        
        
        
        Scanner scan3 = c.createScanner("rya_selectivity", new Authorizations());
        scan3.setRange(Range.prefix("objectsubject" + DELIM + iri + 3 +DELIM +iri +1 ));
        int k = 8;

        for (Map.Entry<Key, Value> entry : scan3) {

            int val = Integer.parseInt(entry.getKey().getColumnQualifier().toString());

            Assert.assertTrue(val == k);
            k--;
        }
        Assert.assertTrue(k == 5);
        
        
        
       
        
        

    }


    
    
    
    @Test
    public void testMap2() throws Exception {
        
        System.out.println("*********************Test2******************* ");

        init();

        BatchWriter bw_table1 = c.createBatchWriter("rya_spo", new BatchWriterConfig());
        for (int i = 1; i < 4; i++) {

            RyaStatement rs = new RyaStatement(new RyaIRI(iri + 1), new RyaIRI(iri + 2), new RyaType(iri + i));
            Map<TABLE_LAYOUT, TripleRow> tripleRowMap = ryaContext.serializeTriple(rs);
            TripleRow tripleRow = tripleRowMap.get(TABLE_LAYOUT.SPO);
            Mutation m = JoinSelectStatsUtil.createMutation(tripleRow);
            bw_table1.addMutation(m);

        }
        bw_table1.close();

        BatchWriter bw_table2 = c.createBatchWriter("rya_prospects", new BatchWriterConfig());
        for (int i = 1; i < 4; i++) {

            for (String s : cardList) {
                Mutation m = new Mutation(new Text(s + DELIM + iri + i + DELIM + i));
                m.put(new Text(), new Text(), new Value(new IntWritable(i + 2).toString().getBytes()));
                bw_table2.addMutation(m);
            }

        }
        bw_table2.close();

        Assert.assertEquals(0, ToolRunner.run(new JoinSelectTestDriver(), new String[]{""}));
        Scanner scan1 = c.createScanner("rya_selectivity" , new Authorizations());
        scan1.setRange(Range.prefix("subject" +DELIM + iri + 1));
        int i = 0;
        
        for (Map.Entry<Key, Value> entry : scan1) {
            
            Assert.assertTrue(entry.getKey().getColumnQualifier().toString().equals("12")); 
            i++;
        }
        Assert.assertTrue(i == 6);
        
        Scanner scan2 = c.createScanner("rya_selectivity" , new Authorizations());
        scan2.setRange(Range.prefix("predicate" +DELIM + iri + 2));
        int j = 0;
        
        for (Map.Entry<Key, Value> entry : scan2) {
            
            if(j < 3) {
                Assert.assertTrue(entry.getKey().getColumnQualifier().toString().equals("12"));
            }
            if(j > 3  && j < 6) {
                Assert.assertTrue(entry.getKey().getColumnQualifier().toString().equals("9"));
            }
            j++;
        }
        Assert.assertTrue(j == 6);
        
        Scanner scan3 = c.createScanner("rya_selectivity" , new Authorizations());
        scan3.setRange(Range.prefix("predicateobject" +DELIM + iri + 2 +DELIM + iri + 2));
        int k = 0;
        
        for (Map.Entry<Key, Value> entry : scan3) {
            Assert.assertTrue(entry.getKey().getColumnQualifier().toString().equals("3")); 
            k++;
        }
        Assert.assertTrue(k == 3);
        

    }

    
    
    
    @Test
    public void testMap3() throws Exception {
        init();
        
        System.out.println("*************************Test3**************************** ");
        
        BatchWriter bw_table1 = c.createBatchWriter("rya_spo", new BatchWriterConfig());
        for (int i = 1; i < 3; i++) {
            for (int j = 1; j < 3; j++) {
                for (int k = 1; k < 3; k++) {

                    RyaStatement rs = new RyaStatement(new RyaIRI(iri + i), new RyaIRI(iri + (j)), new RyaType(iri + k));
                    Map<TABLE_LAYOUT, TripleRow> tripleRowMap = ryaContext.serializeTriple(rs);
                    TripleRow tripleRow = tripleRowMap.get(TABLE_LAYOUT.SPO);
                    Mutation m = JoinSelectStatsUtil.createMutation(tripleRow);
                    bw_table1.addMutation(m);

                }
            }

        }
        bw_table1.close();

        BatchWriter bw_table2 = c.createBatchWriter("rya_prospects", new BatchWriterConfig());
        for (int i = 1; i < 3; i++) {

            int k = 1;
            for (String s : cardList) {
                Mutation m = new Mutation(new Text(s + DELIM + iri + i + DELIM + i));
                m.put(new Text(), new Text(), new Value(new IntWritable(i + k).toString().getBytes()));
                bw_table2.addMutation(m);
                k++;
            }

            for (int j = 1; j < 3; j++) {
                k = 1;
                for (String s : aggCardList) {
                    Mutation m = new Mutation(new Text(s + DELIM + iri + i + DELIM + iri + j + DELIM + i));
                    m.put(new Text(), new Text(), new Value(new IntWritable(i + k +j).toString().getBytes()));
                    bw_table2.addMutation(m);
                    k++;
                }
            }

        }
        bw_table2.close();
        
        
        
        

        Assert.assertEquals(0, ToolRunner.run(new JoinSelectTestDriver(), new String[]{""}));
        Scanner scan = c.createScanner("rya_selectivity", new Authorizations());
        scan.setRange(new Range());

        for (Map.Entry<Key, Value> entry : scan) {
            System.out.println("Key row string is " + entry.getKey().getRow().toString());
            System.out.println("Join type is " + entry.getKey().getColumnFamily().toString());
            System.out.println("Value is " + entry.getKey().getColumnQualifier().toString());
        }

        
        
        Scanner scan1 = c.createScanner("rya_selectivity" , new Authorizations());
        scan1.setRange(Range.prefix("subject" +DELIM + iri + 1));
        int i = 0;
        
        for (Map.Entry<Key, Value> entry : scan1) {
            
            Key key = entry.getKey();
            String s = key.getColumnFamily().toString();
            int val = Integer.parseInt(key.getColumnQualifier().toString());
            
            if(s.equals("predicatepredicate")) {
                Assert.assertTrue(val == 14);
            } 
            if(s.equals("objectobject")) {
                Assert.assertTrue(val == 18);
            } 
            if(s.equals("predicateobjectpredicateobject")) {
                Assert.assertTrue(val == 28);
            } 
            if(s.equals("predicateobjectsubjectpredicate")) {
                Assert.assertTrue(val == 20);
            }
            if(s.equals("predicateobjectobjectsubject")) {
                Assert.assertTrue(val == 16);
            }
            
            i++;
        }
        Assert.assertTrue(i == 12);
        
        
        
       
        
        

    }


    
    
    
    @Test
    public void testMap4() throws Exception {
        init();
        
        System.out.println("*************************Test4**************************** ");
        System.out.println("*************************Test4**************************** ");
        
        BatchWriter bw_table1 = c.createBatchWriter("rya_spo", new BatchWriterConfig());
        for (int i = 1; i < 3; i++) {
            for (int j = 1; j < 3; j++) {
                for (int k = 1; k < 3; k++) {

                    if(j == 1 && k ==2) {
                        break;
                    }
                    
                    RyaStatement rs = new RyaStatement(new RyaIRI(iri + i), new RyaIRI(iri + (j)), new RyaType(iri + k));
                    Map<TABLE_LAYOUT, TripleRow> tripleRowMap = ryaContext.serializeTriple(rs);
                    TripleRow tripleRow = tripleRowMap.get(TABLE_LAYOUT.SPO);
                    Mutation m = JoinSelectStatsUtil.createMutation(tripleRow);
                    bw_table1.addMutation(m);

                }
            }

        }
        bw_table1.close();

        BatchWriter bw_table2 = c.createBatchWriter("rya_prospects", new BatchWriterConfig());
        for (int i = 1; i < 3; i++) {

            int k = 1;
            for (String s : cardList) {
                Mutation m = new Mutation(new Text(s + DELIM + iri + i + DELIM + i));
                m.put(new Text(), new Text(), new Value(new IntWritable(i + k).toString().getBytes()));
                bw_table2.addMutation(m);
                k++;
            }

            for (int j = 1; j < 3; j++) {
                k = 1;
                for (String s : aggCardList) {
                    Mutation m = new Mutation(new Text(s + DELIM + iri + i + DELIM + iri + j + DELIM + i));
                    m.put(new Text(), new Text(), new Value(new IntWritable(i + k + 2*j).toString().getBytes()));
                    bw_table2.addMutation(m);
                    k++;
                }
            }

        }
        bw_table2.close();
        
        
        
        

        Assert.assertEquals(0, ToolRunner.run(new JoinSelectTestDriver(), new String[]{""}));
        Scanner scan = c.createScanner("rya_selectivity", new Authorizations());
        scan.setRange(new Range());

        for (Map.Entry<Key, Value> entry : scan) {
            System.out.println("Key row string is " + entry.getKey().getRow().toString());
            System.out.println("Join type is " + entry.getKey().getColumnFamily().toString());
            System.out.println("Value is " + entry.getKey().getColumnQualifier().toString());
        }

        
        
        Scanner scan1 = c.createScanner("rya_selectivity" , new Authorizations());
        scan1.setRange(Range.prefix("subject" +DELIM + iri + 1));
        int i = 0;
        
        for (Map.Entry<Key, Value> entry : scan1) {
            
            Key key = entry.getKey();
            String s = key.getColumnFamily().toString();
            int val = Integer.parseInt(key.getColumnQualifier().toString());
            
            if(s.equals("predicatepredicate")) {
                Assert.assertTrue(val == 11);
            } 
            if(s.equals("objectobject")) {
                Assert.assertTrue(val == 13);
            } 
            if(s.equals("predicateobjectobjectpredicate")) {
                Assert.assertTrue(val == 26);
            } 
            if(s.equals("predicateobjectpredicateobject")) {
                Assert.assertTrue(val == 25);
            } 
            if(s.equals("predicateobjectsubjectpredicate")) {
                Assert.assertTrue(val == 19);
            }
            if(s.equals("predicateobjectpredicatesubject")) {
                Assert.assertTrue(val == 20);
            }
            
            i++;
        }
        Assert.assertTrue(i == 12);
        
        
        
        Scanner scan2 = c.createScanner("rya_selectivity" , new Authorizations());
        scan2.setRange(Range.prefix("predicate" +DELIM + iri + 1));
        int j = 0;
        
        for (Map.Entry<Key, Value> entry : scan2) {
            
            Key key = entry.getKey();
            String s = key.getColumnFamily().toString();
            int val = Integer.parseInt(key.getColumnQualifier().toString());
            
            if(s.equals("subjectsubject")) {
                Assert.assertTrue(val == 5);
            } 
            if(s.equals("objectobject")) {
                Assert.assertTrue(val == 8);
            } 
            if(s.equals("objectsubjectsubjectpredicate")) {
                Assert.assertTrue(val == 11);
            } 
            if(s.equals("objectsubjectpredicateobject")) {
                Assert.assertTrue(val == 15);
            } 
            if(s.equals("objectsubjectobjectsubject")) {
                Assert.assertTrue(val == 9);
            }
            if(s.equals("objectsubjectsubjectobject")) {
                Assert.assertTrue(val == 10);
            }
            
            j++;
        }
        Assert.assertTrue(j == 12);
        
        
        
        
       
        
        

    }

    
    
    
    
    
    
    
    
    
    

}