We’re happy to announce the release of GroupDocs.Search for Python v26.10, available as of November 2026. This is the initial release of the product, bringing the full functionality of GroupDocs.Search 26.10 engine to Python developers. It enables building and maintaining full-text indexes over folders of documents — including PDF, Word, Excel, PowerPoint, email, eBook, archive and many other formats (80+ in total) — and searching them with advanced query types: keyword, phrase, wildcard, regex, fuzzy, boolean, faceted, and date-range searches. The release supports Python 3.5–3.14 on Windows x64, Linux x64 (glibc 2.27+), and macOS 13+ (Intel and Apple Silicon), embedding the .NET 10.0.14 runtime.

What’s new in this release

  • [Feature] Initial release of GroupDocs.Search for Python via .NET (SEARCHPYTHONNET-40)

Public API changes

This is the first release, so there is nothing to upgrade from. The API follows GroupDocs.Search for .NET 26.10: classes keep their .NET names, while methods, properties and parameters are written in snake_case (Index.Search is index.search, SearchResult.DocumentCount is result.document_count) and enum members in upper case (OutputFormat.HTML). Assigning an attribute that a class does not have raises AttributeError with a “Did you mean” hint, instead of creating a Python-only attribute the engine never sees.

Modules

  • groupdocs.search: Index, IndexSettings, IndexRepository, IndexUpdater, SearchQuery, Extractor, License, Metered, GroupDocsSearchException, LicenseError, CancellationTokenSource.
  • groupdocs.search.options: IndexingOptions, SearchOptions, FuzzySearchOptions, SimilarityLevel, UpdateOptions, HighlightOptions, OutputFormat, SeparateProcessOptions, ImageSearchOptions.
  • groupdocs.search.results: SearchResult, FoundDocument, FoundDocumentField, DocumentInfo, FileType, FormatFamily.
  • groupdocs.search.highlighters: DocumentHighlighter, FragmentHighlighter.
  • groupdocs.search.common: FileOutputAdapter, StringOutputAdapter, StreamOutputAdapter, Document, DocumentField, ExtractedData, FileLogger, AttributeChangeBatch.
  • groupdocs.search.dictionaries: SynonymDictionary, HomophoneDictionary, StopWordDictionary, SpellingCorrector, AliasDictionary, CharacterReplacementPair.
  • groupdocs.search.events: EventHub, FileIndexingEventArgs, IndexErrorEventArgs, OperationProgressEventArgs, PasswordRequiredEventArgs.
  • groupdocs.search.exceptions: SearchException, LicenseRestrictionException.
  • groupdocs.search.scaling: SearchNetworkNode, Indexer, Searcher.
  • groupdocs.search.scaling.configuring: Configuration, Configurator, TcpSettings.

New features

Index documents and search them

Index(folder) creates an index in a folder, or opens the index already there. add() indexes a folder, a file, a list of paths, streams or extracted data, and search() takes a query in the GroupDocs.Search query language: keywords, phrases in quotes, wildcards (? for one character, ?(1~5) for one to five), regular expressions after ^, AND, OR and NOT, field queries such as content: Bern or filename: einstein, and date and number ranges. SearchQuery builds the same queries as objects.

from groupdocs.search import Index

with Index("./index") as index:              # creates the index folder, or opens it
    index.add("./documents")                 # indexes every supported file in the folder
    for query in ["relativity", '"theory of relativity"', "relativ?ty",
                  "^relativ.*", "Einstein AND NOT Newton", "content: Bern"]:
        result = index.search(query)
        print("%-26s %d documents, %d occurrences"
              % (query, result.document_count, result.occurrence_count))

Fuzzy search tolerates typing and OCR errors. Synonym, homophone and word-form search widen a query through the built-in English dictionaries, which index.dictionaries lets you edit, and spelling and keyboard-layout correction are search options too.

from groupdocs.search import Index
from groupdocs.search.options import SearchOptions, SimilarityLevel

with Index("./index") as index:
    index.add("./documents")

    fuzzy = SearchOptions()
    fuzzy.fuzzy_search.enabled = True
    fuzzy.fuzzy_search.fuzzy_algorithm = SimilarityLevel(0.8)   # 0.0 (loose) .. 1.0 (strict)
    print("relativty:", index.search("relativty").document_count,
          "->", index.search("relativty", fuzzy).document_count)

    synonyms = SearchOptions()
    synonyms.use_synonym_search = True
    print("picture:", index.search("picture").document_count,
          "->", index.search("picture", synonyms).document_count)

    word_forms = SearchOptions()
    word_forms.use_word_forms_search = True
    print("letter:", index.search("letter").document_count,
          "->", index.search("letter", word_forms).document_count)

