Skip to content

glazing.verbnet.search

Searching VerbNet data.

search

VerbNet search functionality.

This module provides search capabilities for VerbNet data, including searches by thematic roles, syntactic patterns, semantic predicates, selectional restrictions, and member verbs.

CLASS DESCRIPTION
VerbNetSearch

Search interface for VerbNet data.

Classes

VerbNetSearch(classes: list[VerbClass] | None = None)

Search interface for VerbNet data.

Provides methods for finding verb classes by various criteria including thematic roles, syntactic patterns, semantic predicates, and selectional restrictions.

PARAMETER DESCRIPTION
classes

Initial verb classes to index. If None, creates empty search.

TYPE: list[VerbClass] | None DEFAULT: None

ATTRIBUTE DESCRIPTION
_classes

Mapping from class ID to verb class object.

TYPE: dict[VerbClassID, VerbClass]

_classes_by_member

Mapping from member lemma to class IDs.

TYPE: dict[str, set[VerbClassID]]

_classes_by_role

Mapping from thematic role to class IDs.

TYPE: dict[ThematicRoleType, set[VerbClassID]]

_classes_by_predicate

Mapping from semantic predicate to class IDs.

TYPE: dict[PredicateType, set[VerbClassID]]

METHOD DESCRIPTION
add_class

Add a verb class to the search index.

by_themroles

Find classes with specified thematic roles.

by_syntax

Find classes with matching syntactic patterns.

by_predicate

Find classes using a specific semantic predicate.

by_predicates

Find classes using multiple semantic predicates.

by_restriction

Find classes with selectional restrictions.

by_members

Find classes containing specific member verbs.

complex_search

Multi-criteria search for verb classes.

Examples:

>>> search = VerbNetSearch()
>>> search.add_class(give_class)
>>> classes = search.by_themroles(["Agent", "Theme", "Recipient"])
>>> motion_classes = search.by_predicate("motion")

Initialize VerbNet search with optional initial classes.

Source code in src/glazing/verbnet/search.py
def __init__(self, classes: list[VerbClass] | None = None) -> None:
    """Initialize VerbNet search with optional initial classes."""
    self._classes: dict[VerbClassID, VerbClass] = {}
    self._classes_by_member: dict[str, set[VerbClassID]] = defaultdict(set)
    self._classes_by_role: dict[ThematicRoleType, set[VerbClassID]] = defaultdict(set)
    self._classes_by_predicate: dict[PredicateType, set[VerbClassID]] = defaultdict(set)

    if classes:
        for verb_class in classes:
            self.add_class(verb_class)
Functions
add_class(verb_class: VerbClass) -> None

Add a verb class to the search index.

PARAMETER DESCRIPTION
verb_class

Verb class to add to index.

TYPE: VerbClass

RAISES DESCRIPTION
ValueError

If class with same ID already exists.

Source code in src/glazing/verbnet/search.py
def add_class(self, verb_class: VerbClass) -> None:
    """Add a verb class to the search index.

    Parameters
    ----------
    verb_class : VerbClass
        Verb class to add to index.

    Raises
    ------
    ValueError
        If class with same ID already exists.
    """
    if verb_class.id in self._classes:
        msg = f"Class with ID {verb_class.id} already exists"
        raise ValueError(msg)

    self._classes[verb_class.id] = verb_class

    # Index members
    for member in verb_class.members:
        self._classes_by_member[member.name].add(verb_class.id)

    # Index thematic roles
    for role in verb_class.themroles:
        self._classes_by_role[role.type].add(verb_class.id)

    # Index semantic predicates
    for frame in verb_class.frames:
        for predicate in frame.semantics.predicates:
            self._classes_by_predicate[predicate.value].add(verb_class.id)

    # Recursively add subclasses
    for subclass in verb_class.subclasses:
        self.add_class(subclass)
by_members(lemmas: list[str]) -> list[VerbClass]

Find classes containing specific member verbs.

PARAMETER DESCRIPTION
lemmas

List of verb lemmas to search for.

TYPE: list[str]

