Skip to content

Commit

Permalink
convert json function
Browse files Browse the repository at this point in the history
Signed-off-by: crazyyanchao <[email protected]>
  • Loading branch information
crazyyanhcao committed Dec 3, 2019
1 parent 586eacd commit ee7132f
Show file tree
Hide file tree
Showing 3 changed files with 599 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package casia.isiteam.zdr.neo4j.index;
/**
*         ┏┓ ┏┓+ +
*        ┏┛┻━━━━━━━┛┻┓ + +
*        ┃       ┃
*        ┃   ━   ┃ ++ + + +
*        █████━█████ ┃+
*        ┃       ┃ +
*        ┃   ┻   ┃
*        ┃       ┃ + +
*        ┗━━┓    ┏━┛
* ┃   ┃
*          ┃   ┃ + + + +
*          ┃   ┃ Code is far away from bug with the animal protecting
*          ┃   ┃ +
*          ┃   ┃
*          ┃   ┃  +
*          ┃    ┗━━━┓ + +
*          ┃      ┣┓
*          ┃      ┏┛
*          ┗┓┓┏━━━┳┓┏┛ + + + +
*           ┃┫┫  ┃┫┫
*           ┗┻┛  ┗┻┛+ + + +
*/

import org.apache.lucene.queryparser.classic.ParseException;
import org.neo4j.graphdb.DependencyResolver;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.schema.IndexDefinition;
import org.neo4j.graphdb.schema.Schema;
import org.neo4j.internal.kernel.api.IndexReference;
import org.neo4j.internal.kernel.api.exceptions.schema.IndexNotFoundKernelException;
import org.neo4j.kernel.api.KernelTransaction;
import org.neo4j.kernel.api.impl.fulltext.FulltextAdapter;
import org.neo4j.kernel.api.impl.fulltext.FulltextProcedures;
import org.neo4j.kernel.api.impl.fulltext.ScoreEntityIterator;
import org.neo4j.kernel.impl.api.KernelTransactionImplementation;
import org.neo4j.procedure.Context;
import org.neo4j.procedure.Description;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.Procedure;
import org.neo4j.storageengine.api.EntityType;
import org.neo4j.storageengine.api.schema.IndexDescriptor;
import org.neo4j.util.FeatureToggles;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import static org.neo4j.procedure.Mode.READ;

