class_docstr: Processes source nodes before other nodes are joined.
  
  Generally, the source nodes will be combined with other dataflow plan nodes to produce a new set of nodes to realize
  a condition of the query. For example, to realize a time range constraint, a ConstrainTimeRangeNode will be added
  to the source nodes.
  
  e.g.
  
  <SomeDataflowPlanNode/>
  
  ->
  
  <ConstrainTimeRangeNode>
      <SomeDataflowPlanNode/>
  </ConstrainTimeRangeNode>
docstr: Filters out many of the nodes that can't possibly be useful for joins to obtain the desired linkable specs.
  
  A simple filter is to remove any nodes that don't share a common element with the query. Having a common element
  doesn't mean that the node will be useful, but not having common elements definitely means it's not useful.
docstr_tok: ["Filters","out","many","of","the","nodes","that","ca","n't","possibly","be","useful","for","joins","to","obtain","the","desired","linkable","specs",".","A","simple","filter","is","to","remove","any","nodes","that","do","n't","share","a","common","element","with","the","query",".","Having","a","common","element","does","n't","mean","that","the","node","will","be","useful",",","but","not","having","common","elements","definitely","means","it","'s","not","useful","."]
code: def remove_unnecessary_nodes(
      self,
      desired_linkable_specs: Sequence[LinkableInstanceSpec],
      nodes: Sequence[BaseOutput],
      metric_time_dimension_reference: TimeDimensionReference,
  ) -> Sequence[BaseOutput]:
      """Filters out many of the nodes that can't possibly be useful for joins to obtain the desired linkable specs.
  
      A simple filter is to remove any nodes that don't share a common element with the query. Having a common element
      doesn't mean that the node will be useful, but not having common elements definitely means it's not useful.
      """
      relevant_element_names = {
          x.element_name for x in desired_linkable_specs
      }.union(
          {
              y.element_name
              for x in desired_linkable_specs
              for y in x.entity_links
          }
      )
  
      # The metric time dimension is used everywhere, so don't count it unless specifically desired in linkable spec
      # that has entity links.
      metric_time_dimension_used_in_linked_spec = any(
          [
              len(linkable_spec.entity_links) > 0
              and linkable_spec.element_name
              == metric_time_dimension_reference.element_name
              for linkable_spec in desired_linkable_specs
          ]
      )
  
      if (
          metric_time_dimension_reference.element_name
          in relevant_element_names
          and not metric_time_dimension_used_in_linked_spec
      ):
          relevant_element_names.remove(
              metric_time_dimension_reference.element_name
          )
  
      logger.info(f"Relevant names are: {relevant_element_names}")
  
      relevant_nodes = []
  
      for node in nodes:
          data_set = self._node_data_set_resolver.get_output_data_set(
              node
          )
          element_names_in_data_set = ToElementNameSet().transform(
              data_set.instance_set.spec_set
          )
  
          if (
              len(
                  element_names_in_data_set.intersection(
                      relevant_element_names
                  )
              )
              > 0
          ):
              relevant_nodes.append(node)
  
      return relevant_nodes
  
imports: from __future__ import annotations
  import logging
  from dataclasses import dataclass
  from typing import List, Optional, Sequence, Set
  from dbt_semantic_interfaces.pretty_print import pformat_big_objects
  from dbt_semantic_interfaces.references import EntityReference, TimeDimensionReference
  from metricflow.dataflow.builder.node_data_set import DataflowPlanNodeOutputDataSetResolver
  from metricflow.dataflow.builder.partitions import PartitionJoinResolver
  from metricflow.dataflow.dataflow_plan import BaseOutput, ConstrainTimeRangeNode, FilterElementsNode, JoinDescription, JoinToBaseOutputNode
  from metricflow.filters.time_constraint import TimeRangeConstraint
  from metricflow.model.semantics.semantic_model_join_evaluator import MAX_JOIN_HOPS, SemanticModelJoinEvaluator
  from metricflow.protocols.semantics import SemanticModelAccessor
  from metricflow.specs.spec_set_transforms import ToElementNameSet
  from metricflow.specs.specs import InstanceSpecSet, LinkableInstanceSpec, LinklessEntitySpec
  from metricflow.sql.sql_plan import SqlJoinType
label_desc: Use image node_id 6 for calling the PreJoinNodeProcessor obj's underlying member method code with example usage: obj.remove_unnecessary_nodes(desired_linkable_specs, nodes, metric_time_dimension_reference) and returns: relevant_nodes