diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2018-04-29 18:50:33 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2018-04-29 18:50:33 +0200 |
commit | 50a4e701cd5791b5400ca4c8b438b17baee351b0 (patch) | |
tree | 6db06916d47297c8cde3008f1fa80265066b7982 /themes/new_theme/layouts | |
parent | e2bcd2fa26b04fd2ea246b1eb765b9b52e7324fa (diff) | |
download | www-andreasbaumann-cc-50a4e701cd5791b5400ca4c8b438b17baee351b0.tar.gz www-andreasbaumann-cc-50a4e701cd5791b5400ca4c8b438b17baee351b0.tar.bz2 |
replace google site search with an ElasticLunr search
Diffstat (limited to 'themes/new_theme/layouts')
4 files changed, 345 insertions, 246 deletions
diff --git a/themes/new_theme/layouts/partials/ranklist.html b/themes/new_theme/layouts/partials/ranklist.html index 9b732d1..5c7786b 100644 --- a/themes/new_theme/layouts/partials/ranklist.html +++ b/themes/new_theme/layouts/partials/ranklist.html @@ -1,106 +1,29 @@ <script src="/js/jquery.js" type="text/javascript"></script> <script src="/js/url-search-params.js" type="text/javascript"></script> -<script src="/js/Snowball.min.js" type="text/javascript"></script> +<script src="/js/elasticlunr.min.js" type="text/javascript"></script> <script src="/js/loadingoverlay.min.js" type="text/javascript"></script> <script language="Javascript"> - var englishStemmer = new Snowball( "english" ); - - function stem( s ) { - englishStemmer.setCurrent( s ); - englishStemmer.stem( ); - return englishStemmer.getCurrent( ); - } - - function normalize_term( s ) { - var r = stem( s ); - return r.toLowerCase( ); - } - - function get_terms( s ) { - var terms = []; - var words = s.trim( ).split( ' ' ); - for( var i in words ) { - terms.push( - { - term: { - type: "word", - value: normalize_term( words[i] ) - } - } - ); - } - return terms; - } - - function get_features( query ) { - var features = []; - var words = query.trim( ).split( ' ' ); - for( var i in words ) { - features.push( - { - name: "feat", - value: { - term: { - type: "word", - value: normalize_term( words[i] ) - } - }, - weight: 1.0 - } - ); - } - features.push( - { - name: "sel", - value: { - expression : { - operator: "union", - range: 0, - cardinality: 0, - terms: get_terms( query ) - } - }, - weight: 1.0 - } - ) - return features; - } - - function draw_ranklist( query, data ) { + function draw_ranklist( query, results ) { var html = ''; - - if( data.ranklist.ranks.length == 0 ) { + + if( results.length == 0 ) { return "<p>No hits for query '" + query + "'...</p>"; } else { - html += "<p>" + data.ranklist.documents_ranked + " hits found</p>"; + html += "<p>" + results.length + " hits found</p>"; } - + var start = 1; html += "<ol class=\"ranklist\" start=\"" + start + "\">"; - for( var i = 0; i < data.ranklist.ranks.length; i++ ) { - var rank = data.ranklist.ranks[i]; - var abstract = ''; - var title = ''; - var title_attribute = 'No title'; - var docid = ''; - html += "<li>"; - for( var j = 0; j < rank.attributes.length; j++ ) { - var attribute = rank.attributes[j]; - if( attribute.key == 'title' ) { - title += ' ' + attribute.value; - } else if( attribute.key == 'title_attribute' ) { - title_attribute = attribute.value; - } else if( attribute.key == 'docid' ) { - docid = attribute.value; - } else if( attribute.key == 'text' ) { - abstract += ' ' + escapeHtml( attribute.value ); - } - } + for( var i = 0; i < results.length; i++ ) { + var rank = results[i]['doc']; + var abstract = rank['abstract']; + var title = rank['title']; if( title == '' ) { - title = title_attribute; + title = 'No title'; } - title = title.replaceAll( "#SMARK#", "<i>" ).replaceAll( "#EMARK#", "</i>" ); + var docid = results[i]['ref']; + html += "<li>"; html += "<div class='title'>" html += "<a href=\"" + docid + "\">" + title + "</a></div>"; if( abstract != '' ) { @@ -110,6 +33,7 @@ html += "</li>"; } html += "</ol>"; + return html; } @@ -123,153 +47,14 @@ } function executeQuery( query ) { - var request = { - query: { - first_rank: 0, - nof_ranks: 100, - features: get_features( query ), - select: [ - "sel" - ], - restrict: [ - ], - exclude: [ - ], - weighting: [ - { - name: "bm25", - params: [ - { - key : "match", - value : "feat" - } - ], - weight : 1.0 - } - ], - summarizer: [ - { - attribute: "docid", - name: "attribute", - params: [ - { - key : "name", - value : "docid" - } - ] - }, - { - attribute: "title_attribute", - name: "attribute", - params: [ - { - key : "name", - value : "title" - } - ], - resultnames: [ - { - key : "resultname", - value : "title_attribute" - } - ] - }, - { - attribute: "title", - name: "test", - params: [ - { - key: "type", - value: "title" - }, - { - key: "match", - value: "feat" - }, - { - key: "N", - value: 50 - }, - { - key: "add_dots", - value: 0 - }, - { - key: "start_first_match", - value: 0 - }, - { - key: "mark", - value: "#SMARK#%1%#EMARK#" - } - ], - resultnames: [ - { - key: "resultname", - value: "title" - } - ] - }, - { - attribute: "abstract", - name: "test", - params: [ - { - key: "type", - value: "text" - }, - { - key: "match", - value: "feat" - }, - { - key: "N", - value: 50 - }, - { - key: "add_dots", - value: 1 - }, - //~ { - //~ key: "sentence", - //~ value: "sentence" - //~ }, - //~ { - //~ key: "nof_sentences", - //~ value: 3 - //~ }, - { - key: "start_first_match", - value: 1 - }, - { - key: "mark", - value: "#SMARK#%1%#EMARK#" - } - ], - resultnames: [ - { - key: "resultname", - value: "text" - } - ] - } - ] - } - }; - var json = JSON.stringify( request, null, " " ); - console.log( "debug request: " + json ); - $( "#query" ).LoadingOverlay( "show" ); - + $.ajax( { - type : 'POST', - url : {{ .Site.Params.strus_url }}, - data : json, - contentType : 'application/json', + type : 'GET', + url : '/index/posts.index', cache : false, - timeout: 5000 + timeout : 5000 } ) .error( function( x, t, m ) { var html = ''; @@ -279,26 +64,24 @@ msg = t; } msg = escapeHtml( msg ); - html = "<pre><font color='red'>There was an error communicating to the strusWebService, reason: " + msg + "</font></pre>\n"; + html = "<pre><font color='red'>There was an error loading the Elasticlunr index, reason: " + msg + "</font></pre>\n"; $( '#ranklist' ).html( html ); $( "#query" ).LoadingOverlay( "hide", true ); } ) .success( function( data ) { - var json = JSON.stringify( data, null, " " ); - console.log( "debug answer: " + json ); - if( data.result == 'ok' ) { - var html = draw_ranklist( query, data ); - $( '#ranklist' ).html( html ); - } else { - var json = JSON.stringify( data, null, " " ); - var html = "<p>The strusWebService returned the following error:</p><pre><font color='red'>" + json + "</font></pre>"; - $( '#ranklist' ).html( html ); - } + var index = elasticlunr.Index.load( JSON.parse( data ) ); + + var results = index.search( query, { fields: { title : { boost : 2 }, content : { boost : 1 } } } ); + + var html = draw_ranklist( query, results ); + + $( '#ranklist' ).html( html ); $( "#query" ).LoadingOverlay( "hide" ); } ); + }; $( window ).load( function( ) { diff --git a/themes/new_theme/layouts/partials/ranklist_strus.html b/themes/new_theme/layouts/partials/ranklist_strus.html new file mode 100644 index 0000000..9b732d1 --- /dev/null +++ b/themes/new_theme/layouts/partials/ranklist_strus.html @@ -0,0 +1,316 @@ +<script src="/js/jquery.js" type="text/javascript"></script> +<script src="/js/url-search-params.js" type="text/javascript"></script> +<script src="/js/Snowball.min.js" type="text/javascript"></script> +<script src="/js/loadingoverlay.min.js" type="text/javascript"></script> +<script language="Javascript"> + + var englishStemmer = new Snowball( "english" ); + + function stem( s ) { + englishStemmer.setCurrent( s ); + englishStemmer.stem( ); + return englishStemmer.getCurrent( ); + } + + function normalize_term( s ) { + var r = stem( s ); + return r.toLowerCase( ); + } + + function get_terms( s ) { + var terms = []; + var words = s.trim( ).split( ' ' ); + for( var i in words ) { + terms.push( + { + term: { + type: "word", + value: normalize_term( words[i] ) + } + } + ); + } + return terms; + } + + function get_features( query ) { + var features = []; + var words = query.trim( ).split( ' ' ); + for( var i in words ) { + features.push( + { + name: "feat", + value: { + term: { + type: "word", + value: normalize_term( words[i] ) + } + }, + weight: 1.0 + } + ); + } + features.push( + { + name: "sel", + value: { + expression : { + operator: "union", + range: 0, + cardinality: 0, + terms: get_terms( query ) + } + }, + weight: 1.0 + } + ) + return features; + } + + function draw_ranklist( query, data ) { + var html = ''; + + if( data.ranklist.ranks.length == 0 ) { + return "<p>No hits for query '" + query + "'...</p>"; + } else { + html += "<p>" + data.ranklist.documents_ranked + " hits found</p>"; + } + + var start = 1; + html += "<ol class=\"ranklist\" start=\"" + start + "\">"; + for( var i = 0; i < data.ranklist.ranks.length; i++ ) { + var rank = data.ranklist.ranks[i]; + var abstract = ''; + var title = ''; + var title_attribute = 'No title'; + var docid = ''; + html += "<li>"; + for( var j = 0; j < rank.attributes.length; j++ ) { + var attribute = rank.attributes[j]; + if( attribute.key == 'title' ) { + title += ' ' + attribute.value; + } else if( attribute.key == 'title_attribute' ) { + title_attribute = attribute.value; + } else if( attribute.key == 'docid' ) { + docid = attribute.value; + } else if( attribute.key == 'text' ) { + abstract += ' ' + escapeHtml( attribute.value ); + } + } + if( title == '' ) { + title = title_attribute; + } + title = title.replaceAll( "#SMARK#", "<i>" ).replaceAll( "#EMARK#", "</i>" ); + html += "<div class='title'>" + html += "<a href=\"" + docid + "\">" + title + "</a></div>"; + if( abstract != '' ) { + abstract = abstract.replaceAll( "#SMARK#", "<b>" ).replaceAll( "#EMARK#", "</b>" ); + html += "<div class='abstract'>" + abstract + "</div>"; + } + html += "</li>"; + } + html += "</ol>"; + return html; + } + + String.prototype.replaceAll = function(search, replacement) { + var target = this; + return target.replace(new RegExp(search, 'g'), replacement); + }; + + function escapeHtml( text ) { + return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">" ); + } + + function executeQuery( query ) { + var request = { + query: { + first_rank: 0, + nof_ranks: 100, + features: get_features( query ), + select: [ + "sel" + ], + restrict: [ + ], + exclude: [ + ], + weighting: [ + { + name: "bm25", + params: [ + { + key : "match", + value : "feat" + } + ], + weight : 1.0 + } + ], + summarizer: [ + { + attribute: "docid", + name: "attribute", + params: [ + { + key : "name", + value : "docid" + } + ] + }, + { + attribute: "title_attribute", + name: "attribute", + params: [ + { + key : "name", + value : "title" + } + ], + resultnames: [ + { + key : "resultname", + value : "title_attribute" + } + ] + }, + { + attribute: "title", + name: "test", + params: [ + { + key: "type", + value: "title" + }, + { + key: "match", + value: "feat" + }, + { + key: "N", + value: 50 + }, + { + key: "add_dots", + value: 0 + }, + { + key: "start_first_match", + value: 0 + }, + { + key: "mark", + value: "#SMARK#%1%#EMARK#" + } + ], + resultnames: [ + { + key: "resultname", + value: "title" + } + ] + }, + { + attribute: "abstract", + name: "test", + params: [ + { + key: "type", + value: "text" + }, + { + key: "match", + value: "feat" + }, + { + key: "N", + value: 50 + }, + { + key: "add_dots", + value: 1 + }, + //~ { + //~ key: "sentence", + //~ value: "sentence" + //~ }, + //~ { + //~ key: "nof_sentences", + //~ value: 3 + //~ }, + { + key: "start_first_match", + value: 1 + }, + { + key: "mark", + value: "#SMARK#%1%#EMARK#" + } + ], + resultnames: [ + { + key: "resultname", + value: "text" + } + ] + } + ] + } + }; + + var json = JSON.stringify( request, null, " " ); + console.log( "debug request: " + json ); + + $( "#query" ).LoadingOverlay( "show" ); + + $.ajax( { + type : 'POST', + url : {{ .Site.Params.strus_url }}, + data : json, + contentType : 'application/json', + cache : false, + timeout: 5000 + } ) + .error( function( x, t, m ) { + var html = ''; + if( x.status > 0 ) { + msg = x.responseText; + } else { + msg = t; + } + msg = escapeHtml( msg ); + html = "<pre><font color='red'>There was an error communicating to the strusWebService, reason: " + msg + "</font></pre>\n"; + $( '#ranklist' ).html( html ); + + $( "#query" ).LoadingOverlay( "hide", true ); + } ) + .success( function( data ) { + var json = JSON.stringify( data, null, " " ); + console.log( "debug answer: " + json ); + + if( data.result == 'ok' ) { + var html = draw_ranklist( query, data ); + $( '#ranklist' ).html( html ); + } else { + var json = JSON.stringify( data, null, " " ); + var html = "<p>The strusWebService returned the following error:</p><pre><font color='red'>" + json + "</font></pre>"; + $( '#ranklist' ).html( html ); + } + + $( "#query" ).LoadingOverlay( "hide" ); + } ); + }; + + $( window ).load( function( ) { + var paramsString = window.location.search; + var searchParams = new URLSearchParams( paramsString ); + if( searchParams.has( "q" ) ) { + executeQuery( searchParams.get( "q" ) ); + } else { + // TODO: come up with something here + } // Show full page LoadingOverlay + } ); + +</script> +<div id="ranklist"> +</div> diff --git a/themes/new_theme/layouts/partials/sidebar.html b/themes/new_theme/layouts/partials/sidebar.html index 8241753..a69d2a9 100644 --- a/themes/new_theme/layouts/partials/sidebar.html +++ b/themes/new_theme/layouts/partials/sidebar.html @@ -1,5 +1,5 @@ <aside class="sidebar" itemscope="itemscope" itemtype="http://schema.org/WPSideBar"> - {{ partial "widgets/google_site_search.html" . }} + {{ partial "widgets/elasticlunr_search.html" . }} {{ $section := .Section }} {{ if or ( eq $section "blog" ) ( eq $section "" ) }} {{ partial "widgets/recent.html" . }} diff --git a/themes/new_theme/layouts/partials/widgets/google_site_search.html b/themes/new_theme/layouts/partials/widgets/google_site_search.html index 2c4befa..6221b27 100644 --- a/themes/new_theme/layouts/partials/widgets/google_site_search.html +++ b/themes/new_theme/layouts/partials/widgets/google_site_search.html @@ -4,7 +4,7 @@ <form class="widget-search__form" role="search" method="get" action="//google.com/search"> <label> <span class="screen-reader-text">Search for:</span> - <input class="widget-search__field" type="search" placeholder="GOOGLE SEARCH..." value="" name="q"> + <input class="widget-search__field" type="search" placeholder="SEARCH..." value="" name="q"> </label> <input class="widget-search__submit" type="submit" value="Search"> <input type="hidden" name="sitesearch" value="{{ .Site.BaseURL }}" /> |