RETURNS DESCRIPTION
list[VerbClass]

Verb classes containing any of the specified members.

Source code in src/glazing/verbnet/search.py
def by_members(self, lemmas: list[str]) -> list[VerbClass]:
    """Find classes containing specific member verbs.

    Parameters
    ----------
    lemmas : list[str]
        List of verb lemmas to search for.

    Returns
    -------
    list[VerbClass]
        Verb classes containing any of the specified members.
    """
    matching_ids = set()
    for lemma in lemmas:
        matching_ids |= self._classes_by_member.get(lemma, set())

    classes = [self._classes[cid] for cid in matching_ids]
    return sorted(classes, key=lambda c: c.id)
by_predicate(predicate: PredicateType) -> list[VerbClass]

Find classes using a specific semantic predicate.

PARAMETER DESCRIPTION
predicate

Semantic predicate to search for.

TYPE: PredicateType

RETURNS DESCRIPTION
list[VerbClass]

Verb classes using the predicate.

Source code in src/glazing/verbnet/search.py
def by_predicate(self, predicate: PredicateType) -> list[VerbClass]:
    """Find classes using a specific semantic predicate.

    Parameters
    ----------
    predicate : PredicateType
        Semantic predicate to search for.

    Returns
    -------
    list[VerbClass]
        Verb classes using the predicate.
    """
    class_ids = self._classes_by_predicate.get(predicate, set())
    classes = [self._classes[cid] for cid in class_ids]
    return sorted(classes, key=lambda c: c.id)
by_predicates(predicates: list[PredicateType], require_all: bool = True) -> list[VerbClass]

Find classes using multiple semantic predicates.

PARAMETER DESCRIPTION
predicates

List of semantic predicates to search for.

TYPE: list[PredicateType]

require_all

If True, require all predicates. If False, require at least one.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
list[VerbClass]

Verb classes using the predicates.

Source code in src/glazing/verbnet/search.py
def by_predicates(
    self, predicates: list[PredicateType], require_all: bool = True
) -> list[VerbClass]:
    """Find classes using multiple semantic predicates.

    Parameters
    ----------
    predicates : list[PredicateType]
        List of semantic predicates to search for.
    require_all : bool
        If True, require all predicates. If False, require at least one.

    Returns
    -------
    list[VerbClass]
        Verb classes using the predicates.
    """
    if not predicates:
        return []

    if require_all:
        # Intersection of classes for all predicates
        matching_ids = None
        for predicate in predicates:
            pred_classes = self._classes_by_predicate.get(predicate, set())
            if matching_ids is None:
                matching_ids = pred_classes.copy()
            else:
                matching_ids &= pred_classes

        if matching_ids is None:
            return []
    else:
        # Union of classes for any predicate
        matching_ids = set()
        for predicate in predicates:
            matching_ids |= self._classes_by_predicate.get(predicate, set())

    classes = [self._classes[cid] for cid in matching_ids]
    return sorted(classes, key=lambda c: c.id)
by_restriction(role: ThematicRoleType, restriction_type: SelectionalRestrictionType, value: RestrictionValue) -> list[VerbClass]

Find classes with selectional restrictions.

PARAMETER DESCRIPTION
role

Thematic role to check restrictions on.

TYPE: ThematicRoleType

restriction_type

Type of selectional restriction.

TYPE: SelectionalRestrictionType

value

Restriction value ("+" or "-").

TYPE: RestrictionValue

RETURNS DESCRIPTION
list[VerbClass]

Verb classes with matching restrictions.

Source code in src/glazing/verbnet/search.py
def by_restriction(
    self,
    role: ThematicRoleType,
    restriction_type: SelectionalRestrictionType,
    value: RestrictionValue,
) -> list[VerbClass]:
    """Find classes with selectional restrictions.

    Parameters
    ----------
    role : ThematicRoleType
        Thematic role to check restrictions on.
    restriction_type : SelectionalRestrictionType
        Type of selectional restriction.
    value : RestrictionValue
        Restriction value ("+" or "-").

    Returns
    -------
    list[VerbClass]
        Verb classes with matching restrictions.
    """
    matching_classes = []

    for verb_class in self._classes.values():
        for themrole in verb_class.themroles:
            if (
                themrole.type == role
                and themrole.sel_restrictions
                and self._has_restriction(themrole.sel_restrictions, restriction_type, value)
            ):
                matching_classes.append(verb_class)
                break

    return sorted(matching_classes, key=lambda c: c.id)
by_role_properties(optional: bool | None = None, indexed: bool | None = None, verb_specific: bool | None = None, pp_type: str | None = None) -> list[VerbClass]

Find classes by role properties.

PARAMETER DESCRIPTION
optional

Filter for optional roles (? prefix).

TYPE: bool | None DEFAULT: None

indexed

Filter for indexed roles (_I, _J suffix).

TYPE: bool | None DEFAULT: None

verb_specific

Filter for verb-specific roles (V_ prefix).

TYPE: bool | None DEFAULT: None

pp_type

Filter for specific PP type.

TYPE: str | None DEFAULT: None

RETURNS DESCRIPTION
list[VerbClass]

Classes with matching role properties.

Source code in src/glazing/verbnet/search.py
def by_role_properties(
    self,
    optional: bool | None = None,
    indexed: bool | None = None,
    verb_specific: bool | None = None,
    pp_type: str | None = None,
) -> list[VerbClass]:
    """Find classes by role properties.

    Parameters
    ----------
    optional : bool | None, optional
        Filter for optional roles (? prefix).
    indexed : bool | None, optional
        Filter for indexed roles (_I, _J suffix).
    verb_specific : bool | None, optional
        Filter for verb-specific roles (V_ prefix).
    pp_type : str | None, optional
        Filter for specific PP type.

    Returns
    -------
    list[VerbClass]
        Classes with matching role properties.
    """
    matching_classes = []
    for verb_class in self._classes.values():
        filtered_roles = filter_roles_by_properties(
            verb_class.themroles,
            optional=optional,
            indexed=indexed,
            verb_specific=verb_specific,
            base_role=pp_type,  # pp_type maps to base_role
        )
        if filtered_roles:
            matching_classes.append(verb_class)

    return sorted(matching_classes, key=lambda c: c.id)
by_syntax(pattern: str) -> list[VerbClass]

Find classes with matching syntactic patterns.

Supports hierarchical matching where general patterns match specific ones: - "NP V PP" matches "NP V PP.instrument", "NP V PP.goal", etc. - "NP V NP *" matches any frame with NP V NP followed by anything

PARAMETER DESCRIPTION
pattern

Syntactic pattern to search for (e.g., "NP V PP", "NP V PP.instrument").

TYPE: str

RETURNS DESCRIPTION
list[VerbClass]

Verb classes with frames matching the pattern.

Source code in src/glazing/verbnet/search.py
def by_syntax(self, pattern: str) -> list[VerbClass]:
    """Find classes with matching syntactic patterns.

    Supports hierarchical matching where general patterns match specific ones:
    - "NP V PP" matches "NP V PP.instrument", "NP V PP.goal", etc.
    - "NP V NP *" matches any frame with NP V NP followed by anything

    Parameters
    ----------
    pattern : str
        Syntactic pattern to search for (e.g., "NP V PP", "NP V PP.instrument").

    Returns
    -------
    list[VerbClass]
        Verb classes with frames matching the pattern.
    """
    parser = SyntaxParser()
    query_pattern = parser.parse(pattern)
    matching_class_ids = set()

    for verb_class in self._classes.values():
        for frame in verb_class.frames:
            # Extract pattern from VerbNet frame syntax elements
            frame_pattern = parser.parse_verbnet_elements(frame.syntax.elements)

            # Check for pattern match
            if self._patterns_match(query_pattern, frame_pattern):
                matching_class_ids.add(verb_class.id)
                break  # Found match in this class

    classes = [self._classes[cid] for cid in matching_class_ids]
    return sorted(classes, key=lambda c: c.id)
by_themroles(roles: list[ThematicRoleType], only: bool = False) -> list[VerbClass]

Find classes with specified thematic roles.

PARAMETER DESCRIPTION
roles

List of thematic role types to search for.

TYPE: list[ThematicRoleType]

only

If True, return only classes with exactly these roles. If False, return classes containing at least these roles.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
list[VerbClass]

Verb classes matching the role criteria.

Source code in src/glazing/verbnet/search.py
def by_themroles(self, roles: list[ThematicRoleType], only: bool = False) -> list[VerbClass]:
    """Find classes with specified thematic roles.

    Parameters
    ----------
    roles : list[ThematicRoleType]
        List of thematic role types to search for.
    only : bool
        If True, return only classes with exactly these roles.
        If False, return classes containing at least these roles.

    Returns
    -------
    list[VerbClass]
        Verb classes matching the role criteria.
    """
    if not roles:
        return []

    # Find classes with all specified roles
    matching_ids = None
    for role in roles:
        role_classes = self._classes_by_role.get(role, set())
        if matching_ids is None:
            matching_ids = role_classes.copy()
        else:
            matching_ids &= role_classes

    if matching_ids is None:
        return []

    # Get classes
    classes = [self._classes[cid] for cid in matching_ids]

    # If only exact matches requested, filter further
    if only:
        filtered = []
        role_set = set(roles)
        for verb_class in classes:
            class_roles = {r.type for r in verb_class.themroles}
            if class_roles == role_set:
                filtered.append(verb_class)
        classes = filtered

    return sorted(classes, key=lambda c: c.id)

Multi-criteria search for verb classes.

PARAMETER DESCRIPTION
predicates

Semantic predicates to require.

TYPE: list[PredicateType] | None DEFAULT: None

themroles

Thematic roles to require.

TYPE: list[ThematicRoleType] | None DEFAULT: None

restrictions

ThematicRoleType, list[tuple[RestrictionValue, SelectionalRestrictionType]]

TYPE: dict[ DEFAULT: None

syntax

Syntactic pattern to match.

TYPE: str | None DEFAULT: None

RETURNS DESCRIPTION
list[VerbClass]

Verb classes matching all specified criteria.

Source code in src/glazing/verbnet/search.py
def complex_search(
    self,
    predicates: list[PredicateType] | None = None,
    themroles: list[ThematicRoleType] | None = None,
    restrictions: (
        dict[ThematicRoleType, list[tuple[RestrictionValue, SelectionalRestrictionType]]] | None
    ) = None,
    syntax: str | None = None,
) -> list[VerbClass]:
    """Multi-criteria search for verb classes.

    Parameters
    ----------
    predicates : list[PredicateType] | None
        Semantic predicates to require.
    themroles : list[ThematicRoleType] | None
        Thematic roles to require.
    restrictions : dict[
        ThematicRoleType, list[tuple[RestrictionValue, SelectionalRestrictionType]]
    ] | None
        Selectional restrictions by role.
    syntax : str | None
        Syntactic pattern to match.

    Returns
    -------
    list[VerbClass]
        Verb classes matching all specified criteria.
    """
    # Start with all classes
    results = set(self._classes.keys())

    # Apply filters progressively
    results = self._filter_by_predicates(results, predicates)
    results = self._filter_by_thematic_roles(results, themroles)

    if not results:  # Early exit if no classes remain
        return []

    results = self._filter_by_restrictions(results, restrictions)
    results = self._filter_by_syntax(results, syntax)

    # Get class objects and sort
    classes = [self._classes[cid] for cid in results]
    return sorted(classes, key=lambda c: c.id)
from_jsonl_file(path: Path | str) -> VerbNetSearch classmethod

Load search index from JSON Lines file.

PARAMETER DESCRIPTION
path

Path to JSON Lines file containing verb classes.

TYPE: Path | str

RETURNS DESCRIPTION
VerbNetSearch

Search index populated with classes from file.

RAISES DESCRIPTION
FileNotFoundError

If file does not exist.

ValueError

If file contains invalid data.

Source code in src/glazing/verbnet/search.py
@classmethod
def from_jsonl_file(cls, path: Path | str) -> VerbNetSearch:
    """Load search index from JSON Lines file.

    Parameters
    ----------
    path : Path | str
        Path to JSON Lines file containing verb classes.

    Returns
    -------
    VerbNetSearch
        Search index populated with classes from file.

    Raises
    ------
    FileNotFoundError
        If file does not exist.
    ValueError
        If file contains invalid data.
    """
    path = Path(path)
    if not path.exists():
        msg = f"File not found: {path}"
        raise FileNotFoundError(msg)

    classes = []
    with path.open(encoding="utf-8") as f:
        for line_raw in f:
            line = line_raw.strip()
            if line:
                verb_class = VerbClass.model_validate_json(line)
                classes.append(verb_class)

    return cls(classes)
get_all_classes() -> list[VerbClass]

Get all verb classes in the search index.

RETURNS DESCRIPTION
list[VerbClass]

All verb classes sorted by ID.

Source code in src/glazing/verbnet/search.py
def get_all_classes(self) -> list[VerbClass]:
    """Get all verb classes in the search index.

    Returns
    -------
    list[VerbClass]
        All verb classes sorted by ID.
    """
    return sorted(self._classes.values(), key=lambda c: c.id)
get_all_members() -> list[str]

Get all unique member lemmas.

RETURNS DESCRIPTION
list[str]

Sorted list of unique member lemmas.

Source code in src/glazing/verbnet/search.py
def get_all_members(self) -> list[str]:
    """Get all unique member lemmas.

    Returns
    -------
    list[str]
        Sorted list of unique member lemmas.
    """
    return sorted(self._classes_by_member.keys())
get_all_predicates() -> list[PredicateType]

Get all unique semantic predicates.

RETURNS DESCRIPTION
list[PredicateType]

Sorted list of unique predicates.

Source code in src/glazing/verbnet/search.py
def get_all_predicates(self) -> list[PredicateType]:
    """Get all unique semantic predicates.

    Returns
    -------
    list[PredicateType]
        Sorted list of unique predicates.
    """
    return sorted(self._classes_by_predicate.keys())
get_all_roles() -> list[ThematicRoleType]

Get all unique thematic roles.

RETURNS DESCRIPTION
list[ThematicRoleType]

Sorted list of unique roles.

Source code in src/glazing/verbnet/search.py
def get_all_roles(self) -> list[ThematicRoleType]:
    """Get all unique thematic roles.

    Returns
    -------
    list[ThematicRoleType]
        Sorted list of unique roles.
    """
    return sorted(self._classes_by_role.keys())
get_by_id(class_id: VerbClassID) -> VerbClass | None

Get a verb class by its ID.

PARAMETER DESCRIPTION
class_id

ID of the verb class to retrieve.

TYPE: VerbClassID

RETURNS DESCRIPTION
VerbClass | None

The verb class if found, None otherwise.

Source code in src/glazing/verbnet/search.py
def get_by_id(self, class_id: VerbClassID) -> VerbClass | None:
    """Get a verb class by its ID.

    Parameters
    ----------
    class_id : VerbClassID
        ID of the verb class to retrieve.

    Returns
    -------
    VerbClass | None
        The verb class if found, None otherwise.
    """
    return self._classes.get(class_id)
get_statistics() -> dict[str, int]

Get search index statistics.

RETURNS DESCRIPTION
dict[str, int]

Statistics about indexed data.

Source code in src/glazing/verbnet/search.py
def get_statistics(self) -> dict[str, int]:
    """Get search index statistics.

    Returns
    -------
    dict[str, int]
        Statistics about indexed data.
    """
    total_members = sum(len(c.members) for c in self._classes.values())
    total_frames = sum(len(c.frames) for c in self._classes.values())

    return {
        "class_count": len(self._classes),
        "unique_predicates": len(self._classes_by_predicate),
        "unique_roles": len(self._classes_by_role),
        "unique_members": len(self._classes_by_member),
        "total_members": total_members,
        "total_frames": total_frames,
    }

Functions