/* * Copyright 2013 SFB 632. * * Licensed 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. */ package annis.dao.autogenqueries; import annis.GraphHelper; import annis.dao.QueryDao; import annis.examplequeries.ExampleQuery; import annis.ql.parser.QueryData; import annis.service.objects.AnnisCorpus; import annis.service.objects.Match; import annis.service.objects.MatchGroup; import annis.sqlgen.extensions.AnnotateQueryData; import annis.sqlgen.extensions.LimitOffsetQueryData; import java.sql.Types; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.corpus_tools.salt.common.SaltProject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; /** * Controlls the generating of automatic generated queries. * * For creating automatic generated queries, you have to implement the * {@link QueryBuilder} interface and register the new class in the * CommonDAO.xml file. * * @author Benjamin Weißenfels <b.pixeldrama@gmail.com> */ public class QueriesGenerator { private final Logger log = LoggerFactory.getLogger(QueriesGenerator.class); // for executing AQL queries private QueryDao queryDao; // only contains one element: the top level corpus id of the imported corpus private List<Long> corpusIds; // the name of the imported top level corpus private String corpusName; // defines which cols of the tmp table are selected private Map<String, String> tableInsertSelect; // a set of query builder, which generate the example queries. private Set<QueryBuilder> queryBuilder; // to execute some sql commands directly private JdbcTemplate jdbcTemplate; /** * All automatic generated queries must implement this interface. * */ public interface QueryBuilder { /** * Getter for a trial query, which is not put into the database. This is * used for retrieving a {@link SaltProject}, which could be analyzed with * {@link #analyzingQuery(de.hu_berlin.german.korpling.saltnpepper.salt.saltCommon.SaltProject)}. * * @return The final AQL query. */ public String getAQL(); /** * Specifies the size of the result set. * * @return Returns a {@link LimitOffsetQueryData}. May not be null. The * {@link AbstractAutoQuery} class provides a good default. */ public LimitOffsetQueryData getLimitOffsetQueryData(); /** * Specifies the left and right context of the query from {@link #getAQL()}. * Further you could set the segmentation layer. * * @return Returns a {@link AnnotateQueryData}. May not be null. The * {@link AbstractAutoQuery} class provides a good default. */ public AnnotateQueryData getAnnotateQueryData(); /** * Analyzes the resut of the {@link #getAQL()}. * * @param saltProject Is the result of the query, which is getting from * {@link #getAQL()}. */ public void analyzingQuery(SaltProject saltProject); /** * Provides the final example query. The {@link AbstractAutoQuery} class * provides a good default. * * @return The final {@link ExampleQuery}, which is written to the database. */ public ExampleQuery getExampleQuery(); } /** * Deletes all example queries for a specific corpus. * * @param corpusId References the corpus of the example queries. */ public void delExampleQueries(long corpusId) { log.info("delete example queries of {}", corpusId); jdbcTemplate.execute( "DELETE FROM example_queries WHERE corpus_ref = " + corpusId); } /** * Deletes all example queries for a given corpus list. * * @param corpusNames Determines the example queries to delete. If null the * example_querie tab is truncated. */ public void delExampleQueries(List<String> corpusNames) { if (corpusNames == null || corpusNames.isEmpty()) { log.info("delete all example queries"); jdbcTemplate.execute("TRUNCATE example_queries"); } else { List<Long> ids = queryDao.mapCorpusNamesToIds(corpusNames); for (Long id : ids) { delExampleQueries(id); } } } /** * Iterates over all registered {@link QueryBuilder} and generate example * queries. * * @param corpusId Determines the corpus, for which the example queries are * generated for. It must be the final ANNIS id of the corpus. * * @param delete Deletes the already existing example queries in the database. */ public void generateQueries(long corpusId, boolean delete) { if (delete) { delExampleQueries(corpusId); } generateQueries(corpusId); } /** * Iterates over all registered {@link QueryBuilder} and generate example * queries. * * @param corpusId Determines the corpus, for which the example queries are * generated for. It must be the final ANNIS id of the corpus. */ public void generateQueries(long corpusId) { corpusIds = new ArrayList<>(); corpusIds.add(corpusId); List<String> corpusNames = getQueryDao().mapCorpusIdsToNames(corpusIds); if(!corpusNames.isEmpty()) { corpusName = corpusNames.get(0); if (queryBuilder != null) { for (QueryBuilder qB : queryBuilder) { generateQuery(qB); } } } } /** * Iterates over all registered {@link QueryBuilder} and generate example * queries. * * @param name Determines the corpus, for which the example queries are * generated for. It must be the final ANNIS id of the corpus. */ public void generateQueries(String name, boolean delete) { List<String> names = new ArrayList<>(); names.add(name); List<Long> ids = queryDao.mapCorpusNamesToIds(names); if (!ids.isEmpty()) { generateQueries(ids.get(0), delete); } else { log.error("{} is unknown to the system", name); } } /** * Generates example queries for all imported corpora. * * @param overwrite Deletes already exisiting example queries. */ public void generateQueries(Boolean overwrite) { List<AnnisCorpus> corpora = queryDao.listCorpora(); for (AnnisCorpus annisCorpus : corpora) { generateQueries(annisCorpus.getId(), overwrite); } } private void generateQuery(QueryBuilder queryBuilder) { try { // retrieve the aql query for analyzing purposes String aql = queryBuilder.getAQL(); // set some necessary extensions for generating complete sql QueryData queryData = getQueryDao().parseAQL(aql, this.corpusIds); queryData.addExtension(queryBuilder.getLimitOffsetQueryData()); // retrieve the salt project to analyze List<Match> matches = getQueryDao().find(queryData); if(matches.isEmpty()) { return; } QueryData matchQueryData = GraphHelper.createQueryData(new MatchGroup(matches), queryDao); matchQueryData.addExtension(queryBuilder.getAnnotateQueryData()); SaltProject saltProject = getQueryDao().graph(matchQueryData); queryBuilder.analyzingQuery(saltProject); // set the corpus name ExampleQuery exampleQuery = queryBuilder.getExampleQuery(); exampleQuery.setCorpusName(corpusName); // copy the example query to the database if (exampleQuery.getExampleQuery() != null && !"".equals(exampleQuery.getExampleQuery())) { if (getTableInsertSelect().containsKey("example_queries")) { Object[] values = new Object[] { exampleQuery.getExampleQuery(), exampleQuery.getDescription(), exampleQuery.getType() == null ? "" : exampleQuery.getType(), exampleQuery.getNodes(), "{}", corpusIds.get(0) }; int[] argTypes = new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.VARCHAR, Types.INTEGER }; getJdbcTemplate().update("INSERT INTO example_queries(" + getTableInsertSelect().get("example_queries") + ") VALUES(?, ?, ?, ?, ?::text[], ?)", values, argTypes); log.info("generated example query: {}", exampleQuery.getExampleQuery()); } } else { log.warn("could not generating auto query with {}", queryBuilder. getClass().getName()); } } catch(Exception ex) { log.warn("Cannot generate example query", ex); } } /** * Defines the table columns of the temporary example query table are copied * to the final table. The important table name for example queries is * "example_queries". * * @return Returns a map of table names to column names. */ public Map<String, String> getTableInsertSelect() { return tableInsertSelect; } /** * Defines the table columns of the temporary example query table are copied * to the final table. This field is set by using spring beans. * * @param tableInsertSelect the tableInsertSelect to set */ public void setTableInsertSelect(Map<String, String> tableInsertSelect) { this.tableInsertSelect = tableInsertSelect; } /** * * @return the jdbcTemplate */ public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } /** * @param jdbcTemplate the jdbcTemplate to set */ public void setJdbcTemplate( JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /** * @return the queryDao */ public QueryDao getQueryDao() { return queryDao; } /** * @param queryDao the queryDao to set */ public void setQueryDao(QueryDao queryDao) { this.queryDao = queryDao; } /** * @return the queryBuilder */ public Set<QueryBuilder> getQueryBuilder() { return queryBuilder; } /** * @param queryBuilder the queryBuilder to set */ public void setQueryBuilder(Set<QueryBuilder> queryBuilder) { this.queryBuilder = queryBuilder; } }