Package org.neo4j.examples.imdb.domain

Source Code of org.neo4j.examples.imdb.domain.ImdbSearchEngineImpl

/**
* Licensed to Neo Technology under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Neo Technology licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.neo4j.examples.imdb.domain;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;

import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.springframework.beans.factory.annotation.Autowired;

public class ImdbSearchEngineImpl implements ImdbSearchEngine
{
    private static final String NAME_PART_INDEX = "name.part";
    private static final String WORD_PROPERTY = "word";
    private static final String COUNT_PROPERTY = "count_uses";
    private static final String TITLE_PART_INDEX = "title.part";
    private static final String SEARCH_INDEX_NAME = "search";

    private GraphDatabaseService graphDbService;

    private Index<Node> nodeIndex;

    @Autowired
    public void setGraphDbService(GraphDatabaseService graphDbService) {
        this.graphDbService = graphDbService;
        this.nodeIndex = graphDbService.index().forNodes(SEARCH_INDEX_NAME);
    }

    @Override
    public void indexActor( Actor actor )
    {
        index( actor.getName(), ((ActorImpl) actor).getUnderlyingNode(),
            NAME_PART_INDEX, ImdbSearchRelTypes.PART_OF_NAME );
    }

    @Override
    public void indexMovie( Movie movie )
    {
        index( movie.getTitle(), ((MovieImpl) movie).getUnderlyingNode(),
            TITLE_PART_INDEX, ImdbSearchRelTypes.PART_OF_TITLE );
    }

    @Override
    public Node searchActor( String name )
    {
        return searchSingle( name, NAME_PART_INDEX, ImdbSearchRelTypes.PART_OF_NAME );
    }

    @Override
    public Node searchMovie( String title )
    {
        return searchSingle( title, TITLE_PART_INDEX, ImdbSearchRelTypes.PART_OF_TITLE );
    }

    private String[] splitSearchString( final String value )
    {
        return value.toLowerCase( Locale.ENGLISH ).split( "[^\\w]+" );
    }

    private Node getSingleNode(String key, String value)
    {
        IndexHits<Node> hits = nodeIndex.get( key, value );
        for ( Node node : hits )
        {
            return node;
        }
        return null;
    }

    private void index( final String value, final Node node,
        final String partIndexName, final ImdbSearchRelTypes relType )
    {
        for ( String part : splitSearchString( value ) )
        {
            Node wordNode = getSingleNode(partIndexName, part);
            if ( wordNode == null )
            {
                wordNode = graphDbService.createNode();
                // not needed for the functionality
                nodeIndex.add(wordNode, partIndexName, part);

                wordNode.setProperty( WORD_PROPERTY, part );
            }
            wordNode.createRelationshipTo( node, relType );
            wordNode.setProperty( COUNT_PROPERTY, ((Integer) wordNode
                .getProperty( COUNT_PROPERTY, 0 )) + 1 );
        }
    }

    private Node searchSingle( final String value, final String indexName,
        final ImdbSearchRelTypes wordRelType )
    {
        // get the words in the search
        final List<Node> wordList = findSearchWords( value, indexName );
        if ( wordList.isEmpty() )
        {
            return null;
        }
        final Node startNode = wordList.remove( 0 );
        // set up a match to use if everything else fails
        Node match = startNode.getRelationships( wordRelType ).iterator()
            .next().getEndNode();
        // check if there is only one node in the list
        if ( wordList.isEmpty() )
        {
            return match;
        }
        int bestCount = 0;
        final int listSize = wordList.size();
        for ( Relationship targetRel : startNode.getRelationships( wordRelType ) )
        {
            Node targetNode = targetRel.getEndNode();
            int hitCount = 0;
            for ( Relationship wordRel : targetNode
                .getRelationships( wordRelType ) )
            {
                if ( wordList.contains( wordRel.getStartNode() ) )
                {
                    if ( ++hitCount == listSize )
                    {
                        return targetNode;
                    }
                }
            }
            if ( hitCount > bestCount )
            {
                match = targetNode;
                bestCount = hitCount;
            }
        }
        return match;
    }

    private List<Node> findSearchWords( final String userInput,
        final String partIndexName )
    {
        final List<Node> wordList = new ArrayList<Node>();
        // prepare search terms
        for ( String part : splitSearchString( userInput ) )
        {
            Node wordNode = getSingleNode(partIndexName, part);
            if ( wordNode == null || !wordNode.hasRelationship()
                || wordList.contains( wordNode ) )
            {
                continue;
            }
            wordList.add( wordNode );
        }
        if ( wordList.isEmpty() )
        {
            return Collections.emptyList();
        }
        // sort words according to the number of relationships (ascending)
        Collections.sort( wordList, new Comparator<Node>()
        {
            @Override
            public int compare( final Node left, final Node right )
            {
                int leftCount = (Integer) left.getProperty( COUNT_PROPERTY, 0 );
                int rightCount = (Integer) right
                    .getProperty( COUNT_PROPERTY, 0 );
                return leftCount - rightCount;
            }
        } );
        return wordList;
    }
}
TOP

Related Classes of org.neo4j.examples.imdb.domain.ImdbSearchEngineImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.