FSCrawler Documentation

repository·main·Indexed 23 days ago

https://github.com/dadoonet/fscrawler

FSCrawler is a tool for indexing binary documents (such as PDF, MS Office, and Open Office files) from local or remote file systems into Elasticsearch. It supports local file system crawling, remote crawling via SSH or FTP, and provides a REST interface for direct document uploads. The tool includes a CLI for managing jobs, support for Docker and Docker Compose deployment, and integration with OpenTelemetry for tracing.

Tokens
49.3K
Snippets
142
Records
210
Agent score
76%

What's inside FSCrawler

  1. Overview of FSCrawler features

    main

    FSCrawler is a file system crawler for Elasticsearch designed to index binary documents such as PDF, Open Office, and MS Office files.

    Key capabilities include:

    • Local File System Crawling: Indexes new files, updates existing ones, and removes old ones from a local file system or mounted drive.
    • Remote Crawling: Supports crawling remote file systems via SSH or FTP.
    • REST Interface: Provides a REST interface to 'upload' binary documents directly to Elasticsearch.
  2. Understand the FSCrawler directory layout

    main

    FSCrawler's directory structure organizes executable scripts, configuration, dependencies, and logs. Key directories include:

    • bin/: Contains the execution scripts (fscrawler for Unix-like systems and fscrawler.bat for Windows).
    • lib/: Contains the FSCrawler JAR file and all required dependencies.
    • config/: Contains configuration files, such as log4j2.xml.
    • external/: A location for optional JAR files to extend functionality (e.g., adding jai-imageio-jpeg2000 for JPEG2000 support in PDFs).
    • logs/: Contains runtime log files, including fscrawler.log and documents.log.
     .
     ├── NOTICE
     ├── LICENSE
     ├── README.md
     ├── bin
     │   ├── fscrawler
     │   └── fscrawler.bat
     ├── config
     │   ├── log4j2.xml
     │   └── log4j2-file.xml
     ├── external
     ├── lib
     └── logs
         ├── documents.log
         └── fscrawler.log
  3. Pass parameters to FSCrawler REST APIs

    main

    FSCrawler REST APIs allow parameters to be passed in two primary ways:

    1. Query string parameters: Appended to the URL (e.g., ?param1=foo).
    2. Header parameters: Passed via HTTP headers (e.g., -H "param1=foo").

    Unless otherwise specified in the documentation, examples assume the use of query string parameters.

    curl "http://127.0.0.1:8080/API?param1=foo&param2=bar"
    curl -H "param1=foo" -H "param2=bar" "http://127.0.0.1:8080/API"
  4. Thread Leak Detection in FSCrawler tests

    main

    FSCrawler uses thread filters to detect leaks during testing. These are registered on AbstractFSCrawlerTestCase via the @DetectThreadLeaks.ExcludeThreads annotation.

    Commonly excluded thread groups include:

    • SystemThreadFilter: System groups, ForkJoinPool.commonPool, JFR, AWT, etc.
    • ForkJoinPoolThreadFilter: ForkJoinPool-* worker threads.
    • JUnitThreadsFilter: Threads created by @Timeout via junit-jupiter-timeout-watcher.
    • TestContainerThreadFilter: testcontainers group threads and process reapers.
    • Java2DThreadFilter: Java2D Disposer, AppKit Thread, AWT-* (often triggered by PDFBox/Tika).

    Specific test classes may also exclude:

    • MinioThreadFilter: Okio Watchdog, OkHttp TaskRunner (from MinIO client).
    • WireMockThreadFilter: qtp*, WireMock, Jetty threads.
  5. Configure Semantic Search

    main

    Semantic search improves results by using vector embeddings. It requires Elasticsearch 8.17.0+ and a trial or enterprise license.

    • Activation: Enabled by default if requirements are met. Disable via elasticsearch.semantic_search: false.
    • Mechanism: When active, a content_semantic field of type semantic_text is created. It uses an inference API (defaulting to the Elser model) to extract semantic information.
    • Custom Models: You can change the model by defining your own fscrawler_INDEX_mapping_content_semantic component template with a specific inference_id.
    # Example: Using multilingual-e5-small for semantic search
    PUT _component_template/fscrawler_fscrawler_mapping_content_semantic
    {
     "template": {
       "mappings": {
         "properties": {
           "content": {
             "type": "text",
             "copy_to": "content_semantic"
           },
           "content_semantic": {
             "type": "semantic_text",
             "inference_id": ".multilingual-e5-small-elasticsearch"
           }
         }
       }
     }
    }
  6. Manage Elasticsearch Component Templates

    main

    FSCrawler uses Elasticsearch Component Templates to define mappings and settings.

    Template Management Behavior

    • Default: FSCrawler checks if templates exist. If they do, it skips management to preserve your custom templates.
    • Disable management: Set elasticsearch.push_templates: false to prevent FSCrawler from managing templates.
    • Force overwrite: Set elasticsearch.force_push_templates: true to overwrite all existing templates with FSCrawler's defaults.

    Customizing Mappings

    To use custom analyzers or mappings, create the specific component template before starting FSCrawler. FSCrawler will detect the existing template and skip it, allowing you to inject your own logic (e.g., a custom French analyzer) while it fills in the remaining required templates.

    # Example: Define a custom content mapping before starting FSCrawler
    PUT _component_template/fscrawler_fscrawler_mapping_content
    {
     "template": {
       "mappings": {
         "properties": {
           "content": {
             "type": "text",
             "analyzer": "french"
           }
         }
       }
     }
    }
  7. Deduplicate documents using extracted text fingerprinting

    main

    If you want to deduplicate based on the extracted text (content) rather than the binary file, use the Elasticsearch fingerprint ingest processor.

    1. Create the Elasticsearch Ingest Pipeline: This pipeline computes a fingerprint of the content field, stores it in a temporary field, sets it as the _id, and then removes the temporary field.
    PUT _ingest/pipeline/content-fingerprint-id
    {
      "description": "Compute a fingerprint from content and set it as the document _id",
      "processors": [
        {
          "fingerprint": {
            "fields": ["content"],
            "target_field": "_tmp_fingerprint",
            "method": "SHA-256"
          }
        },
        {
          "set": {
            "field": "_id",
            "value": "{{{_tmp_fingerprint}}}"
          }
        },
        {
          "remove": {
            "field": "_tmp_fingerprint",
            "ignore_missing": true
          }
        }
      ]
    }
    1. Configure the FSCrawler job: Set elasticsearch.pipeline: "content-fingerprint-id" in your job settings.

    Important Caveats:

    • Overwrite behavior: With bulk_operation: index (default), the last writer wins. With create, the first writer wins.
    • Text vs Binary: This method treats files with different binary content but identical extracted text as duplicates. It will overwrite documents that have no extracted text.
    • Folder documents: Documents representing folders are not sent through the ingest pipeline and cannot use this method.
    PUT _ingest/pipeline/content-fingerprint-id
    {
      "description": "Compute a fingerprint from content and set it as the document _id",
      "processors": [
        {
          "fingerprint": {
            "fields": ["content"],
            "target_field": "_tmp_fingerprint",
            "method": "SHA-256"
          }
        },
        {
          "set": {
            "field": "_id",
            "value": "{{{_tmp_fingerprint}}}"
          }
        },
        {
          "remove": {
            "field": "_tmp_fingerprint",
            "ignore_missing": true
          }
        }
      ]
    }
  8. Understand the generated document schema in Elasticsearch

    main

    FSCrawler generates documents in Elasticsearch with several structured fields depending on your configuration. The main fields include:

    • content: The extracted text content.
    • content_semantic: A semantic-text copy of the content (enabled when semantic search is configured).
    • attachment: A BASE64-encoded binary file (enabled when fs.base64 is set).
    • meta.*: Metadata extracted by Apache Tika (e.g., author, title, date, language).
    • file.*: File attributes such as filename, extension, filesize, and url.
    • path.*: Path information including real, virtual, and root paths.
    • attributes.*: Filesystem-level attributes like owner, group, and permissions.
    • external: Additional tags provided via external metadata.
    {
        "content":"This is a sample text available in page 1\n\nThis second part of the text is in Page 2\n\n",
        "content_semantic":"This is a sample text available in page 1\n\nThis second part of the text is in Page 2\n\n",
        "file":{
           "content_type":"application/vnd.oasis.opendocument.text",
           "created":"2018-07-30T11:35:08.000+0000",
           "extension":"odt",
           "filename":"test.odt",
           "filesize":6236,
           "indexing_date":"2018-07-30T11:35:19.781+0000",
           "last_accessed":"2018-07-30T11:35:08.000+0000",
           "last_modified":"2018-07-30T11:35:08.000+0000",
           "url":"file:///tmp/test.odt"
        },
        "meta":{
           "author":"David Pilato",
           "created":"2016-07-07T16:37:00.000+0000",
           "date":"2016-07-07T16:37:00.000+0000",
           "description":"Comments",
           "keywords":[
              "keyword1",
              "  keyword2"
           ],
           "language":"en",
           "title":"Test Tika title"
        },
        "path":{
           "real":"/tmp/test.odt",
           "root":"7537e4fb47e553f110a1ec312c2537c0",
           "virtual":"/test.odt"
        }
     }
  9. How FSCrawler handles crashes and network errors

    main

    Automatic resume after crash

    If FSCrawler crashes or is forcefully terminated, it will automatically resume from the last saved checkpoint when restarted. Checkpoints are saved periodically (every 100 files by default) and whenever the crawler state changes.

    Network error recovery

    FSCrawler handles network errors using exponential backoff:

    1. Saves the current checkpoint.
    2. Waits with exponential backoff (starting at 1 second, doubling each retry).
    3. Attempts to reconnect.
    4. Resumes from the failed directory.

    After 10 consecutive failures, the crawler will stop with an ERROR state. You must fix the network issue and restart FSCrawler to resume from the checkpoint.

  10. Deduplicate documents using a binary checksum (fs.checksum)

    main

    To index only one copy of duplicate files based on their binary content, use an Elasticsearch ingest pipeline to set the _id from the file.checksum field.

    1. Enable checksum in FSCrawler settings: Set fs.checksum to a supported algorithm (e.g., SHA-256).

    2. Create an Elasticsearch Ingest Pipeline:

    PUT _ingest/pipeline/set-id-from-checksum
    {
      "description": "Set the _id from file.checksum",
      "processors": [
        {
          "set": {
            "field": "_id",
            "value": "{{{file.checksum}}}"
          }
        }
      ]
    }
    1. Configure the FSCrawler job: Set elasticsearch.pipeline to the name of your pipeline.

    Handling Duplicates:

    • Last writer wins: Use the default elasticsearch.bulk_operation: index. The last path discovered for a specific content hash will overwrite previous ones.
    • First writer wins: Set elasticsearch.bulk_operation: create. Subsequent duplicates will fail with a conflict, which FSCrawler treats as a non-fatal event, preserving the first indexed version.

    Note: The checksum is computed from the binary file, not the extracted text.

    name: "test"
    fs:
      index_content: true
      checksum: "SHA-256"
    eslasticsearch:
      pipeline: "set-id-from-checksum"
      bulk_operation: "create"