private NLGElement getNLFromExpressions(List<Expr> expressions) { List<NLGElement> nlgs = new ArrayList<NLGElement>(); NLGElement elt; for (Expr e : expressions) { elt = getNLFromSingleExpression(e); if (elt != null) { nlgs.add(elt); } } // now process if (nlgs.isEmpty()) { return null; } if (nlgs.size() == 1) { return nlgs.get(0); } else { CoordinatedPhraseElement cpe; cpe = nlgFactory.createCoordinatedPhrase(nlgs.get(0), nlgs.get(1)); for (int i = 2; i < nlgs.size(); i++) { cpe.addComplement(nlgs.get(i)); } cpe.setConjunction("and"); return cpe; } }
public NLGElement getNLForTripleList(List<Triple> triples, String conjunction) { if (triples.isEmpty()) { return null; } if (triples.size() == 1) { return getNLForTriple(triples.get(0)); } else { CoordinatedPhraseElement cpe; Triple t0 = triples.get(0); Triple t1 = triples.get(1); cpe = nlgFactory.createCoordinatedPhrase(getNLForTriple(t0), getNLForTriple(t1)); for (int i = 2; i < triples.size(); i++) { cpe.addCoordinate(getNLForTriple(triples.get(i))); } cpe.setConjunction(conjunction); return cpe; } }
/** * Processes a list of elements. These can be elements of the where clause or of an optional * clause * * @param e List of query elements * @return Conjunctive natural representation of the list of elements. */ public NLGElement getNLFromElements(List<Element> e) { if (e.isEmpty()) { return null; } if (e.size() == 1) { return getNLFromSingleClause(e.get(0)); } else { CoordinatedPhraseElement cpe; cpe = nlgFactory.createCoordinatedPhrase( getNLFromSingleClause(e.get(0)), getNLFromSingleClause(e.get(1))); for (int i = 2; i < e.size(); i++) { cpe.addCoordinate(getNLFromSingleClause(e.get(i))); } cpe.setConjunction("and"); return cpe; } }
private NLGElement processTypes( Map<String, Set<String>> typeMap, Set<String> vars, boolean count, boolean distinct) { List<NPPhraseSpec> objects = new ArrayList<NPPhraseSpec>(); // process the type information to create the object(s) for (String s : typeMap.keySet()) { if (vars.contains(s)) { // contains the objects to the sentence NPPhraseSpec object; object = nlgFactory.createNounPhrase("?" + s); Set<String> types = typeMap.get(s); if (types.size() == 1) { NPPhraseSpec np = getNPPhrase(types.iterator().next(), true); if (distinct) { np.addModifier("distinct"); } object.addPreModifier(np); } else { Iterator<String> typeIterator = types.iterator(); String type0 = typeIterator.next(); String type1 = typeIterator.next(); NPPhraseSpec np0 = getNPPhrase(type0, true); // if (distinct) { // np0.addModifier("distinct"); // } NPPhraseSpec np1 = getNPPhrase(type1, true); // if (distinct) { // np1.addModifier("distinct"); // } CoordinatedPhraseElement cpe = nlgFactory.createCoordinatedPhrase(np0, np1); while (typeIterator.hasNext()) { NPPhraseSpec np = getNPPhrase(typeIterator.next(), true); // if (distinct) { // np.addModifier("distinct"); // } cpe.addCoordinate(np); } cpe.setConjunction("as well as"); if (distinct) { cpe.addPreModifier("distinct"); } object.addPreModifier(cpe); } object.setFeature(Feature.CONJUNCTION, "or"); objects.add(object); } } if (objects.size() == 1) { // if(count) objects.get(0).addPreModifier("the number of"); return objects.get(0); } else { CoordinatedPhraseElement cpe = nlgFactory.createCoordinatedPhrase(objects.get(0), objects.get(1)); if (objects.size() > 2) { for (int i = 2; i < objects.size(); i++) { cpe.addCoordinate(objects.get(i)); } } // if(count) cpe.addPreModifier("the number of"); return cpe; } }
/** * Generates a natural language representation for SELECT queries * * @param query Input query * @return Natural Language Representation */ public DocumentElement convertSelectAndAsk(Query query) { // List of sentences for the output List<DocumentElement> sentences = new ArrayList<DocumentElement>(); // System.out.println("Input query = " + query); // preprocess the query to get the relevant types TypeExtractor tEx = new TypeExtractor(endpoint); Map<String, Set<String>> typeMap = tEx.extractTypes(query); // System.out.println("Processed query = " + query); // contains the beginning of the query, e.g., "this query returns" SPhraseSpec head = nlgFactory.createClause(); String conjunction = "such that"; NLGElement body; NLGElement postConditions; List<Element> whereElements = getWhereElements(query); List<Element> optionalElements = getOptionalElements(query); // first sort out variables Set<String> projectionVars = typeMap.keySet(); Set<String> whereVars = getVars(whereElements, projectionVars); // case we only have stuff such as rdf:type queries if (whereVars.isEmpty()) { whereVars = projectionVars; } Set<String> optionalVars = getVars(optionalElements, projectionVars); // important. Remove variables that have already been declared in first // sentence from second sentence for (String var : whereVars) { if (optionalVars.contains(var)) { optionalVars.remove(var); } } // process SELECT queries if (query.isSelectType()) { // process head // we could create a lexicon from which we could read these head.setSubject("This query"); if (!tEx.isCount()) { head.setVerb("retrieve"); } else { head.setVerb("retrieve the number of"); } } // process ASK queries else { // process factual ask queries (no variables at all) if (typeMap.isEmpty()) { head.setSubject("This query"); head.setVerb("ask whether"); head.setObject(getNLFromElements(whereElements)); head.setFeature(Feature.SUPRESSED_COMPLEMENTISER, true); phrases.add(head); sentences.add(nlgFactory.createSentence(head)); return nlgFactory.createParagraph(sentences); } // process head // we could create a lexicon from which we could read these head.setSubject("This query"); head.setVerb("ask for the existence of"); } NLGElement e = processTypes(typeMap, whereVars, tEx.isCount(), query.isDistinct()); head.setObject(e); // now generate body if (!whereElements.isEmpty()) { body = getNLFromElements(whereElements); // now add conjunction CoordinatedPhraseElement phrase1 = nlgFactory.createCoordinatedPhrase(head, body); phrase1.setConjunction("such that"); // add as first sentence sentences.add(nlgFactory.createSentence(phrase1)); phrases.add(phrase1); // this concludes the first sentence. } else { sentences.add(nlgFactory.createSentence(head)); phrases.add(head); } // The second sentence deals with the optional clause (if it exists) if (optionalElements != null && !optionalElements.isEmpty()) { // the optional clause exists // if no supplementary projection variables are used in the clause if (optionalVars.isEmpty()) { SPhraseSpec optionalHead = nlgFactory.createClause(); optionalHead.setSubject("it"); optionalHead.setVerb("retrieve"); optionalHead.setObject("data"); optionalHead.setFeature(Feature.CUE_PHRASE, "Additionally, "); NLGElement optionalBody = getNLFromElements(optionalElements); CoordinatedPhraseElement optionalPhrase = nlgFactory.createCoordinatedPhrase(optionalHead, optionalBody); optionalPhrase.setConjunction("such that"); optionalPhrase.addComplement("if such exist"); sentences.add(nlgFactory.createSentence(optionalPhrase)); } // if supplementary projection variables are used in the clause else { SPhraseSpec optionalHead = nlgFactory.createClause(); optionalHead.setSubject("it"); optionalHead.setVerb("retrieve"); optionalHead.setObject( processTypes(typeMap, optionalVars, query.isDistinct(), query.isDistinct())); optionalHead.setFeature(Feature.CUE_PHRASE, "Additionally, "); if (!optionalElements.isEmpty()) { NLGElement optionalBody; optionalBody = getNLFromElements(optionalElements); // now add conjunction CoordinatedPhraseElement optionalPhrase = nlgFactory.createCoordinatedPhrase(optionalHead, optionalBody); optionalPhrase.setConjunction("such that"); // add as second sentence optionalPhrase.addComplement("if such exist"); sentences.add(nlgFactory.createSentence(optionalPhrase)); phrases.add(optionalPhrase); // this concludes the second sentence. } else { optionalHead.addComplement("if such exist"); sentences.add(nlgFactory.createSentence(optionalHead)); phrases.add(optionalHead); } } } // The last sentence deals with the result modifiers if (query.hasHaving()) { SPhraseSpec modifierHead = nlgFactory.createClause(); modifierHead.setSubject("it"); modifierHead.setVerb("return exclusively"); modifierHead.setObject("results"); modifierHead.getObject().setPlural(true); modifierHead.setFeature(Feature.CUE_PHRASE, "Moreover, "); List<Expr> expressions = query.getHavingExprs(); CoordinatedPhraseElement phrase = nlgFactory.createCoordinatedPhrase(modifierHead, getNLFromExpressions(expressions)); phrase.setConjunction("such that"); sentences.add(nlgFactory.createSentence(phrase)); } if (query.hasOrderBy()) { SPhraseSpec order = nlgFactory.createClause(); order.setSubject("The results"); order.getSubject().setPlural(true); order.setVerb("be ordered by"); List<SortCondition> sc = query.getOrderBy(); if (sc.size() == 1) { Expr expr = sc.get(0).getExpression(); if (expr instanceof ExprVar) { ExprVar ev = (ExprVar) expr; order.setObject(ev.toString()); } if (sc.get(0).direction < 0) { order.addComplement("in descending order"); } else { order.addComplement("in ascending order"); } } phrases.add(order); sentences.add(nlgFactory.createSentence(order)); } if (query.hasLimit()) { SPhraseSpec limitOffset = nlgFactory.createClause(); long limit = query.getLimit(); if (query.hasOffset()) { long offset = query.getOffset(); limitOffset.setSubject("The query"); limitOffset.setVerb("return"); limitOffset.setObject("results between number " + limit + " and " + (offset + limit)); } else { limitOffset.setSubject("The query"); limitOffset.setVerb("return"); if (limit > 1) { if (query.hasOrderBy()) { limitOffset.setObject("at most the first " + limit + " results"); } else { limitOffset.setObject("at most " + limit + " results"); } } else { if (query.hasOrderBy()) { limitOffset.setObject("at most the first result"); } else { limitOffset.setObject("at most one result"); } } } phrases.add(limitOffset); sentences.add(nlgFactory.createSentence(limitOffset)); } DocumentElement result = nlgFactory.createParagraph(sentences); return result; }