Skip to content

Feature Request: Include alternative in query result #341

Description

@matthias-stemmler

The following feature would be useful for Annimate and potentially other users of graphANNIS. I'm happy to contribute a PR, but I wanted to clarify first if this makes sense.

Feature Description

The CorpusStorage::find method currently returns a list of match IDs, each of which includes the matched node name and the matched annotation key. However, in case of an OR query with multiple alternatives, it's not possible to tell for a match which alternative of the query produced it. Using CorpusStorage::node_descriptions, it is only sometimes, but not always, possible to reconstruct this information from the number of nodes and/or the matched annotation keys.

It would be good to have a variant of CorpusStorage::find that returns the alternative index together with each match. For instance, for the query pos=/N.*/ | pos=/V.*/, it would return 0 if pos=/N.*/ matches and 1 if pos=/V.*/ matches. If multiple alternatives match at the same time, it would return the index of the first matching alternative.

Why is it useful?

There's a request in Annimate where a user wants to export the variable name (and possibly also the query fragment) of the query node that produces a given match node. If the alternative index for a match was known, one could filter the list returned from node_descriptions by this alternative index, after which it would nicely pair up (same count, matching order) with the node names returned from find.

API proposal

This could be a new method on CorpusStorage:

pub fn find_extra<S: AsRef<str>>(  // named after CorpusStorage::count_extra
    &self,
    query: SearchQuery<S>,
    offset: usize,
    limit: Option<usize>,
    order: ResultOrder,
) -> Result<Vec<MatchExtra>>;

#[non_exhaustive]
pub struct MatchExtra {      // named after `CountExtra`
    pub match_id: String,    // what is currently returned from `find`
    pub alternative: usize,  // NEW: the index of the alternative that produced the match, named after `QueryAttributeDescription::alternative`
}

With #[non_exhaustive], this can later be extended with more fields in a non-breaking way, e.g., with an information on which corpus a match comes from.

Other Considerations/Questions

  • This would expose the fact that queries are internally normalized to DNF, because alternative would refer to the alternatives of the DNF. However, that's already exposed through node_descriptions, so it should be fine, especially if we make it clear in the docs that alternative is supposed to be compared to QueryAttributeDescription::alternative.
  • Should the new functionality also be exposed via FFI? I only need the Rust API at this point.

Implementation complexity

I prototyped an implementation where I pass the necessary info from ExecutionPlan::from_disjunction to the API surface with relatively minor changes. The parts common to find and find_extra can be extracted to avoid duplication.


Would you accept such a contribution? Happy to discuss any changes!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions