search is completely working in frontend now
This commit is contained in:
parent
b0d6f724ef
commit
1cba014948
@ -2,33 +2,57 @@ import logging
|
|||||||
import json
|
import json
|
||||||
from elasticsearch import Elasticsearch
|
from elasticsearch import Elasticsearch
|
||||||
from elasticsearch_dsl import Search, Q
|
from elasticsearch_dsl import Search, Q
|
||||||
from elasticsearch_dsl.connections import connections
|
|
||||||
|
|
||||||
from pillar import current_app
|
from pillar import current_app
|
||||||
|
|
||||||
#elk_hosts = current_app.config['ELASTIC_SEARCH_HOSTS']
|
|
||||||
#
|
|
||||||
#connections.create_connection(
|
|
||||||
# hosts=elk_hosts,
|
|
||||||
# sniff_on_start=True,
|
|
||||||
# timeout=20)
|
|
||||||
#
|
|
||||||
client = Elasticsearch()
|
client = Elasticsearch()
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
node_agg_terms = ['node_type', 'media', 'tags', 'is_free']
|
||||||
|
user_agg_terms = ['roles', ]
|
||||||
|
|
||||||
|
|
||||||
def add_aggs_to_search(search):
|
def add_aggs_to_search(search, agg_terms):
|
||||||
"""
|
"""
|
||||||
|
Add facets / aggregations to the search result
|
||||||
"""
|
"""
|
||||||
|
|
||||||
agg_terms = ['node_type', 'media', 'tags', 'is_free']
|
|
||||||
|
|
||||||
for term in agg_terms:
|
for term in agg_terms:
|
||||||
search.aggs.bucket(term, 'terms', field=term)
|
search.aggs.bucket(term, 'terms', field=term)
|
||||||
|
|
||||||
#search.aggs.bucket('project', 'terms', field='project.name')
|
|
||||||
|
def make_must(terms):
|
||||||
|
"""
|
||||||
|
Given some term parameters
|
||||||
|
we must match those
|
||||||
|
"""
|
||||||
|
|
||||||
|
must = []
|
||||||
|
|
||||||
|
for field, value in terms.items():
|
||||||
|
|
||||||
|
print(field, value)
|
||||||
|
|
||||||
|
if value:
|
||||||
|
must.append({'match': {field: value}})
|
||||||
|
|
||||||
|
return must
|
||||||
|
|
||||||
|
|
||||||
|
def nested_bool(should, terms):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
must = []
|
||||||
|
must = make_must(terms)
|
||||||
|
bool_query = Q('bool', should=should)
|
||||||
|
must.append(bool_query)
|
||||||
|
bool_query = Q('bool', must=must)
|
||||||
|
|
||||||
|
search = Search(using=client)
|
||||||
|
search.query = bool_query
|
||||||
|
|
||||||
|
return search
|
||||||
|
|
||||||
|
|
||||||
def do_search(query: str, terms: dict) -> dict:
|
def do_search(query: str, terms: dict) -> dict:
|
||||||
@ -46,16 +70,14 @@ def do_search(query: str, terms: dict) -> dict:
|
|||||||
Q('term', tags=query),
|
Q('term', tags=query),
|
||||||
]
|
]
|
||||||
|
|
||||||
#must = []
|
if query:
|
||||||
|
search = nested_bool(should, terms)
|
||||||
|
else:
|
||||||
|
# do a match all for the aggregations
|
||||||
|
search = Search(using=client)
|
||||||
|
search.query = Q('term', _type='node')
|
||||||
|
|
||||||
#for field, value in terms.items():
|
add_aggs_to_search(search, node_agg_terms)
|
||||||
# must.append(
|
|
||||||
|
|
||||||
bool_query = Q('bool', should=should)
|
|
||||||
search = Search(using=client)
|
|
||||||
search.query = bool_query
|
|
||||||
|
|
||||||
add_aggs_to_search(search)
|
|
||||||
|
|
||||||
if current_app.config['DEBUG']:
|
if current_app.config['DEBUG']:
|
||||||
print(json.dumps(search.to_dict(), indent=4))
|
print(json.dumps(search.to_dict(), indent=4))
|
||||||
@ -68,7 +90,7 @@ def do_search(query: str, terms: dict) -> dict:
|
|||||||
return response.to_dict()
|
return response.to_dict()
|
||||||
|
|
||||||
|
|
||||||
def do_user_search(query: str) -> dict:
|
def do_user_search(query: str, terms: dict) -> dict:
|
||||||
"""
|
"""
|
||||||
return user objects
|
return user objects
|
||||||
"""
|
"""
|
||||||
@ -76,17 +98,23 @@ def do_user_search(query: str) -> dict:
|
|||||||
Q('match', username=query),
|
Q('match', username=query),
|
||||||
Q('match', full_name=query),
|
Q('match', full_name=query),
|
||||||
]
|
]
|
||||||
bool_query = Q('bool', should=should)
|
|
||||||
search = Search(using=client)
|
if query:
|
||||||
search.query = bool_query
|
search = nested_bool(should, terms)
|
||||||
|
else:
|
||||||
|
# do a match all for the aggregations
|
||||||
|
search = Search(using=client)
|
||||||
|
search.query = Q('term', _type='user')
|
||||||
|
|
||||||
|
add_aggs_to_search(search, user_agg_terms)
|
||||||
|
|
||||||
if current_app.config['DEBUG']:
|
if current_app.config['DEBUG']:
|
||||||
log.debug(json.dumps(search.to_dict(), indent=4))
|
print(json.dumps(search.to_dict(), indent=4))
|
||||||
|
|
||||||
response = search.execute()
|
response = search.execute()
|
||||||
|
|
||||||
if current_app.config['DEBUG']:
|
if current_app.config['DEBUG']:
|
||||||
log.debug('%s', json.dumps(response.to_dict(), indent=4))
|
print(json.dumps(response.to_dict(), indent=4))
|
||||||
|
|
||||||
return response.to_dict()
|
return response.to_dict()
|
||||||
|
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from bson import ObjectId
|
from flask import Blueprint, request
|
||||||
from flask import Blueprint, request, current_app, make_response, url_for
|
|
||||||
from flask import Response
|
|
||||||
from werkzeug import exceptions as wz_exceptions
|
from werkzeug import exceptions as wz_exceptions
|
||||||
|
from pillar.api.utils import authorization, jsonify
|
||||||
|
|
||||||
from pillar.api.utils import authorization, jsonify, str2id
|
from . import queries
|
||||||
from pillar.api.utils import mongo
|
|
||||||
from pillar.api.utils.authorization import require_login, check_permissions
|
|
||||||
from pillar.auth import current_user
|
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
blueprint_search = Blueprint('elksearch', __name__)
|
blueprint_search = Blueprint('elksearch', __name__)
|
||||||
|
|
||||||
from . import queries
|
|
||||||
|
|
||||||
|
|
||||||
def _valid_search() -> str:
|
def _valid_search() -> str:
|
||||||
@ -25,19 +18,23 @@ def _valid_search() -> str:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
searchword = request.args.get('q', '')
|
searchword = request.args.get('q', '')
|
||||||
if not searchword:
|
# if not searchword:
|
||||||
raise wz_exceptions.BadRequest('You are forgetting a "?q=whatareyoulookingfor"')
|
# raise wz_exceptions.BadRequest(
|
||||||
|
# 'You are forgetting a "?q=whatareyoulookingfor"')
|
||||||
return searchword
|
return searchword
|
||||||
|
|
||||||
|
|
||||||
def _term_filters() -> dict:
|
def _term_filters() -> dict:
|
||||||
"""
|
"""
|
||||||
Check if frontent want to filter stuff
|
Check if frontent wants to filter stuff
|
||||||
|
on specific fields AKA facets
|
||||||
"""
|
"""
|
||||||
|
|
||||||
terms = [
|
terms = [
|
||||||
'node_type', 'media',
|
'node_type', 'media',
|
||||||
'tags', 'is_free', 'projectname']
|
'tags', 'is_free', 'projectname',
|
||||||
|
'roles',
|
||||||
|
]
|
||||||
|
|
||||||
parsed_terms = {}
|
parsed_terms = {}
|
||||||
|
|
||||||
@ -60,7 +57,8 @@ def search_user():
|
|||||||
|
|
||||||
searchword = _valid_search()
|
searchword = _valid_search()
|
||||||
|
|
||||||
data = queries.do_user_search(searchword)
|
terms = _term_filters()
|
||||||
|
data = queries.do_user_search(searchword, terms)
|
||||||
|
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
@ -8,7 +8,9 @@ $(document).ready(function() {
|
|||||||
var $hits = $('#hits');
|
var $hits = $('#hits');
|
||||||
var $stats = $('#stats');
|
var $stats = $('#stats');
|
||||||
var $facets = $('#facets');
|
var $facets = $('#facets');
|
||||||
|
//var facets = [];
|
||||||
var $pagination = $('#pagination');
|
var $pagination = $('#pagination');
|
||||||
|
var what = '';
|
||||||
|
|
||||||
// Templates binding
|
// Templates binding
|
||||||
var hitTemplate = Hogan.compile($('#hit-template').text());
|
var hitTemplate = Hogan.compile($('#hit-template').text());
|
||||||
@ -19,6 +21,7 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
// something elasticy!
|
// something elasticy!
|
||||||
var search = elasticSearcher;
|
var search = elasticSearcher;
|
||||||
|
|
||||||
// facets: $.map(FACET_CONFIG, function(facet) {
|
// facets: $.map(FACET_CONFIG, function(facet) {
|
||||||
// return !facet.disjunctive ? facet.name : null;
|
// return !facet.disjunctive ? facet.name : null;
|
||||||
// }),
|
// }),
|
||||||
@ -137,17 +140,23 @@ $(document).ready(function() {
|
|||||||
// If no results
|
// If no results
|
||||||
if (content.hits.length === 0) {
|
if (content.hits.length === 0) {
|
||||||
$facets.empty();
|
$facets.empty();
|
||||||
|
facets =[];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var storeValue = function (values, label){
|
var storeValue = function (values, label){
|
||||||
|
|
||||||
|
|
||||||
return function(item){
|
return function(item){
|
||||||
|
|
||||||
|
let refined = search.isRefined(label, item.key);
|
||||||
|
|
||||||
values.push({
|
values.push({
|
||||||
facet: label,
|
facet: label,
|
||||||
label: item.key,
|
label: item.key,
|
||||||
value: item.key,
|
value: item.key,
|
||||||
count: item.doc_count,
|
count: item.doc_count,
|
||||||
|
refined: refined,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -164,6 +173,8 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
if (buckets.length === 0) { continue; }
|
if (buckets.length === 0) { continue; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
buckets.forEach(storeValue(values, label));
|
buckets.forEach(storeValue(values, label));
|
||||||
|
|
||||||
facets.push({
|
facets.push({
|
||||||
@ -252,7 +263,7 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.toggleRefine', function() {
|
$(document).on('click', '.toggleRefine', function() {
|
||||||
search.addTerm($(this).data('facet'), $(this).data('value'));
|
search.toggleTerm($(this).data('facet'), $(this).data('value'));
|
||||||
search.execute();
|
search.execute();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@ -277,6 +288,7 @@ $(document).ready(function() {
|
|||||||
$('#facets').on("mouseenter mouseleave", ".button-checkbox", function(e) {
|
$('#facets').on("mouseenter mouseleave", ".button-checkbox", function(e) {
|
||||||
$(this).parent().find('.facet_link').toggleClass("hover");
|
$(this).parent().find('.facet_link').toggleClass("hover");
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#facets').on("mouseenter mouseleave", ".facet_link", function(e) {
|
$('#facets').on("mouseenter mouseleave", ".facet_link", function(e) {
|
||||||
$(this).parent().find('.button-checkbox button.btn').toggleClass("hover");
|
$(this).parent().find('.button-checkbox button.btn').toggleClass("hover");
|
||||||
});
|
});
|
||||||
@ -330,7 +342,7 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
var query = decodeURIComponent(sURLVariables[0].split('=')[1]);
|
var query = decodeURIComponent(sURLVariables[0].split('=')[1]);
|
||||||
$inputField.val(query);
|
$inputField.val(query);
|
||||||
search.setQuery(query);
|
search.setQuery(query, what);
|
||||||
|
|
||||||
for (var i = 2; i < sURLVariables.length; i++) {
|
for (var i = 2; i < sURLVariables.length; i++) {
|
||||||
var sParameterName = sURLVariables[i].split('=');
|
var sParameterName = sURLVariables[i].split('=');
|
||||||
@ -362,4 +374,8 @@ $(document).ready(function() {
|
|||||||
location.replace(urlParams);
|
location.replace(urlParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do empty search to fill aggregations
|
||||||
|
search.setQuery('', what);
|
||||||
|
search.execute();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -14,7 +14,7 @@ var elasticSearcher = (function() {
|
|||||||
page: 0,
|
page: 0,
|
||||||
|
|
||||||
setQuery: (function(q, _url){
|
setQuery: (function(q, _url){
|
||||||
console.log('setQuery!: ' + q);
|
console.log('setQuery!: ' + q + 'what :'+ _url);
|
||||||
deze.query=q;
|
deze.query=q;
|
||||||
if (_url !== undefined) {
|
if (_url !== undefined) {
|
||||||
deze.url=_url;
|
deze.url=_url;
|
||||||
@ -45,8 +45,19 @@ var elasticSearcher = (function() {
|
|||||||
return deze.newhits.aggregations;
|
return deze.newhits.aggregations;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
addTerm: (function(term, value){
|
toggleTerm: (function(term, value){
|
||||||
deze.terms[term] = value;
|
if (deze.terms[term] !== undefined) {
|
||||||
|
delete deze.terms[term];
|
||||||
|
} else {
|
||||||
|
deze.terms[term] = value;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
isRefined: (function(term, value){
|
||||||
|
if (deze.terms[term] === value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
//get response from elastic and rebuild json
|
//get response from elastic and rebuild json
|
||||||
@ -89,7 +100,8 @@ var elasticSearcher = (function() {
|
|||||||
setCurrentPage: deze.setCurrentPage,
|
setCurrentPage: deze.setCurrentPage,
|
||||||
query: deze.query,
|
query: deze.query,
|
||||||
page: deze.page,
|
page: deze.page,
|
||||||
addTerm: deze.addTerm,
|
toggleTerm: deze.toggleTerm,
|
||||||
|
isRefined: deze.isRefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
this.autocomplete({hint: false}, [
|
this.autocomplete({hint: false}, [
|
||||||
{
|
{
|
||||||
source: elasticSearch($, '/user'),
|
source: elasticSearch($, '/user'),
|
||||||
displayKey: 'full_name',
|
displayKey: 'full_name',
|
||||||
async: true,
|
async: true,
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
templates: {
|
templates: {
|
||||||
|
@ -22,6 +22,7 @@ style.
|
|||||||
type="text",
|
type="text",
|
||||||
name="q",
|
name="q",
|
||||||
id="q",
|
id="q",
|
||||||
|
what="/user",
|
||||||
autocomplete="off",
|
autocomplete="off",
|
||||||
spellcheck="false",
|
spellcheck="false",
|
||||||
autocorrect="false",
|
autocorrect="false",
|
||||||
@ -92,14 +93,6 @@ script(type="text/template", id="stats-template")
|
|||||||
| {% endblock %}
|
| {% endblock %}
|
||||||
|
|
||||||
| {% block footer_scripts %}
|
| {% block footer_scripts %}
|
||||||
script().
|
|
||||||
var APPLICATION_ID = '{{config.ALGOLIA_USER}}';
|
|
||||||
var SEARCH_ONLY_API_KEY = '{{config.ALGOLIA_PUBLIC_KEY}}';
|
|
||||||
var INDEX_NAME = '{{config.ALGOLIA_INDEX_USERS}}';
|
|
||||||
var sortByCountDesc = null;
|
|
||||||
var FACET_CONFIG = [
|
|
||||||
{ name: 'roles', title: 'Roles', disjunctive: false, sortFunction: sortByCountDesc },
|
|
||||||
];
|
|
||||||
|
|
||||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/algoliasearch-3.19.0.min.js')}}")
|
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/algoliasearch-3.19.0.min.js')}}")
|
||||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/algoliasearch.helper.min.js') }}")
|
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/algoliasearch.helper.min.js') }}")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user