More search options

This commit is contained in:
Simon 2018-06-26 21:38:26 -04:00
parent b1ad39c204
commit b570e81bec
4 changed files with 102 additions and 38 deletions

33
app.py
View File

@ -10,6 +10,7 @@ import config
from flask_caching import Cache
from task import TaskDispatcher, Task, CrawlServer
from search.search import ElasticSearchEngine
from jinja2 import Undefined
app = Flask(__name__)
recaptcha = ReCaptcha(app=app,
@ -239,9 +240,27 @@ def search():
size_max = request.args.get("size_max") if "size_max" in request.args else "size_max"
size_max = int(size_max) if size_max.isdigit() else 0
match_all = "all" in request.args
field_name = "field_name" in request.args
field_trigram = "field_trigram" in request.args
field_path = "field_path" in request.args
if not field_name and not field_trigram and not field_path:
# If no fields are selected, search in all
field_name = field_path = field_trigram = True
fields = []
if field_path:
fields.append("path")
if field_name:
fields.append("name^5")
if field_trigram:
fields.append("name.nGram^2")
if len(q) >= 3:
try:
hits = searchEngine.search(q, page, per_page, sort_order, extensions, size_min, size_max)
hits = searchEngine.search(q, page, per_page, sort_order, extensions, size_min, size_max, match_all, fields)
hits = db.join_website_on_search_result(hits)
except InvalidQueryException as e:
flash("<strong>Invalid query:</strong> " + str(e), "warning")
@ -250,9 +269,15 @@ def search():
hits = None
return render_template("search.html",
results=hits, q=q, p=page, sort_order=sort_order,
per_page=per_page, results_set=config.RESULTS_PER_PAGE,
extensions=",".join(extensions), size_min=size_min, size_max=size_max)
results=hits,
q=q,
p=page, per_page=per_page,
sort_order=sort_order,
results_set=config.RESULTS_PER_PAGE,
extensions=",".join(extensions),
size_min=size_min, size_max=size_max,
match_all=match_all,
field_trigram=field_trigram, field_path=field_path, field_name=field_name)
@app.route("/contribute")

View File

@ -16,7 +16,7 @@ class SearchEngine:
def import_json(self, in_str: str, website_id: int):
raise NotImplementedError
def search(self, query, page, per_page, sort_order, extension, size_min, size_max) -> {}:
def search(self, query, page, per_page, sort_order, extension, size_min, size_max, match_all, fields) -> {}:
raise NotImplementedError
def reset(self):
@ -142,7 +142,7 @@ class ElasticSearchEngine(SearchEngine):
action_string = '{"index":{}}\n'
return "\n".join("".join([action_string, ujson.dumps(doc)]) for doc in docs)
def search(self, query, page, per_page, sort_order, extensions, size_min, size_max) -> {}:
def search(self, query, page, per_page, sort_order, extensions, size_min, size_max, match_all, fields) -> {}:
filters = []
if extensions:
@ -167,8 +167,8 @@ class ElasticSearchEngine(SearchEngine):
"must": {
"multi_match": {
"query": query,
"fields": ["name^5", "name.nGram^2", "path"],
"operator": "or"
"fields": fields,
"operator": "or" if match_all else "and"
}
},
"filter": filters

View File

