Skip to content

Instantly share code, notes, and snippets.

@Centril
Last active December 10, 2015 06:07
Show Gist options
  • Save Centril/18606483f883c17d9694 to your computer and use it in GitHub Desktop.
Save Centril/18606483f883c17d9694 to your computer and use it in GitHub Desktop.
Fuzzy predicate logic searching with relevance, HOF style.
interface SearchResult<T> {
T getResult();
double getRelevance();
// Just for being able to "clone" with other relevance...
SearchResult<? extends T> withRelevance( double relevance );
}
interface SearchCriteria<T> {
SearchResult<? extends T> apply( SearchResult<? extends T> result );
}
interface SearchQuery<T> {
List<? extends SearchCriteria<? extends T>> getCriterias();
}
class AndCriteria<T> implements SearchCriteria<T> {
SearchCriteria<? extends T> left;
SearchCriteria<? extends T> right;
AndCriteria( SearchCriteria<? extends T> left, SearchCriteria<? extends T> right ) {
this.left = left;
this.right = right;
}
SearchResult<? extends T> apply( SearchResult<? extends T> result ) {
double r = result.getRelevance();
return result.withRelevance( left.apply( result ).getRelevance() > r &&
right.apply( result).getRelevance() > r
? r * 4
: 0 );
}
}
class OrCriteria<T> implements SearchCriteria<T> {
SearchCriteria<? extends T> left;
SearchCriteria<? extends T> right;
OrCriteria( SearchCriteria<? extends T> left, SearchCriteria<? extends T> right ) {
this.left = left;
this.right = right;
}
SearchResult<? extends T> apply( SearchResult<? extends T> result ) {
double r = result.getRelevance();
return result.withRelevance( left.apply( result ).getRelevance() > r ||
right.apply( result).getRelevance() > r
? r * 2
: r / 2 );
}
}
class NotCriteria<T> implements SearchCriteria<T> {
SearchCriteria<? extends T> criteria;
NotCriteria( SearchCriteria<? extends T> criteria ) {
this.criteria = criteria;
}
SearchResult<? extends T> apply( SearchResult<? extends T> result ) {
return result.withRelevance( result.getRelevance() * r -
criteria.apply( result ).getRelevance() );
}
}
import java.util.function.Function;
import java.util.function.BiPredicate;
class MatchesCriteria<I, T> implements SearchCriteria<T> {
I input;
BiPredicate<? extends I, ? extends I> predicate;
Function<? extends T, ? extends I> transform;
MatchesCriteria( I input,
Function<? extends T, ? extends I> transform,
BiPredicate<? extends I, ? extends I> predicate ) {
this.input = input;
this.predicate = predicate;
this.transform = transform;
}
SearchResult<? extends T> apply( SearchResult<? extends T> sr ) {
double r = sr.getRelevance();
return sr.withRelevance( predicate.test( input,
transform.apply( sr.getResult() ) )
? r * 2
: r / 2 );
}
}
import java.util.stream.Stream;
class Searcher<T> {
List<SearchResult<? extends T>> search( List<SearchResult<? extends T>> results,
SearchQuery<? extends T> query ) {
Stream<SearchResult<? extends T>> stream = results.stream();
for ( SearchCriteria<? extends T> criteria : query.getCriterias() ) {
stream = stream.map( criteria )
}
return stream.filter( { sr -> sr.getRelevance() >= 1 } )
.collect( Collectors.toList() );
}
}
class ConcreteSR<T> implements SearchResult<T> {
T result;
double relevance;
ConcreteSR( T r, double rel ) {
result = r;
relevance = rel;
}
// Just for being able to "clone" with other relevance...
SearchResult<? extends T> withRelevance( double relevance ) {
return new ConcreteSR( result, relevance );
}
}
def static main( args ) {
def r = new MatchesCriteria( 4, { ++it }, { input, v -> input == 2 * v } )
.apply( new ConcreteSR<Integer>( 1, 1 ) );
System.out.println( r.getRelevance() );
}
-- Types:
type Frac = Double
data SearchResult a = SR { result :: a, relevance :: Frac }
type SearchCriteria a = SearchResult a -> SearchResult a
type SearchQuery a = [SearchCriteria a]
-- APIs:
andCriteria :: SearchCriteria a -> SearchCriteria a -> SearchCriteria a
andCriteria l r = mapResult (\sr rel -> if relevance (l sr) > rel &&
relevance (r sr) > rel
then rel * 4
else 0)
orCriteria :: SearchCriteria a -> SearchCriteria a -> SearchCriteria a
orCriteria l r = mapResult (\sr rel -> doubleOrHalf rel $
relevance (l sr) > rel ||
relevance (r sr) > rel)
andCriteria2 :: SearchCriteria a -> SearchCriteria a -> SearchCriteria a
andCriteria2 l r = mapResult (\sr rel -> min (relevance $ l sr)
(relevance $ r sr))
orCriteria2 :: SearchCriteria a -> SearchCriteria a -> SearchCriteria a
orCriteria2 l r = mapResult (\sr rel -> max (relevance $ l sr)
(relevance $ r sr))
notCriteria :: SearchCriteria a -> SearchCriteria a
notCriteria c = mapResult (\sr rel -> 2 * rel - relevance (c sr))
matchesCriteria :: b -> (a -> b) -> (b -> b -> Bool) -> SearchCriteria a
matchesCriteria obj f p = mapResult (\sr rel ->
(doubleOrHalf rel . p obj . f . result) sr)
search :: [SearchResult a] -> SearchQuery a -> [SearchResult a]
search results criterias = filter ((>= 1) . relevance) $
(foldl $ flip map) results criterias
search2 :: [a] -> SearchQuery a -> [SearchResult a]
search2 = search . map (flip SR 1)
-- Helpers:
doubleOrHalf :: Frac -> Bool -> Frac
doubleOrHalf r s = if s then r * 2 else r / 2
mapResult :: (SearchResult a -> Frac -> Frac) -> SearchResult a -> SearchResult a
mapResult f sr@(SR a r) = SR a (f sr r)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment