[Guide] Advanced text search

The Keyword filter works very well in Workshop and now supports “All”, “Any”, and “Phrase” searches. I’ve been working on a hybrid search that searches for any space-separated string and all quoted words or phrases. Ultimately, the goal is to incorporate all the advanced search features here: https://www.google.com/advanced_search.

For now though, the below TypeScript searches space-separated words and all quoted text.
The only requirements from the backend are a unique, non-null PrimaryKey property and a search_property property that concatenates all properties into a single text string (with spaces).

import { Filters, Function } from "@foundry/functions-api"
import { ObjectSet, MyObjectType} from "@foundry/ontology-api";

export class MyFunctions {
    @Function()
    public async filter_text(objs : ObjectSet<MyObjectType>, str : string): Promise<ObjectSet<MyObjectType>> {
        str = str.trim();
        str = str.replace(/[^a-zA-Z0-9"\s]/g, '');  // Clean searches like 0:0, which throw a TooManyClauses error in Workshop
        if (!str) {  // Check for empty strings
            return objs;
        } else {
            // Extract quoted phrases
            const quoted_phrases_regex = /("[^"]*")/g;
            const quoted_phrases = str.match(quoted_phrases_regex) || [];
            let filtered_str = str;
            for (const quoted_phrase of quoted_phrases) {
                filtered_str = filtered_str.replace(quoted_phrase, "");
            }

            // Extract words not in quoted phrases
            const regex = /(\S+)/g;
            const unquoted_words = filtered_str.match(regex) || [];

            // Initialize filteredObjs according to the presence of unquoted search terms
            let filteredObjs; // Declare filteredObjs
            if (unquoted_words.length === 0) {
                filteredObjs = objs;  // Initialize a complete set
            } else {
                filteredObjs = objs.filter(obj => Filters.not(obj.primaryKey_.hasProperty()));  // Initialize an empty set
            }

            // Union searches with unquoted words (search any of these)
            for (const word of unquoted_words) {
                console.log(word)
                filteredObjs = filteredObjs.union(objs.filter(obj => obj.search_property.phrasePrefix(word)));
            }

            // Intersect searches with quoted words or phrases (search all of these)
            for (const phrase of quoted_phrases) {
                console.log(phrase);
                filteredObjs = filteredObjs.intersect(objs.filter(obj => obj.search_property.phrasePrefix(phrase)));
            }

            return filteredObjs;
        }
    }
}
5 Likes