private long queryNearestVector(List<VectorResult> listResult, LSHVector vector,
			double similarityThreshold, double significanceThreshold, int maxVectors)
			throws ElasticException {
		if (connection == null) {
			return 0;
		}
		StringBuilder vecEncode = new StringBuilder();
		vector.saveBase64(vecEncode, Base64Lite.encode);
		StringBuilder buffer = new StringBuilder();
		buffer.append("{ \"size\": ").append(maxVectors).append(", ");
		buffer.append("  \"query\": { ");
		buffer.append("  \"function_score\": { ");
		buffer.append("    \"query\": { ");
		buffer.append("      \"match\": { ");
		buffer.append("        \"features\": \"");
		buffer.append(vecEncode);
		buffer.append("\" } }, ");
		buffer.append("    \"min_score\": 0.00001, ");		// Make sure a 0.0 score is filtered
		buffer.append("    \"boost_mode\": \"replace\", ");
		buffer.append("    \"functions\": [ { ");
		buffer.append("      \"script_score\": { ");
		buffer.append("        \"script\": { ");
		buffer.append("          \"lang\": \"bsim_scripts\", ");
		buffer.append("          \"source\": \"lsh_compare\", ");
		buffer.append("          \"params\": { ");
		buffer.append("            \"indexname\": \"lsh_").append(repository).append("\", ");
		buffer.append("            \"vector\": \"");
		buffer.append(vecEncode);
		buffer.append("\",          \"simthresh\": ").append(similarityThreshold);
		buffer.append(",            \"sigthresh\": ").append(significanceThreshold);
		buffer.append(" } } } } ] } } }");
		JsonObject resp =
			connection.executeStatement(ElasticConnection.GET, "vector/_search", buffer.toString());
		JsonObject baseHits = (JsonObject) resp.get("hits");
		if (baseHits == null) {
			throw new ElasticException("Could not find hits document");
		}
		JsonObject totalRec = (JsonObject) baseHits.get("total");
		long numHits = totalRec.get("value").getAsLong();
		if (numHits == 0) {
			return 0;
		}
		JsonArray hitsArray = (JsonArray) baseHits.get("hits");
		char[] decodeBuffer = Base64VectorFactory.allocateBuffer();
		VectorCompare vecCompare = new VectorCompare();
		try {
			int returnedHits = hitsArray.size();
			for (int i = 0; i < returnedHits; ++i) {
				JsonObject mainHit = (JsonObject) hitsArray.get(i);
				VectorResult vecRes = new VectorResult();
				vecRes.vectorid = Base64Lite.decodeLongBase64(mainHit.get("_id").getAsString());
				vecRes.hitcount = -1;		// Cannot fill in at this time
				vecRes.sim = mainHit.get("_score").getAsDouble();
				JsonObject source = (JsonObject) mainHit.get("_source");
				StringReader reader = new StringReader(source.get("features").getAsString());
				vecRes.vec = vectorFactory.restoreVectorFromBase64(reader, decodeBuffer);
				vector.compareCounts(vecRes.vec, vecCompare);
				vecCompare.dotproduct = vecRes.sim * vector.getLength() * vecRes.vec.getLength();
				vecRes.signif = vectorFactory.calculateSignificance(vecCompare);
				listResult.add(vecRes);
			}
		}
		catch (IOException ex) {
			throw new ElasticException("Bad encoding in result document");
		}
		long totalCount = 0;
		Iterator<VectorResult> iter1 = listResult.iterator();
		Iterator<VectorResult> iter2 = listResult.iterator();
		while (iter1.hasNext()) {
			totalCount += fetchVectorCounts(iter1, iter2, MAX_VECTORCOUNT_WINDOW);
		}
		return totalCount;
	}
Query the database for all vectors that are "near" a given vector in terms
of similarity and significance. The routine returns a list of VectorResult
objects with the id, LSHVector, and hitcount filled in.
@param listResult is the discovered list of VectorResults
@param vector is the vector being queried
@param similarityThreshold is the similarity threshold results must exceed
@param significanceThreshold is the significance threshold results must exceed
@param maxVectors is the maximum number of (distinct) vectors to return
@return the total number of functions matching one of the returned vectors
@throws ElasticException for communication problems with the server
Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java