@ -92,8 +92,8 @@
mark {
background-color: rgba(255, 255, 0, 0.4);
border-radius: 2px;
padding: 1px;
border-radius: 0;
padding: 1px 0;
}
body {
color: #BBBBBB;

View File

@ -14,13 +14,59 @@
<div class="form-row">
{# Query #}
<div class="form-group col-md-7">
<div class="input-group form-group">
<div class="input-group-prepend">
<div class="input-group-text">
<label for="matchAll" style="margin-bottom: 0">Match any word&nbsp</label>
<input title="Toggle between 'match all words' and 'match any word'" type="checkbox" id="matchAll" name="all" {{ "checked" if match_all }}>
</div>
</div>
<input class="form-control" name="q" id="q" placeholder="Query" value="{{ q }}">
</div>
{# Sort order #}
</div>
{# Size #}
<div class="text-muted" style="text-align: center">File size</div>
<input title="File size" id="sizeSlider">
<input type="hidden" name="size_min" id="sizeMin" value="{{ size_min }}">
<input type="hidden" name="size_max" id="sizeMax" value="{{ size_max }}">
<div class="form-row">
{# File extension #}
<div class="form-group col-md-6">
<div class="text-muted">File extension</div>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">.</div>
</div>
<input name="ext" placeholder="Extensions, comma-separated" class="form-control"
value="{{ extensions }}">
</div>
</div>
{# Fields #}
<div class="col-md-5" style="margin-left: 1em">
<div class="text-muted">Search in</div>
<div class="form-group form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="field_name" name="field_name"{{ "checked" if field_name else ""}}>
<label class="form-check-label" for="field_name">name</label>
</div>
<div class="form-group form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="field_trigram" name="field_trigram"{{ "checked" if field_trigram else ""}}>
<label class="form-check-label" for="field_trigram">name.trigram</label>
</div>
<div class="form-group form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="field_path" name="field_path" {{ "checked" if field_path else ""}}>
<label class="form-check-label" for="field_path">path</label>
</div>
</div>
</div>
<div class="text-muted">Display options</div>
<div class="form-row">
<div class="form-group col-md-3">
{# Sort order #}
<select class="form-control" name="sort_order" title="Sort order">
<option disabled>Select sort order</option>
<option disabled>Sort order</option>
<option value="score" {{ "selected" if sort_order == "score" else "" }}>Relevance </option>
<option value="size_asc" {{ "selected" if sort_order == "size_asc" else "" }}>Size ascending </option>
<option value="size_dsc" {{ "selected" if sort_order == "size_dsc" else "" }}>Size descending</option>
@ -38,27 +84,12 @@
{% endfor %}
</select>
</div>
</div>
{# Filters #}
<span class="text-muted">Filters</span>
<div class="form-row">
{# File extension #}
<div class="form-group col-md-6">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">.</div>
</div>
<input name="ext" placeholder="Extensions, comma-separated" class="form-control" value="{{ extensions }}">
{# Search button #}
<div class="form-group col-md-7">
<input class="btn btn-primary btn-shadow" type="submit" value="Search" style="float: right">
</div>
</div>
</div>
{# Size #}
<input title="File size" id="sizeSlider">
<input type="hidden" name="size_min" id="sizeMin" value="{{ size_min }}">
<input type="hidden" name="size_max" id="sizeMax" value="{{ size_max }}">
<input class="btn btn-primary btn-shadow" type="submit" value="Search">
</form>
</div>
@ -76,7 +107,14 @@
{% for hit in results["hits"]["hits"] %}
{% set src = hit["_source"] %}
{% set hl_name = hit["highlight"]["name"][0] if "name" in hit["highlight"] else src["name"] %}
{% if "name" in hit["highlight"] %}
{% set hl_name = hit["highlight"]["name"][0] %}
{% elif "name.nGram" in hit["highlight"] %}
{% set hl_name = hit["highlight"]["name.nGram"][0] %}
{% else %}
{% set hl_name = src["name"] %}
{% endif %}
{% set hl_path = hit["highlight"]["path"][0] if "path" in hit["highlight"] else src["path"] %}
<tr>
@ -98,7 +136,8 @@
{% endif %}
{# File path #}
<div class="text-muted" title="{{ path }}" style="font-size: 10px;">
<a title="See files from this website" href="/website/{{ src["website_id"] }}">{{ src["website_url"] }}</a>{{ hl_path|safe }}
<a title="See files from this website"
href="/website/{{ src["website_id"] }}">{{ src["website_url"] }}</a>{{ hl_path|safe }}
</div>
</td>
{# File size & date #}
@ -112,11 +151,11 @@
</table>
</div>
{% if results["hits"]["total"] > (p + 1) * per_page %}
<a href="/search?q={{ q }}&p={{ p + 1 }}&sort_order={{ sort_order }}&per_page={{ per_page }}&ext={{ extensions }}&size_min={{ size_min }}&size_max={{ size_max }}"
<a href="/search?q={{ q }}&p={{ p + 1 }}&sort_order={{ sort_order }}&per_page={{ per_page }}&ext={{ extensions }}&size_min={{ size_min }}&size_max={{ size_max }}{{ "&field_path=on" if field_path else "" }}{{ "&field_name=on" if field_name else "" }}{{ "&field_trigram" if field_trigram else "" }}"
class="btn btn-primary" style="float: right">Next</a>
{% endif %}
{% if p > 0 %}
<a href="/search?q={{ q }}&p={{ p - 1 }}&sort_order={{ sort_order }}&per_page={{ per_page }}&ext={{ extensions }}&size_min={{ size_min }}&size_max={{ size_max }}"
<a href="/search?q={{ q }}&p={{ p - 1 }}&sort_order={{ sort_order }}&per_page={{ per_page }}&ext={{ extensions }}&size_min={{ size_min }}&size_max={{ size_max }}{{ "&field_path=on" if field_path else "" }}{{ "&field_name=on" if field_name else "" }}{{ "&field_trigram" if field_trigram else "" }}"
class="btn btn-primary">Previous</a>
{% endif %}