Skip to content

Instantly share code, notes, and snippets.

@johtani
Last active December 12, 2023 09:22
Show Gist options
  • Save johtani/3e40c6738424f95f38c117e18181a010 to your computer and use it in GitHub Desktop.
Save johtani/3e40c6738424f95f38c117e18181a010 to your computer and use it in GitHub Desktop.
ブログ記事のOrama検索実装の紹介用Gist
{{/* Generates an array of blog contents for indexing orama */}}
{{- $.Scratch.Add "item" slice -}}
{{- $section := $.Site.GetPage "section" .Section }}
{{- range .Site.AllPages -}}
{{- if or (and (.IsDescendant $section) (and (not .Draft) (not .Params.private))) $section.IsHome -}}
{{- if (and (eq .Section "post") .File) -}}
{{- if .Params.Tags -}}
{{- $.Scratch.Add "item" (dict "id" .File.UniqueID "date" .Date.UTC.Unix "dir" .File.Dir "lang" .Lang "lastmod" .Lastmod.UTC.Unix "permalink" .Permalink "publishdate" .PublishDate "title" .Title "tags" .Params.Tags "summary" .Summary "contents" .Plain)}}
{{- else -}}
{{- $.Scratch.Add "item" (dict "id" .File.UniqueID "date" .Date.UTC.Unix "dir" .File.Dir "lang" .Lang "lastmod" .Lastmod.UTC.Unix "permalink" .Permalink "publishdate" .PublishDate "title" .Title "summary" .Summary "contents" .Plain)}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- $.Scratch.Get "item" | jsonify -}}
#!/usr/bin/env node
import { readFileSync, writeFileSync } from 'fs';
import { tokenize } from 'wakachigaki';
import { create, insertMultiple } from '@orama/orama';
import { persistToFile } from '@orama/plugin-data-persistence/server';
import { persist } from '@orama/plugin-data-persistence';
async function main() {
console.log("exec from : " + process.cwd());
const documents = readFileSync('../../public/orama.json', 'utf8');
console.log("read file");
const docsJson = JSON.parse(documents);
console.log("parse json");
const db = await create({
schema: {
id: 'string',
title: 'string',
summary: 'string',
tags: 'string[]',
date: 'number'
},
components: {
tokenizer: {
language: "english",
stemming: false,
normalizationCache: new Map(),
tokenize: (raw) => {
return tokenize(raw)
},
},
},
plugins: [
{
name: 'delete-contents-plugin',
beforeInsert: (orama, id, document) => {
delete document['contents'];
console.log(document)
}
}
]
})
await insertMultiple(db, docsJson)
console.log("inserted multiple");
const data = await persist(db, 'dpack')
writeFileSync("pearsist.dpack", data);
console.log("finish!")
}
main();
<script src="https://cdn.jsdelivr.net/npm/moment@2.22.2/min/moment.min.js"></script>
<script type="importmap">
{
"imports": {
"@orama/orama": "https://unpkg.com/@orama/orama@latest/dist/index.js",
"@orama/highlight": "https://unpkg.com/@orama/highlight@latest/dist/index.js",
"@orama/orama/internals": "https://unpkg.com/@orama/orama@latest/dist/internals.js",
"@orama/plugin-data-persistence": "https://unpkg.com/@orama/plugin-data-persistence@latest/dist/index.js",
"@msgpack/msgpack": "https://cdn.jsdelivr.net/npm/@msgpack/msgpack@2.8.0/+esm",
"dpack": "https://cdn.jsdelivr.net/npm/dpack@0.6.22/+esm",
"wakachigaki": "https://unpkg.com/wakachigaki@latest"
}
}
</script>
<div id="search-searchbar">
<label for="search-input" class="form-label">Search</label>
<input type="search" class="form-control mb-3" id="search-input" />
</div>
<div id="stats"></div>
<div class="post-list" id="search-hits">
</div>
<script type="module">
import { tokenize } from 'wakachigaki'
import { create, search, insert, insertMultiple } from '@orama/orama'
import { restore } from '@orama/plugin-data-persistence';
import { Highlight } from '@orama/highlight'
const tmp = await fetch("/orama_index.json")
const persisted_index = await tmp.text()
const highlighter = new Highlight();
const db = await restore('dpack', persisted_index);
db.tokenizer = {
language: "english",
stemming: false,
normalizationCache: new Map(),
tokenize: (raw) => {
return tokenize(raw)
},
}
const searchInput = document.getElementById("search-input");
["change", "cut", "focus", "input", "paste", "search"].forEach((type) =>
searchInput.addEventListener(type, query)
);
async function query(event) {
var sort = {
property: 'date',
order: 'DESC'
}
if(event.target.value){
sort = undefined
}
const searchResponse = await search(db, {
term: event.target.value,
properties: "*",
sortBy: sort,
});
document.getElementById("stats").innerHTML = "<span>"+searchResponse.count+" results found in "+searchResponse.elapsed.formatted+"</span>";
document.getElementById("search-hits").innerHTML = searchResponse.hits
.map(
(i) =>
`
<div class="post-item">
<h2><a class="post-link" href="${i.document.permalink}">${highlighter.highlight(i.document.title, tokenize(event.target.value).join(" ")).HTML}</a></h2>
<span class="post-meta">${moment.unix(i.document.date).format('MMM D, YYYY')}</span>
<div class="post-snippet">${highlighter.highlight(i.document.summary.slice(0, 100), tokenize(event.target.value).join(" ")).HTML}</div>
<hr/>
</div>
`
)
.join("");
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment