ModelIndex indexes mentities by their name and full name

It provides methods to find mentities based on a prefix or string similarity.

var index = new ModelIndex
for mentity in model.collect_mentities do
    if mentity isa MClassDef or mentity isa MPropDef then continue
    index.index(mentity)
end

for e in index.find("Foo").uniq.sort(new ScoreComparator).limit(10) do
    print " * {e.score}: {e.mentity.name} ({e.mentity.full_name})"
end

Introduced properties

private var _full_name_distances: BKTree

nitc :: ModelIndex :: _full_name_distances

Distance tree for mentities full_name
private var _full_name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: _full_name_prefixes

Prefix tree for mentities full_name
private var _full_names: HashMap[String, MEntity]

nitc :: ModelIndex :: _full_names

Map of all mentities indexed by their full_name
private var _mentities: Array[MEntity]

nitc :: ModelIndex :: _mentities

List of all indexed mentities.
private var _name_distances: BKTree

nitc :: ModelIndex :: _name_distances

Distance tree for mentities name
private var _name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: _name_prefixes

Prefix tree for mentities name
private var _names: HashMap[String, Array[MEntity]]

nitc :: ModelIndex :: _names

Map of all mentities indexed by their name
fun find(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find

Find all mentities that matches name
fun find_by_full_name(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_full_name

Find mentities by full name trying firt by prefix then by similarity
fun find_by_full_name_prefix(prefix: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_full_name_prefix

Find all mentities where MEntity::full_name matches the prefix
fun find_by_full_name_similarity(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_full_name_similarity

Rank all mentities by the distance between MEntity::full_name and full_name
fun find_by_name(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_name

Find mentities by name trying first by prefix then by similarity
fun find_by_name_prefix(prefix: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_name_prefix

Find all mentities where MEntity::name matches the prefix
fun find_by_name_similarity(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_name_similarity

Rank all mentities by the distance between MEntity::name and name
fun find_by_similarity(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_similarity

Rank all mentities by the distance between name and both the mentity name and full name
fun full_name_distances: BKTree

nitc :: ModelIndex :: full_name_distances

Distance tree for mentities full_name
protected fun full_name_distances=(full_name_distances: BKTree)

nitc :: ModelIndex :: full_name_distances=

Distance tree for mentities full_name
fun full_name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: full_name_prefixes

Prefix tree for mentities full_name
protected fun full_name_prefixes=(full_name_prefixes: Trie[Array[MEntity]])

nitc :: ModelIndex :: full_name_prefixes=

Prefix tree for mentities full_name
fun full_names: HashMap[String, MEntity]

nitc :: ModelIndex :: full_names

Map of all mentities indexed by their full_name
protected fun full_names=(full_names: HashMap[String, MEntity])

nitc :: ModelIndex :: full_names=

Map of all mentities indexed by their full_name
fun index(mentity: MEntity)

nitc :: ModelIndex :: index

Index mentity so it can be retrieved by a find query
private fun index_by_full_name(mentity: MEntity)

nitc :: ModelIndex :: index_by_full_name

Index mentity by its MEntity::full_name
private fun index_by_name(mentity: MEntity)

nitc :: ModelIndex :: index_by_name

Index mentity by it's MEntity::name
fun mentities: Array[MEntity]

nitc :: ModelIndex :: mentities

List of all indexed mentities.
protected fun mentities=(mentities: Array[MEntity])

nitc :: ModelIndex :: mentities=

List of all indexed mentities.
fun name_distances: BKTree

nitc :: ModelIndex :: name_distances

Distance tree for mentities name
protected fun name_distances=(name_distances: BKTree)

nitc :: ModelIndex :: name_distances=

Distance tree for mentities name
fun name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: name_prefixes

Prefix tree for mentities name
protected fun name_prefixes=(name_prefixes: Trie[Array[MEntity]])

nitc :: ModelIndex :: name_prefixes=

Prefix tree for mentities name
fun names: HashMap[String, Array[MEntity]]

nitc :: ModelIndex :: names

Map of all mentities indexed by their name
protected fun names=(names: HashMap[String, Array[MEntity]])

nitc :: ModelIndex :: names=

Map of all mentities indexed by their name
private fun score_results_incremental(array: Array[Array[MEntity]], filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: score_results_incremental

Translate Trie results to SearchResult

Redefined properties

redef type SELF: ModelIndex

nitc $ ModelIndex :: SELF

Type of this instance, automatically specialized in every class

All properties

fun !=(other: nullable Object): Bool

core :: Object :: !=

Have self and other different values?
fun ==(other: nullable Object): Bool

core :: Object :: ==

Have self and other the same value?
type CLASS: Class[SELF]

core :: Object :: CLASS

The type of the class of self.
type SELF: Object

core :: Object :: SELF

Type of this instance, automatically specialized in every class
private var _full_name_distances: BKTree

nitc :: ModelIndex :: _full_name_distances

Distance tree for mentities full_name
private var _full_name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: _full_name_prefixes

Prefix tree for mentities full_name
private var _full_names: HashMap[String, MEntity]

nitc :: ModelIndex :: _full_names

Map of all mentities indexed by their full_name
private var _mentities: Array[MEntity]

nitc :: ModelIndex :: _mentities

List of all indexed mentities.
private var _name_distances: BKTree

nitc :: ModelIndex :: _name_distances

Distance tree for mentities name
private var _name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: _name_prefixes

Prefix tree for mentities name
private var _names: HashMap[String, Array[MEntity]]

nitc :: ModelIndex :: _names

Map of all mentities indexed by their name
protected fun class_factory(name: String): CLASS

core :: Object :: class_factory

Implementation used by get_class to create the specific class.
fun class_name: String

core :: Object :: class_name

The class name of the object.
fun find(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find

Find all mentities that matches name
fun find_by_full_name(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_full_name

Find mentities by full name trying firt by prefix then by similarity
fun find_by_full_name_prefix(prefix: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_full_name_prefix

Find all mentities where MEntity::full_name matches the prefix
fun find_by_full_name_similarity(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_full_name_similarity

Rank all mentities by the distance between MEntity::full_name and full_name
fun find_by_name(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_name

Find mentities by name trying first by prefix then by similarity
fun find_by_name_prefix(prefix: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_name_prefix

Find all mentities where MEntity::name matches the prefix
fun find_by_name_similarity(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_name_similarity

Rank all mentities by the distance between MEntity::name and name
fun find_by_similarity(name: String, filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: find_by_similarity

Rank all mentities by the distance between name and both the mentity name and full name
fun full_name_distances: BKTree

nitc :: ModelIndex :: full_name_distances

Distance tree for mentities full_name
protected fun full_name_distances=(full_name_distances: BKTree)

nitc :: ModelIndex :: full_name_distances=

Distance tree for mentities full_name
fun full_name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: full_name_prefixes

Prefix tree for mentities full_name
protected fun full_name_prefixes=(full_name_prefixes: Trie[Array[MEntity]])

nitc :: ModelIndex :: full_name_prefixes=

Prefix tree for mentities full_name
fun full_names: HashMap[String, MEntity]

nitc :: ModelIndex :: full_names

Map of all mentities indexed by their full_name
protected fun full_names=(full_names: HashMap[String, MEntity])

nitc :: ModelIndex :: full_names=

Map of all mentities indexed by their full_name
fun get_class: CLASS

core :: Object :: get_class

The meta-object representing the dynamic type of self.
fun hash: Int

core :: Object :: hash

The hash code of the object.
fun index(mentity: MEntity)

nitc :: ModelIndex :: index

Index mentity so it can be retrieved by a find query
private fun index_by_full_name(mentity: MEntity)

nitc :: ModelIndex :: index_by_full_name

Index mentity by its MEntity::full_name
private fun index_by_name(mentity: MEntity)

nitc :: ModelIndex :: index_by_name

Index mentity by it's MEntity::name
init init

core :: Object :: init

fun inspect: String

core :: Object :: inspect

Developer readable representation of self.
protected fun inspect_head: String

core :: Object :: inspect_head

Return "CLASSNAME:#OBJECTID".
intern fun is_same_instance(other: nullable Object): Bool

core :: Object :: is_same_instance

Return true if self and other are the same instance (i.e. same identity).
fun is_same_serialized(other: nullable Object): Bool

core :: Object :: is_same_serialized

Is self the same as other in a serialization context?
intern fun is_same_type(other: Object): Bool

core :: Object :: is_same_type

Return true if self and other have the same dynamic type.
fun mentities: Array[MEntity]

nitc :: ModelIndex :: mentities

List of all indexed mentities.
protected fun mentities=(mentities: Array[MEntity])

nitc :: ModelIndex :: mentities=

List of all indexed mentities.
fun name_distances: BKTree

nitc :: ModelIndex :: name_distances

Distance tree for mentities name
protected fun name_distances=(name_distances: BKTree)

nitc :: ModelIndex :: name_distances=

Distance tree for mentities name
fun name_prefixes: Trie[Array[MEntity]]

nitc :: ModelIndex :: name_prefixes

Prefix tree for mentities name
protected fun name_prefixes=(name_prefixes: Trie[Array[MEntity]])

nitc :: ModelIndex :: name_prefixes=

Prefix tree for mentities name
fun names: HashMap[String, Array[MEntity]]

nitc :: ModelIndex :: names

Map of all mentities indexed by their name
protected fun names=(names: HashMap[String, Array[MEntity]])

nitc :: ModelIndex :: names=

Map of all mentities indexed by their name
private intern fun native_class_name: CString

core :: Object :: native_class_name

The class name of the object in CString format.
intern fun object_id: Int

core :: Object :: object_id

An internal hash code for the object based on its identity.
fun output

core :: Object :: output

Display self on stdout (debug only).
intern fun output_class_name

core :: Object :: output_class_name

Display class name on stdout (debug only).
private fun score_results_incremental(array: Array[Array[MEntity]], filter: nullable ModelFilter): IndexMatches

nitc :: ModelIndex :: score_results_incremental

Translate Trie results to SearchResult
fun serialization_hash: Int

core :: Object :: serialization_hash

Hash value use for serialization
intern fun sys: Sys

core :: Object :: sys

Return the global sys object, the only instance of the Sys class.
abstract fun to_jvalue(env: JniEnv): JValue

core :: Object :: to_jvalue

fun to_s: String

core :: Object :: to_s

User readable representation of self.
package_diagram nitc::ModelIndex ModelIndex core::Object Object nitc::ModelIndex->core::Object

Parents

interface Object

core :: Object

The root of the class hierarchy.

Class definitions

nitc $ ModelIndex
# ModelIndex indexes mentities by their name and full name
#
# It provides methods to find mentities based on a prefix or string similarity.
#
# ~~~nitish
# # Build index
# var index = new ModelIndex
# for mentity in model.collect_mentities do
#	if mentity isa MClassDef or mentity isa MPropDef then continue
#	index.index(mentity)
# end
#
# for e in index.find("Foo").uniq.sort(new ScoreComparator).limit(10) do
#	print " * {e.score}: {e.mentity.name} ({e.mentity.full_name})"
# end
# ~~~
class ModelIndex

	# List of all indexed mentities.
	#
	# Faster than traversing the tries.
	var mentities = new Array[MEntity]

	# Map of all mentities indexed by their `name`
	var names = new HashMap[String, Array[MEntity]]

	# Prefix tree for mentities `name`
	#
	# Because multiple mentities can share the same `name`, we use a Trie of
	# arrays of mentities.
	#
	# As for now, we do not index class and property definitions.
	# TODO add an option.
	var name_prefixes = new Trie[Array[MEntity]]

	# Distance tree for mentities `name`
	var name_distances = new BKTree

	# Map of all mentities indexed by their `full_name`
	var full_names = new HashMap[String, MEntity]

	# Prefix tree for mentities `full_name`
	#
	# Even if two mentities cannot share the same `full_name`, we use a Trie of
	# arrays of mentities to be consistent with `name_prefixes`.
	var full_name_prefixes = new Trie[Array[MEntity]]

	# Distance tree for mentities `full_name`
	var full_name_distances = new BKTree

	# Index `mentity` by it's `MEntity::name`
	#
	# See `name_prefixes`.
	private fun index_by_name(mentity: MEntity) do
		var name = mentity.name

		# Index name
		if not names.has_key(name) then
			names[name] = new Array[MEntity]
		end
		names[name].add mentity

		# Index prefix
		if not name_prefixes.has_key(name) then
			name_prefixes[name] = new Array[MEntity]
		end
		name_prefixes[name].add mentity

		# Index distance
		name_distances.add(name)
	end

	# Index `mentity` by its `MEntity::full_name`
	private fun index_by_full_name(mentity: MEntity) do
		var name = mentity.full_name

		# Index full name
		full_names[name] = mentity

		# Index prefix
		if not full_name_prefixes.has_key(name) then
			full_name_prefixes[name] = new Array[MEntity]
		end
		full_name_prefixes[name].add mentity

		# Index distance
		full_name_distances.add(name)
	end

	# Index `mentity` so it can be retrieved by a find query
	#
	# MEntities are indexed by both name and full_name.
	fun index(mentity: MEntity) do
		mentities.add mentity
		index_by_name mentity
		index_by_full_name mentity
	end

	# Translate Trie results to `SearchResult`
	#
	# This method is used internally to translate each mentity returned by a prefix
	# match in a Trie into a SearchResult that can be ranked by score.
	#
	# Results from the Trie are returned in a breadth first manner so we get the
	# matches ordered by prefix.
	# We preserve that order by giving an incremental score to the `array` items.
	private fun score_results_incremental(array: Array[Array[MEntity]], filter: nullable ModelFilter): IndexMatches do
		var results = new IndexMatches
		var score = 1
		for mentities in array do
			for mentity in mentities do
				if filter != null and not filter.accept_mentity(mentity) then continue
				results.add new IndexMatch(mentity, score)
			end
			score += 1
		end
		return results
	end

	# Find all mentities where `MEntity::name` matches the `prefix`
	fun find_by_name_prefix(prefix: String, filter: nullable ModelFilter): IndexMatches do
		return score_results_incremental(name_prefixes.find_by_prefix(prefix), filter)
	end

	# Find all mentities where `MEntity::full_name` matches the `prefix`
	fun find_by_full_name_prefix(prefix: String, filter: nullable ModelFilter): IndexMatches do
		return score_results_incremental(full_name_prefixes.find_by_prefix(prefix), filter)
	end

	# Rank all mentities by the distance between `MEntity::name` and `name`
	#
	# Use the Levenshtein algorithm on all the indexed mentities `name`.
	# Warning: may not scale to large indexes.
	fun find_by_name_similarity(name: String, filter: nullable ModelFilter): IndexMatches do
		var results = new IndexMatches
		for match in name_distances.search(name) do
			var dist = match.distance
			var mname = match.key
			if not names.has_key(mname) then continue
			for mentity in names[mname] do
				if mentity isa MClassDef or mentity isa MPropDef then continue
				if filter != null and not filter.accept_mentity(mentity) then continue
				results.add new IndexMatch(mentity, dist)
			end
		end
		return results
	end

	# Rank all mentities by the distance between `MEntity::full_name` and `full_name`
	#
	# Use the Levenshtein algorithm on all the indexed mentities `full_name`.
	# Warning: may not scale to large indexes.
	fun find_by_full_name_similarity(name: String, filter: nullable ModelFilter): IndexMatches do
		var results = new IndexMatches
		for match in full_name_distances.search(name) do
			var dist = match.distance
			var mname = match.key
			if not full_names.has_key(mname) then continue
			var mentity = full_names[mname]
			if mentity isa MClassDef or mentity isa MPropDef then continue
			if filter != null and not filter.accept_mentity(mentity) then continue
			results.add new IndexMatch(mentity, dist)
		end
		return results
	end

	# Rank all mentities by the distance between `name` and both the mentity name and full name
	fun find_by_similarity(name: String, filter: nullable ModelFilter): IndexMatches do
		var results = new IndexMatches
		results.add_all find_by_full_name_similarity(name, filter)
		results.add_all find_by_name_similarity(name, filter)
		return results
	end

	# Find mentities by name trying first by prefix then by similarity
	fun find_by_name(name: String, filter: nullable ModelFilter): IndexMatches do
		var results = find_by_name_prefix(name, filter)
		results.add_all find_by_name_similarity(name, filter)
		return results
	end

	# Find mentities by full name trying firt by prefix then by similarity
	fun find_by_full_name(name: String, filter: nullable ModelFilter): IndexMatches do
		var results = find_by_full_name_prefix(name)
		results.add_all find_by_full_name_similarity(name, filter)
		return results
	end

	# Find all mentities that matches `name`
	#
	# 1. try by name prefix
	# 2. add full name prefix matches
	# 3. try similarity by name
	# 4. try similarity by full_name
	fun find(name: String, filter: nullable ModelFilter): IndexMatches do
		var results = find_by_name_prefix(name, filter)
		results.add_all find_by_full_name_prefix(name, filter)
		results.add_all find_by_similarity(name, filter)
		return results
	end
end
src/model/model_index.nit:227,1--427,3