questions.getRelated()
Retrieves questions that are algorithmically determined to be related to a specific question based on content similarity, tags, and other factors.
Syntax
Section titled “Syntax”async getRelated(questionId: number, options?: GetLinkedQuestionsOptions): Promise<PaginatedLinkedOrRelatedQuestions>
Parameters
Section titled “Parameters”Parameter | Type | Required | Description |
---|---|---|---|
questionId | number | Yes | The unique identifier of the question to find related questions for |
options | GetLinkedQuestionsOptions | No | Configuration options for pagination and sorting |
GetLinkedQuestionsOptions
Section titled “GetLinkedQuestionsOptions”Property | Type | Required | Default | Description |
---|---|---|---|---|
page | number | No | 1 | The page number to retrieve (1-based) |
pageSize | 15 | 30 | 50 | 100 | No | 30 | Number of questions to return per page |
sort | LinkedOrRelatedQuestionsSortParameter | No | Sort by: "hot" , "creation" , "activity" , or "score" | |
order | SortOrder | No | Sort order: "asc" (ascending) or "desc" (descending) |
Return Value
Section titled “Return Value”Returns a Promise<PaginatedLinkedOrRelatedQuestions>
containing:
Property | Type | Description |
---|---|---|
totalCount | number | Total number of related questions found |
pageSize | number | Number of items per page |
page | number | Current page number |
totalPages | number | Total number of pages available |
sort | LinkedOrRelatedQuestionsSortParameter | Sort parameter used |
order | SortOrder | Sort order used |
items | QuestionSummaryResponseModel[] | Array of related question summaries |
Examples
Section titled “Examples”Basic Related Questions Retrieval
Section titled “Basic Related Questions Retrieval”import { StackOverflowSDK } from 'so-teams-sdk';
const sdk = new StackOverflowSDK({ accessToken: 'your-access-token', baseUrl: 'https://[your-site].stackenterprise.co/api/v3'});
// Get related questions for a specific questionconst relatedQuestions = await sdk.questions.getRelated(12345);
console.log(`Found ${relatedQuestions.totalCount} related questions`);
relatedQuestions.items.forEach(question => { console.log(`- ${question.title}`); console.log(` Score: ${question.score}, Answers: ${question.answerCount}`); console.log(` Tags: ${question.tags?.map(t => t.name).join(', ')}`); console.log(` Views: ${question.viewCount}`); console.log('');});
Related Questions with Different Sorting
Section titled “Related Questions with Different Sorting”// Get hottest related questions (trending/active)const hotRelatedQuestions = await sdk.questions.getRelated(12345, { sort: 'hot', order: 'desc', pageSize: 20});
console.log('Hottest related questions:');hotRelatedQuestions.items.forEach((question, index) => { console.log(`${index + 1}. ${question.title}`); console.log(` Score: ${question.score}, Activity: ${question.lastActivityDate}`);});
// Get highest scoring related questionsconst topRelatedQuestions = await sdk.questions.getRelated(12345, { sort: 'score', order: 'desc', pageSize: 15});
console.log('\nTop scoring related questions:');topRelatedQuestions.items.forEach((question, index) => { console.log(`${index + 1}. ${question.title} (${question.score} points)`);});
// Get newest related questionsconst recentRelatedQuestions = await sdk.questions.getRelated(12345, { sort: 'creation', order: 'desc', pageSize: 10});
console.log('\nNewest related questions:');recentRelatedQuestions.items.forEach(question => { console.log(`- ${question.title}`); console.log(` Created: ${question.creationDate}`);});
Related Questions Analysis and Recommendations
Section titled “Related Questions Analysis and Recommendations”async function analyzeRelatedQuestions(questionId: number) { try { // Get the original question and related questions const [originalQuestion, relatedQuestions] = await Promise.all([ sdk.questions.get(questionId), sdk.questions.getRelated(questionId, { pageSize: 100, sort: 'hot', order: 'desc' }) ]);
console.log(`Analyzing related questions for: ${originalQuestion.title}`); console.log(`Found ${relatedQuestions.totalCount} algorithmically related questions`);
if (relatedQuestions.totalCount === 0) { console.log('No related questions found'); return { originalQuestion, relatedQuestions: [], analysis: null }; }
const analysis = { totalRelated: relatedQuestions.totalCount, similarity: { tagOverlap: calculateTagOverlap(originalQuestion, relatedQuestions.items), topicClusters: identifyTopicClusters(relatedQuestions.items), difficultySpread: analyzeDifficultySpread(relatedQuestions.items) }, engagement: { averageScore: relatedQuestions.items.reduce((sum, q) => sum + (q.score || 0), 0) / relatedQuestions.items.length, averageViews: relatedQuestions.items.reduce((sum, q) => sum + (q.viewCount || 0), 0) / relatedQuestions.items.length, answeredRate: relatedQuestions.items.filter(q => q.isAnswered).length / relatedQuestions.items.length * 100, totalAnswers: relatedQuestions.items.reduce((sum, q) => sum + (q.answerCount || 0), 0) }, quality: { highQuality: relatedQuestions.items.filter(q => (q.score || 0) >= 5).length, mediumQuality: relatedQuestions.items.filter(q => (q.score || 0) >= 1 && (q.score || 0) < 5).length, lowQuality: relatedQuestions.items.filter(q => (q.score || 0) < 1).length }, recommendations: generateRelatedQuestionsRecommendations(originalQuestion, relatedQuestions.items), topRecommendations: relatedQuestions.items .sort((a, b) => calculateRelevanceScore(originalQuestion, b) - calculateRelevanceScore(originalQuestion, a)) .slice(0, 5) };
console.log('\nRelated Questions Analysis:'); console.log(`- Average score: ${analysis.engagement.averageScore.toFixed(1)}`); console.log(`- Average views: ${Math.round(analysis.engagement.averageViews)}`); console.log(`- Answer rate: ${analysis.engagement.answeredRate.toFixed(1)}%`); console.log(`- Quality distribution: High(${analysis.quality.highQuality}), Medium(${analysis.quality.mediumQuality}), Low(${analysis.quality.lowQuality})`);
console.log('\nTag Overlap Analysis:'); analysis.similarity.tagOverlap.forEach(([tag, count, percentage]) => { console.log(`- ${tag}: ${count} questions (${percentage.toFixed(1)}%)`); });
console.log('\nTop Recommended Related Questions:'); analysis.topRecommendations.forEach((q, index) => { const relevanceScore = calculateRelevanceScore(originalQuestion, q); console.log(`${index + 1}. ${q.title}`); console.log(` Relevance: ${relevanceScore.toFixed(1)}, Score: ${q.score}, Answers: ${q.answerCount}`); });
console.log('\nRecommendations:'); analysis.recommendations.forEach(rec => console.log(`- ${rec}`));
return { originalQuestion, relatedQuestions: relatedQuestions.items, analysis }; } catch (error) { console.error('Related questions analysis failed:', error.message); throw error; }}
function calculateTagOverlap(original: any, related: any[]): [string, number, number][] { const originalTags = original.tags?.map(t => t.name) || []; const tagOverlap = new Map<string, number>();
originalTags.forEach(tag => { const count = related.filter(q => q.tags?.some(t => t.name === tag) ).length;
if (count > 0) { tagOverlap.set(tag, count); } });
return Array.from(tagOverlap.entries()) .map(([tag, count]) => [tag, count, (count / related.length) * 100]) .sort(([,a], [,b]) => b - a);}
function identifyTopicClusters(questions: any[]): Record<string, any[]> { const clusters: Record<string, any[]> = {};
// Group by primary tag combinations questions.forEach(question => { const tags = question.tags?.map(t => t.name) || []; const primaryTags = tags.slice(0, 2).sort(); const clusterKey = primaryTags.join('-') || 'untagged';
if (!clusters[clusterKey]) { clusters[clusterKey] = []; }
clusters[clusterKey].push(question); });
// Filter clusters with meaningful size Object.keys(clusters).forEach(key => { if (clusters[key].length < 2) { delete clusters[key]; } });
return clusters;}
function analyzeDifficultySpread(questions: any[]): { beginner: number, intermediate: number, advanced: number } { return questions.reduce((spread, question) => { const difficulty = assessQuestionDifficulty(question); spread[difficulty]++; return spread; }, { beginner: 0, intermediate: 0, advanced: 0 });}
function assessQuestionDifficulty(question: any): 'beginner' | 'intermediate' | 'advanced' { const tags = question.tags?.map(t => t.name.toLowerCase()) || []; const advancedKeywords = ['advanced', 'performance', 'architecture', 'optimization', 'design-patterns']; const intermediateKeywords = ['async', 'promises', 'generics', 'middleware', 'patterns'];
if (tags.some(tag => advancedKeywords.some(keyword => tag.includes(keyword)))) { return 'advanced'; }
if (tags.some(tag => intermediateKeywords.some(keyword => tag.includes(keyword))) || (question.score || 0) > 5) { return 'intermediate'; }
return 'beginner';}
function calculateRelevanceScore(original: any, related: any): number { let score = 0;
// Tag similarity (40% weight) const originalTags = new Set(original.tags?.map(t => t.name) || []); const relatedTags = new Set(related.tags?.map(t => t.name) || []); const commonTags = new Set([...originalTags].filter(x => relatedTags.has(x))); const tagSimilarity = commonTags.size / Math.max(originalTags.size, relatedTags.size, 1); score += tagSimilarity * 40;
// Quality score (30% weight) const qualityScore = Math.min((related.score || 0) / 10, 1); score += qualityScore * 30;
// Answer availability (20% weight) const answerScore = related.isAnswered ? 1 : 0.5; score += answerScore * 20;
// Activity recency (10% weight) const daysSinceActivity = (Date.now() - new Date(related.lastActivityDate).getTime()) / (1000 * 60 * 60 * 24); const recencyScore = Math.max(0, 1 - (daysSinceActivity / 365)); score += recencyScore * 10;
return score;}
function generateRelatedQuestionsRecommendations(original: any, related: any[]): string[] { const recommendations = [];
const highQualityRelated = related.filter(q => (q.score || 0) >= 5); if (highQualityRelated.length > 0) { recommendations.push(`${highQualityRelated.length} high-quality related questions available for deeper learning`); }
const unansweredRelated = related.filter(q => !q.isAnswered); if (unansweredRelated.length > 0) { recommendations.push(`${unansweredRelated.length} unanswered related questions - opportunity to contribute`); }
const recentRelated = related.filter(q => { const daysSince = (Date.now() - new Date(q.creationDate).getTime()) / (1000 * 60 * 60 * 24); return daysSince <= 30; });
if (recentRelated.length > related.length * 0.2) { recommendations.push('Topic has recent activity - consider following for updates'); }
const strongTagOverlap = related.filter(q => { const originalTags = new Set(original.tags?.map(t => t.name) || []); const questionTags = new Set(q.tags?.map(t => t.name) || []); const overlap = new Set([...originalTags].filter(x => questionTags.has(x))); return overlap.size >= 2; });
if (strongTagOverlap.length > 0) { recommendations.push(`${strongTagOverlap.length} questions with strong topical overlap for comprehensive understanding`); }
return recommendations;}
const relatedAnalysis = await analyzeRelatedQuestions(12345);
Learning Path Generation from Related Questions
Section titled “Learning Path Generation from Related Questions”async function createLearningPathFromRelated(questionId: number) { console.log(`Creating learning path from related questions for question ${questionId}...`);
try { const [originalQuestion, relatedQuestions] = await Promise.all([ sdk.questions.get(questionId), sdk.questions.getRelated(questionId, { pageSize: 100 }) ]);
console.log(`Building learning path for: ${originalQuestion.title}`);
if (relatedQuestions.totalCount === 0) { console.log('No related questions found for learning path generation'); return null; }
// Categorize questions by difficulty and topic const categorizedQuestions = { prerequisites: [], core: [], advanced: [], supplementary: [] };
relatedQuestions.items.forEach(question => { const difficulty = assessQuestionDifficulty(question); const relevance = calculateRelevanceScore(originalQuestion, question);
if (relevance > 70 && difficulty === 'beginner') { categorizedQuestions.prerequisites.push({ question, relevance, difficulty }); } else if (relevance > 60 && difficulty === 'intermediate') { categorizedQuestions.core.push({ question, relevance, difficulty }); } else if (relevance > 50 && difficulty === 'advanced') { categorizedQuestions.advanced.push({ question, relevance, difficulty }); } else if (relevance > 30) { categorizedQuestions.supplementary.push({ question, relevance, difficulty }); } });
// Sort by relevance within each category Object.keys(categorizedQuestions).forEach(category => { categorizedQuestions[category].sort((a, b) => b.relevance - a.relevance); });
const learningPath = { topic: extractMainTopic(originalQuestion), originalQuestion: { id: originalQuestion.id, title: originalQuestion.title, difficulty: assessQuestionDifficulty(originalQuestion) }, path: { prerequisites: categorizedQuestions.prerequisites.slice(0, 5), core: categorizedQuestions.core.slice(0, 8), advanced: categorizedQuestions.advanced.slice(0, 5), supplementary: categorizedQuestions.supplementary.slice(0, 10) }, estimatedStudyTime: calculateEstimatedStudyTime(categorizedQuestions), progressTracking: { completed: 0, total: Object.values(categorizedQuestions).reduce((sum, cat) => sum + Math.min(cat.length, cat === categorizedQuestions.supplementary ? 10 : cat === categorizedQuestions.core ? 8 : 5), 0) } };
console.log(`\nLearning Path: ${learningPath.topic}`); console.log(`Total questions in path: ${learningPath.progressTracking.total}`); console.log(`Estimated study time: ${learningPath.estimatedStudyTime} hours`);
console.log('\nLearning Path Structure:');
if (learningPath.path.prerequisites.length > 0) { console.log(`\n📚 Prerequisites (${learningPath.path.prerequisites.length}):`); learningPath.path.prerequisites.forEach((item, index) => { console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`); }); }
if (learningPath.path.core.length > 0) { console.log(`\n🎯 Core Topics (${learningPath.path.core.length}):`); learningPath.path.core.forEach((item, index) => { console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`); }); }
if (learningPath.path.advanced.length > 0) { console.log(`\n🚀 Advanced Topics (${learningPath.path.advanced.length}):`); learningPath.path.advanced.forEach((item, index) => { console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`); }); }
if (learningPath.path.supplementary.length > 0) { console.log(`\n📖 Supplementary Reading (${learningPath.path.supplementary.length}):`); learningPath.path.supplementary.slice(0, 5).forEach((item, index) => { console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`); }); }
return learningPath; } catch (error) { console.error('Learning path generation failed:', error.message); throw error; }}
function extractMainTopic(question: any): string { const tags = question.tags?.map(t => t.name) || [];
// Priority topics const priorityTopics = ['typescript', 'react', 'nodejs', 'python', 'javascript', 'java']; const primaryTopic = tags.find(tag => priorityTopics.includes(tag.toLowerCase()));
if (primaryTopic) { return primaryTopic.charAt(0).toUpperCase() + primaryTopic.slice(1); }
// Use first tag or extract from title if (tags.length > 0) { return tags[0].charAt(0).toUpperCase() + tags[0].slice(1); }
// Extract from title const title = question.title.toLowerCase(); for (const topic of priorityTopics) { if (title.includes(topic)) { return topic.charAt(0).toUpperCase() + topic.slice(1); } }
return 'Programming';}
function calculateEstimatedStudyTime(categorizedQuestions: any): number { // Rough estimates: Prerequisites (15 min), Core (30 min), Advanced (45 min), Supplementary (10 min) const timeEstimates = { prerequisites: 0.25, // 15 minutes core: 0.5, // 30 minutes advanced: 0.75, // 45 minutes supplementary: 0.17 // 10 minutes };
let totalHours = 0; Object.entries(categorizedQuestions).forEach(([category, questions]) => { const maxQuestions = category === 'supplementary' ? 10 : category === 'core' ? 8 : 5; const questionCount = Math.min(questions.length, maxQuestions); totalHours += questionCount * timeEstimates[category]; });
return Math.round(totalHours * 10) / 10; // Round to 1 decimal place}
const learningPath = await createLearningPathFromRelated(12345);
Related Questions Discovery Engine
Section titled “Related Questions Discovery Engine”async function createRelatedQuestionsEngine() { console.log('Creating related questions discovery engine...');
const discoveryCache = new Map<number, any>();
async function discoverRelatedQuestionsTree(rootQuestionId: number, depth: number = 2): Promise<any> { if (discoveryCache.has(rootQuestionId)) { return discoveryCache.get(rootQuestionId); }
try { const [rootQuestion, relatedQuestions] = await Promise.all([ sdk.questions.get(rootQuestionId), sdk.questions.getRelated(rootQuestionId, { pageSize: 50, sort: 'hot' }) ]);
const discoveryNode = { id: rootQuestion.id, title: rootQuestion.title, tags: rootQuestion.tags?.map(t => t.name) || [], score: rootQuestion.score, depth: 0, relatedQuestions: relatedQuestions.items.map(q => ({ id: q.id, title: q.title, score: q.score, relevance: calculateRelevanceScore(rootQuestion, q), tags: q.tags?.map(t => t.name) || [] })).sort((a, b) => b.relevance - a.relevance), branches: [] };
discoveryCache.set(rootQuestionId, discoveryNode);
// Explore branches if depth allows if (depth > 1) { const topRelated = relatedQuestions.items.slice(0, 3); // Limit to prevent explosion
for (const related of topRelated) { try { const branch = await discoverRelatedQuestionsTree(related.id, depth - 1); if (branch) { branch.depth = 1; discoveryNode.branches.push(branch); } } catch (error) { console.error(`Failed to explore branch ${related.id}:`, error.message); } } }
return discoveryNode; } catch (error) { console.error(`Discovery failed for question ${rootQuestionId}:`, error.message); return null; } }
async function findTopicClusters(questionIds: number[]): Promise<Record<string, any[]>> { const clusters: Record<string, any[]> = {};
for (const questionId of questionIds) { try { const relatedQuestions = await sdk.questions.getRelated(questionId, { pageSize: 30 });
relatedQuestions.items.forEach(question => { const tags = question.tags?.map(t => t.name) || [];
// Create cluster keys from tag combinations tags.slice(0, 2).forEach(tag => { if (!clusters[tag]) { clusters[tag] = []; }
if (!clusters[tag].find(q => q.id === question.id)) { clusters[tag].push({ id: question.id, title: question.title, score: question.score, tags: tags }); } }); }); } catch (error) { console.error(`Failed to cluster question ${questionId}:`, error.message); } }
// Filter clusters with meaningful size Object.keys(clusters).forEach(key => { if (clusters[key].length < 3) { delete clusters[key]; } else { // Sort by score within cluster clusters[key].sort((a, b) => b.score - a.score); } });
return clusters; }
async function generateDiscoveryReport(rootQuestionId: number): Promise<any> { console.log(`Generating discovery report for question ${rootQuestionId}...`);
const discoveryTree = await discoverRelatedQuestionsTree(rootQuestionId, 2);
if (!discoveryTree) { return null; }
const allDiscoveredQuestions = [ ...discoveryTree.relatedQuestions, ...discoveryTree.branches.flatMap(branch => branch.relatedQuestions || []) ];
// Remove duplicates const uniqueQuestions = allDiscoveredQuestions.filter((question, index, array) => array.findIndex(q => q.id === question.id) === index );
const report = { rootQuestion: { id: discoveryTree.id, title: discoveryTree.title, tags: discoveryTree.tags }, discovery: { totalDiscovered: uniqueQuestions.length, directRelated: discoveryTree.relatedQuestions.length, indirectRelated: uniqueQuestions.length - discoveryTree.relatedQuestions.length, branches: discoveryTree.branches.length }, quality: { highQuality: uniqueQuestions.filter(q => q.score >= 5).length, mediumQuality: uniqueQuestions.filter(q => q.score >= 1 && q.score < 5).length, lowQuality: uniqueQuestions.filter(q => q.score < 1).length }, topDiscoveries: uniqueQuestions .sort((a, b) => b.relevance - a.relevance) .slice(0, 10), topicDistribution: analyzeTopicDistribution(uniqueQuestions) };
console.log('\nDiscovery Report:'); console.log(`- Total questions discovered: ${report.discovery.totalDiscovered}`); console.log(`- Direct relationships: ${report.discovery.directRelated}`); console.log(`- Indirect relationships: ${report.discovery.indirectRelated}`); console.log(`- Exploration branches: ${report.discovery.branches}`);
console.log('\nTop Discoveries:'); report.topDiscoveries.forEach((q, index) => { console.log(`${index + 1}. ${q.title} (Relevance: ${q.relevance.toFixed(1)}, Score: ${q.score})`); });
return report; }
function analyzeTopicDistribution(questions: any[]): Record<string, number> { const topicCounts: Record<string, number> = {};
questions.forEach(question => { question.tags.forEach(tag => { topicCounts[tag] = (topicCounts[tag] || 0) + 1; }); });
return Object.fromEntries( Object.entries(topicCounts) .sort(([,a], [,b]) => b - a) .slice(0, 10) ); }
return { discoverRelatedQuestionsTree, findTopicClusters, generateDiscoveryReport };}
const discoveryEngine = await createRelatedQuestionsEngine();
// Generate comprehensive discovery reportconst discoveryReport = await discoveryEngine.generateDiscoveryReport(12345);
// Find topic clusters across multiple questionsconst topicClusters = await discoveryEngine.findTopicClusters([12345, 12346, 12347]);console.log('\nTopic Clusters:');Object.entries(topicClusters).forEach(([topic, questions]) => { console.log(`${topic}: ${questions.length} questions`);});
Team Context Related Questions
Section titled “Team Context Related Questions”// Team context related questionsconst teamSDK = sdk.forTeam('team-123');
async function exploreTeamRelatedQuestions(questionId: number) { try { console.log(`Exploring team-related questions for question ${questionId}...`);
const [teamQuestion, teamRelatedQuestions] = await Promise.all([ teamSDK.questions.get(questionId), teamSDK.questions.getRelated(questionId, { pageSize: 50, sort: 'hot' }) ]);
console.log(`Team Question: ${teamQuestion.title}`); console.log(`Team-related questions found: ${teamRelatedQuestions.totalCount}`);
if (teamRelatedQuestions.totalCount === 0) { console.log('No team-related questions found'); return null; }
// Analyze team-specific relationship patterns const teamAnalysis = { internalQuestions: teamRelatedQuestions.items.filter(q => q.tags?.some(tag => ['internal', 'team', 'company'].includes(tag.name.toLowerCase())) ), workflowRelated: teamRelatedQuestions.items.filter(q => q.tags?.some(tag => ['workflow', 'process', 'deployment', 'ci-cd'].includes(tag.name.toLowerCase())) ), toolsAndInfrastructure: teamRelatedQuestions.items.filter(q => q.tags?.some(tag => ['tools', 'infrastructure', 'devops', 'monitoring'].includes(tag.name.toLowerCase())) ), knowledgeSharing: teamRelatedQuestions.items.filter(q => q.tags?.some(tag => ['documentation', 'guide', 'best-practices', 'standards'].includes(tag.name.toLowerCase())) ), crossTeamInteractions: teamRelatedQuestions.items.filter(q => { // Questions that might involve multiple teams or external dependencies return q.tags?.some(tag => ['api', 'integration', 'external', 'collaboration'].includes(tag.name.toLowerCase())); }) };
console.log('\nTeam Related Questions Analysis:'); console.log(`- Internal questions: ${teamAnalysis.internalQuestions.length}`); console.log(`- Workflow related: ${teamAnalysis.workflowRelated.length}`); console.log(`- Tools & Infrastructure: ${teamAnalysis.toolsAndInfrastructure.length}`); console.log(`- Knowledge sharing: ${teamAnalysis.knowledgeSharing.length}`); console.log(`- Cross-team interactions: ${teamAnalysis.crossTeamInteractions.length}`);
// Show most relevant categories if (teamAnalysis.knowledgeSharing.length > 0) { console.log('\nKnowledge Sharing Opportunities:'); teamAnalysis.knowledgeSharing.slice(0, 3).forEach(q => { console.log(`- ${q.title} (Score: ${q.score})`); }); }
if (teamAnalysis.workflowRelated.length > 0) { console.log('\nWorkflow Related Questions:'); teamAnalysis.workflowRelated.slice(0, 3).forEach(q => { console.log(`- ${q.title} (Answers: ${q.answerCount})`); }); }
// Generate team-specific recommendations const teamRecommendations = [];
if (teamAnalysis.knowledgeSharing.length > 2) { teamRecommendations.push('Consider creating a knowledge base from these related questions'); }
if (teamAnalysis.workflowRelated.length > 3) { teamRecommendations.push('Multiple workflow questions suggest process documentation opportunities'); }
if (teamAnalysis.toolsAndInfrastructure.length > 0) { teamRecommendations.push('Infrastructure questions could benefit from standardized solutions'); }
console.log('\nTeam Recommendations:'); teamRecommendations.forEach(rec => console.log(`- ${rec}`));
return { teamQuestion, relatedQuestions: teamRelatedQuestions.items, analysis: teamAnalysis, recommendations: teamRecommendations }; } catch (error) { console.error('Team related questions exploration failed:', error.message); throw error; }}
const teamRelatedAnalysis = await exploreTeamRelatedQuestions(12345);
Related Questions Monitoring System
Section titled “Related Questions Monitoring System”async function createRelatedQuestionsMonitor(questionId: number, checkInterval: number = 300000) { console.log(`Starting related questions monitor for question ${questionId}`); console.log(`Check interval: ${checkInterval / 1000} seconds`);
let previousRelatedCount = 0; let previousTopRelated = [];
// Initial baseline try { const initialRelated = await sdk.questions.getRelated(questionId, { pageSize: 20 }); previousRelatedCount = initialRelated.totalCount; previousTopRelated = initialRelated.items.slice(0, 5);
console.log(`Initial baseline: ${previousRelatedCount} related questions`); } catch (error) { console.error('Failed to establish baseline:', error.message); return null; }
const monitor = setInterval(async () => { try { const currentRelated = await sdk.questions.getRelated(questionId, { pageSize: 20, sort: 'hot' });
const changes = [];
// Check for count changes if (currentRelated.totalCount !== previousRelatedCount) { const countChange = currentRelated.totalCount - previousRelatedCount; changes.push({ type: 'count_change', change: countChange, newTotal: currentRelated.totalCount, previousTotal: previousRelatedCount }); }
// Check for new top related questions const currentTopRelated = currentRelated.items.slice(0, 5); const newQuestions = currentTopRelated.filter(current => !previousTopRelated.some(prev => prev.id === current.id) );
if (newQuestions.length > 0) { changes.push({ type: 'new_top_related', newQuestions: newQuestions.map(q => ({ id: q.id, title: q.title, score: q.score })) }); }
// Check for score changes in existing top questions const scoreChanges = currentTopRelated .map(current => { const previous = previousTopRelated.find(prev => prev.id === current.id); if (previous && current.score !== previous.score) { return { id: current.id, title: current.title, previousScore: previous.score, currentScore: current.score, change: current.score - previous.score }; } return null; }) .filter(Boolean);
if (scoreChanges.length > 0) { changes.push({ type: 'score_changes', changes: scoreChanges }); }
if (changes.length > 0) { console.log(`\n[${new Date().toLocaleTimeString()}] Related questions changes detected:`);
changes.forEach(change => { switch (change.type) { case 'count_change': console.log(`- Total related questions: ${change.previousTotal} → ${change.newTotal} (${change.change > 0 ? '+' : ''}${change.change})`); break;
case 'new_top_related': console.log(`- New top related questions:`); change.newQuestions.forEach(q => { console.log(` • ${q.title} (Score: ${q.score})`); }); break;
case 'score_changes': console.log(`- Score changes in top related:`); change.changes.forEach(sc => { console.log(` • ${sc.title}: ${sc.previousScore} → ${sc.currentScore} (${sc.change > 0 ? '+' : ''}${sc.change})`); }); break; } }); }
// Update baseline previousRelatedCount = currentRelated.totalCount; previousTopRelated = currentTopRelated;
} catch (error) { console.error('Monitoring error:', error.message); } }, checkInterval);
// Return function to stop monitoring return () => { clearInterval(monitor); console.log(`Stopped monitoring related questions for question ${questionId}`); };}
// Start monitoring (checks every 5 minutes)const stopMonitoring = await createRelatedQuestionsMonitor(12345, 300000);
// Stop after 1 hoursetTimeout(() => { if (stopMonitoring) stopMonitoring();}, 3600000);
Error Handling
Section titled “Error Handling”This method can throw the following errors:
Error Type | Status Code | Description |
---|---|---|
AuthenticationError | 401 | Invalid or missing authentication token |
TokenExpiredError | 401 | Authentication token has expired |
ForbiddenError | 403 | Insufficient permissions to access related questions |
NotFoundError | 404 | Question with the specified ID does not exist |
SDKError | Various | Other API or network errors |
Example Error Handling
Section titled “Example Error Handling”import StackOverflowSDK, { NotFoundError, ForbiddenError, AuthenticationError } from 'so-teams-sdk';
const sdk = new StackOverflowSDK({ accessToken: 'your-access-token', baseUrl: 'https://[your-site].stackenterprise.co/api/v3'});
try { const relatedQuestions = await sdk.questions.getRelated(12345, { sort: 'hot', order: 'desc', pageSize: 25 });
console.log(`Found ${relatedQuestions.totalCount} related questions`);} catch (error) { if (error instanceof NotFoundError) { console.error('Question not found'); } else if (error instanceof ForbiddenError) { console.error('Access denied to related questions'); } else if (error instanceof AuthenticationError) { console.error('Authentication required'); } else { console.error('Failed to retrieve related questions:', error.message); }}
- Algorithmic Relationships: Related questions are determined by content analysis, not explicit links
- Dynamic Results: Related questions may change as the algorithm learns and content evolves
- Similarity Factors: Typically based on tags, content similarity, user behavior, and other signals
- Sort Options:
"hot"
combines recent activity with relevance; other options prioritize different factors - Content Discovery: Primary tool for discovering topically similar questions
- Learning Aid: Useful for understanding topic breadth and finding comprehensive coverage
- Quality Varies: Algorithmic relationships may include varying quality levels
- Complementary Tool: Works best alongside linked questions and search for complete discovery
- Performance Dependent: Results quality depends on platform’s recommendation algorithm sophistication