/**
* @author YanchaoMa [email protected]
* @PACKAGE_NAME: casia.isiteam.zdr.neo4j.index
* @Description: TODO(自定义全文检索得分算法)
* @date 2019/8/16 14:30
*/
public class CustomizeFullTextSearcher {

private static final long INDEX_ONLINE_QUERY_TIMEOUT_SECONDS = FeatureToggles.getInteger(
FulltextProcedures.class, "INDEX_ONLINE_QUERY_TIMEOUT_SECONDS", 30);

@Context
public KernelTransaction tx;

@Context
public GraphDatabaseService db;

@Context
public DependencyResolver resolver;

@Context
public FulltextAdapter accessor;

/**
* @param name:索引名
* @param query:查询STRING
* @return
* @Description: TODO(使用SimHash计算得分)
*/
@Description("Query the given fulltext index. Returns the matching nodes and their lucene query score, ordered by score.")
@Procedure(name = "db.index.fulltext.queryNodesBySimHash", mode = READ)
public Stream<NodeOutput> queryFulltextForNodesBySimHash(@Name("indexName") String name, @Name("queryString") String query)
throws ParseException, IndexNotFoundKernelException, IOException {
IndexReference indexReference = getValidIndexReference(name);
awaitOnline(indexReference);
EntityType entityType = indexReference.schema().entityType();
if (entityType != EntityType.NODE) {
throw new IllegalArgumentException("The '" + name + "' index (" + indexReference + ") is an index on " + entityType +
", so it cannot be queried for nodes.");
}
ScoreEntityIterator resultIterator = accessor.query(tx, name, query);
// return resultIterator.stream()
// .map(result -> NodeOutput.forExistingEntityOrNull(db, result))
// .filter(Objects::nonNull);
return null;
}

private IndexReference getValidIndexReference(@Name("indexName") String name) {
IndexReference indexReference = tx.schemaRead().indexGetForName(name);
if (indexReference == IndexReference.NO_INDEX) {
throw new IllegalArgumentException("There is no such fulltext schema index: " + name);
}
return indexReference;
}

private void awaitOnline(IndexReference indexReference) throws IndexNotFoundKernelException {
// We do the isAdded check on the transaction state first, because indexGetState will grab a schema read-lock, which can deadlock on the write-lock
// held by the index populator. Also, if we index was created in this transaction, then we will never see it come online in this transaction anyway.
// Indexes don't come online until the transaction that creates them has committed.
if (!((KernelTransactionImplementation) tx).txState().indexDiffSetsBySchema(indexReference.schema()).isAdded((IndexDescriptor) indexReference)) {
// If the index was not created in this transaction, then wait for it to come online before querying.
Schema schema = db.schema();
IndexDefinition index = schema.getIndexByName(indexReference.name());
schema.awaitIndexOnline(index, INDEX_ONLINE_QUERY_TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
// If the index was created in this transaction, then we skip this check entirely.
// We will get an exception later, when we try to get an IndexReader, so this is fine.
}

public static final class NodeOutput
{
public final Node node;
public final double score;

protected NodeOutput( Node node, double score )
{
this.node = node;
this.score = score;
}

// public static FulltextProcedures.NodeOutput forExistingEntityOrNull(GraphDatabaseService db, ScoreEntityIterator.ScoreEntry result )
// {
// try
// {
// return new FulltextProcedures.NodeOutput( db.getNodeById( result.entityId() ), result.score() );
// }
// catch ( NotFoundException ignore )
// {
// // This node was most likely deleted by a concurrent transaction, so we just ignore it.
// return null;
// }
// }
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package casia.isiteam.zdr.neo4j.index;
/**
*         ┏┓ ┏┓+ +
*        ┏┛┻━━━━━━━┛┻┓ + +
*        ┃       ┃
*        ┃   ━   ┃ ++ + + +
*        █████━█████ ┃+
*        ┃       ┃ +
*        ┃   ┻   ┃
*        ┃       ┃ + +
*        ┗━━┓    ┏━┛
* ┃   ┃
*          ┃   ┃ + + + +
*          ┃   ┃ Code is far away from bug with the animal protecting
*          ┃   ┃ +
*          ┃   ┃
*          ┃   ┃  +
*          ┃    ┗━━━┓ + +
*          ┃      ┣┓
*          ┃      ┏┛
*          ┗┓┓┏━━━┳┓┏┛ + + + +
*           ┃┫┫  ┃┫┫
*           ┗┻┛  ┗┻┛+ + + +
*/

import org.neo4j.kernel.api.impl.index.collector.ValuesIterator;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
* @author YanchaoMa [email protected]
* @PACKAGE_NAME: casia.isiteam.zdr.neo4j.index
* @Description: TODO(Iterator over entity ids together with their respective score.)
* @date 2019/8/16 16:41
*/
public class CustomizeScoreEntityIterator implements Iterator<CustomizeScoreEntityIterator.ScoreEntry> {
private final ValuesIterator iterator;
private final Predicate<ScoreEntry> predicate;
private CustomizeScoreEntityIterator.ScoreEntry next;

CustomizeScoreEntityIterator( ValuesIterator sortedValuesIterator )
{
this.iterator = sortedValuesIterator;
this.predicate = null;
}

private CustomizeScoreEntityIterator( ValuesIterator sortedValuesIterator, Predicate<CustomizeScoreEntityIterator.ScoreEntry> predicate )
{
this.iterator = sortedValuesIterator;
this.predicate = predicate;
}

public Stream<ScoreEntry> stream()
{
return StreamSupport.stream( Spliterators.spliteratorUnknownSize( this, Spliterator.ORDERED ), false );
}

@Override
public boolean hasNext()
{
while ( next == null && iterator.hasNext() )
{
long entityId = iterator.next();
float score = iterator.currentScore();
CustomizeScoreEntityIterator.ScoreEntry tmp = new CustomizeScoreEntityIterator.ScoreEntry( entityId, score );
if ( predicate == null || predicate.test( tmp ) )
{
next = tmp;
}
}
return next != null;
}

@Override
public CustomizeScoreEntityIterator.ScoreEntry next()
{
if ( hasNext() )
{
CustomizeScoreEntityIterator.ScoreEntry tmp = next;
next = null;
return tmp;
}
else
{
throw new NoSuchElementException( "The iterator is exhausted" );
}
}

CustomizeScoreEntityIterator filter( Predicate<CustomizeScoreEntityIterator.ScoreEntry> predicate )
{
if ( this.predicate != null )
{
predicate = this.predicate.and( predicate );
}
return new CustomizeScoreEntityIterator( iterator, predicate );
}

/**
* Merges the given iterators into a single iterator, that maintains the aggregate descending score sort order.
*
* @param iterators to concatenate
* @return a {@link CustomizeScoreEntityIterator} that iterates over all of the elements in all of the given iterators
*/
static CustomizeScoreEntityIterator mergeIterators( List<CustomizeScoreEntityIterator> iterators )
{
return new CustomizeScoreEntityIterator.ConcatenatingScoreEntityIterator( iterators );
}

private static class ConcatenatingScoreEntityIterator extends CustomizeScoreEntityIterator
{
private final List<? extends CustomizeScoreEntityIterator> iterators;
private final CustomizeScoreEntityIterator.ScoreEntry[] buffer;
private boolean fetched;
private CustomizeScoreEntityIterator.ScoreEntry nextHead;

ConcatenatingScoreEntityIterator( List<? extends CustomizeScoreEntityIterator> iterators )
{
super( null );
this.iterators = iterators;
this.buffer = new CustomizeScoreEntityIterator.ScoreEntry[iterators.size()];
}

@Override
public boolean hasNext()
{
if ( !fetched )
{
fetch();
}
return nextHead != null;
}

private void fetch()
{
int candidateHead = -1;
for ( int i = 0; i < iterators.size(); i++ )
{
CustomizeScoreEntityIterator.ScoreEntry entry = buffer[i];
//Fill buffer if needed.
if ( entry == null && iterators.get( i ).hasNext() )
{
entry = iterators.get( i ).next();
buffer[i] = entry;
}

//Check if entry might be candidate for next to return.
if ( entry != null && (nextHead == null || entry.score > nextHead.score) )
{
nextHead = entry;
candidateHead = i;
}
}
if ( candidateHead != -1 )
{
buffer[candidateHead] = null;
}
fetched = true;
}

@Override
public CustomizeScoreEntityIterator.ScoreEntry next()
{
if ( hasNext() )
{
fetched = false;
CustomizeScoreEntityIterator.ScoreEntry best = nextHead;
nextHead = null;
return best;
}
else
{
throw new NoSuchElementException( "The iterator is exhausted" );
}
}
}

/**
* A ScoreEntry consists of an entity id together with its score.
*/
static class ScoreEntry
{
private final long entityId;
private final float score;

long entityId()
{
return entityId;
}

float score()
{
return score;
}

ScoreEntry( long entityId, float score )
{
this.entityId = entityId;
this.score = score;
}

@Override
public String toString()
{
return "ScoreEntry[entityId=" + entityId + ", score=" + score + "]";
}
}
}
Loading

0 comments on commit ee7132f

Please sign in to comment.