private Query getTermQuery(final ExpressionTerm expressionTerm) {
        String field = expressionTerm.getField();
        final Condition condition = expressionTerm.getCondition();
        String value = expressionTerm.getValue();
        final DocRef docRef = expressionTerm.getDocRef();

        // Clean strings to remove unwanted whitespace that the user may have added accidentally
        if (field != null) {
            field = field.trim();
        }
        if (value != null) {
            value = value.trim();
        }

        // Validate the field
        if (field == null || field.isEmpty()) {
            throw new IllegalArgumentException("Field not set");
        }
        final IndexField indexField = indexFieldCache.get(indexDocRef, field);
        if (!(indexField instanceof final ElasticIndexField elasticIndexField)) {
            throw new SearchException("Field not found in index: " + field);
        }
        final String fieldName = elasticIndexField.getFldName();

        // Validate the expression
        if (value == null || value.isEmpty()) {
            return null;
        }
        if (Condition.IN_DICTIONARY.equals(condition)) {
            if (docRef == null || docRef.getUuid() == null) {
                throw new IllegalArgumentException("Dictionary not set for field: " + field);
            }
        }

        // Special case: if the expression is a wildcard, use the `exists` query
        if (value.equals("*")) {
            if (Condition.EQUALS.equals(condition)) {
                return QueryBuilders.exists(q -> q.field(fieldName));
            } else if (Condition.NOT_EQUALS.equals(condition)) {
                return QueryBuilders.bool()
                        .mustNot(QueryBuilders.exists(q -> q.field(fieldName)))
                        .build()._toQuery();
            }
        }

        // Create a query based on the field type and condition.
        final FieldType elasticFieldType = elasticIndexField.getFldType();
        if (elasticFieldType.equals(FieldType.ID) ||
                elasticFieldType.equals(FieldType.LONG) ||
                elasticFieldType.equals(FieldType.INTEGER)) {
            return buildScalarQuery(condition, elasticIndexField, fieldName, value, this::getNumber, docRef);
        } else if (elasticFieldType.equals(FieldType.FLOAT)) {
            return buildScalarQuery(condition, elasticIndexField, fieldName, value, this::getFloat, docRef);
        } else if (elasticFieldType.equals(FieldType.DOUBLE)) {
            return buildScalarQuery(condition, elasticIndexField, fieldName, value, this::getDouble, docRef);
        } else if (elasticFieldType.equals(FieldType.DATE)) {
            return buildScalarQuery(condition, elasticIndexField, fieldName, value, this::getDate, docRef);
        } else if (elasticFieldType.equals(FieldType.IPV4_ADDRESS)) {
            return buildScalarQuery(condition, elasticIndexField, fieldName, value, this::getIpV4Address, docRef);
        } else {
            return buildStringQuery(condition, value, docRef, elasticIndexField, fieldName);
        }
    }
Convert our query objects to an Elasticsearch Query DSL query.
stroom-search/stroom-search-elastic/src/main/java/stroom/search/elastic/search/SearchExpressionQueryBuilder.java