Search code examples
javaneo4jcyphergraph-databasescolumnsorting

Neo4j - Order by relevance


I'd like to order returned data by relevance in Neo4j.

For my purpose, relevance can be simplified to "Index of the word I'm searching for", where the lower index the higher relevance.

Example

I have these three nodes:

node : {
    Label: PROD
    properties : {
        name: "Bearing replacement Skateboard"
    }
}

node : {
    Label: PROD
    properties : {
        name: "Skateboard"
    }
}

node : {
    Label: PROD
    properties : {
        name: "L7 Skateboard"
    }
}

I want them to be returned with this order:

node : {
    Label: PROD
    properties : {
        name: "Skateboard" // name.indexOf("Skateboard") = 0
    }
}

node : {
    Label: PROD
    properties : {
        name: "L7 Skateboard"  // name.indexOf("Skateboard") = 3
    }
}

node : {
    Label: PROD
    properties : {
        name: "Bearing replacement Skateboard"  // name.indexOf("Skateboard") = 19
    }
}

What I have so far:

String query = "MATCH (n:PROD) where LOWER(n.name) CONTAINS LOWER({textToSearch}) RETURN n ORDER BY LOWER(n.name) ASC LIMIT 15";

String textToSearch = "Skateboard";

Map<String, Object> queryParams = new HashMap<>();
queryParams.put("textToSearch", textToSearch);
try (
    Transaction ignored = database.beginTx();
    Result resultSet = database.execute(query, queryParams)
) {
    Iterator<Node> results = resultSet.columnAs("n");
    while (results.hasNext()) {
        Node node = results.next();
        /* data processing here */
    }
}

This just orders results by name ascendant. Is there a way to tell neo4j to sort based on n.name.indexOf({textToFind})?


Solution

  • How about doing something like this in Cypher

    MATCH (n:PROD) 
    WHERE n.name_lc CONTAINS toLower({textToSearch})
    WITH n, SPLIT(n.name_lc, toLower({textToSearch})) as parts
    RETURN n.name, SIZE(parts[0]) AS leading
    ORDER BY leading
    

    To make effective use of the above...

    Create an index on a lowercase version of the property

    CREATE INDEX ON :PROD(name_lc)
    

    Copy the regular name to a lowercase version

    MATCH (n:PPOD)
    SET n.name_lc = toLower(n.name)