The QueryBuilder class provides a fluent API for constructing complex Europe PMC search queries with type safety and validation.
from pyeuropepmc import QueryBuilder
qb = QueryBuilder(validate=False) # Optional validation
QueryBuilder(validate: bool = False) -> QueryBuilder
Parameters:
validate (bool, optional): Whether to validate queries using search-query package. Defaults to False.Add a keyword search term.
keyword(term: str, field: FieldType | None = None) -> QueryBuilder
Parameters:
term (str): Search termfield (FieldType, optional): Field to search inReturns: QueryBuilder (for method chaining)
Example:
qb.keyword("cancer").keyword("therapy", field="title")
Generic field search with optional value transformation.
field(
field_name: FieldType,
value: str | int | bool,
escape: bool = True,
transform: Callable[[str | int | bool], str | int | bool] | None = None
) -> QueryBuilder
Parameters:
field_name (FieldType): Field to search (e.g., “author”, “title”)value (str |
int | bool): Search value |
escape (bool, optional): Whether to escape special characters. Defaults to True.transform (Callable, optional): Function to transform value before formattingReturns: QueryBuilder (for method chaining)
Examples:
# Basic field search
qb.field("author", "Smith J")
# With transformation
qb.field("pmcid", "1234567", transform=lambda x: f"PMC{x}" if not str(x).startswith("PMC") else str(x))
Add publication date constraints.
date_range(
start_year: int | None = None,
end_year: int | None = None,
start_date: str | None = None,
end_date: str | None = None
) -> QueryBuilder
Parameters:
start_year (int, optional): Start year (inclusive)end_year (int, optional): End year (inclusive)start_date (str, optional): Start date in YYYY-MM-DD formatend_date (str, optional): End date in YYYY-MM-DD formatReturns: QueryBuilder (for method chaining)
Examples:
# Year range
qb.date_range(start_year=2020, end_year=2023)
# Date range
qb.date_range(start_date="2020-01-01", end_date="2023-12-31")
Add citation count filters.
citation_count(min_count: int | None = None, max_count: int | None = None) -> QueryBuilder
Parameters:
min_count (int, optional): Minimum citation count (inclusive)max_count (int, optional): Maximum citation count (inclusive)Returns: QueryBuilder (for method chaining)
Examples:
# Papers with at least 10 citations
qb.citation_count(min_count=10)
# Papers with 5-50 citations
qb.citation_count(min_count=5, max_count=50)
Search by PMC ID.
pmcid(pmcid: str) -> QueryBuilder
Parameters:
pmcid (str): PMC ID (with or without “PMC” prefix)Returns: QueryBuilder (for method chaining)
Example:
qb.pmcid("PMC1234567") # Also accepts "1234567"
Search by data source.
source(source: str) -> QueryBuilder
Parameters:
source (str): Data source code (e.g., “MED”, “PMC”, “AGR”)Returns: QueryBuilder (for method chaining)
Example:
qb.source("MED")
Search by accession type.
accession_type(accession_type: str) -> QueryBuilder
Parameters:
accession_type (str): Accession type (automatically lowercased)Returns: QueryBuilder (for method chaining)
Example:
qb.accession_type("pdb") # Automatically lowercased
Search for papers that cite a specific article.
cites(article_id: str, source: str = "med") -> QueryBuilder
Parameters:
article_id (str): Article ID to find citations forsource (str, optional): Data source. Defaults to “med”.Returns: QueryBuilder (for method chaining)
Example:
qb.cites("8521067", source="med")
Add AND operator between query parts.
and_() -> QueryBuilder
Returns: QueryBuilder (for method chaining)
Example:
qb.keyword("cancer").and_().keyword("therapy")
Add OR operator between query parts.
or_() -> QueryBuilder
Returns: QueryBuilder (for method chaining)
Example:
qb.keyword("cancer").or_().keyword("tumor")
Add NOT operator before the next query part.
not_() -> QueryBuilder
Returns: QueryBuilder (for method chaining)
Example:
qb.keyword("cancer").and_().not_().keyword("review")
Add a grouped sub-query.
group(builder: QueryBuilder) -> QueryBuilder
Parameters:
builder (QueryBuilder): Sub-query to groupReturns: QueryBuilder (for method chaining)
Example:
sub_query = QueryBuilder().keyword("cancer").or_().keyword("tumor")
qb.group(sub_query).and_().keyword("therapy")
Add raw query string.
raw(query_string: str) -> QueryBuilder
Parameters:
query_string (str): Raw query stringReturns: QueryBuilder (for method chaining)
Example:
qb.raw("(cancer OR tumor) AND therapy")
Build and return the final query string.
build(validate: bool = True) -> str
Parameters:
validate (bool, optional): Whether to validate the query. Defaults to True.Returns: str - The constructed query string
Example:
query = qb.keyword("cancer").and_().keyword("therapy").build()
print(query) # "cancer AND therapy"
Save query to JSON file in standard format.
save(
file_path: str,
platform: str = "pubmed",
authors: list[dict[str, str]] | None = None,
record_info: dict[str, Any] | None = None,
date_info: dict[str, str] | None = None,
database: list[str] | None = None,
include_generic: bool = False
) -> None
Parameters:
file_path (str): Path to save JSON fileplatform (str, optional): Query platform. Defaults to “pubmed”.authors (list[dict[str, str]], optional): Author informationrecord_info (dict, optional): Additional record metadatadate_info (dict, optional): Date informationdatabase (list[str], optional): Database informationinclude_generic (bool, optional): Include generic query representationLoad query from string.
@classmethod
from_string(
query_string: str,
platform: str = "pubmed",
validate: bool = False
) -> QueryBuilder
Parameters:
query_string (str): Query string to parseplatform (str, optional): Platform syntax. Defaults to “pubmed”.validate (bool, optional): Whether to validate. Defaults to False.Returns: QueryBuilder instance
Load query from JSON file.
@classmethod
from_file(file_path: str, validate: bool = False) -> QueryBuilder
Parameters:
file_path (str): Path to JSON filevalidate (bool, optional): Whether to validate. Defaults to False.Returns: QueryBuilder instance
Translate query to another platform’s syntax.
translate(target_platform: str) -> str
Parameters:
target_platform (str): Target platform (“pubmed”, “wos”, “ebsco”, “generic”)Returns: str - Query in target platform syntax
Example:
qb = QueryBuilder.from_string('("cancer"[Title])', platform="pubmed")
wos_query = qb.translate("wos") # TI="cancer"
Convert to search-query Query object.
to_query_object(platform: str = "pubmed") -> Any
Parameters:
platform (str, optional): Platform for parsing. Defaults to “pubmed”.Returns: Query object from search-query package
Evaluate search effectiveness against records.
evaluate(records: dict[str, dict[str, str]], platform: str = "pubmed") -> dict[str, float]
Parameters:
records (dict): Records with IDs as keys, containing ‘title’ and ‘colrev_status’platform (str, optional): Platform for evaluation. Defaults to “pubmed”.Returns: dict with ‘recall’, ‘precision’, and ‘f1_score’
Log query to SearchLog for systematic review tracking.
log_to_search(
search_log: Any,
database: str = "Europe PMC",
filters: dict[str, Any] | None = None,
results_returned: int | None = None,
notes: str | None = None,
raw_results: Any = None,
raw_results_dir: str | None = None,
platform: str | None = None,
export_path: str | None = None
) -> None
Parameters:
search_log (SearchLog): SearchLog instance to record querydatabase (str, optional): Database name. Defaults to “Europe PMC”.filters (dict, optional): Applied filtersresults_returned (int, optional): Number of results returnednotes (str, optional): Additional notesraw_results (Any, optional): Raw API responseraw_results_dir (str, optional): Directory for raw resultsplatform (str, optional): Search platform usedexport_path (str, optional): Path to exported resultsThe FieldType literal type includes all 150+ searchable fields:
Core Fields: title, abstract, author, journal, doi, pmid, pmcid
Date Fields: pub_year, first_pdate, e_pdate, update_date
Author Fields: affiliation, authorid, auth_first, auth_last
Content Fields: keyword, mesh, chemical, disease, gene_protein
Citation Fields: citation_count, cites, cited, reffed_by
Full-Text Fields: has_pdf, has_fulltext, open_access, in_pmc
And many more… See Field Metadata for complete list.
QueryBuilder uses specific error codes:
QUERY001: Empty or invalid query parametersQUERY002: Invalid date/year/citation valuesQUERY003: Incorrect operator usageQUERY004: Query parsing/validation failuresCONFIG003: Missing search-query dependencyfrom pyeuropepmc import QueryBuilder
qb = QueryBuilder()
# Simple keyword search
query1 = qb.keyword("machine learning").build()
# "machine learning"
# Field-specific search
query2 = qb.field("author", "Smith J").build()
# "AUTH:Smith J"
# Complex query with operators
query3 = (qb
.keyword("cancer", field="title")
.and_()
.keyword("therapy")
.and_()
.date_range(start_year=2020)
.build())
# "(TITLE:cancer) AND therapy AND (PUB_YEAR:[2020 TO *])"
# Citation-based filtering
query = (qb
.keyword("CRISPR")
.and_()
.citation_count(min_count=50)
.build())
# Multi-field search with OR logic
query = (qb
.field("title", "machine learning")
.or_()
.field("abstract", "machine learning")
.and_()
.field("pub_year", 2023)
.build())
# Complex nested query
sub_query = QueryBuilder().keyword("cancer").or_().keyword("tumor")
main_query = (qb
.group(sub_query)
.and_()
.field("journal", "Nature")
.build())
from pyeuropepmc.utils.search_logging import start_search
# Start systematic review log
log = start_search("CRISPR Review", executed_by="Researcher Name")
# Build and execute query
qb = QueryBuilder()
query = (qb
.keyword("CRISPR")
.and_()
.keyword("gene editing")
.and_()
.date_range(start_year=2018)
.build())
# Log the search
qb.log_to_search(
search_log=log,
filters={"date_range": "2018+", "keywords": ["CRISPR", "gene editing"]},
results_returned=150,
notes="Initial broad search for CRISPR literature"
)
# Save the log
log.save("systematic_review_searches.json")
# Save query
qb.save("my_search.json",
authors=[{"name": "John Doe", "ORCID": "0000-0000-0000-0001"}],
date_info={"data_entry": "2025-11-07", "search_conducted": "2025-11-07"})
# Load query
loaded_qb = QueryBuilder.from_file("my_search.json")
translated = loaded_qb.translate("wos") # Translate to Web of Science syntax
See Also: