Beiträge zu “jekyll”

Jekyll: (Even) Bettertube

Auf einigen meiner Jekyll Blogs verwende ich das Plugin Bettertube. Damit kann man verhindern das das Video direkt von Youtube geladen wird. Es wird statt dessen ein Thumbnail angezeigt und erst wenn man auf den “Playbutton” drückt wird das Video gestartet.

Leider gab es immer noch den Download des Thumbnails von Youtube beim Aufruf der Seite durch den Benutzer. Das Bild unten zeigt die Abfrage.

Mit dieser kleinen Änderung kann dies abgeschaltet werden. Beim erstellen der Seite wird das Thumbnail heruntergeladen und in ein Verzeichnis geladen. Dieses dann statische Bild wird beim Erzeugen der Site als Hintergrundbild verwendet.

Es fehlt noch eine Fehlerbehandlung wenn das Thumbnail nicht gefunden wird oder wenn man vielleicht ein eigenes verwenden möchte.

   thumbnail = "<figure class='BetterTube' data-youtube-id='#{id}' data-player-width='#{w}' data-player-height='#{h}' id='#{id}' style='padding-bottom: #{padding_bottom}'><a class='BetterTubePlayer' href='http://www.youtube.com/watch?v=a_426RiwST8' style='background: url(/youtube/#{id}.jpg) 50% 50% no-repeat rgb(0, 0, 0);'></a><div class='BetterTube-playBtn'></div>&nbsp;</figure>"
   padding_bottom = ("%.2f" % intrinsic).to_s  + "%"
   url = "https://img.youtube.com/vi/#{id}/hqdefault.jpg"
   download = open(url)
   IO.copy_stream(download, "youtube/#{id}.jpg")
10.5.18
Weitere Beiträge zu: jekyll   youtube  

Jekyll: Disqus Kommentare nur wenn gewünscht

Jekyll bietet von Hause aus keine Kommentar an. Die meisten verwenden für diese Funktionen externe Dienste wie Disqus.

Eigentlich bin ich kein großer Fan von Kommentaren da ich in der Vergangenheit hauptsächlich Spam Kommentare bekommen habe und mehr mit dem Löschen als mit dem Beantworten beschäftigt gewesen bin.

Außerdem hat mit bisher gestört das über die Standardintegration jeder Aufruf auf meiner Seite an Disqus weiterleitet wurde. Das geht auf die Ladezeiten und außerdem wird das Surfverhalten meiner Besucher an Disqus.com gemeldet was ich nicht möchte.

Da es wohl doch Anwender gibt die Kommentieren oder Fragen wollen habe ich nun eine Möglichkeit gefunden die Disqus Funktionen über einen Button / Link zu aktivieren. Wenn ein Leser es also möchte kann er es nutzen.

Zurerst erstellen wir einen neuen Disqus Channel für die Webseite. Aus dem angebotenen Universal Code kopiert man sich folgende Url

webseiten-channel-name.disqus.com/count.js

In dem Template für Posts habe ich ans Ende folgendes Javascript Code angehängt (natürlich sollte die URL für Euch eine andere sein)

    <script type="text/javascript">
   var myLink = document.getElementById('showDisquss');
   myLink.onclick = function(){
       var script = document.createElement("script");
       script.type = "text/javascript";
       script.src = " webseiten-channel-name.disqus.com/count.js"; 
       document.getElementsByTagName("head")[0].appendChild(script);
       return false;
   }
   </script>

Und dann an einer geeigneten Stelle folgenden Link/Button im Post Template verwendet.

 <a href="" style="border: 1px solid #ddd;   height: 40px;" title="Kommentieren" id="showDisquss" role="button" aria-label="Kommentare aktivieren">Disqus Kommentare aktivieren</a>

Dann erst werden die ganzen Diqus Dateien geladen und das folgende Div wird mit den Kommentaren gefüllt

    <div id="disqus_thread"></div>

Funktioniert bis her ganz gut.

14.12.15
Weitere Beiträge zu: jekyll   disqus  

Jekyll: Youtube Videos einbinden

Natürlich kann man Youtube Videos einfach über den normalen von Youtube vorgegebenen IFrame einbinden. Ich mache das nur ausgeprochen ungern weil zum einen damit auch Informationen über meine Leser an Youtube gegeben werden und zum anderen diese Abfragen auch die Ladezeit der Webseite erhöhen.

Bettertube ist ein Jekyll Plugin das hier mit einer kleineren Anpassung Abhilfe schaffen kann.

Einfach das Bettertube.rb in das _plugins Verzeichnis legen und die Javascript / CSS Dateien in die Webseite einbinden.

Dann braucht Ihr Euch nur noch die ID des Videos zu nehmen und mit dem Tag

 {% youtube sPZK8w55cBQ %}

in dem Text einfügen. Es wird dann durch das Plugin ein HTML Tag generiert der automatisch das von Youtube definierte Thumbnail für das Video und einen “Play Button” einbindet. Erst nachdem ein Leser den Play Button klickt wird der Player von Youtube geladen.

sss

Datenschutzhinweis - Dieser Link startet einen externen Abruf des Videos bei Youtube

Damit kann man sicherstellen das der Aufruf von Youtube nicht auf die Ladezeit Einfluss nimmt.

Leider wird immer noch ein Aufruf an Youtube gesendet. Um den Aufruf des Thumbnails auszuschalten und gleichzeitig die Möglichkeit zu haben ein eigenes Bild für den Hintergrund zu verwenden habe ich folgenden kleine Anpassung vorgenommen.

In Plugin Bettertub.rb bei der Definition des Plugins

 http://img.youtube.com/vi/#{id}/hqdefault.jpg

gegen

 /images/youtube/#{id}

tauschen. Wenn man dann in einem neuen Verzeichnis /images/youtube das gewünschte Hintergrundbild unter dem Dateinamen “youtube-id” ablegt wird einem dieses gewünschte Bild als Hintergrund angezeigt und es erfolgt auch keine Abfrage bei Youtube.

12.12.15
Weitere Beiträge zu: jekyll   youtube  

Jekyll: Responsive Images

Bei aller Optimierung der Webseite ergibt sich immer noch ein relativ großes Problem mit Bildern.

Man kann zwar größere Bilder für kleinere Geräte “herunter rechnen”, nur müssen trotzdem die Daten erst einmal übertragen werden.

Könnte man nicht bei einem kleinen Gerät, das wahrscheinlich über eine langsamere Leitung angebunden ist, nicht einfach ein kleineres Bild übertragen?

Mit “Responsive Images” geht das. Es gib inzwischen ein “picture” Tag in dem man sagen kann:

  • bei großer Auflösung nimm das große Bild
  • bei mittlerer Auflösung nimm das mittlere Bild
  • bei kleiner Auflösung nimm ein kleines Bild
  • bei ganz kleiner Auflösung nimm das kleine Bild und schneide oben und unten noch etwas ab.

So weit so gut. Nur wer schreibt den ganzen HTML Kram und muss ich die ganzen Bilder manuell erstellen? Das Jekyll Plugin Jekyll Picture Tag nimmt einem diese ganze Arbeit ab. Einfach das Bild mit

  {% picture /pfad/zumbild.jpg alt="ein ganz tolles Bild" %}

in den Text einfügen. Der Rest geht automatisch

Die Installation ist recht einfach

     sudo gem install jekyll-picture-tag
 
 

und das Plugin von hier in den _plugin Folder. Die aktuellen Browser unterstützen schon das neue Picture Tag und für die älteren gibt es eine Javascript Bibliothek Polyfill.

Die Konfiguration geschieht in der _config.yml von Jekyll. Ich habe erst mal mit den Standardwerten begonnen. Mal sehen was ich über die Zeit noch anpassen muss.

Habt Ihr schon Erfahrungen?

12.9.15
Weitere Beiträge zu: jekyll   performance  

Jekyll: CSS Optimierungen "above the fold" mit Grunt

Bevor der Browser die Seite darstellen kann muss er die Formatierungen (CSS) und den Inhalt (html) der Seite im Speicher haben. Das bedeutet in den meisten Fällen das die Seite erst dann dargestellt wird wenn CSS und HTML Datei geladen sind.

Eine auch von Google empfohlene Möglichkeit ist das man die großen CSS Dateien erst am Schluss lädt und die für die Darstellung des sichtbaren Bereichs notwendigen CSS Information direkt in den HTML Bereich stellt.

Dann kann der Browser mit der Darstellung des sichtbaren Bereichs beginnen wenn er Formatierungen und Inhalt und der Rest wird nachgeladen.

So weit die Theorie. Die Frage ist nur “Welche CSS Formatierungen” brauche ich?”.

Wenn man Grunt verwendet gibt es hier ein Werkzeug das einem genau diese notwendigen CSS Anweisungen heraussucht.

Diese Beschreibung für meinen Jekyll Blog geht davon aus, das Grunt bereits installiert und konfiguriert ist.

Zuerst die Module installieren

    sudo npm install grunt-penthouse --save-dev
    sudo npm install penthouse --save-dev
    
    vi Gruntfile.js
    penthouse: {
      extract : {
          outfile :  './_includes/critical.css',
          css : './css/style.min.css',
          url :'http://localhost:4000/',
          width : 1200,
          height : 500
      },
    },
    grunt penthouse

Mit diese Anweisung wird Grunt angewiesen sich die URL anzusehen und für die Bildschirmgröße 1200 x 500 alle CSS Anweisungen aus der Datei css/style.min.css herauszusichen die man braucht und das Ergebnis in die Datei _include/critical.css zu schreiben.

Die Informationen aus dieser Datei importieren ich dann im Jekyll Build Prozess in meinen <head> Abschnitt

    vi _includes/head.htm
      <style>
         .highlight,h1,h3,p,pre,ul{margin-bottom:15px}.wrapper{max-width:-webkit-calc(800px - (30px * 2));max-width:calc(800px - (30px * 2));margin-right:auto;margin-left:auto;padding-right:30px;padding-left:30px}@media screen and (max-width:800px){.wrapper{max-width:-webkit-calc(800px - (30px));max-width:calc(800px - (30px));padding-right:15px;padding-left:15px}}.wrapper:after{content:"";display:table;clear:both}.page-content{padding:30px 0}.post-list{margin-left:0;list-style:none}.post-link{display:block}.highlight{background:#fff}@font-face{font-family:icons;src:url(/fonts/icons.eot?d30c1b80659ee9dba62c4125fe8fca0c);src:url(/fonts/icons.eot?#iefix) format("embedded-opentype"),url(/fonts/icons.woff2?d30c1b80659ee9dba62c4125fe8fca0c) format("woff2"),url(/fonts/icons.woff?d30c1b80659ee9dba62c4125fe8fca0c) format("woff"),url(/fonts/icons.ttf?d30c1b80659ee9dba62c4125fe8fca0c) format("truetype"),url(/fonts/icons.svg?d30c1b80659ee9dba62c4125fe8fca0c#icons) format("svg");font-weight:400;font-style:normal}.icon{font-family:icons;display:inline-block;vertical-align:middle;line-height:1;font-weight:400;font-style:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon_Blue_and_yellow_ribbon:before{content:"\f101"}.icon_box_archive:before{content:"\f102"}.icon_glyphicons-28-search:before{content:"\f104"}.icon_glyphicons-66-tag:before{content:"\f108"}.icon_glyphicons-social-38-rss:before{content:"\f10c"}.icon_meisen-cam:before{content:"\f10e"}.icon_solar_pannel_solar_cell:before{content:"\f10f"}.icon_weather-station:before{content:"\f111"}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}header{display:block}a{background-color:transparent}img{border:0}pre{overflow:auto}code,pre{font-size:1em}button{color:inherit;font:inherit;margin:0}button{overflow:visible}button{text-transform:none}button{-webkit-appearance:button;cursor:pointer}button::-moz-focus-inner{border:0;padding:0}@media print{:after,:before{background:transparent!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:16px;line-height:1.42857;background-color:#efefef}button{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#ff8f00;text-decoration:none}img{vertical-align:middle}.img-circle{border-radius:50%}h1,h3{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1,h3{margin-top:22px;margin-bottom:11px}h1{font-size:35px}h3{font-size:28px}code,pre{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}pre{display:block;font-size:15px;line-height:1.42857;word-break:break-all;word-wrap:break-word}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.container:after,.container:before{content:" ";display:table}.container:after{clear:both}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.row{margin-left:-15px;margin-right:-15px}.row:after,.row:before{content:" ";display:table}.row:after{clear:both}.col-md-9,.col-sm-3,.col-sm-9,.col-xs-6{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-6{float:left}.col-xs-6{width:50%}@media (min-width:768px){.col-sm-3,.col-sm-9{float:left}.col-sm-3{width:25%}.col-sm-9{width:75%}}@media (min-width:992px){.col-md-9{float:left}.col-md-9{width:75%}}.collapse{display:none}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav:after,.nav:before{content:" ";display:table}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.navbar{position:relative;min-height:50px;margin-bottom:22px;border:1px solid transparent}.navbar:after,.navbar:before{content:" ";display:table}.navbar:after{clear:both}@media (min-width:768px){.navbar{border-radius:4px}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse:after,.navbar-collapse:before{content:" ";display:table}.navbar-collapse:after{clear:both}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-fixed-top .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse{max-height:200px}}.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-brand{float:left;padding:14px 15px;height:50px}@media (min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:22px}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:14px;padding-bottom:14px}}@media (min-width:768px){.navbar-right{float:right!important;margin-right:-15px}}.navbar-inverse{background-color:#607d8b;border-color:#4b626d}.navbar-inverse .navbar-brand{color:#fff}.navbar-inverse .navbar-nav>li>a{color:#fff}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse{border-color:#516a76}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:transparent;border:1px solid none;border-radius:4px}.visible-xs{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}#sidebar{height:100%;padding-right:0;padding-top:20px}#sidebar .nav{width:95%}@media screen and (max-width:767px){.row-offcanvas{position:relative;-webkit-transition:all .25s ease-out;-moz-transition:all .25s ease-out;transition:all .25s ease-out}.row-offcanvas-right .sidebar-offcanvas{right:-41.6%}.sidebar-offcanvas{position:absolute;top:0;width:41.6%}#sidebar{padding-top:0}}ul{list-style:square inside}ul li{padding-left:1em;margin-bottom:.5em}body,h1,h3,p,pre,ul{margin:0;padding:0;color:#757575}p{margin:0 0 9px}body{padding-top:50px;padding-bottom:40px}.sidebar-nav{padding:9px 0}img{max-width:100%;height:auto}.hb-entry-title a{color:#757575;display:block;margin-top:10px;padding:0 0 3px;text-decoration:none}.widget-header{font-size:22px}.navbar-inverse .navbar-nav>li>a{font-size:20px}.navbar-brand{box-sizing:border-box;display:block;font-size:24px;color:#fff;font-weight:400;letter-spacing:.02em;line-height:1;position:relative}.widget-content{margin:5px 30px 30px;position:relative}.highlight pre{overflow-x:auto}.highlight pre code{white-space:pre}.highlight pre,pre{background-color:#f8f8f8;border:1px solid #ccc;padding:6px 10px;border-radius:3px}.navbar-toggle .icon-bar:nth-of-type(2){top:1px}.navbar-toggle .icon-bar:nth-of-type(3){top:2px}.navbar-toggle .icon-bar{position:relative;transition:all 500ms ease-in-out}
      </style>

Damit bin ich zu mindestens für den Desktop Bereich mit den von Google Pagespeed vorgeschlagenen Optimierungen durch.

page insights

29.8.15
Weitere Beiträge zu: jekyll   grunt   performance  

Jekyll Einträge mit "Weiter lesen" Links

Manchmal ist es sinnvoll einen Blogeintrag auf den Indexseiten nicht komplett darzustellen sondern abzukürzen und mit einem Link auf den gesamten Beitrag zu versehen.

Für Jekyll habe ich dazu an dieser Stelle einen Ansatz gefunden den ich mit leichten Modifikationen hier eingebaut habe.

Zum einen brauchen wir ein Plugin postmore.rb im Pluginverzeichnis

 module PostMore
 def postmorefilter(input, url)
 if input.include? "<!--more-->"
  input.split("<!--more-->").first + "<p class='more'><a href='#{url}'>weiter lesen -> </a></p>"
else
  input
end
 end
end
Liquid::Template.register_filter(PostMore)

Dann kann man im Template der Indizes den folgenden Filter verwenden

{{ post.content | postmorefilter: post.url  }}  
28.7.15
Weitere Beiträge zu: jekyll  

Tag Cloud Images aus Jekyll Tags erstellen

Ich wollte aus den Tags meines Jekyll Blogs ein kleines Bild einer Tagcloud des Blogs erstellen um dies in der rechten Spalte als Icon anzuzeigen. Es gäbe zwar die Möglichkeit eine echte verlinkte Tagcloud zu erstellen nur hat dies den Nachteil das es die Buildzeit in der aktuellen Jekyll Version in unakzeptable Zeiten bringt. Die Tagcloud würde für jede Seite einzeln erstellt werden.

Das Python Modul word_cloud kann recht einfach auf Basis eines Textes solche Wortwolken erstellen.

Zuerst erzeuge in in einem Layout einen Text mit allen Tags der Blogbeiträge

    
    ---
    layout: none
    ---
    {% for post in site.posts %}
            {% if post.draft != true %}
    {% for tag in post.tags %}{{ tag }}  {% endfor %}
            {% endif %}
        {% endfor %}
    

Auf Basis der Beispielprogramme habe ich mir folgendes Script erstellt das mir mit dem gerade erzeugten Text eine einfarbige Tagcloud erstellt und an die “richtige” Stelle kopiert

    #!/usr/bin/env python2
    from os import path
    import matplotlib.pyplot as plt
    from wordcloud import WordCloud,STOPWORDS
    def red_color_func(word, font_size, position, orientation, random_state=None, **kwargs):
        return (182,16,36)
    d = path.dirname(__file__)
    stopwords = STOPWORDS.copy()
    stopwords.add("movabletype")
    stopwords.add("prism")
    text = open(path.join(d, '_site/tagcloud.txt')).read()
    wordcloud = WordCloud(background_color="white", max_words=25, stopwords=stopwords).generate(text)
    plt.imshow(wordcloud.recolor(color_func=red_color_func, random_state=3))
    wordcloud.to_file(path.join(d, "assets/tag-cloud.png"))
25.7.15
Weitere Beiträge zu: jekyll   wordcloud  

Jekyll Inhalte mit Elasticsearch indexieren

Was länger währt wird manchmal ganz passabel. Nach längeren Vorarbeiten habe ich meine erste Version einer Elasticsearch Suche auf meinem statischen Jekyll Blog eingerichtet.

Rechts oben über die Lupe kommt man zu dem Formular.

Die wesentliche Schritte waren:

Was ist noch offen:

  • Ich würde gerne den Zugriff auf den Elasticsearch über einen Apache Proxy laufen lassen
  • Die Updates von neuen Inhalten geschehen aktuell über einen Cronjob der automatisiert jeden Abend die letzten 3 Beiträge in den Index lädt. Hier wäre ein Plugin schöner und für viele andere Anwender wahrscheinlich notwendig.
  • Eine Voransicht der Treffer mit Highlights der Suchbegriffe
  • Eine Sortierung der Jahreszahlen in den Facetten nach Jahr und nicht nach Anzahl der Treffer

Jekyll Elasticsearch

14.7.15
Weitere Beiträge zu: jekyll   elasticsearch  

Jekyll: ElasticsearchUI integrieren

Mit elasticsearchUI möchte ich einen Suchindex in Elasticsearch in meinem Jekyll Blog integrieren. Mit Hilfe der Demodateien konnte ich schon schnell meinen Index durchsuchen und Trefferlisten mit Facetten darstellen.

Die Integration in Jekyll ist im Prinzip auch ziemlich einfach. Man muss nur die Javascript Dateien im Header laden und den HTML Code aus dem Demodaten an die gewünschte Stelle in einem Markdown Template positionieren.

Wichtig ist dabei aber das man die AngularJS Anweisungen, die über eine doppelte Klammer gekennzeichnet sind, mit einem raw und endraw umschließt. Sonst werden diese beim Konvertieren durch Jekyll bereits als Liquid Tag interpretiert und gelöscht. Dann werden später auch keine Suchergebnisse angezeigt.

Da kann man dann schon mal die eine oder andere Stunde Fehlersuche betreiben.

1.7.15
Weitere Beiträge zu: elasticsearch   jekyll  

Jekyll: Liquid Tags in HTML Kommentaren

Möchte man Liquid Befehle in Jekyll “ausschalten” reicht es nicht die Liquid Tags im Markdown mit HTML Kommentare auszukommentieren.

<!--
{% if site.identity == 'hbauer' %}    {% include left-column_hb.html %} {% endif %}
-->

Nur so als Tipp.

30.6.15
Weitere Beiträge zu: jekyll   liquid  

Elasticsearch: Bulk Upload

Nachdem ich meine ersten Geh- (Stolper)versuche mit Elasticsearch bestanden habe wolle ich im nächsten Schritt meinen Index mit für mich relevanten Daten füllen. Diese Daten sollen dann die Basis für meine ersten Erfahrungen mit sinnvollen Suchanfragen bilden.

Dieser Bulkupload soll später durch einen individuellen Upload einzelner Dokumente ersetzt werden um Bandbreiten zu sparen. Im Verlauf dieser Übung habe ich auch festgestellt das man mit so einem Upload auch schnell alle Probleme findet die sich ergeben wenn man umfangreichere Texte in einen Index überführen möchte.

Leider reicht dieser Beitrag doch nicht komplett. Das JSON File das hier erzeugt wird ist nicht für einen Bulkupload geeignet.

Hier das Template das ich verwendet habe und mit dem ich nach etwas probieren alle Beiträge in den Index hoch laden konnte.

---
layout: none
---
{% for post in site.posts %}
        {% if post.draft != true %}
{"index":{"_index":"blog2", "_type" : "post" , "_id": "{{ post.date | date: "%y%m%d%k%M"}}"}}\n
{"title": "{{ post.title | escape  }}", "url": "{{ site.url }}{{ post.url }}", "tags": "{% for tag in post.tags %}{{ tag }};{% endfor %}", "content": "{{ post.content | strip_html | strip_newlines | remove:  "   " | remove: "\" | escape  }}"}
        {% endif %}
{% endfor %}

Als _postid verwende ich einfach das Datum mit der Uhrzeit. Das ist mit Sicherheit nicht für alle Szenarien ausreichend aber für meinen Blog wird es wohl reichen. Die Filter für den Titel und den Content sind notwendig da ich an vielen Stellen Hochkommas in den Texten verwende die den Import stören. Wichtig ist auch das alles in einer Zeile steht. Sonst bekommt man beim Import eine Fehlermeldung die einen auf eine falsche Fährte führt.

Der Upload geht dann so

 curl -XPOST 'https://username:passwort@try1-yourserver.eu-west-1.bonsai.io/_bulk'  --data-binary @_site/search.json

Als Ergebnis bekommt man dann die Fehlermeldungen bei denen der Import nicht geklappt hat. In meinem Fall musste ich etwas Zeit in die Filter für den Content investieren bis ich alle Sonderzeichen und unzulässigen Escapesequenzen heraus gefiltert hatte.

Irgendwann beginnt dann das Ergebnis mit

{"took":386,"errors":false,"items":[{

Dann hat man alle Fehler eliminiert und der Index ist mit allen Dokumenten des Jekyll Blogs gefüllt.

24.6.15
Weitere Beiträge zu: elasticsearch   jekyll  

Elasticsearch: meine ersten Gehversuche

Das Thema Suchengine interessiert mich schon länger aber seitdem ich mit Jekyll einen Blogsystem verwende das von Hause aus keine Suchmöglichkeit mitbringt gibt es einen echten persönlichen Bedarf. Bisher verwende ich dort DuckDuckGo aber so richtig zufrieden bin ich damit nicht. Außerdem interessiert mich wie man die Suchergebnisse durch Facetten besser gestalten kann.

Elasticsearch scheint momentan neben Solr das Werkzeug der Wahl zu sein. Aufgrund der zusätzlichen Möglichkeit der Logfile Analyse habe ich mich aber nach meinen ersten Versuchen mit Solr entschieden mit Elasticsearch weiterzumachen.

Um die ersten Schritte möglichst einfach zu gestalten verwende ich bonsai.io. Dort kann man einen kostenlosen Suchindex einrichten.

Elasticsearch möchte sein Input als Datei im JSON Format haben und auf Basis dieses Beitrages konnte ich schnell meinen Jekyll Blog in ein JSON Format überführen.

Richtet man seine Suchindex bei bonsai.io ein bekommt man eine URL über die man die notwendigen Aktionen ausführen kann. Dies Aktionen werden als http Operationen durchgeführt und da man das dann schön in einen Text überführen kann verwende ich curl auf der Kommandozeile um die Operationen auszuführen. Das sieht komplizierter aus als es ist.

Für die ersten Gehversuche möchte ich einen Index erstellen, zwei Dokumente einstellen und dann danach suchen.

Zuerst erstelle ich mir einen Index für meine Blog Dokumente

   curl -XPUT 'https://username:passwort@try1-yourserver.eu-west-1.bonsai.io/blog'
   {"acknowledged":true}

Dann werden die ersten Dokumente erzeugt. Als Werte nehme ich Dokumente aus der JSON Datei die ich mit Jekyll erzeugt habe.

curl -XPOST 'https://username:passwort@try1-yourserver.eu-west-1.bonsai.io/blog/posts' -d ' {
                 "title": "GPXViewer: Ein Werkzeug zur Darstellung von GPX Dateien",
                 "url": "http://127.0.0.1:4000/2015/06/gpxviewer.html",
                 "path": "/2015/06/gpxviewer.html",
                 "content": "Wenn man mal schnell GPX Daten auf einer Google Maps Karte darstellen möchte sollte man sich auf jeden Fall mal den GPXViewer anschauen. Neben der Route auf Google Maps wird auch das Höhenprofil mit Tagesetappen angezeigt.Wirklich gut gemacht.",
                 "categories": "",
                 "date": "2015-06-18 20:26:56 +0200" } '
{"_index":"blog","_type":"posts","_id":"AU4VTna2oGwl_2cZDTqn","_version":1,"created":true}


curl -XPOST 'https://username:passwort@try1-yourserver.eu-west-1.bonsai.io/blog/posts' -d ' {
                "title": "WeeWX: get archive interval failed",
                "url": "http://127.0.0.1:4000/2015/06/weewx-failed.html",
                "path": "/2015/06/weewx-failed.html",
                "content": "Meine Wetterstation hat die letzten Tage keine Aufzeichnungen dokumentiert. Der Prozess brach kurz nach dem Start ab und im Logfile fand ich folgende Zeilenweewx[]: engine: Record generation will be attempted in 'hardware'weewx[]: fousb: get archive interval failed attempt 1 of 3: could not detach kernel driver from ten verfügbarweewx[]: fousb: get archive interval failed attempt 2 of 3: could not detach kernel driver from ten verfügbarweewx[]: fousb: get archive interval failed attempt 3 of 3: could not detach kernel driver from ten verfügbarweewx[]: engine: Caught WeeWxIOError: Unable to read archive interval after 3 triesweewx[]:     ****  Exiting...An dieser fand ich den Hinweis: Einfach mal die Wetterstation von USB und Strom trennen.Jetzt lüppt es wieder",
                "categories": "",
                "date": "2015-06-17 20:26:56 +0200" } '

So und jetzt die ersten Suchversuche. Der erste Versuch sucht nach einem Begriff der nicht verwendet wird und die zweite nach einem vorhandenen Begriff.

curl -XGET 'https://username:passwort@try1-yourserver.eu-west-1.bonsai.io/blog/_search?q=GPdX'
{"took":1,"timed_out":false,"_shards":{"total":1,"successful":1,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}

curl -XGET 'https://username:passwort@try1-yourserver.eu-west-1.bonsai.io/blog/_search?q=GPX'
{"took":1,"timed_out":false,"_shards":{"total":1,"successful":1,"failed":0},"hits":{"total":1,"max_score":0.17677669,"hits":[{"_index":"blog","_type":"posts","_id":"AU4VUkPZoGwl_2cZDTxR","_score":0.17677669,"_source": {
                 "title": "GPXViewer: Ein Werkzeug zur Darstellung von GPX Dateien",
                 "url": "http://127.0.0.1:4000/2015/06/gpxviewer.html",
                 "path": "/2015/06/gpxviewer.html",
                 "content": "Wenn man mal schnell GPX Daten auf einer Google Maps Karte darstellen möchte sollte man sich auf jeden Fall mal den GPXViewer anschauen. Neben der Route auf Google Maps wird auch das Höhenprofil mit Tagesetappen angezeigt.Wirklich gut gemacht.",
                 "categories": "",
                 "date": "2015-06-18 20:26:56 +0200"
             }

Falls man einen Index löschen möchte kann man das so machen

curl -XDELETE 'https://username:passwort@try1-yourserver.eu-west-1.bonsai.io/blog'
{"acknowledged":true}

Das fängt ja schon mal gut an. Als nächstes möchte ich herausfinden wie ich einen ganzen Satz von Dokumenten auf einmal indizieren kann und meine Tags und die Jahresangaben als Facetten verwenden kann.

20.6.15
Weitere Beiträge zu: elasticsearch   jekyll  

Dies ist ein privater Blog von Hagen Bauer- berufstätiger Vater, Ehemann, Naturliebhaber, Läufer, Zelter, technikverliebt.


Creative Commons License
This blog is licensed under a Creative Commons License