Skip to content
Snippets Groups Projects
Commit 4b8d9597 authored by Quentin Bramas's avatar Quentin Bramas
Browse files

Venue Rank

parent 3926d651
Branches
No related merge requests found
Pipeline #94597 passed with stage
in 6 minutes and 1 second
No preview for this file type
2
\ No newline at end of file
3
\ No newline at end of file
......@@ -5,7 +5,6 @@ import {
} from "solid-start/entry-server";
export default createHandler(
renderAsync((event) => <StartServer event={event} />)
);
......@@ -24,11 +24,11 @@ export async function init() {
const version = await res.text();
let need_download = false;
if(!fs.existsSync(dbVersionPath) || fs.readFileSync(dbVersionPath, 'utf8').trim() != version.trim()) {
need_download = true;
fs.writeFileSync(dbVersionPath, version);
}
console.log('Checking database version (need update ? ', need_download, ')');
// check if the db file exists
if(!fs.existsSync(dbPath) || need_download) {
......
import server$ from "solid-start/server";
import {db, init} from "~/models/db";
import predefinedCommunities from "~/predefined-communities";
......@@ -12,67 +13,107 @@ interface Row {
rank: number
}
const current_year = new Date().getFullYear();
const first_interesting_year = 2005;
// type is null or object with string keys and Row[] values
let predefinedCommunityRanks : null | Record<string, {journals:Row[], conferences: Row[]}> = null;
let predefinedCommunityRanks : null | Record<string, Record<number, {journals:Row[], conferences: Row[]}>> = null;
const initRanks = async () => {
export const initRanks = async () => {
if(predefinedCommunityRanks !== null) return;
predefinedCommunityRanks = {};
await init();
predefinedCommunityRanks = {};
console.log('Initializing predefined community ranks');
const from_year = 2022 - 6;
const year_window = 6;
for(const pc of Object.values(predefinedCommunities))
{
console.log('Initializing', pc);
try{
if(pc.query.startsWith('author_id'))
{
const q = pc.query.replaceAll(':from_year', from_year.toString());
const journals = await db().all<Row[]>(`
SELECT _V.id, _V.name, SUM(_AV.contrib) as score
FROM authors_journals as _AV
LEFT JOIN journals as _V ON (_AV.venue_id = _V.id)
WHERE _AV.year >= ${from_year}
AND _AV.${q}
GROUP BY _V.id ORDER by score DESC`);
const conferences = await db().all<Row[]>(`
SELECT _V.id, _V.name, SUM(_AV.contrib) as score
FROM authors_conferences as _AV
LEFT JOIN conferences as _V ON (_AV.venue_id = _V.id)
WHERE _AV.year >= ${from_year}
AND _AV.${q}
GROUP BY _V.id ORDER by score DESC`);
predefinedCommunityRanks[pc.slug] = {
journals: journals.map((c,i) => ({...c, rank: i+1})),
conferences: conferences.map((c,i) => ({...c, rank: i+1}))
};
console.log('Found journal:', journals.length,' conferences:',conferences.length);
}
else
{
throw new Error('Unsupported predefined community query');
predefinedCommunityRanks[pc.slug] = {};
for(let to_year = first_interesting_year; to_year <= current_year; to_year++)
{
const from_year = to_year - year_window;
console.log('Initializing', to_year, pc);
try{
if(pc.query.startsWith('author_id'))
{
const q = pc.query
.replaceAll(':from_year', from_year.toString())
.replaceAll(':to_year', to_year.toString());
const journals = await db().all<Row[]>(`
SELECT _V.id, _V.name, _V.fullname, _V.key, SUM(_AV.contrib) as score
FROM authors_journals as _AV
LEFT JOIN journals as _V ON (_AV.venue_id = _V.id)
WHERE _AV.year >= ${from_year}
AND _AV.year <= ${to_year}
AND _AV.${q}
GROUP BY _V.id ORDER by score DESC`);
const conferences = await db().all<Row[]>(`
SELECT _V.id, _V.name, _V.fullname, _V.key, SUM(_AV.contrib) as score
FROM authors_conferences as _AV
LEFT JOIN conferences as _V ON (_AV.venue_id = _V.id)
WHERE _AV.year >= ${from_year}
AND _AV.year <= ${to_year}
AND _AV.${q}
GROUP BY _V.id ORDER by score DESC`);
predefinedCommunityRanks[pc.slug][to_year] = {
journals: journals.map((c,i) => ({...c, rank: i+1})),
conferences: conferences.map((c,i) => ({...c, rank: i+1}))
};
console.log('Found journal:', journals.length,' conferences:',conferences.length);
}
else
{
throw new Error('Unsupported predefined community query');
}
} catch(e) {
console.log('Error initializing predefined community ranks: '+pc.slug);
console.error(e);
}
} catch(e) {
console.log('Error initializing predefined community ranks: '+pc.slug);
console.error(e);
}
}
}
export default {
async getPredefinedRank(slug:string) : Promise<{journals:Row[], conferences: Row[]}> {
async getPredefinedRank(slug:string, year:number = current_year) : Promise<{journals:Row[], conferences: Row[]}> {
console.log('getPredefinedRank', slug, 'init ? ', (predefinedCommunityRanks !== null));
await initRanks();
return predefinedCommunityRanks[slug];
return predefinedCommunityRanks[slug][year];
},
async getVenueRank(key:string, category:string) : Promise<{year:number, rank:number|null}[]> {
try{
const res : {year:number, rank:number|null}[] = [];
for(let y in predefinedCommunityRanks[category])
{
const confOrJournal = key.startsWith('conf') ? 'conferences' : 'journals';
const r = predefinedCommunityRanks[category][y][confOrJournal].find(c => c.key === key);
res.push({
year: parseInt(y),
rank: r ? r.rank : null
})
}
return res;
} catch(e) {
console.error(e);
return [];
}
},
async getVenueInfo(key:string) : Promise<Row> {
const table = key.startsWith('conf') ? 'conferences' : 'journals'
const res = await db().get<Row>(`
SELECT fullname, name, key
FROM ${table}
WHERE key = ?`, key);
return res;
}
}
\ No newline at end of file
}
export default {
cs: {
slug: 'cs',
name: 'Computer science',
query: 'author_id != -1' // i.e., select all
},
dist: {
slug: 'dist',
name: 'Distributed Computing',
query: 'author_id IN (SELECT AV.author_id FROM authors_conferences as AV INNER JOIN conferences as V ON AV.venue_id = V.id WHERE AV.year >= :from_year AND V.name IN ("DISC", "PODC", "OPODIS", "SIROCCO") GROUP BY AV.author_id)'
query: 'author_id IN (SELECT AV.author_id FROM authors_conferences as AV INNER JOIN conferences as V ON AV.venue_id = V.id WHERE AV.year >= :from_year AND AV.year <= :to_year AND V.name IN ("DISC", "PODC", "OPODIS", "SIROCCO") GROUP BY AV.author_id)'
},
network: {
slug: 'network',
name: 'Networking',
query: 'author_id IN (SELECT AV.author_id FROM authors_conferences as AV INNER JOIN conferences as V ON AV.venue_id = V.id WHERE AV.year >= :from_year AND V.name IN ("SIGCOMM", "CoNEXT") GROUP BY AV.author_id)'
query: 'author_id IN (SELECT AV.author_id FROM authors_conferences as AV INNER JOIN conferences as V ON AV.venue_id = V.id WHERE AV.year >= :from_year AND AV.year <= :to_year AND V.name IN ("SIGCOMM", "CoNEXT") GROUP BY AV.author_id)'
},
algotel:{
slug: 'algotel',
......
......@@ -2,7 +2,9 @@
import { For } from "solid-js";
import { A, parseCookie } from "solid-start";
import server$ from "solid-start/server";
import Counter from "~/components/Counter";
import { initRanks } from "~/models/rank";
import predefinedCommunities from "~/predefined-communities";
......@@ -37,8 +39,13 @@ const Input = (props) => (
</div>
);
const init = server$(() => {
console.log('INIT');
initRanks();
});
export default function Home() {
init();
return (
<main class="text-center mx-auto text-gray-700 p-4">
<h1 class="max-6-xs text-3xl text-sky-700 font-thin my-16">
......
import { A } from "solid-start";
import { A, useLocation } from "solid-start";
import { APIEvent, json } from "solid-start/api";
import { useParams, RouteDataArgs } from "solid-start";
import { createServerData$ } from "solid-start/server";
......@@ -9,16 +9,17 @@ import predefinedCommunities from "~/predefined-communities";
import { For, Suspense, Accessor, createResource, Show, createSignal } from "solid-js";
import { useRouteData } from "solid-start";
export function routeData({ params } : RouteDataArgs) {
console.log(params.category);
const category = params.category;
const ranks = createServerData$(async ([,category], op) => {
const ranks = await Rank.getPredefinedRank(category);
return ranks;
},{
key: () => ["rank", params.category]
key: () => ["rank", category]
});
return ranks;
}
......@@ -103,9 +104,10 @@ const EmptyRow = () => <>
export default function RankCategory() {
const params = useParams();
const category = params.category;
console.log('RankCategory', category);
const ranks = useRouteData<typeof routeData>();
console.log('RankCategory', ranks());
const [searchInput, setSearchInput] = createSignal('');
const [isConference, setIsConference] = createSignal(true);
......@@ -164,13 +166,13 @@ export default function RankCategory() {
{conf.fullname}
</td>
<td class="py-4 px-6">
{conf.score}
{Math.ceil(conf.score)}
</td>
<td class="py-4 px-6">
#{(conf.rank)}, {rankToABC(conf.rank, isConference() ? ranks().conferences.length : ranks().journals.length)}
</td>
<td class="py-4 px-6 text-right">
<a href="#" class="font-medium text-blue-600 dark:text-blue-500 hover:underline">Details</a>
<A href={"/rank/venue/"+category+'/'+conf.key} class="font-medium text-blue-600 dark:text-blue-500 hover:underline">Details</A>
</td>
</tr>
</Show>}
......
import { A, useLocation, useNavigate } from "solid-start";
import { APIEvent, json } from "solid-start/api";
import { useParams, RouteDataArgs } from "solid-start";
import { createServerData$ } from "solid-start/server";
import Rank from "~/models/rank";
import predefinedCommunities from "~/predefined-communities";
import { For, Suspense, Accessor, createResource, Show, createSignal } from "solid-js";
import { useRouteData } from "solid-start";
export function routeData({ params } : RouteDataArgs) {
const [category, ...keyParts] = params.key.split('/');
const key = keyParts.join('/');
const ranks = createServerData$(async ([,venue_key, category], op) => {
const ranks = await Rank.getVenueRank(venue_key, category);
const info = await Rank.getVenueInfo(venue_key);
return {
ranks,
info
};
},{
key: () => ["conf", key, category],
});
return ranks;
}
export default function RankVenue() {
const params = useParams();
const [category, ...keyParts] = params.key.split('/');
const key = keyParts.join('/');
const ranks = useRouteData<typeof routeData>();
return (
<Suspense fallback={<span>...</span>}>
<Show when={ranks()}>
<Show when={!ranks().info}>
<main class="text-center mx-auto text-gray-700 p-4">
<h1 class="max-6-xs text-3xl text-sky-700 font-thin my-16">
Unable to find a conference of journal with key "{key}"
</h1>
</main>
</Show>
<Show when={ranks().info}>
<main class="text-center mx-auto text-gray-700 p-4">
<h1 class="max-6-xs text-3xl text-sky-700 font-thin mt-16 mb-2">
Ranking of
{ranks().info.key.startsWith('conf') ? 'the Conference' : 'the Journal'}
:<br/><span class="font-bold">
{ranks().info.name}
</span>
</h1>
<h3 class="max-6-xs text-1xl text-sky-700 font-thin mb-10">
{ranks().info.fullname}
</h3>
<h3 class="max-6-xs text-3xl text-sky-700 font-thin mb-10">
in the community {ranks().info.fullname}
</h3>
<For each={ranks().ranks}>
{rank => (
<div>
<span>{rank.year} : </span>
<span>{rank.rank ? '#'+rank.rank : '-'}</span>
</div>
)}
</For>
</main>
</Show>
</Show>
</Suspense>
)
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment