Regexes are now compiled only once by search engine.

This commit is contained in:
NerdNumber9 2017-01-04 00:06:53 -05:00
parent 097a83e3ba
commit c49b865ee7
3 changed files with 42 additions and 23 deletions

View File

@ -1,4 +1,4 @@
package exh.search package exh.search
class Namespace(var namespace: Text, class Namespace(var namespace: String,
var tag: Text? = null) : QueryComponent() var tag: Text? = null) : QueryComponent()

View File

@ -2,22 +2,18 @@ package exh.search
import exh.metadata.models.ExGalleryMetadata import exh.metadata.models.ExGalleryMetadata
import exh.metadata.models.Tag import exh.metadata.models.Tag
import ru.lanwen.verbalregex.VerbalExpression
import java.util.*
class SearchEngine { class SearchEngine {
//TODO Namespace alias //TODO Namespace alias
fun matches(metadata: ExGalleryMetadata, query: List<QueryComponent>): Boolean { fun matches(metadata: ExGalleryMetadata, query: List<QueryComponent>): Boolean {
fun matchTagList(tags: List<Tag>, fun matchTagList(tags: List<Tag>,
component: Text, component: Text): Boolean {
builder: VerbalExpression.Builder,
built: VerbalExpression): Boolean {
//Match tags //Match tags
val tagMatcher = if(!component.exact) val tagMatcher = if(!component.exact)
builder.anything().build() component.asLenientRegex()
else else
built component.asRegex()
//Match beginning of tag //Match beginning of tag
if (tags.find { if (tags.find {
tagMatcher.testExact(it.name) tagMatcher.testExact(it.name)
@ -32,28 +28,21 @@ class SearchEngine {
for(component in query) { for(component in query) {
if(component is Text) { if(component is Text) {
val builder = component.asRegex()
val built = builder.build()
//Match title //Match title
if (built.test(metadata.title?.toLowerCase()) if (component.asRegex().test(metadata.title?.toLowerCase())
|| built.test(metadata.altTitle?.toLowerCase())) { || component.asRegex().test(metadata.altTitle?.toLowerCase())) {
continue continue
} }
//Match tags //Match tags
if(!matchTagList(metadata.tags.entries.flatMap(MutableMap.MutableEntry<String, ArrayList<Tag>>::value), if(!matchTagList(metadata.tags.entries.flatMap { it.value },
component, component)) return false
builder,
built))
return false
} else if(component is Namespace) { } else if(component is Namespace) {
//Match namespace //Match namespace
val ns = metadata.tags.entries.filter { val ns = metadata.tags.entries.filter {
it.key == component.namespace.rawTextOnly() it.key == component.namespace
}.flatMap { it.value } }.flatMap { it.value }
//Match tags //Match tags
val builder = component.tag!!.asRegex() if(!matchTagList(ns, component.tag!!))
val built = builder.build()
if(!matchTagList(ns, component.tag!!, builder, built))
return false return false
} }
} }
@ -110,7 +99,20 @@ class SearchEngine {
nextIsExact = true nextIsExact = true
} else if(char == ':') { } else if(char == ':') {
flushText() flushText()
namespace = Namespace(flushToText(), null) var flushed = flushToText().rawTextOnly()
//Map tag aliases
flushed = when(flushed) {
"a" -> "artist"
"c", "char" -> "character"
"f" -> "female"
"g", "creator", "circle" -> "group"
"l", "lang" -> "language"
"m" -> "male"
"p", "series" -> "parody"
"r" -> "reclass"
else -> flushed
}
namespace = Namespace(flushed, null)
} else if(char == ' ' && !inQuotes) { } else if(char == ' ' && !inQuotes) {
flushAll() flushAll()
} else { } else {

View File

@ -6,7 +6,24 @@ import ru.lanwen.verbalregex.VerbalExpression
class Text: QueryComponent() { class Text: QueryComponent() {
val components = mutableListOf<TextComponent>() val components = mutableListOf<TextComponent>()
fun asRegex(): VerbalExpression.Builder { private var regex: VerbalExpression? = null
private var lenientRegex: VerbalExpression? = null
fun asRegex(): VerbalExpression {
if(regex == null) {
regex = baseBuilder().build()
}
return regex!!
}
fun asLenientRegex(): VerbalExpression {
if(lenientRegex == null) {
lenientRegex = baseBuilder().anything().build()
}
return lenientRegex!!
}
fun baseBuilder(): VerbalExpression.Builder {
val builder = VerbalExpression.regex() val builder = VerbalExpression.regex()
for(component in components) { for(component in components) {
when(component) { when(component) {