0

I have a program wherein a hash map, in the form of a tuple serving as the key (which represents a sentence read from an input file), and an integer (the number of times it was observed in the data) is capable of being populated with data but incapable of responding to my attempt to print it's contents. It's populated inside of the 'for' loop in the code below, and at the bottom of that snippet is where it's meant to print.

public static void main(String[] args) throws IOException 
{
    Ontology ontology = new Ontology();
    BufferedReader br = new BufferedReader(new FileReader("/home/matthias/Workbench/SUTD/2_January/learning_first-order_horn_clauses_from_web_text/reverb/code/input_data/stackoverflow_test.txt"));
    Pattern p = Pattern.compile("'(.*?)'\\('(.*?)',\\s*'(.*?)'\\)\\.");
    String line;
    while ((line = br.readLine()) != null) 
    {
        Matcher m = p.matcher(line);
        if( m.matches() ) 
        {
            String verb    = m.group(1);
            String object  = m.group(2);
            String subject = m.group(3);
            ontology.addSentence( new Sentence( verb, object, subject ) );
        }
    }

    for( String joint: ontology.getJoints() )
    {
        for( Integer subind: ontology.getSubjectIndices( joint ) )
        {
            Sentence xaS = ontology.getSentence( subind );

            for( Integer obind: ontology.getObjectIndices( joint ) )
            {

                Sentence yOb = ontology.getSentence( obind );

                Sentence s = new Sentence( xaS.getVerb(),
                                           xaS.getObject(),
                                           yOb.getSubject() );

                //System.out.println( s );                
                ontology.numberRules( s ); 

            }
        }
    }
    for (Map.Entry<Sentence, Integer> entry : ontology.numberRules.entrySet()) 
    {
        System.out.println(entry.getKey()+" : "+entry.getValue());
    }     
}

The bottom of the following file is where the hash map is implemented. This also takes the input sentences and searches for overlapping values in the subject and object of sentences. What the system is trying to do is learn "rules" by inference from input data, i.e. contains(vitamin c, oranges), prevents(scurvy, vitamin c) would yeild the output prevents(scurvy, oranges), the thing is, in my test data there are many identical rules so i want to keep track of the number of times they're observed, while also storing only one copy of the unique "rule". which is why the hash map stores sentences as keys and integer (count) as value.

private List<Sentence> sentences = new ArrayList<>();
/*
 * The following maps store the relation of a string occurring
 * as a subject or object, respectively, to the list of Sentence
 * ordinals where they occur.
 */
private Map<String,List<Integer>> subject2index = new HashMap<>();
private Map<String,List<Integer>> object2index = new HashMap<>();

/*
 * This set contains strings that occur as both,
 * subject and object. This is useful for determining strings
 * acting as an in-between connecting two relations. 
 */
private Set<String> joints = new HashSet<>();

public void addSentence( Sentence s )
{

    // add Sentence to the list of all Sentences
    sentences.add( s );

    // add the Subject of the Sentence to the map mapping strings
    // occurring as a subject to the ordinal of this Sentence
    List<Integer> subind = subject2index.get( s.getSubject() );
    if( subind == null )
    {
        subind = new ArrayList<>();
        subject2index.put( s.getSubject(), subind );
    }
    subind.add( sentences.size() - 1 );

    // add the Object of the Sentence to the map mapping strings
    // occurring as an object to the ordinal of this Sentence
    List<Integer> objind = object2index.get( s.getObject() );
    if( objind == null )
    {
        objind = new ArrayList<>();
        object2index.put( s.getObject(), objind );
    }
    objind.add( sentences.size() - 1 );

    // determine whether we've found a "joining" string
    if( subject2index.containsKey( s.getObject() ) )
    {
        joints.add( s.getObject() );
    }
    if( object2index.containsKey( s.getSubject() ) )
    {
        joints.add( s.getSubject() );
    }
}

public Collection<String> getJoints()
{
    return joints;
}
public List<Integer> getSubjectIndices( String subject )
{
    return subject2index.get( subject );
}
public List<Integer> getObjectIndices( String object )
{
    return object2index.get( object );
}
public Sentence getSentence( int index )
{
    return sentences.get( index );
}

//map to store learned 'rules'
Map<Sentence, Integer> ruleCount = new HashMap<>();

//store data
public void numberRules(Sentence sentence) 
{
    if (!ruleCount.containsKey(sentence))
    {
        ruleCount.put(sentence, 0);
    }
    ruleCount.put(sentence, ruleCount.get(sentence) + 1);
}   

This is the object for storing sentences.

public class Sentence 
{
private String verb;
private String object;
private String subject;
public Sentence(String verb, String object, String subject )
{
    this.verb = verb;
    this.object = object;
    this.subject = subject;
}

public String getVerb()
{
    return verb; 
}

public String getObject()
{
    return object; 
}

public String getSubject()
{
    return subject;
}

public String toString()
{
    return verb + "(" + object + ", " + subject + ").";
}

}

input data looks like this

'prevents'('scurvy','vitamin C').
'contains'('vitamin C','orange').
'contains'('vitamin C','sauerkraut').
'isa'('fruit','orange').
'improves'('health','fruit').

I hope output data can tell me, for instance

prevents(scurvy, orange).      2
prevents(scurvy, sauerkraut).  4
improves(health, orange).      1

Where the sentences are the key of the hash map and the integer is the associated value, corresponding to the number of times that sentence was observed in the data.

5
  • Does your code compile or does it not? hash map 'cannot be resolved' looks like a compilation error, yet you claim you can execute the methods. Do you get any output? Commented Jan 25, 2015 at 8:29
  • your sentence class needs implement hashcode() and equals method Commented Jan 25, 2015 at 8:31
  • @Eran if i get rid of that print statement it compiles Commented Jan 25, 2015 at 8:32
  • @Hector what do you mean? Commented Jan 25, 2015 at 8:32
  • 1
    see this link "common mistake" programcreek.com/2011/07/java-equals-and-hashcode-contract Commented Jan 25, 2015 at 8:37

1 Answer 1

2

I don't see a numberRules member in your Ontology class.

Perhaps you meant to use the ruleCount member, which is the only variable of type Map<Sentence, Integer> I see in your code.

for (Map.Entry<Sentence, Integer> entry : ontology.ruleCount.entrySet()) 
{
    System.out.println(entry.getKey()+" : "+entry.getValue());
}  

Regarding Hector's comment, that's a different problem. When you use one of your custom classes as a key in a HashMap (Sentence class in your case), you must override equals and hashCode. If you don't a.equals(b) will return true only if a==b, which is probably not the behavior you desire. You probably want a.equals(b) to return true when the verb, object and subject of the two compared sentences are equal to each other respectively. hashCode should be implemented in a way that if a.equals(b) is true, a.hashCode() == b.hashCode().

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.