Highlight what was found

DocumentHighlighter writes a whole document with the found terms marked, and FragmentHighlighter only the fragments around them, as HTML or plain text, into a file, a string or a binary file object.

from groupdocs.search import Index
from groupdocs.search.common import FileOutputAdapter
from groupdocs.search.highlighters import DocumentHighlighter
from groupdocs.search.options import OutputFormat

with Index("./index") as index:
    index.add("./documents")
    result = index.search("relativity")
    if result.document_count > 0:
        found = result.get_found_document(0)
        adapter = FileOutputAdapter(OutputFormat.HTML, "./highlighted.html")
        index.highlight(found, DocumentHighlighter(adapter))
        print(found.document_info.file_path, "-> highlighted.html")

.NET events as Python handlers

Every event of the index is a Python event: subscribe with += and unsubscribe with -=. A handler can skip a document, tag it with attributes or supply its password, and follows the progress, errors and phases of indexing and search.

from groupdocs.search import Index

skipped = []

def on_file_indexing(sender, args):
    if args.document_full_path.endswith(".zip"):
        args.skip_indexing = True            # leave archives out of the index
        skipped.append(args.document_full_path)

with Index("./index") as index:
    index.events.file_indexing += on_file_indexing
    index.add("./documents")
    index.events.file_indexing -= on_file_indexing
    print(len(index.get_indexed_documents()), "documents indexed,", len(skipped), "archives skipped")

Python objects for the engine’s extension points

Custom text extractors for formats of your own, loggers, word splitters, word-form providers, document loaders and OCR connectors are plain Python objects or functions, which the engine calls through its interfaces.

from groupdocs.search import Index, IndexSettings

class LogExtractor(object):
    """Text of .log files, which the engine does not read on its own."""
    extensions = [".log"]

    def get_fields(self, source):             # a file path, or the engine's stream
        if isinstance(source, str):
            with open(source, encoding="utf-8") as f:
                text = f.read()
        else:
            text = source.read().decode("utf-8")
        return [("Content", text)]

settings = IndexSettings()
settings.custom_extractors.add(LogExtractor())
with Index("./log-index", settings) as index:
    index.add("./logs")
    print(index.search("quota").document_count, "log file(s) mention a quota")

Keep an index up to date

An index is a folder: build it once and reopen it in a later run. update() re-indexes only the documents that changed since the last add() or update(), optimize() merges the index segments, and delete() removes documents by path.

from groupdocs.search import Index

with Index("./index") as index:
    index.add("./documents")
    # ... files in ./documents are added, changed or removed ...
    index.update()        # re-indexes only what changed
    index.optimize()      # merges index segments so searches stay fast
    print(len(index.get_indexed_documents()), "documents in the index")

A license from the environment

Set GROUPDOCS_LIC_PATH to the path or URL of a license file, and the license is applied at the first call into the engine; License().set_license(path) does the same in code. A license that cannot be applied raises LicenseError from that first call on, instead of falling back to evaluation mode. Without a license, an index takes at most 100 documents and only the first 10 found documents of a search can be read.

export GROUPDOCS_LIC_PATH="/path/to/GroupDocs.Search.lic"

Code example

See the “Index documents and search them”, “Fuzzy, synonym and word-form search”, “Highlight what was found”, “.NET events as Python handlers”, “Python objects for the engine’s extension points”, and “Keep an index up to date” sections above for working code examples.

How to get the update

PyPI

Direct download

Download the wheel for your platform from the GroupDocs.Search for Python via .NET 26.10 page, then install the file:

  • Windows x64: pip install groupdocs_search_net-26.10.0-py3-none-win_amd64.whl
  • Linux x64: pip install groupdocs_search_net-26.10.0-py3-none-manylinux_2_27_x86_64.whl
  • macOS Intel: pip install groupdocs_search_net-26.10.0-py3-none-macosx_13_0_x86_64.whl
  • macOS Apple Silicon: pip install groupdocs_search_net-26.10.0-py3-none-macosx_13_0_arm64.whl

Resources